@@ -509,6 +509,7 @@ describe("installContextEngineLoopHook", () => {
509509 prePromptMessageCount : number ;
510510 } ) => Record < string , unknown > | undefined ,
511511 onAfterTurnCheckpoint ?: ( messageCount : number ) => void ,
512+ isHeartbeat ?: boolean ,
512513 ) : ( ) => void {
513514 return installContextEngineLoopHook ( {
514515 agent,
@@ -521,6 +522,7 @@ describe("installContextEngineLoopHook", () => {
521522 ...( prePromptCount !== undefined ? { getPrePromptMessageCount : ( ) => prePromptCount } : { } ) ,
522523 ...( getRuntimeContext ? { getRuntimeContext } : { } ) ,
523524 ...( onAfterTurnCheckpoint ? { onAfterTurnCheckpoint } : { } ) ,
525+ ...( isHeartbeat !== undefined ? { isHeartbeat } : { } ) ,
524526 } ) ;
525527 }
526528
@@ -984,7 +986,7 @@ describe("installContextEngineLoopHook", () => {
984986 it ( "ingests new messages in batches when afterTurn is absent" , async ( ) => {
985987 const agent = makeGuardableAgent ( ) ;
986988 const engine = makeMockEngine ( { omitAfterTurn : true } ) ;
987- installHook ( agent , engine ) ;
989+ installHook ( agent , engine , undefined , undefined , undefined , true ) ;
988990
989991 const batch0 = [ makeUser ( "first" ) , makeToolResult ( "call_1" , "r1" ) ] ;
990992 await callTransform ( agent , batch0 ) ;
@@ -1001,7 +1003,9 @@ describe("installContextEngineLoopHook", () => {
10011003 throw new Error ( "expected ingestBatch mock" ) ;
10021004 }
10031005 expect ( recordMockArg ( ingestBatch ) . messages ) . toEqual ( batch1 . slice ( 2 ) ) ;
1006+ expect ( recordMockArg ( ingestBatch ) . isHeartbeat ) . toBe ( true ) ;
10041007 expect ( recordMockArg ( ingestBatch , 1 ) . messages ) . toEqual ( batch2 . slice ( 4 ) ) ;
1008+ expect ( recordMockArg ( ingestBatch , 1 ) . isHeartbeat ) . toBe ( true ) ;
10051009 expect ( engine . assemble ) . toHaveBeenCalledTimes ( 2 ) ;
10061010 } ) ;
10071011
@@ -1019,9 +1023,23 @@ describe("installContextEngineLoopHook", () => {
10191023 expect ( ingestParams ?. sessionId ) . toBe ( sessionId ) ;
10201024 expect ( ingestParams ?. sessionKey ) . toBe ( sessionKey ) ;
10211025 expect ( ingestParams ?. message ) . toBe ( toolResult ) ;
1026+ expect ( ingestParams ?. isHeartbeat ) . toBeUndefined ( ) ;
10221027 expect ( engine . assemble ) . toHaveBeenCalledTimes ( 1 ) ;
10231028 } ) ;
10241029
1030+ it ( "passes heartbeat state through per-message ingest fallbacks" , async ( ) => {
1031+ const agent = makeGuardableAgent ( ) ;
1032+ const engine = makeMockEngine ( { omitAfterTurn : true , omitIngestBatch : true } ) ;
1033+ installHook ( agent , engine , 1 , undefined , undefined , true ) ;
1034+
1035+ const toolResult = makeToolResult ( "call_1" , "r1" ) ;
1036+ const messages = [ makeUser ( "first" ) , toolResult ] ;
1037+ await callTransform ( agent , messages ) ;
1038+
1039+ expect ( engine . ingest ) . toHaveBeenCalledTimes ( 1 ) ;
1040+ expect ( recordMockArg ( engine . ingest ) . isHeartbeat ) . toBe ( true ) ;
1041+ } ) ;
1042+
10251043 it ( "falls through to source messages when engine.afterTurn throws" , async ( ) => {
10261044 const agent = makeGuardableAgent ( ) ;
10271045 const engine = makeMockEngine ( {
0 commit comments