@@ -245,6 +245,49 @@ describe("agent bundle end-to-end", () => {
245245 expect ( firstMessages [ 0 ] ) . toContain ( "big 0" ) ;
246246 } ) ;
247247
248+ it ( "never caches a summary from an aborted run, and resumes with the full history" , async ( ) => {
249+ faux . unregister ( ) ;
250+ faux = registerFauxProvider ( {
251+ provider : "faux" ,
252+ models : [ { id : "faux-small" , name : "Faux Small" , contextWindow : 20_270 } ] ,
253+ } ) ;
254+ const firstMessages : string [ ] = [ ] ;
255+ let abortDuringSummary = false ;
256+ let summaries = 0 ;
257+ const opts = {
258+ cwd,
259+ configOverride : { model : faux . getModel ( ) , apiKey : "test-key" , source : "explicit" as const } ,
260+ autoApprove : true ,
261+ } ;
262+ const bundle = createAgent ( opts ) ;
263+ faux . setResponses (
264+ Array . from ( { length : 80 } , ( ) => ( context : Context ) => {
265+ if ( context . systemPrompt ?. startsWith ( "Summarize the prior conversation" ) ) {
266+ summaries ++ ;
267+ // The user hits Ctrl+C while the summary is being written.
268+ if ( abortDuringSummary ) bundle . agent . abort ( ) ;
269+ return fauxAssistantMessage ( `summary #${ summaries } ` ) ;
270+ }
271+ const first = context . messages [ 0 ] ;
272+ firstMessages . push ( typeof first ?. content === "string" ? first . content : JSON . stringify ( first ?. content ) ) ;
273+ return fauxAssistantMessage ( "ok" ) ;
274+ } ) ,
275+ ) ;
276+ for ( let i = 0 ; i < 9 ; i ++ ) await bundle . agent . prompt ( `big ${ i } ${ "x " . repeat ( 300 ) } ` ) ;
277+ abortDuringSummary = true ;
278+ await bundle . agent . prompt ( `big 9 ${ "x " . repeat ( 300 ) } ` ) . catch ( ( ) => undefined ) ;
279+
280+ expect ( summaries ) . toBe ( 1 ) ;
281+ expect ( bundle . sessions . load ( faux . getModel ( ) . id ) ?. compaction ) . toBeUndefined ( ) ;
282+
283+ abortDuringSummary = false ;
284+ firstMessages . length = 0 ;
285+ const resumed = createAgent ( { ...opts , resume : true } ) ;
286+ await resumed . agent . prompt ( "after restart" ) ;
287+ // A fresh compaction may run after resume, but the aborted summary (#1) is never reused.
288+ expect ( firstMessages [ 0 ] ) . not . toContain ( "summary #1" ) ;
289+ } ) ;
290+
248291 it ( "compaction monitor stays inactive when transcript is short" , async ( ) => {
249292 faux . setResponses ( [ fauxAssistantMessage ( "short reply" ) ] ) ;
250293 const bundle = createAgent ( {
0 commit comments