Repository navigation
fix(retry-fallback): exhaustion event leads with the primary failure - #5058
Open
code-yeongyu wants to merge 4 commits into
Open
code-yeongyu wants to merge 4 commits into
code-yeongyu wants to merge 4 commits into
Conversation
… every failed rung (#4084) retry_fallback_exhausted carried only lastError, the error of the rung that ran last, so a primary 400 hid behind a later rung's connection error. The session now records each failed rung (model, reason, error) per turn and the event carries primaryError plus failures, with lastError kept for older clients; client projection runs each rung's text through the same account-limit description as lastError. TUI and print mode lead with the primary failure.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a turn exhausts its fallback chain,
retry_fallback_exhaustednow carries the failure that started the walk and every rung that failed after it, not only the last rung's error. The TUI notice and the print-mode stderr line lead with the primary failure and list the later rungs asthen <model>: <error>.lastErroris unchanged for older clients.Root cause
{ type: "retry_fallback_exhausted"; chainKey; lastError }(packages/coding-agent/src/core/agent-session.ts:765).agent-session.ts:12966,lastError: errorMessage), so nothing recorded the primary's failure. In the reported sequence (primary 400 "out of extra usage", sibling 400, then another provider'sConnection error.), every surface showed onlyConnection error., and triage chased a network problem that did not exist.Fix
retry-fallback/exhaustion.ts: typedFallbackRungFailure { model, reason, error },recordRungFailure(drops an exact repeat, since one failure can be offered to the walk twice), anddescribeFallbackExhaustion, the single primary-first text both surfaces use.agent-session.ts: the session records each rung failure when it offers it to the fallback walk (per turn; cleared where the controller's turn state resets). The eight exhaustion emissions go through one_emitFallbackExhausted, which addsprimaryErrorandfailures. The client projection in_emitpasses each rung's text through the same account-usage-limit description already applied tolastError. The provider text is the stream-boundary-redactederrorMessage, the same textlastErroralready carried.interactive-mode.ts: when earlier rungs failed, the exhaustion notice leads with the primary failure, even if the last rung's error was retryable (which used to route the card to the generic provider-error summary that showed only that error). The single-rung path is unchanged.print-mode.ts:Model fallback exhausted: <chain> (<primary>; then <rung>: <error>; ...).RED -> GREEN
packages/coding-agent/test/suite/regressions/4084-exhaustion-primary-failure.test.tsreplays the reported shape through the faux harness: the primary fails with a 400, the second rung with the same 400, and the last rung withConnection error.. It then asserts the event, the print line and the TUI notice.1261291012(test only): 3 failed. The event had noprimaryError(expected undefined to deeply equal { model: 'faux/faux-1', ... }), the print line did not contain the 400, and the TUI notice did not lead with the primary.CI=1 bun run test(frompackages/coding-agent) on the new test plus the existing exhaustion-surface teststest/interactive-mode-fallback-error-sanitization.test.ts,test/interactive-mode-fallback.test.ts,test/print-mode-fallback-notice.test.tsandtest/suite/regressions/2894-fallback-budget-refused-rung.test.ts: 5 files, 18 passed, 0 failed.bun run check: lint, format, typecheck) and the whole suite run in the sanctioned static and full receipts at this head, not as hand-run gates.Compatibility
primaryErrorandfailuresare optional fields. Events built by older code, and the RPC/JSON stream for consumers that ignore unknown fields, are unaffected.lastErrorkeeps its meaning.Part of #4084 (this is the engine and TUI/print half). The desktop card (
providerFailurePresentation.ts) lives in the desktop repo and still has to readprimaryError.Part of #4090
Summary by cubic
Fixes
retry_fallback_exhaustedevents so they lead with the failure that started the fallback walk instead of only the last rung's error, so an account-limit 400 no longer hides behind a later connection error.primaryErrorandfailures;lastErrorkeeps its meaning for older clients.then <model>: <error>.lastError.Written for commit d51dfab. Summary will update on new commits.