Skip to content

[bug] code-mode exec catalog rejects routed default.update_goal as undeclared #5495

Closed

Description

@yxr1995-maker

Client or integration

Codex App (Desktop)

Provider or upstream service

opencode-go (muse-spark-1.3-contributor; also applies to any routed model that emits OpenCode-native default.* tool names)

OpenCodex version

@bitkyc08/opencodex 2.59.0. Checked on 2026-09-22 via GitHub API against main and tag v2.60.0: CODE_MODE_HELPER_TOOL_NAMES still lists only exec_command, shell_command, write_stdin, apply_patch, view_image.

Endpoint or capability

/v1/responses streaming tool calls, Codex code mode (exec as the only top-level client tool)

Current behaviour

A Codex Desktop code-mode turn against a routed model is killed mid-stream with:

stream disconnected before completion: routed provider emitted undeclared client tool "default.update_goal"; only request-declared tools may be called

The message is produced by undeclaredToolCallMessage in src/server/responses-undeclared-tool-guard.ts. The proxy usage log records HTTP status 200 while the client rollout records the stream termination error.

Observed request: provider opencode-go, model muse-spark-1.3-contributor, inbound responses, timestamp 2026-09-22 14:00:24 (Asia/Shanghai). Upstream emitted a top-level tool call named default.update_goal instead of the code-mode nested helper, and the guard failed the stream closed.

Expected behaviour

Same contract as the code-mode helper remap for apply_patch / write_stdin / view_image / exec_command, and the precedent #4412 / #4475 established for view_image:

  1. When the request catalog is genuine code mode (exec declared, no top-level goal tools declared), provider-emitted update_goal, default.update_goal (and sibling create_goal / get_goal) is not rejected as an undeclared client tool.
  2. The call is restored as the declared exec custom tool, with the body compiled to the nested helper Codex runs:
const result = await tools.update_goal({"status":"complete"});
text(result);

The Codex code-mode exec tool description advertises tools.create_goal(args), tools.get_goal(args), and tools.update_goal(args) alongside other nested helpers; these are not wire tools.

  1. When the catalog declares the bare goal tool, keep [bug] routed provider prefixes bare Codex tool with default.: default.view_image rejected as undeclared #4176 / fix(responses): normalize invented default. namespace back to the declared bare tool #4264 behaviour: an invented default.update_goal rewrites to bare update_goal and is not compiled into exec.
  2. When neither exec nor a goal tool is declared, keep fail-closed.

Minimal redacted request or reproduction

  1. Codex Desktop in code mode: request catalog declares top-level exec (and non-helper interaction tools such as wait, request_user_input). Goal tools exist only as await tools.update_goal(...) inside exec.
  2. Route the turn to a model that emits goal tool calls directly (observed with opencode-go/muse-spark-1.3-contributor).
  3. Upstream emits a top-level function_call with name: "default.update_goal" and arguments: {"status":"complete"}.
  4. normalizeDeclaredToolName strips the invented default. prefix only when the stripped name is in CODE_MODE_HELPER_TOOL_NAMES. Because update_goal is absent from that set, the guard flags the call as undeclared and terminates the stream.

Actual response or error

stream disconnected before completion: routed provider emitted undeclared client tool "default.update_goal"; only request-declared tools may be called

Upstream documentation

Suggested mapping or implementation notes

Catalog Provider emits Today Should become
{ exec } update_goal stream aborted, undeclared exec + tools.update_goal(...)
{ exec } default.update_goal stream aborted, undeclared exec + tools.update_goal(...)
{ update_goal } default.update_goal accepted (#4176 / #4264) unchanged (update_goal)
{} default.update_goal aborted aborted

Concrete two-part change:

  1. src/types/tools.ts: add update_goal, create_goal, get_goal to CODE_MODE_HELPER_TOOL_NAMES.
  2. src/responses/code-mode-helper-compat.ts: add explicit compile branches in compileCodeModeHelperInput for the three goal helpers to emit const result = await tools.<helper>(<args>);\ntext(result);. Without these branches, unhandled helpers fall back to tools.exec_command(...).

Relevant test files: tests/responses/responses-undeclared-tool-guard.test.ts, tests/responses/legacy-shell-compat.test.ts, and tests/responses/responses-code-mode-patch-compile.test.ts.

Additional context

Verified locally on 2.59.0 (macOS, Codex App, opencode-go): applying both parts passes an 18-assertion test covering normalization to exec, guard acceptance, compilation to tools.update_goal(...) instead of tools.exec_command(...), and restoring the item as a custom_tool_call named exec. Undeclared tools remain rejected, and declared bare tools retain precedence.

Uncertainty: the wire trace contained literal default.update_goal in the name field. Providers sending a structured namespace field (namespace: "default", name: "update_goal") have not been observed in this setup and remain unverified; under current code, routedCustomToolTargetName returns undefined when namespace is a string.

Related: #4412 / #4475 (view_image, closed/merged), #4176 / #4264 (bare-name fold), #3402 / #3403 (dotted names).

Activity

  1. added
    catalogModel catalog, slugs, visibility, routed entries
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    toolstool_calls, MCP, web-search / sidecar tools
    on Sep 22, 2026
  2. Ingwannu commented on Sep 23, 2026

    @Ingwannu
    Owner

    Confirmed on current dev: the code-mode helper allowlist still omitted create_goal, get_goal, and update_goal, and the compiler fallback would incorrectly turn an admitted goal helper into tools.exec_command(...). I opened draft PR #5659 with a bounded fix and regression coverage. It preserves bare-tool precedence and still rejects the call when neither the bare goal tool nor genuine code-mode exec is declared. Focused tests are green; exact-head CI and @lidge-jun review are pending before merge.

  3. added 2 commits that reference this issue on Sep 23, 2026
    279b8ff
    aed3bb8
  4. lidge-jun commented on Sep 23, 2026

    @lidge-jun
    Owner

    Fixed on dev by #5675 (squash-merged as aed3bb8, carrying #5659): code-mode exec catalogs accept the routed goal helpers again, so default.update_goal and its siblings are no longer rejected as undeclared.

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

    catalogModel catalog, slugs, visibility, routed entriesproviderProvider 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