Repository navigation
[Provider] OpenCode Free DeepSeek V4 Flash streams object-valued function.name #1824
Description
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-freeusingopenai-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.nameis 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.functioninto the common chunk without validatingfunction.name; toOaCompatibleChunk()copiestc.functionback 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
- The provider compatibility defect is tracked with reproducible structural evidence.
- OpenCodex continues to reject object-valued function names without guessing executable intent.
- Safe compatibility classification can be inspected without enabling raw-payload logging.
- No prompt, arguments, reasoning content, or raw upstream tool-call payload is persisted for this diagnostic.
- A provider-side workaround is added only if the exact malformed shape can be normalized deterministically and safely.
- Existing fix(openai-chat): refuse to emit an unnamed streamed tool call #1531 named/late-name/blank-name/fail-closed regressions remain green.
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
- Existing OpenCodex issues and prior DeepSeek/OpenCode tool-call work were searched.
- Existing upstream OpenCode issues were searched for this exact response-side object-valued-name shape.
- Secrets, identifiers, prompt content, tool arguments, and personal data are excluded.
Activity
coderabbitai commentedon Aug 16, 2026
🔗 Related PRs
#588 - fix(openai-responses): round-trip image-gen namespace [merged]
#1479 - fix(deepseek): preserve parallel reasoning replay [open]
#1499 - fix(deepseek): keep parallel reasoning replay on continuation [open]
#1530 - fix(openai-chat): log redacted invalid tool-call shape [merged]
#1531 - fix(openai-chat): refuse to emit an unnamed streamed tool call [merged]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
lidge-jun commentedon Aug 16, 2026
Closing the OpenCodex-side scope via #1825 (merged to
devas 82f4563).OpenCodex continues to reject object-valued function names without guessing executable intent. What changed:
502/upstream_errorinstead of a misleading client-side failure;This is a mitigation and diagnostics improvement. It does not normalize the provider payload and does not claim the OpenCode Free / DeepSeek upstream defect is fixed; adding
provider-compatibilityso the remaining upstream-side issue stays discoverable.The fix is on
dev. It ships with the next release.