@@ -422,82 +422,6 @@ describe("resume_agent", () => {
422422 expect ( results [ 0 ] ! . stop_reason ) . toBeUndefined ( ) ;
423423 } ) ;
424424
425- test ( "send_input interrupt then successful follow-up wait is done without leftover interrupted stop_reason" , async ( ) => {
426- const sessions = createSubAgentSessionStore ( ) ;
427- const fleetRecords = createFleetMailbox ( sessions ) ;
428- const worker = sessions . start ( {
429- description : "worker" ,
430- agentId : "a" ,
431- brief : "b" ,
432- retained : true ,
433- } ) ;
434- sessions . markRunning ( worker . id ) ;
435- sessions . registerInterrupt ( worker . id , ( ) => { } ) ;
436- let finish : ( reply : string ) => void = ( ) => { } ;
437- sessions . registerFollowup (
438- worker . id ,
439- ( ) =>
440- new Promise < string > ( ( resolve ) => {
441- finish = resolve ;
442- } ) ,
443- ) ;
444- fleetRecords . register ( worker . id ) ;
445-
446- const sendInput = createSendInputTool ( { sessions, fleetRecords } ) ;
447- const wait = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
448-
449- await callTool ( sendInput , { target : worker . id , message : "stop that" , interrupt : true } ) ;
450- const inflight = fleetRecords . peek ( worker . id ) ;
451- expect ( inflight ?. status ) . toBe ( "interrupted" ) ;
452- expect ( inflight ?. stopReason ) . toBe ( "interrupted" ) ;
453- expect ( sessions . get ( worker . id ) ?. stopReason ) . toBe ( "interrupted" ) ;
454- expect ( sessions . get ( worker . id ) ?. lifecycleStatus ) . toBe ( "running" ) ;
455-
456- finish ( "followup report" ) ;
457- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
458- const collected = await callTool ( wait , { targets : [ worker . id ] , timeout_ms : 1000 } ) ;
459- expect ( collected . timed_out ) . toBe ( false ) ;
460- const results = collected . results as {
461- status : string ;
462- report ?: string ;
463- stop_reason ?: string ;
464- } [ ] ;
465- expect ( results [ 0 ] ! . status ) . toBe ( "done" ) ;
466- expect ( results [ 0 ] ! . report ) . toBe ( "followup report" ) ;
467- expect ( results [ 0 ] ! . stop_reason ) . toBeUndefined ( ) ;
468- } ) ;
469-
470- test ( "followup throw after interrupt wait still has stop_reason interrupted" , async ( ) => {
471- const sessions = createSubAgentSessionStore ( ) ;
472- const fleetRecords = createFleetMailbox ( sessions ) ;
473- const worker = sessions . start ( {
474- description : "worker" ,
475- agentId : "a" ,
476- brief : "b" ,
477- retained : true ,
478- } ) ;
479- sessions . markRunning ( worker . id ) ;
480- sessions . registerInterrupt ( worker . id , ( ) => { } ) ;
481- sessions . registerFollowup ( worker . id , async ( ) => {
482- throw new Error ( "send failed" ) ;
483- } ) ;
484- fleetRecords . register ( worker . id ) ;
485-
486- const sendInput = createSendInputTool ( { sessions, fleetRecords } ) ;
487- const wait = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
488-
489- await callTool ( sendInput , { target : worker . id , message : "stop that" , interrupt : true } ) ;
490- await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
491- const collected = await callTool ( wait , { targets : [ worker . id ] , timeout_ms : 1000 } ) ;
492- expect ( collected . timed_out ) . toBe ( false ) ;
493- const results = collected . results as {
494- status : string ;
495- stop_reason ?: string ;
496- } [ ] ;
497- expect ( results [ 0 ] ! . status ) . toBe ( "interrupted" ) ;
498- expect ( results [ 0 ] ! . stop_reason ) . toBe ( "interrupted" ) ;
499- } ) ;
500-
501425 test ( "resume followup rejection invokes close; close_agent tears down leftover" , async ( ) => {
502426 const sessions = createSubAgentSessionStore ( ) ;
503427 const fleetRecords = createFleetMailbox ( sessions ) ;
@@ -670,6 +594,82 @@ describe("interrupt_agent", () => {
670594} ) ;
671595
672596describe ( "send_input" , ( ) => {
597+ test ( "send_input interrupt then successful follow-up wait is done without leftover interrupted stop_reason" , async ( ) => {
598+ const sessions = createSubAgentSessionStore ( ) ;
599+ const fleetRecords = createFleetMailbox ( sessions ) ;
600+ const worker = sessions . start ( {
601+ description : "worker" ,
602+ agentId : "a" ,
603+ brief : "b" ,
604+ retained : true ,
605+ } ) ;
606+ sessions . markRunning ( worker . id ) ;
607+ sessions . registerInterrupt ( worker . id , ( ) => { } ) ;
608+ let finish : ( reply : string ) => void = ( ) => { } ;
609+ sessions . registerFollowup (
610+ worker . id ,
611+ ( ) =>
612+ new Promise < string > ( ( resolve ) => {
613+ finish = resolve ;
614+ } ) ,
615+ ) ;
616+ fleetRecords . register ( worker . id ) ;
617+
618+ const sendInput = createSendInputTool ( { sessions, fleetRecords } ) ;
619+ const wait = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
620+
621+ await callTool ( sendInput , { target : worker . id , message : "stop that" , interrupt : true } ) ;
622+ const inflight = fleetRecords . peek ( worker . id ) ;
623+ expect ( inflight ?. status ) . toBe ( "interrupted" ) ;
624+ expect ( inflight ?. stopReason ) . toBe ( "interrupted" ) ;
625+ expect ( sessions . get ( worker . id ) ?. stopReason ) . toBe ( "interrupted" ) ;
626+ expect ( sessions . get ( worker . id ) ?. lifecycleStatus ) . toBe ( "running" ) ;
627+
628+ finish ( "followup report" ) ;
629+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
630+ const collected = await callTool ( wait , { targets : [ worker . id ] , timeout_ms : 1000 } ) ;
631+ expect ( collected . timed_out ) . toBe ( false ) ;
632+ const results = collected . results as {
633+ status : string ;
634+ report ?: string ;
635+ stop_reason ?: string ;
636+ } [ ] ;
637+ expect ( results [ 0 ] ! . status ) . toBe ( "done" ) ;
638+ expect ( results [ 0 ] ! . report ) . toBe ( "followup report" ) ;
639+ expect ( results [ 0 ] ! . stop_reason ) . toBeUndefined ( ) ;
640+ } ) ;
641+
642+ test ( "followup throw after interrupt wait still has stop_reason interrupted" , async ( ) => {
643+ const sessions = createSubAgentSessionStore ( ) ;
644+ const fleetRecords = createFleetMailbox ( sessions ) ;
645+ const worker = sessions . start ( {
646+ description : "worker" ,
647+ agentId : "a" ,
648+ brief : "b" ,
649+ retained : true ,
650+ } ) ;
651+ sessions . markRunning ( worker . id ) ;
652+ sessions . registerInterrupt ( worker . id , ( ) => { } ) ;
653+ sessions . registerFollowup ( worker . id , async ( ) => {
654+ throw new Error ( "send failed" ) ;
655+ } ) ;
656+ fleetRecords . register ( worker . id ) ;
657+
658+ const sendInput = createSendInputTool ( { sessions, fleetRecords } ) ;
659+ const wait = createWaitAgentsTool ( { sessions, fleetRecords } ) ;
660+
661+ await callTool ( sendInput , { target : worker . id , message : "stop that" , interrupt : true } ) ;
662+ await new Promise ( ( resolve ) => setTimeout ( resolve , 0 ) ) ;
663+ const collected = await callTool ( wait , { targets : [ worker . id ] , timeout_ms : 1000 } ) ;
664+ expect ( collected . timed_out ) . toBe ( false ) ;
665+ const results = collected . results as {
666+ status : string ;
667+ stop_reason ?: string ;
668+ } [ ] ;
669+ expect ( results [ 0 ] ! . status ) . toBe ( "interrupted" ) ;
670+ expect ( results [ 0 ] ! . stop_reason ) . toBe ( "interrupted" ) ;
671+ } ) ;
672+
673673 test ( "soft-delivers without flipping lifecycle or awaiting a reply" , async ( ) => {
674674 const sessions = createSubAgentSessionStore ( ) ;
675675 const worker = sessions . start ( {
0 commit comments