@@ -50,7 +50,7 @@ import {
5050import { handoff } from '../src/handoff' ;
5151import { ModelBehaviorError , UserError } from '../src/errors' ;
5252import { Computer } from '../src/computer' ;
53- import { Usage } from '../src/usage' ;
53+ import { RequestUsage , Usage } from '../src/usage' ;
5454import { setTracingDisabled , withTrace } from '../src' ;
5555
5656import {
@@ -70,7 +70,10 @@ import { RunContext } from '../src/runContext';
7070import { setDefaultModelProvider } from '../src' ;
7171import { Logger } from '../src/logger' ;
7272import type { UnknownContext } from '../src/types' ;
73- import type { Session } from '../src/memory/session' ;
73+ import type {
74+ OpenAIResponsesCompactionResult ,
75+ Session ,
76+ } from '../src/memory/session' ;
7477import type { AgentInputItem } from '../src/types' ;
7578
7679beforeAll ( ( ) => {
@@ -580,8 +583,9 @@ describe('saveToSession', () => {
580583
581584 async runCompaction ( args : {
582585 responseId : string | undefined ;
583- } ) : Promise < void > {
586+ } ) : Promise < OpenAIResponsesCompactionResult | null > {
584587 this . events . push ( `runCompaction:${ args . responseId } ` ) ;
588+ return null ;
585589 }
586590 }
587591
@@ -662,8 +666,11 @@ describe('saveToSession', () => {
662666 this . items = [ ] ;
663667 }
664668
665- async runCompaction ( args ?: { responseId ?: string } ) : Promise < void > {
669+ async runCompaction ( args ?: {
670+ responseId ?: string ;
671+ } ) : Promise < OpenAIResponsesCompactionResult | null > {
666672 this . events . push ( `runCompaction:${ String ( args ?. responseId ) } ` ) ;
673+ return null ;
667674 }
668675 }
669676
@@ -713,6 +720,116 @@ describe('saveToSession', () => {
713720 expect ( session . events ) . toEqual ( [ 'addItems:2' , 'runCompaction:undefined' ] ) ;
714721 expect ( session . items ) . toHaveLength ( 2 ) ;
715722 } ) ;
723+
724+ it ( 'aggregates compaction usage into the run usage' , async ( ) => {
725+ class TrackingSession implements Session {
726+ items : AgentInputItem [ ] = [ ] ;
727+ events : string [ ] = [ ] ;
728+
729+ async getSessionId ( ) : Promise < string > {
730+ return 'session' ;
731+ }
732+
733+ async getItems ( ) : Promise < AgentInputItem [ ] > {
734+ return [ ...this . items ] ;
735+ }
736+
737+ async addItems ( items : AgentInputItem [ ] ) : Promise < void > {
738+ this . events . push ( `addItems:${ items . length } ` ) ;
739+ this . items . push ( ...items ) ;
740+ }
741+
742+ async popItem ( ) : Promise < AgentInputItem | undefined > {
743+ return undefined ;
744+ }
745+
746+ async clearSession ( ) : Promise < void > {
747+ this . items = [ ] ;
748+ }
749+
750+ async runCompaction ( ) : Promise < OpenAIResponsesCompactionResult | null > {
751+ this . events . push ( 'runCompaction:resp_123' ) ;
752+ return {
753+ usage : new RequestUsage ( {
754+ inputTokens : 4 ,
755+ outputTokens : 6 ,
756+ totalTokens : 10 ,
757+ endpoint : 'responses.compact' ,
758+ } ) ,
759+ } ;
760+ }
761+ }
762+
763+ const textAgent = new Agent < UnknownContext , 'text' > ( {
764+ name : 'Recorder' ,
765+ outputType : 'text' ,
766+ instructions : 'capture' ,
767+ } ) ;
768+ const agent = textAgent as unknown as Agent <
769+ UnknownContext ,
770+ AgentOutputType
771+ > ;
772+ const session = new TrackingSession ( ) ;
773+ const context = new RunContext < UnknownContext > ( undefined as UnknownContext ) ;
774+ const state = new RunState <
775+ UnknownContext ,
776+ Agent < UnknownContext , AgentOutputType >
777+ > ( context , 'hello' , agent , 10 ) ;
778+
779+ const modelUsage = new Usage ( {
780+ requests : 1 ,
781+ inputTokens : 2 ,
782+ outputTokens : 3 ,
783+ totalTokens : 5 ,
784+ requestUsageEntries : [
785+ new RequestUsage ( {
786+ inputTokens : 2 ,
787+ outputTokens : 3 ,
788+ totalTokens : 5 ,
789+ endpoint : 'responses.create' ,
790+ } ) ,
791+ ] ,
792+ } ) ;
793+ state . _modelResponses . push ( {
794+ output : [ ] ,
795+ usage : modelUsage ,
796+ responseId : 'resp_123' ,
797+ } ) ;
798+ state . _context . usage . add ( modelUsage ) ;
799+ state . _generatedItems = [
800+ new MessageOutputItem (
801+ {
802+ type : 'message' ,
803+ role : 'assistant' ,
804+ id : 'msg_123' ,
805+ status : 'completed' ,
806+ content : [
807+ {
808+ type : 'output_text' ,
809+ text : 'here is the reply' ,
810+ } ,
811+ ] ,
812+ providerData : { } ,
813+ } ,
814+ textAgent ,
815+ ) ,
816+ ] ;
817+ state . _currentStep = {
818+ type : 'next_step_final_output' ,
819+ output : 'here is the reply' ,
820+ } ;
821+
822+ const result = new RunResult ( state ) ;
823+ await saveToSession ( session , toInputItemList ( state . _originalInput ) , result ) ;
824+
825+ expect ( session . events ) . toEqual ( [ 'addItems:2' , 'runCompaction:resp_123' ] ) ;
826+ expect ( state . usage . inputTokens ) . toBe ( 6 ) ;
827+ expect ( state . usage . outputTokens ) . toBe ( 9 ) ;
828+ expect ( state . usage . totalTokens ) . toBe ( 15 ) ;
829+ expect (
830+ state . usage . requestUsageEntries ?. map ( ( entry ) => entry . endpoint ) ,
831+ ) . toEqual ( [ 'responses.create' , 'responses.compact' ] ) ;
832+ } ) ;
716833} ) ;
717834
718835describe ( 'prepareInputItemsWithSession' , ( ) => {
0 commit comments