@@ -126,10 +126,79 @@ describe("provider failure classification", () => {
126126 kind : "request" ,
127127 defaultCooldownMs : 0 ,
128128 } ) ;
129+ assert . deepEqual (
130+ classifyFailure (
131+ 502 ,
132+ "Your input exceeds the context window of this model. Please adjust your input and try again."
133+ ) ,
134+ { eligible : false , kind : "request" , defaultCooldownMs : 0 }
135+ ) ;
129136 } ) ;
130137} ) ;
131138
132139describe ( "same-provider OAuth account fallback" , ( ) => {
140+ it ( "does not turn context failures into cooldowns or a terminal 429" , async ( ) => {
141+ const store = createStore ( tmpConfig ( ) ) ;
142+ const quotaLock = {
143+ until : Date . now ( ) + 60 * 60_000 ,
144+ status : 429 ,
145+ kind : "quota" ,
146+ reason : "usage limit reached" ,
147+ } ;
148+ store . seed ( {
149+ providers : [
150+ chatgptAccount ( "prov_a" , "token-a" , 100 ) ,
151+ chatgptAccount ( "prov_b" , "token-b" , 200 ) ,
152+ chatgptAccount ( "prov_c" , "token-c" , 300 , { modelLocks : { "*" : quotaLock } } ) ,
153+ ] ,
154+ } ) ;
155+ const calls = [ ] ;
156+ const logger = captureLogger ( ) ;
157+ const router = createRouter ( {
158+ store,
159+ logger,
160+ fetchImpl : async ( _url , options ) => {
161+ calls . push ( authToken ( options ) ) ;
162+ return new Response (
163+ [
164+ "event: response.failed" ,
165+ `data: ${ JSON . stringify ( {
166+ type : "response.failed" ,
167+ response : {
168+ error : {
169+ message :
170+ "Your input exceeds the context window of this model. Please adjust your input and try again." ,
171+ } ,
172+ } ,
173+ } ) } `,
174+ "" ,
175+ ] . join ( "\n" ) ,
176+ { status : 200 , headers : { "Content-Type" : "text/event-stream" } }
177+ ) ;
178+ } ,
179+ } ) ;
180+
181+ const result = await router . chatCompletions ( {
182+ body : {
183+ model : "chatgpt/gpt-5.4" ,
184+ messages : [ { role : "user" , content : "oversized request" } ] ,
185+ stream : true ,
186+ } ,
187+ } ) ;
188+
189+ assert . equal ( result . ok , false ) ;
190+ assert . equal ( result . status , 400 ) ;
191+ assert . deepEqual ( calls , [ "token-a" , "token-b" ] ) ;
192+ assert . match ( result . error . error . message , / C h a t G P T \( o a u t h 1 \) \[ 4 0 0 \] / ) ;
193+ assert . match ( result . error . error . message , / C h a t G P T \( o a u t h 2 \) \[ 4 0 0 \] / ) ;
194+ assert . match ( result . error . error . message , / C h a t G P T \( o a u t h 3 \) \[ 4 2 9 \] / ) ;
195+ const providers = store . load ( ) . providers ;
196+ assert . equal ( providers . find ( ( provider ) => provider . id === "prov_a" ) . modelLocks ?. [ "gpt-5.4" ] , undefined ) ;
197+ assert . equal ( providers . find ( ( provider ) => provider . id === "prov_b" ) . modelLocks ?. [ "gpt-5.4" ] , undefined ) ;
198+ assert . deepEqual ( providers . find ( ( provider ) => provider . id === "prov_c" ) . modelLocks ?. [ "*" ] , quotaLock ) ;
199+ assert . equal ( logger . entries . find ( ( entry ) => entry . meta ?. event === "accounts_exhausted" ) . meta . status , 400 ) ;
200+ } ) ;
201+
133202 it ( "assigns monotonic oauth aliases and advertises only shared model ids" , ( ) => {
134203 const configPath = tmpConfig ( ) ;
135204 const store = createStore ( configPath ) ;
0 commit comments