Skip to content

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

Closed

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.

Activity

  1. coderabbitai commented on Aug 16, 2026

    @coderabbitai
    Contributor
    🔗 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 plan command to generate an implementation plan and prompts that you can use with your favorite coding assistant.

    • Create Plan

    🧪 Issue enrichment is currently in open beta.

    To disable automatic issue enrichment, add the following to your .coderabbit.yaml:

    issue_enrichment:
      auto_enrich:
        enabled: false

    💬 Have feedback or questions? Drop into our discord!

  2. added
    bugSomething isn't working
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    toolstool_calls, MCP, web-search / sidecar tools
    on Aug 16, 2026
  3. lidge-jun commented on Aug 16, 2026

    @lidge-jun
    Owner

    Closing the OpenCodex-side scope via #1825 (merged to dev as 82f4563).

    OpenCodex continues to reject object-valued function names without guessing executable intent. What changed:

    • the malformed provider response is now classified as 502 / upstream_error instead of a misleading client-side failure;
    • the error message carries only bounded, value-free diagnostics (reason, call index, value type);
    • optional debug fingerprints expose structural shape only — allowlisted keys and their types, never nested values, arguments, or call IDs — and are gated behind debug mode.

    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-compatibility so the remaining upstream-side issue stays discoverable.

    The fix is on dev. It ships with the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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