You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
opencode-go (muse-spark-1.3-contributor; also applies to any routed model that emits OpenCode-native default.* tools)
OpenCodex version
@bitkyc08/opencodex 2.51.0, and current dev (aa0dd50). The gap is still present on dev after #4264.
Endpoint or capability
/v1/responses tool calls / streaming, 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.view_image"; only request-declared tools may be called
The message is produced by src/bridge.ts / src/server/responses-undeclared-tool-guard.ts. HTTP/SSE then surfaces as response.failed (undeclared_tool_call / upstream_error). The turn is lost.
This happens after the model captures a screenshot (e.g. screencapture … /tmp/hud-after.png via tools.exec_command) and then tries to look at the PNG.
Expected behaviour
Same contract as the existing code-mode helper remap for apply_patch / write_stdin / exec_command:
When the request catalog is genuine code mode (bare exec declared, no top-level view_image), a provider-emitted view_image or invented default.view_image is not an undeclared client tool.
The call is restored as the declared exec custom tool, with the body compiled to the nested helper Codex actually runs:
That nested API is real. Codex code-mode exec already exposes tools.view_image({ path, detail? }) and image(image_url); successful host output is a custom_tool_call_output that includes input_image.
When neither exec nor view_image is declared, keep fail-closed.
Minimal redacted request or reproduction
Codex Desktop, code mode, model opencode-go/muse-spark-1.3-contributor (or any OpenCode-native model that emits default.* tools).
Ask the model to screenshot a window and inspect the PNG.
Observed sequence: many successful exec / tools.exec_command calls, then a top-level tool call named default.view_image.
Stream ends with the error above.
Request catalog for that turn is the code-mode shape: top-level exec (plus MCP tools such as computer-use). view_image is not a wire tool; it only exists as await tools.view_image(...) inside exec.
Actual response or error
routed provider emitted undeclared client tool "default.view_image"; only request-declared tools may be called
Codex wraps it as stream disconnected before completion: ….
Upstream documentation
Codex code-mode nested helper (observed on the wire): tools.view_image({ path, detail? }) then image(result.image_url).
Concrete change (same files as apply_patch / write_stdin):
src/types/tools.ts — add view_image to CODE_MODE_HELPER_TOOL_NAMES. When exec is declared and default.<helper> was not itself declared, strip the invented default. prefix before helper→exec normalization. Otherwise default.view_image never matches the helper list.
src/responses/code-mode-helper-compat.ts — compile view_image / default.view_image to await tools.view_image(...) + image(result.image_url), with file_path / file / image_path aliases mapped onto Codex's path. Do not compile it as exec_command, and do not replace it with a "not available in Code Mode" text() error. Code mode does have this nested helper.
Tests in tests/responses/legacy-shell-compat.test.ts, tests/adapters/bridge-legacy-shell-normalization.test.ts, tests/responses/responses-undeclared-tool-guard.test.ts.
Please do not land #4171 as-is for this. That draft accepts the name (good) but compiles a soft-fail telling the model to use exec_command to inspect pixels (wrong). exec_command cannot inject an image the way tools.view_image + image() does, so the model will retry or give up. Maintainer review on #4171 already flagged the title/behaviour mismatch.
Sibling failure mode already in the wild: routed opencode-go/deepseek-flash emitting undeclared TaskUpdate on Claude Desktop. Same class (OpenCode-native tool name leaking onto a client that never advertised it). This issue is only about view_image.
I searched existing provider/compatibility issues. Request/response above are redacted. Expected behaviour is the Codex code-mode exec nested-helper contract plus the existing helper remap pattern in this repo.
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.*tools)OpenCodex version
@bitkyc08/opencodex2.51.0, and currentdev(aa0dd50). The gap is still present ondevafter #4264.Endpoint or capability
/v1/responsestool calls / streaming, Codex code mode (execas the only top-level client tool)Current behaviour
A Codex Desktop code-mode turn against a routed model is killed mid-stream with:
The message is produced by
src/bridge.ts/src/server/responses-undeclared-tool-guard.ts. HTTP/SSE then surfaces asresponse.failed(undeclared_tool_call/upstream_error). The turn is lost.This happens after the model captures a screenshot (e.g.
screencapture … /tmp/hud-after.pngviatools.exec_command) and then tries to look at the PNG.Expected behaviour
Same contract as the existing code-mode helper remap for
apply_patch/write_stdin/exec_command:execdeclared, no top-levelview_image), a provider-emittedview_imageor inventeddefault.view_imageis not an undeclared client tool.execcustom tool, with the body compiled to the nested helper Codex actually runs:That nested API is real. Codex code-mode
execalready exposestools.view_image({ path, detail? })andimage(image_url); successful host output is acustom_tool_call_outputthat includesinput_image.view_image, keep [bug] routed provider prefixes bare Codex tool withdefault.:default.view_imagerejected as undeclared #4176 / fix(responses): normalize invented default. namespace back to the declared bare tool #4264 behaviour: inventeddefault.view_imagerewrites to bareview_imageand is not compiled intoexec.execnorview_imageis declared, keep fail-closed.Minimal redacted request or reproduction
opencode-go/muse-spark-1.3-contributor(or any OpenCode-native model that emitsdefault.*tools).exec/tools.exec_commandcalls, then a top-level tool call nameddefault.view_image.Request catalog for that turn is the code-mode shape: top-level
exec(plus MCP tools such as computer-use).view_imageis not a wire tool; it only exists asawait tools.view_image(...)insideexec.Actual response or error
Codex wraps it as
stream disconnected before completion: ….Upstream documentation
tools.view_image({ path, detail? })thenimage(result.image_url).src/server/responses-undeclared-tool-guard.ts.default.prefix when bareview_imageis declared: [bug] routed provider prefixes bare Codex tool withdefault.:default.view_imagerejected as undeclared #4176, fixed ondevby fix(responses): normalize invented default. namespace back to the declared bare tool #4264. That fix does not apply here, because code mode never declares bareview_image.Suggested mapping or implementation notes
This is a different axis from #4176.
{ view_image }default.view_imageview_image){ exec }view_imageexec+tools.view_image(...){ exec }default.view_imageexec+tools.view_image(...){}default.view_imageConcrete change (same files as
apply_patch/write_stdin):src/types/tools.ts— addview_imagetoCODE_MODE_HELPER_TOOL_NAMES. Whenexecis declared anddefault.<helper>was not itself declared, strip the inventeddefault.prefix before helper→execnormalization. Otherwisedefault.view_imagenever matches the helper list.src/responses/code-mode-helper-compat.ts— compileview_image/default.view_imagetoawait tools.view_image(...)+image(result.image_url), withfile_path/file/image_pathaliases mapped onto Codex'spath. Do not compile it asexec_command, and do not replace it with a "not available in Code Mode"text()error. Code mode does have this nested helper.tests/responses/legacy-shell-compat.test.ts,tests/adapters/bridge-legacy-shell-normalization.test.ts,tests/responses/responses-undeclared-tool-guard.test.ts.Please do not land #4171 as-is for this. That draft accepts the name (good) but compiles a soft-fail telling the model to use
exec_commandto inspect pixels (wrong).exec_commandcannot inject an image the waytools.view_image+image()does, so the model will retry or give up. Maintainer review on #4171 already flagged the title/behaviour mismatch.Additional context
Related:
default.:default.view_imagerejected as undeclared #4176 / fix(responses): normalize invented default. namespace back to the declared bare tool #4264 — inventeddefault.prefix when the bare tool is in the catalog.text()availability error. Same symptom, wrong compile target.ns.namealiases for tools that were declared with a namespace. Code-modeview_imagewas never declared underdefault.opencode-go/deepseek-flashemitting undeclaredTaskUpdateon Claude Desktop. Same class (OpenCode-native tool name leaking onto a client that never advertised it). This issue is only aboutview_image.I searched existing provider/compatibility issues. Request/response above are redacted. Expected behaviour is the Codex code-mode
execnested-helper contract plus the existing helper remap pattern in this repo.