You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have updated to the latest minor and patch version of Strands
I have checked the documentation and this is not expected behavior
I have searched ./issues and there are no duplicates of my issue
SDK Language
Python
Strands Version
1.41.0 (also reproduces on main)
Language Runtime Version
Python 3.11.11
Operating System
macOS (Darwin 25.5.0)
Installation Method
pip
Steps to Reproduce
Provider request formatting serializes tool-result {"json": ...} content blocks and tool-call arguments with json.dumps(...), which defaults to ensure_ascii=True and escapes non-ASCII (CJK, emoji) to \uXXXX in the request sent to the model. This is the provider-side counterpart to #2636 — that issue's @tool decorator path was fixed by #2653, but the provider request-formatting paths were not.
Minimal reproduction using the actual provider format functions (no network / API key needed):
fromstrands.models.anthropicimportAnthropicModelfromstrands.models.openaiimportOpenAIModeltool_result= {"toolUseId": "c1", "status": "success", "content": [{"json": {"city": "東京"}}]}
tool_use= {"toolUseId": "c1", "name": "search", "input": {"query": "東京"}}
anthropic=AnthropicModel(client_args={"api_key": "x"}, model_id="claude-sonnet-4-5", max_tokens=8)
# Path A — tool-result {"json": ...} block (this string is sent to the model)print(OpenAIModel.format_request_tool_message(tool_result)["content"])
print(anthropic._format_request_message_content({"toolResult": tool_result})["content"][0]["text"])
# Path B — tool-call arguments (OpenAI-family)print(OpenAIModel.format_request_message_tool_call(tool_use)["function"]["arguments"])
Output:
{"city": "東京"}
{"city": "東京"}
{"query": "東京"}
Expected Behavior
Non-ASCII text is preserved in the request, e.g. {"city": "東京"} — matching what the SDK already does in telemetry/tracer.py and the session managers.
Actual Behavior
Non-ASCII is \uXXXX-escaped in the request sent to the model. For CJK / non-Latin scripts this inflates token usage (and cost) and hurts readability/debuggability.
This is hit by mainstream usage — e.g. agent-as-a-tool / multi-agent structured output (agent/_agent_as_tool.py emits a {"json": result.structured_output.model_dump()} content block), and the context-offloader plugin.
The repo already uses ensure_ascii=False in telemetry/tracer.py and the session managers, and tests/strands/telemetry/test_tracer.py::test_serialize_non_ascii_characters locks in "non-ASCII is preserved (no \u)" as intended behavior.
The TypeScript SDK is unaffected (JSON.stringify does not escape non-ASCII). This is Python-specific.
Possible Solution
Add ensure_ascii=False to the json.dumps(...) calls on the model-visible paths above. I have a PR ready.
Related Issues
Follow-up to #2636. Complements #2653 (decorator path).
Checks
SDK Language
Python
Strands Version
1.41.0 (also reproduces on
main)Language Runtime Version
Python 3.11.11
Operating System
macOS (Darwin 25.5.0)
Installation Method
pip
Steps to Reproduce
Provider request formatting serializes tool-result
{"json": ...}content blocks and tool-call arguments withjson.dumps(...), which defaults toensure_ascii=Trueand escapes non-ASCII (CJK, emoji) to\uXXXXin the request sent to the model. This is the provider-side counterpart to #2636 — that issue's@tooldecorator path was fixed by #2653, but the provider request-formatting paths were not.Minimal reproduction using the actual provider format functions (no network / API key needed):
Output:
Expected Behavior
Non-ASCII text is preserved in the request, e.g.
{"city": "東京"}— matching what the SDK already does intelemetry/tracer.pyand the session managers.Actual Behavior
Non-ASCII is
\uXXXX-escaped in the request sent to the model. For CJK / non-Latin scripts this inflates token usage (and cost) and hurts readability/debuggability.This is hit by mainstream usage — e.g. agent-as-a-tool / multi-agent structured output (
agent/_agent_as_tool.pyemits a{"json": result.structured_output.model_dump()}content block), and the context-offloader plugin.Additional Context
Affected request-formatting paths (model-visible):
{"json": ...}blocks (Anthropic + OpenAI-family):anthropic.py,openai.py,openai_responses.py,writer.py,llamacpp.py,llamaapi.py,mistral.py,ollama.py,sagemaker.pyopenai.py,openai_responses.py,writer.py,llamacpp.py,llamaapi.py,mistral.pyNot affected / intentionally out of scope:
json.dumps), so they are unaffected.gemini.py,ollama.py,bedrock.py) round-trip throughjson.loadsin the event loop, so escaping there is a no-op.json.dumpscalls (sagemaker.pylogs,model.pyheuristic).Precedent / consistency:
ensure_ascii=Falsetotelemetry/tracer.py.ensure_ascii=Falseintelemetry/tracer.pyand the session managers, andtests/strands/telemetry/test_tracer.py::test_serialize_non_ascii_characterslocks in "non-ASCII is preserved (no\u)" as intended behavior.JSON.stringifydoes not escape non-ASCII). This is Python-specific.Possible Solution
Add
ensure_ascii=Falseto thejson.dumps(...)calls on the model-visible paths above. I have a PR ready.Related Issues
Follow-up to #2636. Complements #2653 (decorator path).