Skip to content

Account Pooler: rebuild Codex WebSocket history from streamed output items - #3310

Closed
SawyerHood wants to merge 1 commit into
mainfrom
bb/i-m-running-into-and-issue-with-gpt-models-where-thr_fystzs9y26
Closed

Account Pooler: rebuild Codex WebSocket history from streamed output items#3310
SawyerHood wants to merge 1 commit into
mainfrom
bb/i-m-running-into-and-issue-with-gpt-models-where-thr_fystzs9y26

Conversation

@SawyerHood

Copy link
Copy Markdown
Collaborator

Human comments

What was wrong

Codex talks to the Account Pooler over its Responses WebSocket transport: after the first request on a socket it sends previous_response_id plus only the new input items, and the pooler rebuilds the full history itself before forwarding one HTTPS request upstream. The pooler took the previous response's items from the response.completed event, but the ChatGPT Codex backend streams them only as response.output_item.done events and sends "output": [] in response.completed (verified with a direct probe through the pooler). Every incremental request therefore lost the previous response. Within a turn the API rejected the orphaned tool output with "No tool call found for custom tool call output" and Codex silently retried on a fresh socket, which is why Codex logs show a reconnect for almost every request. At a turn boundary the request is valid without the previous answer, so the model saw the earlier question unanswered and answered it again before the new one. Codex's own log database (~/.codex/logs_2.sqlite) records hundreds of these rejections per day since the WebSocket routing landed in #3056.

What changed

plugins/account-pool/src/codex-websocket.ts accumulates response.output_item.done items in stream order for each forwarded response and uses them as the previous output when the next frame carries previous_response_id. It falls back to the completed event's output only when no items were streamed. This mirrors how Codex builds its own delta baseline. No wire, CLI, or documentation changes.

How you verified

  • New plugins/account-pool/src/codex-websocket.test.ts drives the handler with a fake hub: a tool-call continuation within a turn, a follow-up question across a turn boundary, and the completed-output fallback. The first two fail on the previous handler and pass now.
  • The existing integration test's fake upstream now streams response.output_item.done and sends an empty output in response.completed, matching the real backend, and its history assertion still holds.
  • pnpm exec turbo run test typecheck lint --filter=bb-plugin-account-pool passes.

AGENT GENERATED

🤖 Generated with Claude Code

…items

Codex's Responses WebSocket transport sends previous_response_id plus only
the new input items, and the pooler reassembles the full history before
forwarding one HTTPS request upstream. The pooler took the previous
response's items from response.completed, but the ChatGPT Codex backend
streams them only as response.output_item.done events and sends an empty
output array in response.completed. Every incremental request therefore
lost the previous response: within a turn the API rejected the orphaned
tool output and Codex retried on a fresh socket, while at a turn boundary
the request was accepted without the previous answer and the model
answered the earlier question again.

Accumulate response.output_item.done items in stream order and fall back to
the completed event's output only when nothing was streamed. The
integration test's fake upstream now streams items the way the backend
does, and a unit test covers tool-call continuations, turn boundaries, and
the fallback.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@SawyerHood

Copy link
Copy Markdown
Collaborator Author

Superseded: the same bug was fixed on main in #3307, and a follow-up will remove the WebSocket path from the pooler entirely.

@SawyerHood SawyerHood closed this Sep 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant