Repository navigation
[bug] routed provider prefixes bare Codex tool with default.: default.view_image rejected as undeclared #4176
Description
Activity
- addedbugSomething isn't workingSomething isn't workingstreamingSSE, WebSocket, terminal stream framesSSE, WebSocket, terminal stream frames
on Sep 10, 2026 리뷰 · 우선순위 69 / 80
이 이슈는 Codex App이 라우팅된 비-OpenAI 모델로
view_image를 쓸 때, 업스트림이 도구 이름을default.view_image로 돌려보내면 OpenCodex가 선언되지 않은 클라이언트 도구로 보고 SSE를 끊는 버그입니다. 재현 메시지는 정확히src/server/responses-undeclared-tool-guard.ts/src/bridge.ts가 쓰는 문장입니다.routed provider emitted undeclared client tool "…"; only request-declared tools may be called. 2.48.0에서도 난다고 했고, 지금dev(c15a98caa, package 2.50.0)의 가드 로직을 보면 같은 거절이 그대로입니다.이미 비슷한 sor를 고친 적이 있습니다. #3403(머지됨)은 이미 네임스페이스로 선언된 도구가
ns__name과ns.name두 철자로 메아리칠 때 둘 다 같은 신원으로 받도록src/responses/tool-name-aliases.ts와 undeclared-tool-guard를 고쳤습니다. #3402는default.apply_patch↔default__apply_patch쪽 관측이었습니다. 이번 보고는 그다음 구멍입니다. 요청 카탈로그에는 bareview_image만 있는데, 공급자/직렬화 계층이 합성 네임스페이스default.를 붙여 돌려보냅니다. #3403 별칭은 “선언된 namespace+name”에서 출발하므로, bare만 있는 경우에는default.view_image를view_image로 되돌리지 않습니다.src/types/tools.tsnormalizeDeclaredToolName도 code-modeexec헬퍼 이름만 다루고,default.접두를 벗기지 않습니다. 그래서 가드가declared.has("default.view_image")에서 실패하고 스트림이 죽습니다. Codex App은 reconnect /5를 돌다 턴이 실패합니다. 프롬프트(AGENTS.md)로 “default. 붙이지 말라”고 적어도, 모델/프로바이더 직렬화가 붙이는 경우에는 막지 못한다는 작성자 관찰도 타당합니다.형제 PR #4171은 code-mode
view_image를 unified exec로 넘기는 다른 축입니다. 이 이슈의 “bare ↔ default.bare 정규화”와 겹치지 않습니다. 중복 이슈로 닫지 말고, 가드/별칭 쪽 작은 패치로 받는 게 맞습니다. types/config 분할과도 무관합니다.라인 문제:
src/server/responses-undeclared-tool-guard.ts undeclaredNameInItem - bare 호출 경로에서
normalizeDeclaredToolName후declared.has만 봅니다.default.view_image→view_image폴백이 없어 스트림이 즉시 거절됩니다.src/types/tools.ts normalizeDeclaredToolName - code-mode helper만 정규화합니다. 합성
default.네임스페이스는 범위 밖이라 이 버그를 막지 못합니다.src/responses/tool-name-aliases.ts / collectDeclaredWireToolNames - #3403은 선언된 namespace에서 dotted alias를 등록합니다. bare 선언만 있을 때 공급자가 붙인
default.를 읽어 되돌리는 경로는 아직 없습니다.src/bridge.ts (undeclared client tool 분기) - 가드가 이름을 거절하면 그대로 연결을 끊습니다. 재연결 루프의 직접 원인입니다.
관련 #4171 - view_image 단어는 같지만 code-mode/exec 호환 이슈라서 이 티켓을 Fixes로 묶으면 안 됩니다.
메인테이너의 판단이 필요한 지점
- 작성자가 제안한 조건(이름이
default.<bare>이고, bare가 선언되어 있고,default.<bare>/default__<bare>가 따로 선언되지 않았고, 매핑이 유일할 때만 허용)을 그대로 받을지 - 정규화 위치를 undeclared-tool-guard로 둘지,
normalizeDeclaredToolName/별칭 레이어로 올릴지 default외 다른 합성 네임스페이스까지 열지, 아니면default만 narrowly 허용할지- Windows Codex App 재현 fixture를 CI에 넣을지(없으면 단위 테스트로 wire name만 검증)
너의 추천
이슈를 열린 채로 두고, 위 네 조건을 지키는 작은 fail-closed 패치 PR을 받으세요. #3403을 넓히는 방향이 자연스럽고, #4171과는 분리하세요. 스트림을 끊는 실사용 버거라 우선순위는 중상입니다. 패치 PR이 오면 privacy/typecheck +default.view_image→view_image단위 테스트 후 merge하면 됩니다.이 댓글은 grok-bot이 작성했습니다
- 작성자가 제안한 조건(이름이
Fixed on
devby #4264.
An inventeddefault.namespace is normalized back to the declared bare tool when — and only when — the caller actually declared that bare name.
Credit to @chilung-cgu, whose commits were carried unchanged into the release chain.
Closing manually: pull requests here targetdev, so GitHub'sCloseslinkage only fires on a merge intomain. This will reach users in the next release.
Client or integration
Codex App
Area
Proxy / routing / tool-name normalization
Summary
A routed non-OpenAI model can emit the Codex
view_imagetool asdefault.view_image, which OpenCodex rejects as undeclared and aborts the stream:This still reproduces on OpenCodex 2.48.0.
The observed failure is similar to #3402 / #3403, but appears to be a different alias case.
#3403 fixed a declared namespaced tool whose provider echo used a different spelling:
This report is about a bare Codex tool being returned with an invented/default namespace:
If the request declares bare
view_imagebut does not declaredefault.view_image/default__view_image, the existing dottedns.namealias support does not necessarily identify these as the same tool.Current behaviour
view_imagetool.default.view_image.responses-undeclared-tool-guardtreats it as a different, undeclared client tool.reconnecting /5) and the turn fails.Expected behaviour
OpenCodex should safely normalize a provider-added
default.namespace back to the unique bare request-declared tool when that mapping is unambiguous.For example, if the request-declared tool catalog contains exactly one bare tool named:
and does not contain a real namespaced tool whose canonical/alias name is
default.view_image, then a provider echo of:could be restored to:
before the undeclared-tool guard rejects it.
This should remain fail-closed when the mapping is ambiguous or the bare tool is not actually declared.
Suggested safety constraints
A conservative normalization could apply only when all of the following are true:
default.<name>.<name>is present as a request-declared bare tool.default.<name>/ the corresponding namespaced identity is not itself a declared tool.Otherwise preserve the current undeclared-tool rejection.
This would avoid broadly stripping arbitrary namespaces while handling providers that serialize un-namespaced function calls under a synthetic
defaultnamespace.Reproduction
view_image.default.view_image.Codex App then attempts to reconnect repeatedly.
Version
OpenCodex 2.48.0
Operating system
Windows
Provider and model
Custom / non-OpenAI routed model. The issue appears to be at the tool-call naming/compatibility boundary rather than in Codex's native OpenAI model path.
Related issues
default.apply_patchrejected when the declared namespaced spelling wasdefault__apply_patchns.namealongsidens__nameAdditional context
Prompt-level guidance in
AGENTS.mdwas added to tell non-OpenAI models to use only request-declared tools and exact tool names, including explicitly avoiding invented prefixes such asdefault.. The failure still occurs, suggesting thedefault.prefix may be introduced by the model/provider tool-call serialization path rather than being reliably preventable through prompt instructions alone.Checks
view_image -> default.view_imagecase from the namespaced spelling fix in fix(proxy): accept dotted ns.name tool echo alongside ns__name #3403.