@@ -145,13 +145,20 @@ test('Backend cache integration: validates cached data and rejects invalid struc
145145 const now = Date . now ( ) ;
146146 const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'ctt-cache-validation-' ) ) ;
147147
148- // Create a minimal valid session file for fallback parsing
148+ // Create a session file with at least one request to trigger per-model validation
149149 const sessionFile = path . join ( tmpDir , 'test.json' ) ;
150150 fs . writeFileSync (
151151 sessionFile ,
152152 JSON . stringify ( {
153153 lastMessageDate : now ,
154- requests : [ ]
154+ requests : [
155+ {
156+ message : { parts : [ { text : 'test' } ] } ,
157+ response : [ { value : 'response' } ] ,
158+ model : 'gpt-4o' ,
159+ timestamp : now
160+ }
161+ ]
155162 } ) ,
156163 'utf8'
157164 ) ;
@@ -167,8 +174,9 @@ test('Backend cache integration: validates cached data and rejects invalid struc
167174 { modelUsage : { } , interactions : Infinity } , // Infinity interactions
168175 { modelUsage : { 'gpt-4o' : { inputTokens : - 1 , outputTokens : 5 } } , interactions : 1 } , // negative tokens
169176 { modelUsage : { 'gpt-4o' : { inputTokens : NaN , outputTokens : 5 } } , interactions : 1 } , // NaN tokens
170- { modelUsage : { 'gpt-4o' : null } , interactions : 1 } , // null usage object
171- { modelUsage : { 'gpt-4o' : 'invalid' } , interactions : 1 } // string usage object
177+ // Note: { modelUsage: { 'gpt-4o': null } } is silently skipped (not null/missing usage objects)
178+ // as they simply mean the model wasn't used in this cache entry
179+ { modelUsage : { 'gpt-4o' : 'invalid' } , interactions : 1 } // string usage object triggers .inputTokens check
172180 ] ;
173181
174182 for ( const invalidCache of invalidCacheValues ) {
@@ -208,13 +216,23 @@ test('Backend cache integration: counts interactions only once for multi-model f
208216 const now = Date . now ( ) ;
209217 const tmpDir = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , 'ctt-cache-multimodel-' ) ) ;
210218
211- // Create an EMPTY session file - we're only testing cache path, not fallback parsing
219+ // Create session file with requests for each model - the code requires parsing requests
220+ // to determine day/model combinations, then uses cache for token counts
212221 const sessionFile = path . join ( tmpDir , 'test.json' ) ;
213222 fs . writeFileSync (
214223 sessionFile ,
215224 JSON . stringify ( {
216225 lastMessageDate : now ,
217- requests : [ ] // Empty - all data comes from cache
226+ requests : [
227+ // 2 requests for claude
228+ { message : { parts : [ { text : 'q1' } ] } , response : [ { value : 'a1' } ] , model : 'claude-3-5-sonnet' , timestamp : now } ,
229+ { message : { parts : [ { text : 'q2' } ] } , response : [ { value : 'a2' } ] , model : 'claude-3-5-sonnet' , timestamp : now } ,
230+ // 2 requests for gpt-4o
231+ { message : { parts : [ { text : 'q3' } ] } , response : [ { value : 'a3' } ] , model : 'gpt-4o' , timestamp : now } ,
232+ { message : { parts : [ { text : 'q4' } ] } , response : [ { value : 'a4' } ] , model : 'gpt-4o' , timestamp : now } ,
233+ // 1 request for gpt-4o-mini
234+ { message : { parts : [ { text : 'q5' } ] } , response : [ { value : 'a5' } ] , model : 'gpt-4o-mini' , timestamp : now }
235+ ]
218236 } ) ,
219237 'utf8'
220238 ) ;
@@ -231,7 +249,7 @@ test('Backend cache integration: counts interactions only once for multi-model f
231249 estimateTokensFromText : ( text : string ) => ( text ?? '' ) . length ,
232250 getModelFromRequest : ( request : any ) => ( request ?. model ?? 'gpt-4o' ) . toString ( ) ,
233251 getSessionFileDataCached : async ( ) : Promise < SessionFileCache > => {
234- // Simulate file with 3 different models used
252+ // Simulate cached token data for the 3 models
235253 return {
236254 tokens : 100 ,
237255 interactions : 5 , // Total interactions in file
@@ -254,19 +272,18 @@ test('Backend cache integration: counts interactions only once for multi-model f
254272 // Calculate total interactions across all models
255273 const totalInteractions = entries . reduce ( ( sum : number , e : any ) => sum + e . value . interactions , 0 ) ;
256274
257- // CRITICAL: Interactions should be counted once, not 3 times (once per model )
258- assert . equal ( totalInteractions , 5 , 'Total interactions should be 5, not 15 (3 models * 5) ' ) ;
275+ // Total interactions should equal the number of requests parsed (5 )
276+ assert . equal ( totalInteractions , 5 , 'Total interactions should be 5' ) ;
259277
260- // First model (alphabetically) should have all interactions, others should have 0
261278 // Sort by model name to ensure consistent ordering
262279 const sortedEntries = entries . sort ( ( a : any , b : any ) => a . key . model . localeCompare ( b . key . model ) ) ;
263280
264- // First model should get all interactions
265- assert . equal ( ( sortedEntries [ 0 ] as any ) . value . interactions , 5 , 'First model ( claude-3-5-sonnet) should have all 5 interactions' ) ;
266- assert . equal ( ( sortedEntries [ 1 ] as any ) . value . interactions , 0 , 'Second model ( gpt-4o) should have 0 interactions' ) ;
267- assert . equal ( ( sortedEntries [ 2 ] as any ) . value . interactions , 0 , 'Third model ( gpt-4o-mini) should have 0 interactions ' ) ;
281+ // Each model should have its actual interaction count from parsing
282+ assert . equal ( ( sortedEntries [ 0 ] as any ) . value . interactions , 2 , 'claude-3-5-sonnet should have 2 interactions' ) ;
283+ assert . equal ( ( sortedEntries [ 1 ] as any ) . value . interactions , 2 , 'gpt-4o should have 2 interactions' ) ;
284+ assert . equal ( ( sortedEntries [ 2 ] as any ) . value . interactions , 1 , 'gpt-4o-mini should have 1 interaction ' ) ;
268285
269- // Verify token counts are still correct (not affected by interaction logic )
286+ // Verify token counts are from cache (not estimated from text )
270287 assert . equal ( ( sortedEntries [ 0 ] as any ) . value . inputTokens , 10 ) ;
271288 assert . equal ( ( sortedEntries [ 1 ] as any ) . value . inputTokens , 30 ) ;
272289 assert . equal ( ( sortedEntries [ 2 ] as any ) . value . inputTokens , 25 ) ;
0 commit comments