Skip to content

Classify every Codex turn failure and route it where work continues - #248

Merged
lawrencecchen merged 1 commit into
mainfrom
feat/codex-absorb-terminal-errors
Aug 19, 2026
Merged

lawrencecchen merged 1 commit into
mainfrom
feat/codex-absorb-terminal-errors

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Codex ends the turn on any in-stream failure it does not recognize, so the proxy previously rescued only the two capacity codes it knew. This classifies every failure by who can fix it, with absorb as the default for unknown/future codes: forwarding an unknown code loses the turn, absorbing it costs one Azure attempt and restores the original error if Azure refuses it.

  • Client-caused (context length, invalid prompt, policy, unsupported params): forwarded untouched.
  • Quota (usage_limit_reached, insufficient_quota, usage_not_included, rate_limit_exceeded): account marked exhausted like a 429. SSE turns then serve from Azure; WebSocket turns close 1012 without pinning so the reconnect lands on another pool account, reaching Azure only when nothing in the pool can start it. Terminal quota events no longer reach the client on either transport (supersedes the ws half of Fail over Codex streaming quota errors #212).
  • Everything else, known or future: SSE diverts pre-content (preamble tolerance grown to response.in_progress, four events); WebSocket pins, closes 1012, and the reconnect's 426 pushes the session onto HTTP where the pin serves it.
  • 402 pool status also qualifies for the fallback.

Tests: full suite PASS, -race ./internal/proxy PASS, vet clean. Two existing ws quota tests updated to the new contract (event absorbed + 1012 instead of forwarded).


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Classifies all Codex in‑stream failures and routes turns where work can continue. Previously only two capacity codes were absorbed; forwarding unknown failures lost the turn. Now failures classify by who can fix them, and unknown/future codes default to provider-side absorb.

  • Client-caused (context length, invalid prompt, policy, unsupported params): forwarded untouched.
  • Quota (usage_limit_reached, insufficient_quota, usage_not_included, rate_limit_exceeded): account is marked exhausted like a 429. SSE turns then serve from Azure; WebSocket turns absorb the event and close 1012 without pinning so the reconnect lands on another pool account. Terminal quota events no longer reach the client on either transport.
  • Server/unknown: SSE diverts pre-content (preamble tolerance expanded to response.in_progress, up to four events). WebSocket pins to Azure, closes 1012, and the reconnect gets 426 to push the session onto HTTP where the pin serves the turn. A 402 pool status also triggers the fallback.
  • Pool quota marks use the account-wide key (not model-scoped), aligning stream and WebSocket paths.

Written for commit a25bd59. Summary will update on new commits.

Review in cubic

Codex ends the turn on any in-stream failure it does not recognize, so the
proxy previously only rescued the two capacity codes it knew. Failures now
classify by who can fix them, and the default for a code this proxy has
never seen is absorb, not forward: forwarding an unknown code loses the
turn, absorbing it costs one Azure attempt and restores the original error
if Azure refuses it.

- Client-caused (context length, invalid prompt, policy, unsupported
  parameters): forwarded untouched; every provider refuses them the same way.
- Quota (usage_limit_reached, insufficient_quota, usage_not_included,
  rate_limit_exceeded): the account is marked exhausted the way a 429 would
  mark it. SSE turns are then served from Azure; WebSocket turns close 1012
  without pinning so the reconnect lands on another pool account, reaching
  Azure only when no pool account can start it. Terminal quota events no
  longer reach the client on either transport.
- Everything else, known or future: SSE turns divert to Azure pre-content
  (preamble tolerance grown to response.in_progress, four events); WebSocket
  turns pin, close 1012, and the reconnect's 426 pushes the session onto the
  HTTP transport where the pin serves it.

A 402 pool status now also qualifies for the fallback, and a stream quota
mark uses the account-wide pool key, matching the WebSocket relay.
@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@lawrencecchen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 12 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 09222d7f-dc08-493d-9bec-d0af7b431c37

📥 Commits

Reviewing files that changed from the base of the PR and between 7dadae1 and a25bd59.

📒 Files selected for processing (6)
  • README.md
  • internal/proxy/azure_codex.go
  • internal/proxy/azure_codex_test.go
  • internal/proxy/credential_broker_test.go
  • internal/proxy/proxy.go
  • internal/proxy/proxy_websocket_test.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lawrencecchen
lawrencecchen merged commit cebc2c0 into main Aug 19, 2026
7 checks passed
@lawrencecchen
lawrencecchen deleted the feat/codex-absorb-terminal-errors branch August 19, 2026 06:21
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