Client or integration
Codex App
Area
Streaming
Summary
When an openai-responses passthrough provider emits UUID item IDs instead of canonical Responses prefixes, the upstream request completes and OpenCodex records HTTP 200 plus reported usage, but Codex App never produces an assistant item or completes the turn. The UI remains on Thinking until the user interrupts it.
This is distinct from #864. The stream contains a complete response.completed event, and switching macOS from the default relay path to streamMode: "eager-relay" does not change the result.
The incompatible IDs observed on the wire look like:
response.id = b16df59f-bbc4-458f-80c6-eae4bac8dada
reasoning.id = 4ffa2f22-7283-43ae-ae18-7690736424c1
message.id = 6d66799f-6b2b-4643-8d30-5176244a3a8b
Canonical OpenAI Responses item IDs use type prefixes such as resp_, rs_, and msg_. OpenCodex already has an opt-in responsesItemIdRepair, but it only repairs exact, preconfigured placeholder IDs or missing terminal IDs. It cannot repair randomly generated UUIDs that change on every request.
Reproduction
- Configure an API-key provider using
adapter: "openai-responses" whose native Responses endpoint returns UUID IDs for response/message/reasoning objects.
- Set
statelessResponses: true and route a model through it.
- Start a new Codex App turn with a minimal input such as
Reply only OK.
- Observe that the provider returns the complete sequence:
response.created
response.output_item.added # reasoning item with UUID id
response.reasoning_text.delta
response.output_item.done
response.output_item.added # message item with UUID id
response.output_text.delta
response.output_text.done
response.output_item.done
response.completed # status=completed, output and usage present
- OpenCodex logs the request as
status: 200, usageStatus: "reported", and includes token usage from response.completed.
- Codex App remains on Thinking. Its rollout contains
task_started and the user input, but no assistant response item and no successful turn completion. Interrupting the UI produces turn_aborted.
I also repeated the request after setting:
{"streamMode":"eager-relay"}
The Codex CLI JSON stream still emitted only thread.started and turn.started; it emitted neither an agent message nor turn.completed. This rules out the macOS tee() relay path as the cause.
Directly calling the same OpenCodex /v1/responses route with curl shows that the SSE stream and response.completed frame are complete; the differentiating protocol violation is the UUID item IDs.
Version
2.10.0
Operating system
macOS 26.5.2 (Darwin 25.5.0, Apple Silicon arm64)
Provider and model
OpenAI-compatible native Responses provider / deepseek-v4-flash and deepseek-v4-pro
Logs or error output
# OpenCodex persisted request summary
status=200
usageStatus=reported
inputTokens=14466
outputTokens=81
reasoningOutputTokens=49
# Codex rollout lifecycle
task_started
# no assistant response_item
# no turn_completed
turn_aborted reason=interrupted
Suggested fix
Extend ResponsesItemIdRepairConfig with a provider-local option such as:
{
"responsesItemIdRepair": {
"repairInvalidIds": true,
"repairMissingTerminalIds": true
}
}
In responses-item-id-repair.ts, when repairInvalidIds is enabled, rewrite any existing message or reasoning ID that does not start with its expected prefix:
const shouldRepair = state.placeholders[type].has(rawId)
|| (state.repairInvalidIds && !rawId.startsWith(REPAIRABLE_PREFIXES[type]));
const mapped = shouldRepair
? mintCanonicalId(type, state.scope, outputIndex)
: state.repairMissingTerminalIds
? rawId
: null;
The request-local mapping should be applied consistently to:
response.output_item.added.item.id
- lifecycle event
item_id fields
response.output_item.done.item.id
response.completed.response.output[].id
Function-call IDs and call_id should remain untouched. Because the rewrite is client-facing only, raw upstream snapshots can remain available for provider replay.
Redacted configuration
{
"providers": {
"provider": {
"adapter": "openai-responses",
"baseUrl": "https://redacted.example",
"responsesPath": "/responses",
"authMode": "key",
"models": ["deepseek-v4-flash", "deepseek-v4-pro"],
"statelessResponses": true
}
},
"websockets": false
}
Checks
Client or integration
Codex App
Area
Streaming
Summary
When an
openai-responsespassthrough provider emits UUID item IDs instead of canonical Responses prefixes, the upstream request completes and OpenCodex records HTTP 200 plus reported usage, but Codex App never produces an assistant item or completes the turn. The UI remains on Thinking until the user interrupts it.This is distinct from #864. The stream contains a complete
response.completedevent, and switching macOS from the default relay path tostreamMode: "eager-relay"does not change the result.The incompatible IDs observed on the wire look like:
Canonical OpenAI Responses item IDs use type prefixes such as
resp_,rs_, andmsg_. OpenCodex already has an opt-inresponsesItemIdRepair, but it only repairs exact, preconfigured placeholder IDs or missing terminal IDs. It cannot repair randomly generated UUIDs that change on every request.Reproduction
adapter: "openai-responses"whose native Responses endpoint returns UUID IDs for response/message/reasoning objects.statelessResponses: trueand route a model through it.Reply only OK.status: 200,usageStatus: "reported", and includes token usage fromresponse.completed.task_startedand the user input, but no assistant response item and no successful turn completion. Interrupting the UI producesturn_aborted.I also repeated the request after setting:
{"streamMode":"eager-relay"}The Codex CLI JSON stream still emitted only
thread.startedandturn.started; it emitted neither an agent message norturn.completed. This rules out the macOStee()relay path as the cause.Directly calling the same OpenCodex
/v1/responsesroute with curl shows that the SSE stream andresponse.completedframe are complete; the differentiating protocol violation is the UUID item IDs.Version
2.10.0
Operating system
macOS 26.5.2 (Darwin 25.5.0, Apple Silicon arm64)
Provider and model
OpenAI-compatible native Responses provider /
deepseek-v4-flashanddeepseek-v4-proLogs or error output
Suggested fix
Extend
ResponsesItemIdRepairConfigwith a provider-local option such as:{ "responsesItemIdRepair": { "repairInvalidIds": true, "repairMissingTerminalIds": true } }In
responses-item-id-repair.ts, whenrepairInvalidIdsis enabled, rewrite any existingmessageorreasoningID that does not start with its expected prefix:The request-local mapping should be applied consistently to:
response.output_item.added.item.iditem_idfieldsresponse.output_item.done.item.idresponse.completed.response.output[].idFunction-call IDs and
call_idshould remain untouched. Because the rewrite is client-facing only, raw upstream snapshots can remain available for provider replay.Redacted configuration
{ "providers": { "provider": { "adapter": "openai-responses", "baseUrl": "https://redacted.example", "responsesPath": "/responses", "authMode": "key", "models": ["deepseek-v4-flash", "deepseek-v4-pro"], "statelessResponses": true } }, "websockets": false }Checks