Repository navigation
[Responses] Codex task-input envelopes are rejected by translated adapters #3735
Description
Client or integration
Codex App
Provider or upstream service
Translated Responses adapters, reproduced with Kiro
OpenCodex version
2.44.0 / af344a2
Endpoint or capability
POST /v1/responses, Codex task coordination
Current behaviour
Codex task coordination can add a result-shaped external input item to the destination task. The observed envelope has type function_call_output, non-empty id, name, and namespace fields, a representable output, and no call_id field. It represents input supplied by another task rather than the result of a tool call made in the destination task.
The common Responses parser currently treats this envelope as a standard tool result. The translated-adapter guard added by #3471 then correctly sees a missing tool identity and returns HTTP 400 before calling the upstream adapter. This prevents Codex from creating or resuming tasks through translated adapters.
Expected behaviour
Only the complete external task-input envelope described above should be converted to user input before adapter translation. Standard function_call_output or custom_tool_call_output items without a non-empty call_id must continue returning HTTP 400, as deliberately implemented by #3471. Items with call_id remain tool results, and incomplete or malformed external envelopes must also remain invalid.
Minimal redacted request or reproduction
Submit a Responses request through a translated adapter with this item in input:
{
"type": "function_call_output",
"id": "fco_redacted",
"name": "send_message_to_thread",
"namespace": "codex_app",
"output": "<redacted external task input>"
}The destination task fails before the provider is called.
Actual response or error
HTTP 400
tool result requires a non-empty string call_id
Upstream documentation
OpenAI Responses API reference: https://platform.openai.com/docs/api-reference/responses/create
The public Responses contract uses call_id to associate actual function tool outputs with calls. No public specification was found for Codex App's inter-task input envelope; that envelope is a concrete Codex App client requirement observed during task creation, follow-up messaging, and task resumption.
Suggested mapping or implementation notes
Preserve the translated-adapter guard from #3471. Before producing common parser messages, recognize only a function_call_output that has no call_id property, has non-empty string id, name, and namespace fields, and has representable output content. Convert that narrowly identified external item to user input, preserving its supported content exactly and without adding an orphan-tool marker such as [tool output for unknown call].
Do not match specific tool names, codex_app, XML tags, or ID prefixes. Do not repair custom_tool_call_output items, items with call_id: "", incomplete provenance, or malformed output content. Negative tests should keep all of those cases on the existing HTTP 400 path. Passthrough and routed compaction behavior must remain unchanged because they use the raw request body.
Additional context and attachments
Related: #3259 and merged PR #3471. The same follow-up report was previously opened as #3732 and closed only because it did not use a recognized issue template.
The initial broad repair was rejected during local review because it would have reversed #3471. The narrowed implementation above was validated with 127 parser and compaction-routing tests, 160 passthrough tests, typecheck, and git diff --check. After restarting the proxy on the local fix, live Codex checks covered task creation, a real exec call, a follow-up after deleting the exec input file, and a same-directory fork. The source task retained values from its earlier tool result, and the fork reproduced all three markers from inherited history together with the source-thread delegation envelope. Archive/unarchive and resuming the originally affected task were also exercised. The broad changed-test suite was not rerun because a previous run exhausted system memory and the Linux kernel terminated Chromium; affected suites were run independently.
Checks
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on an upstream specification or a concrete client requirement.
Activity
yrlan-montagnier commentedon Sep 6, 2026
I implemented and validated a narrow local patch against base commit
af344a28eabcee09a5e04c48ab897449792719c2(the currentorigin/devat the time of testing).The patch preserves the guard introduced by merged PR #3471. It recognizes external Codex task input only when all of these conditions hold:
function_call_output;call_idproperty is absent, rather than empty;id,name, andnamespaceare non-blank strings;That envelope becomes ordinary user input before translated-adapter validation. It is not given an orphan-tool marker. Standard or malformed outputs still become tool results with an empty identity and therefore keep the HTTP 400 behavior from #3471. The shared conversion helper also removes duplicate passthrough repair logic without changing that path's marker behavior.
Local patch
Validation:
bun test tests/responses/responses-parser.test.ts tests/responses/responses-compaction-routing.test.ts: 127 pass, 0 failbun test tests/responses/openai-responses-passthrough.test.ts: 160 pass, 0 failbun run typecheck: passedgit diff --check: passedexec, follow-up after deleting the read file, and a fork that recovered inherited contextThe patch is currently uncommitted, so this comment records the exact proposed implementation rather than pointing to a branch that may change.
Ingwannu commentedon Sep 6, 2026
Confirmed the current parser behavior at
af344a28eabcee09a5e04c48ab897449792719c2: your complete external envelope becomesrole: toolResultwith an undefined call id. The translated-route guard insrc/server/responses/core.tsthen rejects that shape. A control containing an actualcall_idremains a tool result. These were isolated parser checks plus source tracing, not a fresh live task-creation test.Please turn the supplied local patch into a separate focused PR against
dev. Preserve #3471's existing missing/empty-call-id rejection and keep passthrough/compaction raw-body behavior unchanged.One concrete issue in the posted helper needs adjustment before review:
isRepairableToolOutput()acceptsencrypted_content, andexternalToolInputContent()replaces it with the non-empty string[encrypted content omitted]. As a result, an envelope whose output contains only encrypted content passesisExternalToolInputItem()'s meaningful-content check and becomes fabricated user input despite having no recoverable task text. That contradicts the proposed representable-content boundary. Do not let placeholder text establish eligibility; reject unsupported/opaque-only envelopes and add a regression for them. Explicitly test mixed supported/unsupported content as well so partial conversion cannot silently drop task input.This is a narrower issue than ordinary orphan-tool repair. The reported client requirement is useful evidence, but arbitrary
id/name/namespacestrings are structural data, not authentication or proof of upstream provenance. Please document the compatibility assumption and keep the negative matrix in the PR. No approval or merge is implied by this confirmation.lidge-jun commentedon Sep 6, 2026
리뷰 · 우선순위 76 / 80
이 이슈는 Codex App이 다른 태스크에서 넘긴 입력을
function_call_output모양으로 넣는데,call_id가 없어서 번역 어댑터 가드에 걸리는 문제입니다. 지금dev(HEADaf344a28e, 이슈가 찍은 것과 동일 SHA)에서src/responses/parser.ts는function_call_output을 보통 도구 결과로 파싱합니다.#3471이src/server/responses/core.ts에 넣은 가드는 번역 경로에서call_id가 비어 있으면 HTTP 400tool result requires a non-empty string call_id를 냅니다. 공개 Responses 계약의 진짜 도구 결과에는 이게 맞지만, Codex 태스크 조율 envelope는id/name/namespace/output만 있고call_id프로퍼티 자체가 없습니다. 그래서 Kiro 같은 번역 어댑터로 태스크 생성·재개가 막힙니다. 패스스루·라우티드 컴팩션은 raw body를 쓰므로 이 구멍과 무관하다는 설명도 이슈에 있습니다.보고자는
#3471가드를 유지한 채,call_id키가 없고 id/name/namespace가 비어 있지 않으며 output이 표현 가능할 때만 user input으로 바꾸는 좁은 패치를 댓글에 올렸습니다.src/responses/tool-output-repair.ts를 새로 두고 parser·openai-responses·core 주석·테스트를 고칩니다. OWNER(Ingwannu)도 HEAD에서 재현을 확인했고, 별도 집중 PR로dev에 내라고 요청했습니다. 동시에 구체적 결함도 짚었습니다.isRepairableToolOutput이encrypted_content를 허용하고externalToolInputContent가[encrypted content omitted]자리표시로 바꿔, encrypted-only envelope가 “의미 있는 내용” 검사를 통과해 가짜 user input이 됩니다. 자리표시 문자로 자격을 주지 말고, opaque-only는 거부하며, 지원/미지원 혼합 회귀도 넣으라고 했습니다. id/name/namespace는 구조 데이터일 뿐 인증이 아니라고도 못 박았습니다.우선순위 76인 이유다. Codex 태스크 조율은 핵심 클라이언트 경로이고,
#3259/#3471불변식과 충돌하지 않게 좁혀야 하는 호환 버그입니다. 재현·패치·메인테이너 확인이 이미 있어 “조사 대기”가 아니라 “PR 착수” 단계입니다.tool-output-repair.ts는 HEAD에 아직 없습니다. 이전 템플릿 없는#3732는 닫혔고 이 이슈가 정식 후속입니다.경로/심볼 -
src/responses/parser.tsfunction_call_output- 현재 call_id 없는 항목도 toolResult로 파싱경로/심볼 -
src/server/responses/core.ts#3471가드 - 번역 어댑터에서 빈/없는 call_id → 400경로/심볼 - 제안
src/responses/tool-output-repair.tsisExternalToolInputItem- call_id 키 부재 + id/name/namespace + repairable output경로/심볼 - Ingwannu 피드백 - encrypted-only가 placeholder로 통과하는 구멍. mixed content 회귀 필요
경로 - 이슈 본문 음성 JSON -
type=function_call_output, id/name/namespace/output, call_id 없음경로/심볼 - 관련
#3259/ 머지#3471/ 닫힌#3732메인테이너의 판단이 필요한 지점
너의 추천
Ingwannu가 요청한 대로 encrypted-only 수정 + 음성/양성 회귀를 넣은 집중 PR을
dev에 열어 주세요. 이 이슈는 PR 링크가 오면 그 PR로 추적하고, 머지 후 닫으면 됩니다. 광범위 orphan-repair로#3471을 되돌리는 방향은 거부합니다.이 댓글은 grok-bot이 작성했습니다
lidge-jun commentedon Sep 6, 2026
Implemented in #3743 and now on dev, including the stateful raw/parsed guidance-order follow-up. Exact-head Linux/macOS CI passed at b7e67d8: https://github.com/lidge-jun/opencodex/actions/runs/34014313740. Existing missing-call-id rejection and raw passthrough controls remain covered. No live Kiro call was made; validation used synthetic protocol regressions and the recorded evidence boundary.
test(responses): cover established task delivery and compaction
test(responses): cover established task delivery and compaction