@@ -14,19 +14,32 @@ import {
1414 reconcileSessionStoreCompactionCountAfterSuccess ,
1515} from "./pi-embedded-subscribe.handlers.compaction.js" ;
1616import type { EmbeddedPiSubscribeContext } from "./pi-embedded-subscribe.handlers.types.js" ;
17+ import { makeZeroUsageSnapshot } from "./usage.js" ;
18+
19+ function makeUsage ( input : number , output : number , totalTokens : number ) {
20+ return {
21+ input,
22+ output,
23+ cacheRead : 0 ,
24+ cacheWrite : 0 ,
25+ totalTokens,
26+ cost : { input : 0 , output : 0 , cacheRead : 0 , cacheWrite : 0 , total : 0 } ,
27+ } ;
28+ }
1729
1830function createCompactionContext ( params : {
1931 storePath : string ;
2032 sessionKey : string ;
2133 agentId ?: string ;
2234 initialCount : number ;
2335 info ?: ( message : string , meta ?: Record < string , unknown > ) => void ;
36+ messages ?: unknown [ ] ;
2437} ) : EmbeddedPiSubscribeContext {
2538 let compactionCount = params . initialCount ;
2639 return {
2740 params : {
2841 runId : "run-test" ,
29- session : { messages : [ ] } as never ,
42+ session : { messages : params . messages ?? [ ] } as never ,
3043 config : { session : { store : params . storePath } } as never ,
3144 sessionKey : params . sessionKey ,
3245 sessionId : "session-1" ,
@@ -306,4 +319,59 @@ describe("handleCompactionEnd", () => {
306319 expect ( await readCompactionCount ( storePath , sessionKey ) ) . toBe ( 2 ) ;
307320 expect ( ctx . noteCompactionTokensAfter ) . toHaveBeenCalledWith ( undefined ) ;
308321 } ) ;
322+
323+ it ( "keeps fresh assistant usage after the latest compaction summary" , async ( ) => {
324+ const tmp = await fs . mkdtemp ( path . join ( os . tmpdir ( ) , "openclaw-compaction-usage-" ) ) ;
325+ const storePath = path . join ( tmp , "sessions.json" ) ;
326+ const sessionKey = "main" ;
327+ await seedSessionStore ( {
328+ storePath,
329+ sessionKey,
330+ compactionCount : 0 ,
331+ } ) ;
332+ const staleUsage = makeUsage ( 120_000 , 3_000 , 123_000 ) ;
333+ const freshUsage = makeUsage ( 1_000 , 250 , 1_250 ) ;
334+ const messages : Array < Record < string , unknown > & { usage ?: unknown } > = [
335+ {
336+ role : "assistant" ,
337+ content : "pre-compaction answer" ,
338+ timestamp : "2026-03-20T00:00:00.000Z" ,
339+ usage : staleUsage ,
340+ } ,
341+ {
342+ role : "compactionSummary" ,
343+ summary : "compressed" ,
344+ timestamp : "2026-03-20T00:00:10.000Z" ,
345+ } ,
346+ {
347+ role : "user" ,
348+ content : "new question" ,
349+ timestamp : "2026-03-20T00:00:20.000Z" ,
350+ } ,
351+ {
352+ role : "assistant" ,
353+ content : "fresh answer" ,
354+ timestamp : "2026-03-20T00:00:30.000Z" ,
355+ usage : freshUsage ,
356+ } ,
357+ ] ;
358+
359+ const ctx = createCompactionContext ( {
360+ storePath,
361+ sessionKey,
362+ initialCount : 0 ,
363+ messages,
364+ } ) ;
365+
366+ handleCompactionEnd ( ctx , {
367+ type : "compaction_end" ,
368+ reason : "threshold" ,
369+ result : { kept : 12 } ,
370+ willRetry : false ,
371+ aborted : false ,
372+ } ) ;
373+
374+ expect ( messages [ 0 ] ?. usage ) . toEqual ( makeZeroUsageSnapshot ( ) ) ;
375+ expect ( messages [ 3 ] ?. usage ) . toEqual ( freshUsage ) ;
376+ } ) ;
309377} ) ;
0 commit comments