mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
Python's json.dumps() defaults to ensure_ascii=True, escaping non-ASCII characters to \uXXXX sequences. For CJK characters this inflates token count 3-4x — a single Chinese character like '中' becomes '\u4e2d' (6 chars vs 3 bytes, ~6 tokens vs ~1 token). Since MCP tool results feed directly into the model's conversation context, this silently multiplied API costs for Chinese, Japanese, and Korean users. Fix: add ensure_ascii=False to all 20 json.dumps calls in mcp_tool.py. Raw UTF-8 is valid JSON per RFC 8259 and all downstream consumers (LLM APIs, display) handle it correctly. Closes #10234
This commit is contained in:
parent
19142810ed
commit
861efe274b
1 changed files with 20 additions and 20 deletions
|
|
@ -506,7 +506,7 @@ class SamplingHandler:
|
|||
"type": "function",
|
||||
"function": {
|
||||
"name": tu.name,
|
||||
"arguments": json.dumps(tu.input) if isinstance(tu.input, dict) else str(tu.input),
|
||||
"arguments": json.dumps(tu.input, ensure_ascii=False) if isinstance(tu.input, dict) else str(tu.input),
|
||||
},
|
||||
})
|
||||
msg_dict: dict = {"role": msg.role, "tool_calls": tc_list}
|
||||
|
|
@ -1274,7 +1274,7 @@ def _interrupted_call_result() -> str:
|
|||
"""Standardized JSON error for a user-interrupted MCP tool call."""
|
||||
return json.dumps({
|
||||
"error": "MCP call interrupted: user sent a new message"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -1361,7 +1361,7 @@ def _make_tool_handler(server_name: str, tool_name: str, tool_timeout: float):
|
|||
if not server or not server.session:
|
||||
return json.dumps({
|
||||
"error": f"MCP server '{server_name}' is not connected"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
async def _call():
|
||||
result = await server.session.call_tool(tool_name, arguments=args)
|
||||
|
|
@ -1375,7 +1375,7 @@ def _make_tool_handler(server_name: str, tool_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
error_text or "MCP tool returned an error"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
# Collect text from content blocks
|
||||
parts: List[str] = []
|
||||
|
|
@ -1394,9 +1394,9 @@ def _make_tool_handler(server_name: str, tool_name: str, tool_timeout: float):
|
|||
return json.dumps({
|
||||
"result": text_result,
|
||||
"structuredContent": structured,
|
||||
})
|
||||
return json.dumps({"result": structured})
|
||||
return json.dumps({"result": text_result})
|
||||
}, ensure_ascii=False)
|
||||
return json.dumps({"result": structured}, ensure_ascii=False)
|
||||
return json.dumps({"result": text_result}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
return _run_on_mcp_loop(_call(), timeout=tool_timeout)
|
||||
|
|
@ -1411,7 +1411,7 @@ def _make_tool_handler(server_name: str, tool_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
f"MCP call failed: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
return _handler
|
||||
|
||||
|
|
@ -1425,7 +1425,7 @@ def _make_list_resources_handler(server_name: str, tool_timeout: float):
|
|||
if not server or not server.session:
|
||||
return json.dumps({
|
||||
"error": f"MCP server '{server_name}' is not connected"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
async def _call():
|
||||
result = await server.session.list_resources()
|
||||
|
|
@ -1441,7 +1441,7 @@ def _make_list_resources_handler(server_name: str, tool_timeout: float):
|
|||
if hasattr(r, "mimeType") and r.mimeType:
|
||||
entry["mimeType"] = r.mimeType
|
||||
resources.append(entry)
|
||||
return json.dumps({"resources": resources})
|
||||
return json.dumps({"resources": resources}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
return _run_on_mcp_loop(_call(), timeout=tool_timeout)
|
||||
|
|
@ -1455,7 +1455,7 @@ def _make_list_resources_handler(server_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
f"MCP call failed: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
return _handler
|
||||
|
||||
|
|
@ -1471,7 +1471,7 @@ def _make_read_resource_handler(server_name: str, tool_timeout: float):
|
|||
if not server or not server.session:
|
||||
return json.dumps({
|
||||
"error": f"MCP server '{server_name}' is not connected"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
uri = args.get("uri")
|
||||
if not uri:
|
||||
|
|
@ -1487,7 +1487,7 @@ def _make_read_resource_handler(server_name: str, tool_timeout: float):
|
|||
parts.append(block.text)
|
||||
elif hasattr(block, "blob"):
|
||||
parts.append(f"[binary data, {len(block.blob)} bytes]")
|
||||
return json.dumps({"result": "\n".join(parts) if parts else ""})
|
||||
return json.dumps({"result": "\n".join(parts) if parts else ""}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
return _run_on_mcp_loop(_call(), timeout=tool_timeout)
|
||||
|
|
@ -1501,7 +1501,7 @@ def _make_read_resource_handler(server_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
f"MCP call failed: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
return _handler
|
||||
|
||||
|
|
@ -1515,7 +1515,7 @@ def _make_list_prompts_handler(server_name: str, tool_timeout: float):
|
|||
if not server or not server.session:
|
||||
return json.dumps({
|
||||
"error": f"MCP server '{server_name}' is not connected"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
async def _call():
|
||||
result = await server.session.list_prompts()
|
||||
|
|
@ -1536,7 +1536,7 @@ def _make_list_prompts_handler(server_name: str, tool_timeout: float):
|
|||
for a in p.arguments
|
||||
]
|
||||
prompts.append(entry)
|
||||
return json.dumps({"prompts": prompts})
|
||||
return json.dumps({"prompts": prompts}, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
return _run_on_mcp_loop(_call(), timeout=tool_timeout)
|
||||
|
|
@ -1550,7 +1550,7 @@ def _make_list_prompts_handler(server_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
f"MCP call failed: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
return _handler
|
||||
|
||||
|
|
@ -1566,7 +1566,7 @@ def _make_get_prompt_handler(server_name: str, tool_timeout: float):
|
|||
if not server or not server.session:
|
||||
return json.dumps({
|
||||
"error": f"MCP server '{server_name}' is not connected"
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
name = args.get("name")
|
||||
if not name:
|
||||
|
|
@ -1593,7 +1593,7 @@ def _make_get_prompt_handler(server_name: str, tool_timeout: float):
|
|||
resp = {"messages": messages}
|
||||
if hasattr(result, "description") and result.description:
|
||||
resp["description"] = result.description
|
||||
return json.dumps(resp)
|
||||
return json.dumps(resp, ensure_ascii=False)
|
||||
|
||||
try:
|
||||
return _run_on_mcp_loop(_call(), timeout=tool_timeout)
|
||||
|
|
@ -1607,7 +1607,7 @@ def _make_get_prompt_handler(server_name: str, tool_timeout: float):
|
|||
"error": _sanitize_error(
|
||||
f"MCP call failed: {type(exc).__name__}: {exc}"
|
||||
)
|
||||
})
|
||||
}, ensure_ascii=False)
|
||||
|
||||
return _handler
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue