Client or integration
Codex App through OpenCodex Responses proxy
Area
Provider adapter / provider compatibility / tool calling / streaming
Summary
opencode-free/deepseek-v4-flash-free can return a streaming Chat Completions tool call where tool_calls[0].function.name is a JSON object instead of a string.
OpenCodex current dev correctly rejects this malformed upstream response through the openai-chat fail-closed validation added by #1531, producing:
upstream response contained invalid tool calls
The privacy-safe provider diagnostic identifies the exact structural failure:
{
"mode": "stream",
"reason": "tool_call_function_name_invalid",
"callIndex": 0,
"valueType": "object"
}
This reproduced twice against an identical request shape, so it is not being tracked as a one-off malformed generation.
Reproduction
- Route a tool-enabled Codex turn through
opencode-free/deepseek-v4-flash-free using openai-chat.
- The request contains 3 normal OpenAI-compatible function tools.
- Let DeepSeek select a tool.
- Observe the returned stream fail validation because
delta.tool_calls[0].function.name is an object.
- Retry the same request shape.
Observed twice:
messageCount=5
toolCount=3
bodyBytes=94379
-> tool_call_function_name_invalid, callIndex=0, valueType=object
The subsequent conversation state produced a different request shape (messageCount=6, bodyBytes=95110).
No prompt, tool arguments, credentials, request IDs, conversation IDs, or raw tool-call payload are included here.
Why this is distinct from #1514 / #1531
#1514 tracked OpenCode Zen / DeepSeek omitting a usable streamed function name. #1531 fixed the OpenCodex-side safety defect: incomplete or non-string names are now rejected at ingest/flush instead of being emitted or throwing.
That local invariant is working here. The new evidence is that the provider still emits an OpenAI-incompatible response shape, specifically an object-valued function.name.
The fix must not revert #1531 or coerce the object into executable intent.
Investigation / root-cause boundary
Current OpenCode source shows:
- the Zen OpenAI-compatible streaming converter copies
toolCall.function into the common chunk without validating function.name;
toOaCompatibleChunk() copies tc.function back onto the OpenAI-compatible wire;
- the Zen handler passes same-format provider streams through directly.
OpenCode also has existing DeepSeek V4 DSML/tool-call compatibility reports (#24566, #34676 in anomalyco/opencode). This reproduction is narrower: the hosted Zen Chat Completions response reaches the client with a structurally invalid object-valued function name.
An attempted issue creation in anomalyco/opencode from the connected GitHub App was rejected with 403 Resource not accessible by integration, so this OpenCodex issue records the evidence and upstream boundary.
Expected behavior
OpenCodex should continue to fail closed when the provider gives an untrustworthy function name. It must not:
- stringify the object;
- select an arbitrary property as the tool name;
- invent a name from the declared catalog;
- log raw tool-call arguments or request content.
If a semantically safe upstream normalization is later proven from an exact provider wire contract, it can be considered separately.
OpenCodex follow-up
The structural reason currently exists only in provider debug output. A separate OpenCodex change should expose the existing safe classification in the normal structured request log / dashboard error details, for example:
{
"reason": "tool_call_function_name_invalid",
"callIndex": 0,
"valueType": "object"
}
without storing raw tool-call payloads.
Also review the HTTP/error classification: this is malformed upstream output, so presenting it as a client-side 400 Bad request is misleading. A 5xx upstream/protocol classification may be more accurate if it can be changed without breaking established adapter contracts.
Acceptance criteria
Version
Observed 2026-08-16 on the current OpenCodex provider path; current dev already contains #1531.
Operating system
Provider-side / OS-independent.
Provider and model
opencode-free/deepseek-v4-flash-free, openai-chat, https://opencode.ai/zen/v1/chat/completions.
Checks
Client or integration
Codex App through OpenCodex Responses proxy
Area
Provider adapter / provider compatibility / tool calling / streaming
Summary
opencode-free/deepseek-v4-flash-freecan return a streaming Chat Completions tool call wheretool_calls[0].function.nameis a JSON object instead of a string.OpenCodex current
devcorrectly rejects this malformed upstream response through theopenai-chatfail-closed validation added by #1531, producing:The privacy-safe provider diagnostic identifies the exact structural failure:
{ "mode": "stream", "reason": "tool_call_function_name_invalid", "callIndex": 0, "valueType": "object" }This reproduced twice against an identical request shape, so it is not being tracked as a one-off malformed generation.
Reproduction
opencode-free/deepseek-v4-flash-freeusingopenai-chat.delta.tool_calls[0].function.nameis an object.Observed twice:
The subsequent conversation state produced a different request shape (
messageCount=6,bodyBytes=95110).No prompt, tool arguments, credentials, request IDs, conversation IDs, or raw tool-call payload are included here.
Why this is distinct from #1514 / #1531
#1514 tracked OpenCode Zen / DeepSeek omitting a usable streamed function name. #1531 fixed the OpenCodex-side safety defect: incomplete or non-string names are now rejected at ingest/flush instead of being emitted or throwing.
That local invariant is working here. The new evidence is that the provider still emits an OpenAI-incompatible response shape, specifically an object-valued
function.name.The fix must not revert #1531 or coerce the object into executable intent.
Investigation / root-cause boundary
Current OpenCode source shows:
toolCall.functioninto the common chunk without validatingfunction.name;toOaCompatibleChunk()copiestc.functionback onto the OpenAI-compatible wire;OpenCode also has existing DeepSeek V4 DSML/tool-call compatibility reports (#24566, #34676 in
anomalyco/opencode). This reproduction is narrower: the hosted Zen Chat Completions response reaches the client with a structurally invalid object-valued function name.An attempted issue creation in
anomalyco/opencodefrom the connected GitHub App was rejected with403 Resource not accessible by integration, so this OpenCodex issue records the evidence and upstream boundary.Expected behavior
OpenCodex should continue to fail closed when the provider gives an untrustworthy function name. It must not:
If a semantically safe upstream normalization is later proven from an exact provider wire contract, it can be considered separately.
OpenCodex follow-up
The structural reason currently exists only in provider debug output. A separate OpenCodex change should expose the existing safe classification in the normal structured request log / dashboard error details, for example:
{ "reason": "tool_call_function_name_invalid", "callIndex": 0, "valueType": "object" }without storing raw tool-call payloads.
Also review the HTTP/error classification: this is malformed upstream output, so presenting it as a client-side
400 Bad requestis misleading. A 5xx upstream/protocol classification may be more accurate if it can be changed without breaking established adapter contracts.Acceptance criteria
Version
Observed 2026-08-16 on the current OpenCodex provider path; current
devalready contains #1531.Operating system
Provider-side / OS-independent.
Provider and model
opencode-free/deepseek-v4-flash-free,openai-chat,https://opencode.ai/zen/v1/chat/completions.Checks