@@ -426,6 +426,48 @@ describe("runPreparedCliAgent context engine lifecycle", () => {
426426 expect ( dispose ) . not . toHaveBeenCalled ( ) ;
427427 } ) ;
428428
429+ it ( "does not finalize context-engine turns for empty successful CLI output" , async ( ) => {
430+ executePreparedCliRunMock . mockResolvedValue ( {
431+ text : " " ,
432+ rawText : " " ,
433+ sessionId : "external-cli-session-empty" ,
434+ usage : { input : 11 , output : 0 , total : 11 } ,
435+ } ) ;
436+ const bootstrap = vi . fn < NonNullable < ContextEngine [ "bootstrap" ] > > ( async ( ) => ( {
437+ bootstrapped : true ,
438+ } ) ) ;
439+ const afterTurn = vi . fn < NonNullable < ContextEngine [ "afterTurn" ] > > ( async ( ) => { } ) ;
440+ const ingestBatch = vi . fn < NonNullable < ContextEngine [ "ingestBatch" ] > > ( async ( ) => ( {
441+ ingestedCount : 0 ,
442+ } ) ) ;
443+ const maintain = vi . fn < NonNullable < ContextEngine [ "maintain" ] > > ( async ( ) =>
444+ createMaintenanceResult ( ) ,
445+ ) ;
446+ const dispose = vi . fn ( async ( ) => { } ) ;
447+ const contextEngine = createContextEngine ( {
448+ bootstrap,
449+ afterTurn,
450+ ingestBatch,
451+ maintain,
452+ dispose,
453+ } ) ;
454+ const { runPreparedCliAgent } = await import ( "./cli-runner.js" ) ;
455+
456+ await expect ( runPreparedCliAgent ( buildPreparedContext ( contextEngine ) ) ) . rejects . toMatchObject ( {
457+ name : "FailoverError" ,
458+ reason : "empty_response" ,
459+ provider : "claude-cli" ,
460+ model : "sonnet-4.6" ,
461+ sessionId : "openclaw-session-1" ,
462+ } ) ;
463+
464+ expect ( bootstrap ) . toHaveBeenCalledTimes ( 1 ) ;
465+ expect ( afterTurn ) . not . toHaveBeenCalled ( ) ;
466+ expect ( ingestBatch ) . not . toHaveBeenCalled ( ) ;
467+ expect ( maintain ) . toHaveBeenCalledTimes ( 1 ) ;
468+ expect ( dispose ) . not . toHaveBeenCalled ( ) ;
469+ } ) ;
470+
429471 it ( "does not dispose context engines when CLI attempts fail" , async ( ) => {
430472 executePreparedCliRunMock . mockRejectedValue ( new Error ( "cli boom" ) ) ;
431473 const dispose = vi . fn ( async ( ) => {
0 commit comments