@@ -53,8 +53,6 @@ export const upsert = internalMutation({
5353
5454 // Store session data we need for later (avoid re-reading)
5555 let sessionId : Id < "sessions" > ;
56- let sessionPromptTokens : number ;
57- let sessionCompletionTokens : number ;
5856 let sessionMessageCount : number ;
5957 let sessionSearchableText : string | undefined ;
6058
@@ -84,14 +82,10 @@ export const upsert = internalMutation({
8482 updatedAt : now ,
8583 } ) ;
8684 // Use defaults since we just created it
87- sessionPromptTokens = 0 ;
88- sessionCompletionTokens = 0 ;
8985 sessionMessageCount = 0 ;
9086 sessionSearchableText = undefined ;
9187 } else {
9288 sessionId = session . _id ;
93- sessionPromptTokens = session . promptTokens ;
94- sessionCompletionTokens = session . completionTokens ;
9589 sessionMessageCount = session . messageCount ;
9690 sessionSearchableText = session . searchableText ;
9791 }
@@ -174,12 +168,10 @@ export const upsert = internalMutation({
174168 const sessionUpdate : Record < string , unknown > = { updatedAt : now } ;
175169
176170 if ( shouldUpdateSessionStats ) {
177- const newPromptTokens = sessionPromptTokens + ( args . promptTokens || 0 ) ;
178- const newCompletionTokens = sessionCompletionTokens + ( args . completionTokens || 0 ) ;
171+ // Only update messageCount. Session tokens are set exclusively by
172+ // session-level sync (the authoritative source). Never accumulate
173+ // per-message tokens onto the session to avoid double-counting.
179174 sessionUpdate . messageCount = sessionMessageCount + 1 ;
180- sessionUpdate . promptTokens = newPromptTokens ;
181- sessionUpdate . completionTokens = newCompletionTokens ;
182- sessionUpdate . totalTokens = newPromptTokens + newCompletionTokens ;
183175 }
184176
185177 if ( newSearchableText ) {
@@ -252,8 +244,6 @@ export const batchUpsert = internalMutation({
252244 . first ( ) ;
253245
254246 // Track session stats for batch update
255- let sessionPromptTokens = 0 ;
256- let sessionCompletionTokens = 0 ;
257247 let sessionMessageCount = 0 ;
258248 let sessionSearchableText = "" ;
259249 let sessionId : Id < "sessions" > ;
@@ -286,8 +276,6 @@ export const batchUpsert = internalMutation({
286276 } ) ;
287277 } else {
288278 sessionId = session . _id ;
289- sessionPromptTokens = session . promptTokens ;
290- sessionCompletionTokens = session . completionTokens ;
291279 sessionMessageCount = session . messageCount ;
292280 sessionSearchableText = session . searchableText || "" ;
293281 }
@@ -304,11 +292,10 @@ export const batchUpsert = internalMutation({
304292
305293 // Early return for dedup
306294 if ( existing && now - existing . createdAt < MESSAGE_DEDUP_MS ) {
307- return { action : "skipped" as const , tokens : { prompt : 0 , completion : 0 } , text : "" } ;
295+ return { action : "skipped" as const , text : "" } ;
308296 }
309297
310298 let messageId : Id < "messages" > ;
311- let addedTokens = { prompt : 0 , completion : 0 } ;
312299
313300 if ( existing ) {
314301 // Update existing
@@ -330,7 +317,7 @@ export const batchUpsert = internalMutation({
330317 await Promise . all ( existingParts . map ( ( p ) => ctx . db . delete ( p . _id ) ) ) ;
331318 }
332319
333- return { action : "updated" as const , tokens : { prompt : 0 , completion : 0 } , text : "" } ;
320+ return { action : "updated" as const , text : "" } ;
334321 }
335322
336323 // Insert new message
@@ -345,10 +332,6 @@ export const batchUpsert = internalMutation({
345332 durationMs : msg . durationMs ,
346333 createdAt : now ,
347334 } ) ;
348- addedTokens = {
349- prompt : msg . promptTokens || 0 ,
350- completion : msg . completionTokens || 0 ,
351- } ;
352335
353336 // Insert parts in parallel
354337 if ( msg . parts && msg . parts . length > 0 ) {
@@ -379,25 +362,21 @@ export const batchUpsert = internalMutation({
379362 . join ( " " ) ;
380363 }
381364
382- return { action : "inserted" as const , tokens : addedTokens , text : textContent } ;
365+ return { action : "inserted" as const , text : textContent } ;
383366 } catch ( e ) {
384- return { action : "error" as const , error : `${ msg . externalId } : ${ e } ` , tokens : { prompt : 0 , completion : 0 } , text : "" } ;
367+ return { action : "error" as const , error : `${ msg . externalId } : ${ e } ` , text : "" } ;
385368 }
386369 } )
387370 ) ;
388371
389372 // Aggregate results for session update
390373 let newMessages = 0 ;
391- let totalPromptTokens = 0 ;
392- let totalCompletionTokens = 0 ;
393374 const textParts : Array < string > = [ ] ;
394375
395376 for ( const result of results ) {
396377 if ( result . action === "inserted" ) {
397378 inserted ++ ;
398379 newMessages ++ ;
399- totalPromptTokens += result . tokens . prompt ;
400- totalCompletionTokens += result . tokens . completion ;
401380 if ( result . text ) textParts . push ( result . text ) ;
402381 } else if ( result . action === "updated" ) {
403382 updated ++ ;
@@ -408,19 +387,16 @@ export const batchUpsert = internalMutation({
408387 }
409388 }
410389
411- // Single session update for all new messages
390+ // Single session update for all new messages. Only messageCount and searchableText.
391+ // Session tokens are set exclusively by session-level sync (the authoritative source).
392+ // Never accumulate per-message tokens onto the session to avoid double-counting.
412393 if ( newMessages > 0 || textParts . length > 0 ) {
413- const newPromptTotal = sessionPromptTokens + totalPromptTokens ;
414- const newCompletionTotal = sessionCompletionTokens + totalCompletionTokens ;
415394 const newSearchable = textParts . length > 0
416395 ? `${ sessionSearchableText } ${ textParts . join ( " " ) } ` . slice ( 0 , 10000 )
417396 : sessionSearchableText ;
418397
419398 await ctx . db . patch ( sessionId , {
420399 messageCount : sessionMessageCount + newMessages ,
421- promptTokens : newPromptTotal ,
422- completionTokens : newCompletionTotal ,
423- totalTokens : newPromptTotal + newCompletionTotal ,
424400 searchableText : newSearchable || undefined ,
425401 updatedAt : now ,
426402 } ) ;
0 commit comments