@@ -51,6 +51,7 @@ type PromptDecisionParams = {
5151 failoverReason : FailoverReason | null ;
5252 harnessOwnsTransport ?: boolean ;
5353 promptTimeoutFallbackSafe ?: boolean ;
54+ timedOutByRunBudget ?: boolean ;
5455 profileRotated : boolean ;
5556} ;
5657
@@ -67,14 +68,6 @@ type AssistantDecisionParams = {
6768 timedOutDuringCompaction : boolean ;
6869 timedOutDuringToolExecution : boolean ;
6970 harnessOwnsTransport ?: boolean ;
70- /**
71- * True when the embedded run-budget timer fired (whole-run deadline
72- * exhausted). When set, no fallback model can help — the run is over
73- * regardless of which provider handles it. Optional (defaults to falsy =
74- * "not a run-budget timeout") so callers that predate this signal keep their
75- * existing rotation behavior; the embedded runner always passes it
76- * explicitly. Closes #60388.
77- */
7871 timedOutByRunBudget ?: boolean ;
7972 profileRotated : boolean ;
8073} ;
@@ -101,6 +94,9 @@ function isTerminalFormatFailure(params: {
10194}
10295
10396function shouldRotatePrompt ( params : PromptDecisionParams ) : boolean {
97+ if ( params . timedOutByRunBudget ) {
98+ return false ;
99+ }
104100 return (
105101 params . failoverFailure &&
106102 params . failoverReason !== "timeout" &&
@@ -125,9 +121,6 @@ function shouldRotateAssistant(params: AssistantDecisionParams): boolean {
125121 if ( isTerminalFormatFailure ( params ) ) {
126122 return false ;
127123 }
128- // Run-budget timeouts are terminal — the run is out of time regardless of
129- // which model handles it. Don't rotate to another profile/model just to have
130- // it time out again. (#62682, closes #60388.)
131124 if ( params . timedOutByRunBudget ) {
132125 return false ;
133126 }
@@ -190,6 +183,12 @@ export function resolveRunFailoverDecision(params: RunFailoverDecisionParams): R
190183 reason : params . failoverReason ,
191184 } ;
192185 }
186+ if ( params . timedOutByRunBudget ) {
187+ return {
188+ action : "surface_error" ,
189+ reason : params . failoverReason ,
190+ } ;
191+ }
193192 if ( params . harnessOwnsTransport && params . failoverReason === "timeout" ) {
194193 // Plugin harness lifecycle timeouts must stay inside the harness boundary;
195194 // only prompt request timeouts proven replay-safe may enter model fallback.
0 commit comments