Skip to content

[Bug]: OpenCode Go native Responses path leaks undeclared apply_patch and shows aborted #1700

Closed

Description

@rodrigueez

Client or integration

Codex App

Area

Provider adapter

Summary

OpenCodex 2.17.0 leaks an undeclared top-level apply_patch function call through the native OpenAI Responses passthrough path when using OpenCode Go. Codex App displays aborted, while the target file remains unchanged.

Expected behavior: an undeclared routed tool should fail closed with an explicit compatibility error before reaching the Codex executor. The supported editing path should remain exec -> tools.apply_patch(...).

Reproduction

  1. Start OpenCodex on port 10100.
  2. Use exec -> tools.apply_patch(...) to create a temporary file containing v1.
  3. Invoke top-level apply_patch with a patch changing v1 to v2.
  4. Codex App displays aborted.
  5. The file remains v1; content and mtime are unchanged.
  6. Run the equivalent patch through exec -> tools.apply_patch(...):
    • an incorrect expected line returns a real apply_patch verification failed error;
    • the correct v1 -> v3 patch succeeds.

The request-visible catalog contains exec, wait, and request_user_input, but no top-level apply_patch schema. The session nevertheless receives function_call(name=apply_patch).

Version

OpenCodex 2.17.0

Operating system

macOS 27.0, Apple Silicon

Provider and model

Provider: opencode-go

Model: deepseek-v4-flash

At reproduction time, the provider default was openai-chat, while this model had an explicit openai-responses adapter override.

Logs or error output

  • Codex result: aborted
  • No corresponding custom_tool_call_output was emitted.
  • OpenCode Go usage record was HTTP 200.
  • No upstream aborted, OpenCodex response.failed, approval denial, or sandbox denial was observed.

Screenshots and supporting files

No screenshots. Reproduction artifacts were written only under /tmp.

Redacted configuration

{
  "providers": {
    "opencode-go": {
      "adapter": "openai-chat",
      "baseUrl": "https://opencode.ai/zen/go/v1",
      "modelAdapters": {
        "deepseek-v4-flash": "openai-responses"
      }
    }
  }
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Aug 14, 2026
  2. assigned and unassigned on Aug 14, 2026
  3. added a commit that references this issue on Aug 16, 2026
    b66ec3d
  4. lidge-jun commented on Aug 16, 2026

    @lidge-jun
    Owner

    Fixed on dev by #1788.

    The native Responses passthrough now fails closed when a routed provider returns a tool call the caller never declared. All four close conditions are covered:

    No-catalog passthrough preserved. The guard only arms when the request carries a readable, non-empty tool catalog and the provider is not authMode: "forward". A request with no tools field, or tools: [], is relayed exactly as before — tested on both transports, because Copilot/DeepSeek passthrough depends on it.

    Hosted-tool rewrite keeps the caller's catalog. Outbound wire names are unioned with the original caller names before either transport branches, so a request declaring image_gen.generate that ships {type:"image_generation"} upstream still gets its own name back without tripping the guard. A name declared in neither place — #1700's apply_patch — is still refused with a 502.

    A rejected turn does not enter previous_response_id state. Non-streaming validates before the cache write. Streaming needed more: an upstream can announce the undeclared call in response.output_item.added, trip the client guard, and then close with a response.completed whose output is empty — the terminal snapshot then looks clean and the refused turn would have been remembered anyway. Rejection is now sticky for the whole turn, set from every parsed payload on the inspection side. That required adding an onParsedPayload seam to SseInspectorHandlers and wiring it through InspectionConsumerOptions so both the eager and tee consumers observe it; without that the flag could never have been set.

    Streaming and non-streaming both covered. Guard rejection, no-catalog passthrough, and continuation-state exclusion each have regressions on both paths. The new streaming continuation test was driven red against the unfixed flag before landing.

    Verified at the exact merge head: full Cross-platform CI green, all four test shards plus the Windows and macOS jobs.

    Closing as completed. The fix is on dev and ships with the next release; it is not in a published version yet.

  5. 7 remaining items

  6. added 4 commits that reference this issue on Sep 17, 2026
    8217e4c
    f22f1cc
    d7c433c
    8a7001d
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