Repository navigation
[Bug] DeepSeek CodeModeOnly: unsupported top-level apply_patch call aborts #1544
Description
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:
- CodeModeOnly instructions/guidance for references to direct
apply_patchwhen that tool is not exposed. - DeepSeek Responses conversion/restoration for legacy or undeclared custom-tool calls.
- Whether undeclared top-level patch calls should be rejected with a clear diagnostic or mapped to the supported Code Mode path.
Additional context
Controls:
- Reproduced in fresh DeepSeek conversations, so this is not inherited model-switch history.
exec -> tools.apply_patchsucceeds in the same environment, ruling out the patch engine and filesystem permissions as the primary failure.- A fresh GLM routed conversation also succeeds through
exec -> tools.apply_patch. - Existing issues grok-4.5 don‘t know how to use apply_patch tool #372, [Bug]: Cursor adapter consistently emits invalid Codex apply_patch payloads #1017, and [Bug]: Cursor's apply_patch still fails on exact-match / mid-turn drift after #1017 #1388 cover malformed or converted patch payloads / exact-match failures. This report is specifically about an undeclared top-level tool call under CodeModeOnly.
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_patchcontrol.
Activity
github-actions commentedon Aug 12, 2026
Issue reopened
The report now contains the information required by the automated check. Thanks for updating it.
[-][DeepSeek][CodeModeOnly] undeclared top-level apply_patch call aborts while exec → tools.apply_patch succeeds[/-][+]DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/+][-]DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/-][+][Bug] DeepSeek CodeModeOnly: unsupported top-level `apply_patch` call aborts[/+]Ingwannu commentedon Aug 13, 2026
Confirmed against current
dev: the patch runtime is healthy, and the failing boundary is the undeclared top-level call. The inbound request does not declareapply_patch, so it is absent fromfreeformToolNames; when the routed model nevertheless emits that name, the bridge currently serializes it as an ordinaryfunction_call. Codex has no matching declared function and surfaces only the unhelpfulabortedresult. The existing non-OpenAI catalog nudge already tells the model thatapply_patchis 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 undeclaredapply_patchcall 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 targetdev.Ingwannu commentedon Aug 13, 2026
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 leavesexec -> 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.fix(responses): reject undeclared routed tool calls (lidge-jun#1544)
lidge-jun commentedon Aug 13, 2026
Fixed on
devin 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_errorinstead 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-levelapply_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, andtests/bridge.test.ts; full suite on the mergeddevis 11516 pass / 0 fail withbun run typecheckclean.Closing manually — PRs here target
dev, so GitHub's auto-close does not fire.fix(responses): reject undeclared routed tool calls (lidge-jun#1544)