@@ -560,84 +560,4 @@ describe('Dispatcher Failover', () => {
560560 expect ( meta ?. attemptCount ) . toBe ( 1 ) ;
561561 expect ( meta ?. finalAttemptProvider ) . toBe ( 'p2' ) ;
562562 } ) ;
563-
564- test ( 'provider error captures all upstream response headers in routing context' , async ( ) => {
565- setConfigForTesting ( makeConfig ( { targetCount : 1 } ) ) ;
566- fetchMock . mockImplementation (
567- async ( ) =>
568- new Response ( JSON . stringify ( { error : { message : 'boom' } } ) , {
569- status : 500 ,
570- headers : {
571- 'Content-Type' : 'application/json' ,
572- 'x-request-id' : 'provider-req-123' ,
573- 'X-Custom-Header' : 'custom-value' ,
574- } ,
575- } )
576- ) ;
577-
578- const dispatcher = new Dispatcher ( ) ;
579-
580- try {
581- await dispatcher . dispatch ( { ...makeChatRequest ( ) , requestId : 'req-headers-test' } ) ;
582- throw new Error ( 'expected dispatch to fail' ) ;
583- } catch ( error : any ) {
584- expect ( error . routingContext ?. providerResponseHeaders ) . toBeDefined ( ) ;
585- expect ( error . routingContext ?. providerResponseHeaders [ 'x-request-id' ] ) . toBe ( 'provider-req-123' ) ;
586- expect ( error . routingContext ?. providerResponseHeaders [ 'x-custom-header' ] ) . toBe ( 'custom-value' ) ;
587- expect ( error . routingContext ?. providerResponseHeaders [ 'content-type' ] ) . toBe ( 'application/json' ) ;
588- }
589- } ) ;
590-
591- test ( 'retry history includes provider response headers on failed attempts' , async ( ) => {
592- setConfigForTesting ( makeConfig ( { targetCount : 2 } ) ) ;
593- fetchMock
594- . mockImplementationOnce (
595- async ( ) =>
596- new Response ( JSON . stringify ( { error : { message : 'first boom' } } ) , {
597- status : 500 ,
598- headers : { 'x-request-id' : 'first-req-id' } ,
599- } )
600- )
601- . mockImplementationOnce ( async ( ) => successChatResponse ( 'model-2' ) ) ;
602-
603- const dispatcher = new Dispatcher ( ) ;
604- const response = await dispatcher . dispatch ( { ...makeChatRequest ( ) , requestId : 'req-retry-hist' } ) ;
605- const meta = ( response as any ) . plexus ;
606- const retryHistory = JSON . parse ( meta ?. retryHistory || '[]' ) ;
607-
608- expect ( retryHistory ) . toHaveLength ( 2 ) ;
609- expect ( retryHistory [ 0 ] ?. status ) . toBe ( 'failed' ) ;
610- expect ( retryHistory [ 0 ] ?. providerResponseHeaders ?. [ 'x-request-id' ] ) . toBe ( 'first-req-id' ) ;
611- expect ( retryHistory [ 1 ] ?. status ) . toBe ( 'success' ) ;
612- } ) ;
613-
614- test ( 'intermediate failures are saved during failover' , async ( ) => {
615- setConfigForTesting ( makeConfig ( { targetCount : 2 } ) ) ;
616- fetchMock
617- . mockImplementationOnce ( async ( ) => errorResponse ( 500 , 'first failed' ) )
618- . mockImplementationOnce ( async ( ) => successChatResponse ( 'model-2' ) ) ;
619-
620- const saveErrorSpy = vi . fn ( ) ;
621- const dispatcher = new Dispatcher ( ) ;
622- dispatcher . setUsageStorage ( {
623- saveError : saveErrorSpy ,
624- recordFailedAttempt : vi . fn ( ) ,
625- recordSuccessfulAttempt : vi . fn ( ) ,
626- } as any ) ;
627-
628- const response = await dispatcher . dispatch ( {
629- ...makeChatRequest ( ) ,
630- requestId : 'req-intermediate' ,
631- } ) ;
632- const meta = ( response as any ) . plexus ;
633-
634- expect ( meta ?. attemptCount ) . toBe ( 2 ) ;
635- // One call for the intermediate failure, one in the route handler doesn't happen
636- // here because dispatch succeeded overall.
637- expect ( saveErrorSpy ) . toHaveBeenCalledTimes ( 1 ) ;
638- const [ savedRequestId , savedError , savedDetails ] = saveErrorSpy . mock . calls [ 0 ] as any [ ] ;
639- expect ( savedRequestId ) . toBe ( 'req-intermediate' ) ;
640- expect ( savedError ?. routingContext ?. statusCode ) . toBe ( 500 ) ;
641- expect ( savedDetails ?. apiType ) . toBe ( 'chat' ) ;
642- } ) ;
643563} ) ;
0 commit comments