Skip to content

[Provider] OpenCode Free DeepSeek V4 Flash streams object-valued function.name #1824

Description

@Wibias

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

  1. Route a tool-enabled Codex turn through opencode-free/deepseek-v4-flash-free using openai-chat.
  2. The request contains 3 normal OpenAI-compatible function tools.
  3. Let DeepSeek select a tool.
  4. Observe the returned stream fail validation because delta.tool_calls[0].function.name is an object.
  5. 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

  • 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions