Skip to content

[Bug] DeepSeek CodeModeOnly: unsupported top-level apply_patch call aborts #1544

Closed

Description

@c3right

Client or integration

Codex App

Provider or upstream service

DeepSeek (deepseek/deepseek-v4-flash)

OpenCodex version

2.13.0

Endpoint or capability

Routed Responses / CodeModeOnly tool calls / file editing

Current behaviour

In a fresh Codex App conversation routed through OpenCodex to DeepSeek V4 Flash, the model can emit a top-level apply_patch call even though apply_patch is not present in the top-level tool schema for the request.

That call fails with only:

aborted

In the same conversation, patching works through the intended Code Mode path:

exec -> tools.apply_patch(...) -> {}

The file is created, verified, and deleted successfully.

The exposed top-level tools reported for the request include exec, wait, request_user_input, search, and related tools, but not apply_patch.

Expected behaviour

For routed code_mode_only models, tool guidance and accepted tool calls should match the tool schema actually exposed to the model.

If patching is available only through Code Mode, the model should use:

exec -> tools.apply_patch(...)

OpenCodex should not encourage or restore an undeclared top-level apply_patch call. If such a call is nevertheless received, it should produce an actionable compatibility error rather than a bare aborted result.

Minimal redacted request or reproduction

Client: Codex App
OpenCodex: 2.13.0
Provider/model: DeepSeek / deepseek-v4-flash
Conversation: fresh

1. Direct path
   tool: apply_patch
   result: aborted

2. Code Mode path in the same conversation
   tool: exec
   inner tool: tools.apply_patch
   result: {}
   file created, verified, deleted

3. Tool surface
   top-level apply_patch: absent

The direct failure was reproduced in another fresh DeepSeek conversation.

Actual response or error

apply_patch -> aborted
exec -> tools.apply_patch(...) -> {}

There is no patch syntax or filesystem error on the failed path. The nested Code Mode path works in the same environment.

Upstream documentation

DeepSeek Tool Calls documentation:
https://api-docs.deepseek.com/guides/tool_calls

Possibly related upstream Codex issue:
openai/codex#30648

Relevant OpenCodex Code Mode work:
#1361

Suggested mapping or implementation notes

The working nested path strongly suggests the patch runtime itself is healthy. The likely failure is a mismatch between the routed CodeModeOnly tool contract and a direct apply_patch call being generated or restored somewhere in the request/response path.

Please inspect:

  1. CodeModeOnly instructions/guidance for references to direct apply_patch when that tool is not exposed.
  2. DeepSeek Responses conversion/restoration for legacy or undeclared custom-tool calls.
  3. Whether undeclared top-level patch calls should be rejected with a clear diagnostic or mapped to the supported Code Mode path.

Additional context

Controls:

Checks

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on the concrete tool contract and the working exec -> tools.apply_patch control.

Activity

  1. added
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    toolstool_calls, MCP, web-search / sidecar tools
    on Aug 12, 2026
  2. github-actions commented on Aug 12, 2026

    @github-actions
    Contributor

    Issue reopened

    The report now contains the information required by the automated check. Thanks for updating it.

  3. changed the title [-][DeepSeek][CodeModeOnly] undeclared top-level apply_patch call aborts while exec → tools.apply_patch succeeds[/-] [+]DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/+] on Aug 13, 2026
  4. changed the title [-]DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/-] [+][Bug] DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/+] on Aug 13, 2026
  5. Ingwannu commented on Aug 13, 2026

    @Ingwannu
    Owner

    Confirmed against current dev: the patch runtime is healthy, and the failing boundary is the undeclared top-level call. The inbound request does not declare apply_patch, so it is absent from freeformToolNames; when the routed model nevertheless emits that name, the bridge currently serializes it as an ordinary function_call. Codex has no matching declared function and surfaces only the unhelpful aborted result. The existing non-OpenAI catalog nudge already tells the model that apply_patch is unavailable, so this is an output-contract enforcement gap rather than a missing prompt alone.

    I will fix this conservatively: keep exec -> tools.apply_patch(...) as the only supported Code Mode path, validate every returned client-tool name against the request-visible catalog at the bridge boundary, and fail closed with an explicit compatibility error when a routed provider emits an undeclared name. I will not auto-convert an undeclared apply_patch call into Code Mode, because that would invent executable caller intent and arguments after generation. The patch will include streaming and non-streaming regressions and document the declared-tool membership invariant; it will target dev.

  6. Ingwannu commented on Aug 13, 2026

    @Ingwannu
    Owner

    The fail-closed contract fix is now in PR #1576 at exact head b2c33e96b. It retains the request-visible tool names, rejects undeclared upstream calls before emitting a client tool item in both streaming and non-streaming responses, and leaves exec -> tools.apply_patch(...) as the supported Code Mode path. Focused coverage is 87/87, with typecheck and privacy scan green. I am leaving the issue open for independent exact-head CI/review and integration.

  7. lidge-jun commented on Aug 13, 2026

    @lidge-jun
    Owner

    Fixed on dev in 7053e00 (Merge pull request #1576).

    Routed turns now keep the exact request-visible tool-name set alongside the existing namespace/custom-tool bridge maps, and both the streaming and non-streaming paths fail closed before emitting a client tool item when a provider invents a name that was never declared. The turn ends with an explicit upstream_error instead of aborting on an unresolvable call.

    exec -> tools.apply_patch(...) stays the Code Mode path; the fix deliberately does not guess an automatic conversion for a top-level apply_patch, since that would paper over a provider sending a tool the client never offered.

    Verification: focused regression across tests/responses-parser.test.ts, tests/responses-stream-tool-events.test.ts, and tests/bridge.test.ts; full suite on the merged dev is 11516 pass / 0 fail with bun run typecheck clean.

    Closing manually — PRs here target dev, so GitHub's auto-close does not fire.

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

    providerProvider 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