fix(core): retry model capacity errors - #31058
Conversation
482ce51 to
99c9a06
Compare
99c9a06 to
49b5b72
Compare
|
@steipete-oai Instead of retrying after 30 second, 2 minutes, 5 minutes and then giving up, can you please implement a proper exponential backoff that starts with 3 seconds and maxes out at 5 minutes? The number of retries should be large enough to prevent overnight goals from aborting. |
|
A bounded default retry capacity makes sense for interactive sessions, but goal-level requeueing, as proposed in #31176, does not help long-running harnesses that do not use /goal. Could users configure the maximum number of capacity retries, including an unlimited option for unattended harnesses? Otherwise, every harness must implement special handling to restart turns that end because the selected model is temporarily at capacity. Unlimited retries could continue at the five-minute base delay with positive jitter, remain cancellation-aware, and use a separate budget from ordinary transport retries. For example: Or: |
|
consideration worth noting: This queue issue here is a big one because often it will break the prompt with this capacity issue presumably from a load balancer but then it will cascade right into the follow up tab queued prompt even though that prompt is/can be dependent on the previous prompt having finished correctly for example, if ive prompted "implement and merge A which fixes B" and then tab queued up "now that B is fixed we can implement C" then "selected model is at capacity" hits, it can immediately halt our finishing of A but then because a load balancer switches us to somewhere where the model is not at capacity, it can from a dirty halfdone feature A begin the confused implementation of C from a partially done conversation. |
Summary
Treat structured model-capacity failures as a bounded, recoverable state instead of ending the turn immediately.
Normal sampling and remote compaction v2 now keep the same turn alive for up to three patient retries. The retry waits have 30-second, 2-minute, and 5-minute minimums, each with positive jitter so clients never retry earlier than the base schedule or synchronize on the same instant.
Why
The Responses API reports temporary model capacity as HTTP 503 with either
server_is_overloadedorslow_down. Previously these responses were consumed by the ordinary fast transport retry layer. Once that short budget was exhausted, an otherwise healthy long-running Codex task stopped and required the user to notice and continue it manually.Capacity is different from a generic transport failure:
Retry behavior
server_is_overloadedorslow_down.StreamErrorevents withServerOverloadedand visibleReconnecting... 1/3,2/3, and3/3progress.Compaction and input safety
Remote compaction v2 uses the same capacity policy as sampling, including its independent budget and cancellation behavior.
Pre-turn compaction runs before the incoming user input is recorded in thread history. If capacity remains exhausted at that point, the protocol now reports
serverOverloadedBeforeInputrather than the ordinaryserverOverloadedvariant. Clients can use that distinction to replay the saved request payload instead of sending an empty continuation or duplicating input.The new error variant is propagated through the core protocol, app-server protocol, generated TypeScript types, and JSON schemas. Both overload variants retain the same rate-limit/capacity presentation in the TUI.
When previous-model compaction is rejected and Codex falls back to the current model, a capacity error or cancellation from the fallback attempt is preserved instead of being hidden behind the original rejection.
Intentional non-changes
The large file count is primarily exhaustive regression coverage plus regenerated protocol schemas.
Test plan
codex-protocolandcodex-app-server-protocol: 492 tests passed on the rebased head.just fix -p codex-core -p codex-protocol -p codex-app-server-protocol -p codex-tuipassed.just fmtpassed.What users see
When the selected model is temporarily at capacity, Codex remains active and retries automatically instead of immediately ending a long-running task.
Related: #31176, #22390, #31278.