Repository navigation
Streaming tool_calls produce duplicate arguments chunks #361
Description
Description
When using stream: true with tool calling, OpenCodex emits duplicate function.arguments chunks. OpenAI-compatible clients that accumulate argument deltas end up with corrupted JSON (concatenated duplicates), making tool calling unusable in streaming mode.
stream: false works correctly — each tool call has exactly one clean arguments JSON string.
Version
opencodex 2.7.35 (latest as of 2026-07-24)
Reproduction
curl -s -N http://127.0.0.1:10100/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "cursor/composer-2.5",
"messages": [{"role": "user", "content": "Run ls /home/opc and read /home/opc/README.md. Do only tool calls, no text."}],
"tools": [
{"type": "function", "function": {"name": "shell", "parameters": {"type": "object", "properties": {"command": {"type": "string"}}, "required": ["command"]}}},
{"type": "function", "function": {"name": "read_file", "parameters": {"type": "object", "properties": {"path": {"type": "string"}}, "required": ["path"]}}}
],
"stream": true
}'Actual behavior (streaming — BROKEN)
Each tool call produces 3 SSE chunks instead of 2:
# Tool call 0 (shell):
Chunk 1: {"index":0,"id":"tool_xxx","function":{"name":"shell","arguments":""}}
Chunk 2: {"index":0,"function":{"arguments":"{\"command\":\"ls /home/opc\"}","name":"shell"}}
Chunk 3: {"index":0,"id":"tool_xxx","function":{"name":"shell","arguments":"{\"command\":\"ls /home/opc\"}"}} ← DUPLICATE
# Tool call 1 (read_file):
Chunk 4: {"index":1,"id":"tool_yyy","function":{"name":"read_file","arguments":""}}
Chunk 5: {"index":1,"function":{"arguments":"{\"path\":\"/home/opc/README.md\"}","name":"read_file"}}
Chunk 6: {"index":1,"id":"tool_yyy","function":{"name":"read_file","arguments":"{\"path\":\"/home/opc/README.md\"}"}} ← DUPLICATE
Chunks 3 and 6 are duplicates — they repeat the full arguments already delivered in chunks 2 and 5, but wrapped in the complete tool_call object (with id field).
Downstream clients that follow the OpenAI streaming spec (accumulate function.arguments deltas) end up with:
{"command":"ls /home/opc"}{"command":"ls /home/opc"} ← corrupt JSON
This causes "Unrepairable tool_call arguments" errors in agents like Hermes.
Expected behavior (non-streaming — WORKS)
{
"tool_calls": [
{
"id": "tool_0dc837b1-...",
"type": "function",
"function": {
"name": "shell",
"arguments": "{\"command\":\"ls /home/opc\"}"
}
},
{
"id": "tool_9bbfae2a-...",
"type": "function",
"function": {
"name": "read_file",
"arguments": "{\"path\":\"/home/opc/README.md\"}"
}
}
]
}Each arguments appears exactly once. ✅
Impact
Severity: Medium — affects any OpenAI-compatible client that accumulates function.arguments deltas in streaming mode. The workaround is to force stream: false.
Additional context
- Cursor models affected:
cursor/composer-2.5,cursor/composer-2.5-fast,cursor/auto - Likely all Cursor models that support tool calling
- Non-streaming path is fine — the bug appears specific to the SSE streaming adapter
Activity