@@ -21,6 +21,35 @@ import { NullTelemetryService } from '../../../telemetry/common/nullTelemetrySer
2121import { ICAPIClientService } from '../../common/capiClient' ;
2222import { AutomodeService } from '../automodeService' ;
2323
24+ function createMockHeaders ( entries : Record < string , string > = { } ) : { get ( name : string ) : string | null } {
25+ const lower : Record < string , string > = { } ;
26+ for ( const [ k , v ] of Object . entries ( entries ) ) {
27+ lower [ k . toLowerCase ( ) ] = v ;
28+ }
29+ return { get : ( name : string ) => lower [ name . toLowerCase ( ) ] ?? null } ;
30+ }
31+
32+ /**
33+ * Creates a mock response with a real stream-backed body so that middleware
34+ * cloning (tee) works correctly. Token responses go through the middleware
35+ * pipeline where {@link cloneResponse} reads the body stream.
36+ */
37+ function makeMockTokenResponse ( body : { available_models : string [ ] ; expires_at : number ; session_token : string } ) {
38+ const serialized = JSON . stringify ( body ) ;
39+ return {
40+ status : 200 ,
41+ headers : createMockHeaders ( ) ,
42+ body : new ReadableStream < Uint8Array > ( {
43+ start ( controller ) {
44+ controller . enqueue ( new TextEncoder ( ) . encode ( serialized ) ) ;
45+ controller . close ( ) ;
46+ } ,
47+ } ) ,
48+ async text ( ) { return serialized ; } ,
49+ async json ( ) { return JSON . parse ( serialized ) ; } ,
50+ } ;
51+ }
52+
2453describe ( 'AutomodeService' , ( ) => {
2554 let automodeService : AutomodeService ;
2655 let mockCAPIClientService : ICAPIClientService ;
@@ -64,14 +93,13 @@ describe('AutomodeService', () => {
6493 }
6594
6695 function mockApiResponse ( available_models : string [ ] , session_token = 'test-token' , expiresInSeconds = 3600 ) : void {
67- ( mockCAPIClientService . makeRequest as ReturnType < typeof vi . fn > ) . mockResolvedValue ( {
68- ok : true ,
69- json : vi . fn ( ) . mockResolvedValue ( {
96+ ( mockCAPIClientService . makeRequest as ReturnType < typeof vi . fn > ) . mockResolvedValue (
97+ makeMockTokenResponse ( {
7098 available_models,
7199 expires_at : Math . floor ( Date . now ( ) / 1000 ) + expiresInSeconds ,
72100 session_token,
73101 } )
74- } ) ;
102+ ) ;
75103 }
76104
77105 function enableRouter ( ) : void {
@@ -85,14 +113,13 @@ describe('AutomodeService', () => {
85113 mockChatEndpoint = createEndpoint ( 'gpt-4o-mini' , 'OpenAI' ) ;
86114
87115 mockCAPIClientService = {
88- makeRequest : vi . fn ( ) . mockResolvedValue ( {
89- ok : true ,
90- json : vi . fn ( ) . mockResolvedValue ( {
116+ makeRequest : vi . fn ( ) . mockResolvedValue (
117+ makeMockTokenResponse ( {
91118 available_models : [ 'gpt-4o' , 'gpt-4o-mini' ] ,
92119 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
93120 session_token : 'test-token'
94121 } )
95- } )
122+ )
96123 } as unknown as ICAPIClientService ;
97124
98125 mockAuthService = {
@@ -154,6 +181,8 @@ describe('AutomodeService', () => {
154181 if ( opts ?. type === RequestType . ModelRouter ) {
155182 return Promise . resolve ( {
156183 ok : true ,
184+ status : 200 ,
185+ headers : createMockHeaders ( ) ,
157186 text : vi . fn ( ) . mockResolvedValue ( JSON . stringify ( {
158187 predicted_label : 'needs_reasoning' ,
159188 confidence : 0.85 ,
@@ -165,14 +194,13 @@ describe('AutomodeService', () => {
165194 } ) )
166195 } ) ;
167196 }
168- return Promise . resolve ( {
169- ok : true ,
170- json : vi . fn ( ) . mockResolvedValue ( {
197+ return Promise . resolve (
198+ makeMockTokenResponse ( {
171199 available_models : [ 'gpt-4o' , 'gpt-4o-mini' ] ,
172200 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
173201 session_token : 'test-token'
174202 } )
175- } ) ;
203+ ) ;
176204 } ) ;
177205
178206 automodeService = createService ( ) ;
@@ -205,6 +233,8 @@ describe('AutomodeService', () => {
205233 capturedBody = req . body ;
206234 return Promise . resolve ( {
207235 ok : true ,
236+ status : 200 ,
237+ headers : createMockHeaders ( ) ,
208238 text : vi . fn ( ) . mockResolvedValue ( JSON . stringify ( {
209239 predicted_label : 'needs_reasoning' ,
210240 confidence : 0.85 ,
@@ -216,14 +246,13 @@ describe('AutomodeService', () => {
216246 } ) )
217247 } ) ;
218248 }
219- return Promise . resolve ( {
220- ok : true ,
221- json : vi . fn ( ) . mockResolvedValue ( {
249+ return Promise . resolve (
250+ makeMockTokenResponse ( {
222251 available_models : [ 'gpt-4o' , 'gpt-4o-mini' ] ,
223252 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
224253 session_token : 'test-token'
225254 } )
226- } ) ;
255+ ) ;
227256 } ) ;
228257
229258 automodeService = createService ( ) ;
@@ -416,6 +445,8 @@ describe('AutomodeService', () => {
416445 if ( opts ?. type === RequestType . ModelRouter ) {
417446 return Promise . resolve ( {
418447 ok : true ,
448+ status : 200 ,
449+ headers : createMockHeaders ( ) ,
419450 text : vi . fn ( ) . mockResolvedValue ( JSON . stringify ( {
420451 predicted_label : 'needs_reasoning' ,
421452 confidence : 0.9 ,
@@ -427,14 +458,13 @@ describe('AutomodeService', () => {
427458 } ) )
428459 } ) ;
429460 }
430- return Promise . resolve ( {
431- ok : true ,
432- json : vi . fn ( ) . mockResolvedValue ( {
461+ return Promise . resolve (
462+ makeMockTokenResponse ( {
433463 available_models,
434464 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
435465 session_token,
436466 } )
437- } ) ;
467+ ) ;
438468 } ) ;
439469 }
440470
@@ -447,14 +477,13 @@ describe('AutomodeService', () => {
447477 if ( opts ?. type === RequestType . ModelRouter ) {
448478 return Promise . reject ( new Error ( 'Network error' ) ) ;
449479 }
450- return Promise . resolve ( {
451- ok : true ,
452- json : vi . fn ( ) . mockResolvedValue ( {
480+ return Promise . resolve (
481+ makeMockTokenResponse ( {
453482 available_models : [ 'claude-sonnet' , 'gpt-4o' ] ,
454483 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
455484 session_token : 'test-token' ,
456485 } )
457- } ) ;
486+ ) ;
458487 } ) ;
459488
460489 automodeService = createService ( ) ;
@@ -498,14 +527,13 @@ describe('AutomodeService', () => {
498527 } ) ;
499528 } ) ;
500529 }
501- return Promise . resolve ( {
502- ok : true ,
503- json : vi . fn ( ) . mockResolvedValue ( {
530+ return Promise . resolve (
531+ makeMockTokenResponse ( {
504532 available_models : [ 'claude-sonnet' , 'gpt-4o' ] ,
505533 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
506534 session_token : 'test-token' ,
507535 } )
508- } ) ;
536+ ) ;
509537 } ) ;
510538
511539 automodeService = createService ( ) ;
@@ -669,6 +697,8 @@ describe('AutomodeService', () => {
669697 if ( opts ?. type === RequestType . ModelRouter ) {
670698 return Promise . resolve ( {
671699 ok : true ,
700+ status : 200 ,
701+ headers : createMockHeaders ( ) ,
672702 text : vi . fn ( ) . mockResolvedValue ( JSON . stringify ( {
673703 predicted_label : 'needs_reasoning' ,
674704 confidence : 0.9 ,
@@ -680,14 +710,13 @@ describe('AutomodeService', () => {
680710 } ) )
681711 } ) ;
682712 }
683- return Promise . resolve ( {
684- ok : true ,
685- json : vi . fn ( ) . mockResolvedValue ( {
713+ return Promise . resolve (
714+ makeMockTokenResponse ( {
686715 available_models : [ 'claude-sonnet' , 'gpt-4o' ] ,
687716 expires_at : Math . floor ( Date . now ( ) / 1000 ) + 3600 ,
688717 session_token : 'test-token' ,
689718 } )
690- } ) ;
719+ ) ;
691720 } ) ;
692721
693722 automodeService = createService ( ) ;
0 commit comments