File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -386,7 +386,7 @@ def _build_task_input_user_content(
386386 try :
387387 import json as _json
388388
389- text = _json .dumps (dict (fc .args ))
389+ text = _json .dumps (dict (fc .args ), ensure_ascii = False )
390390 except (TypeError , ValueError ):
391391 text = str (fc .args )
392392 parts = [types .Part (text = text )]
Original file line number Diff line number Diff line change @@ -64,7 +64,7 @@ def to_user_content(value: Any) -> types.Content:
6464 deep-copied)
6565 - str -> single text part
6666 - BaseModel -> model_dump_json() text part
67- - dict/list -> json.dumps() text part
67+ - dict/list -> json.dumps() text part (non-ASCII preserved, not escaped)
6868 - anything else -> str() text part
6969 """
7070 if isinstance (value , types .Content ):
@@ -74,7 +74,7 @@ def to_user_content(value: Any) -> types.Content:
7474 elif isinstance (value , BaseModel ):
7575 text = value .model_dump_json ()
7676 elif isinstance (value , (dict , list )):
77- text = json .dumps (value )
77+ text = json .dumps (value , ensure_ascii = False )
7878 else :
7979 text = str (value )
8080 return types .Content (role = 'user' , parts = [types .Part (text = text )])
Original file line number Diff line number Diff line change @@ -1894,3 +1894,41 @@ def test_recover_compacted_parallel_call_reinjects_sibling_response():
18941894 if part .function_response
18951895 }
18961896 assert response_ids == {"lr-1" , "reg-1" }
1897+
1898+
1899+ def test_task_input_user_content_preserves_non_ascii ():
1900+ """Delegated task input must not escape non-ASCII FC args (issue #6279).
1901+
1902+ A chat coordinator delegates to a task sub-agent via a function call; the
1903+ task agent's first user turn is rebuilt from the FC args. Escaping non-Latin
1904+ characters to ``\\ uXXXX`` there bloats prompt tokens and degrades responses.
1905+ """
1906+ fc_id = "fc_task_1"
1907+ events = [
1908+ Event (
1909+ invocation_id = "inv1" ,
1910+ author = "coordinator" ,
1911+ content = types .Content (
1912+ role = "model" ,
1913+ parts = [
1914+ types .Part (
1915+ function_call = types .FunctionCall (
1916+ id = fc_id ,
1917+ name = "delegate" ,
1918+ args = {"query" : "שלום עולם" , "city" : "北京" },
1919+ )
1920+ )
1921+ ],
1922+ ),
1923+ ),
1924+ ]
1925+
1926+ content = contents ._build_task_input_user_content ( # pylint: disable=protected-access
1927+ events , isolation_scope = fc_id
1928+ )
1929+
1930+ assert content is not None and content .parts
1931+ text = content .parts [0 ].text
1932+ assert "שלום עולם" in text
1933+ assert "北京" in text
1934+ assert "\\ u" not in text
Original file line number Diff line number Diff line change @@ -66,3 +66,25 @@ def test_to_user_content_other_input_is_str():
6666 content = to_user_content (42 )
6767 assert content .role == 'user'
6868 assert content .parts [0 ].text == '42'
69+
70+
71+ def test_to_user_content_dict_input_preserves_non_ascii ():
72+ """Non-ASCII input must reach the LLM as-is, not as \\ uXXXX escapes.
73+
74+ Escaping (json.dumps' default ensure_ascii=True) turns each non-Latin
75+ character into a ``\\ uXXXX`` sequence, which bloats prompt tokens and
76+ degrades model responses for non-English inputs (issue #6279).
77+ """
78+ content = to_user_content ({'query' : 'שלום עולם' , 'city' : '北京' })
79+ text = content .parts [0 ].text
80+ assert 'שלום עולם' in text
81+ assert '北京' in text
82+ assert '\\ u' not in text
83+
84+
85+ def test_to_user_content_list_input_preserves_non_ascii ():
86+ content = to_user_content (['שלום' , '你好' ])
87+ text = content .parts [0 ].text
88+ assert 'שלום' in text
89+ assert '你好' in text
90+ assert '\\ u' not in text
You can’t perform that action at this time.
0 commit comments