Skip to content

[Bug]: deepseek-v4-flash-free can emit incomplete tool calls that break streamed turns #1514

Description

@yxr1995-maker

Current status

This issue is now narrowed to the remaining OpenCode Zen / DeepSeek streaming compatibility defect.

The startup syntax crash reported against 2.12.0 is already resolved on current dev: the invalid continue outside a loop is no longer present. That part should not be reimplemented.

Current dev also already accepts [DONE] without a finish_reason: the [DONE] branch flushes pending tool calls and emits done. A raw EOF with neither [DONE] nor finish_reason remains a truncation condition and should stay fail-closed unless provider evidence proves a safe alternative.

Remaining defect

openai-chat can still flush a pending tool call with an empty function name.

Current flushToolCalls() emits:

yield { type: "tool_call_start", id: call.id, name: call.name };

without first proving that call.name is non-empty.

The affected OpenCode Zen route can stream argument deltas while omitting the matching function.name. When that incomplete call is flushed, the downstream Codex tool-call contract receives an unusable call and the turn can fail.

This issue now tracks only the provider-compatibility question around incomplete streamed tool-call metadata.

Reproduction

  1. Route Codex through opencode-free/deepseek-v4-flash-free using the openai-chat adapter.
  2. Run a turn that causes the upstream to emit tool-call argument deltas without a usable function.name.
  3. Allow the stream to reach a normal flush boundary such as [DONE].
  4. Observe the pending call being emitted with an empty name and the downstream turn failing.

Expected behavior

OpenCodex must not emit a completed usable tool call with an empty name.

A fix must preserve the existing fail-closed rules for genuinely malformed or truncated tool calls. In particular:

Resolved portion

The 2.12.0 startup failure:

Cannot use "continue" here

is no longer present on current dev and is closed as part of this issue's history.

Related

Acceptance criteria

  • A pending streamed tool call with no usable function name is never emitted as a valid completed tool call.
  • Normal named tool calls remain unchanged.
  • [DONE] without finish_reason remains accepted.
  • Raw EOF without a terminal signal remains fail-closed unless separately proven safe.
  • Malformed nested tool_calls shapes remain fail-closed.
  • Focused regression coverage reproduces the OpenCode Zen incomplete-name shape without weakening generic tool-call safety.

Activity

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 workingcliCLI, config inject, packaging flagsproviderProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportsstreamingSSE, WebSocket, terminal stream framestoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions