@@ -174,7 +174,7 @@ describe("spawn_agent + wait_agents", () => {
174174 expect ( secondResults [ 0 ] ! . report ) . toBe ( "finished" ) ;
175175 } ) ;
176176
177- test ( "wait_agents with no targets waits on all currently running spawned agents " , async ( ) => {
177+ test ( "wait_agents with no targets waits on all uncollected agents in this fleet " , async ( ) => {
178178 const gates = [ deferred < RunSubAgentResult > ( ) , deferred < RunSubAgentResult > ( ) ] ;
179179 let callIndex = 0 ;
180180 const deps = makeDeps ( async ( ) => gates [ callIndex ++ ] ! . promise ) ;
@@ -462,6 +462,64 @@ describe("wait_agents caller scope", () => {
462462 expect ( finishedResults . every ( ( r ) => r . status === "done" ) ) . toBe ( true ) ;
463463 } ) ;
464464
465+ test ( "mode=all with one interrupted target stays blocked until siblings finish" , async ( ) => {
466+ const gates = [ deferred < RunSubAgentResult > ( ) , deferred < RunSubAgentResult > ( ) ] ;
467+ let callIndex = 0 ;
468+ const deps = makeDeps ( async ( params ) => {
469+ params . onAgentReady ?.( {
470+ close : async ( ) => { } ,
471+ interrupt : ( ) => { } ,
472+ followup : async ( ) => "" ,
473+ } ) ;
474+ return gates [ callIndex ++ ] ! . promise ;
475+ } ) ;
476+ const spawn = createSpawnAgentTool ( deps ) ;
477+ const wait = createWaitAgentsTool ( {
478+ sessions : deps . sessions ,
479+ fleetRecords : deps . fleetRecords ,
480+ } ) ;
481+ const interrupt = createInterruptAgentTool ( {
482+ sessions : deps . sessions ,
483+ fleetRecords : deps . fleetRecords ,
484+ } ) ;
485+
486+ const first = await callTool ( spawn , {
487+ description : "a" ,
488+ prompt : "do it" ,
489+ intent : "explore" ,
490+ } ) ;
491+ const second = await callTool ( spawn , {
492+ description : "b" ,
493+ prompt : "do it" ,
494+ intent : "explore" ,
495+ } ) ;
496+ const ids = [ first . agent_id as string , second . agent_id as string ] ;
497+
498+ // Interrupt one of N while mode=all is in flight: interrupted is terminal
499+ // for that target, but mode=all must not complete as "all done" while a
500+ // sibling is still running.
501+ if ( interrupt . kind !== "full" ) throw new Error ( "expected full tool" ) ;
502+ await interrupt . handler (
503+ { id : "int-1" , name : "interrupt_agent" , arguments : { target : ids [ 0 ] ! } } ,
504+ new AbortController ( ) . signal ,
505+ ) ;
506+
507+ const partial = await callTool ( wait , { targets : ids , mode : "all" , timeout_ms : 50 } ) ;
508+ expect ( partial . timed_out ) . toBe ( true ) ;
509+ const partialResults = partial . results as { agent_id : string ; status : string } [ ] ;
510+ expect ( partialResults . find ( ( r ) => r . agent_id === ids [ 0 ] ! ) ?. status ) . toBe ( "interrupted" ) ;
511+ expect ( partialResults . find ( ( r ) => r . agent_id === ids [ 1 ] ! ) ?. status ) . toBe ( "running" ) ;
512+
513+ gates [ 1 ] ! . resolve ( { report : "b done" } ) ;
514+ const finished = await callTool ( wait , { targets : ids , mode : "all" , timeout_ms : 5000 } ) ;
515+ expect ( finished . timed_out ) . toBe ( false ) ;
516+ const finishedResults = finished . results as { agent_id : string ; status : string } [ ] ;
517+ expect ( finishedResults . find ( ( r ) => r . agent_id === ids [ 0 ] ! ) ?. status ) . toBe ( "interrupted" ) ;
518+ expect ( finishedResults . find ( ( r ) => r . agent_id === ids [ 1 ] ! ) ?. status ) . toBe ( "done" ) ;
519+ // Leave the interrupted gate unresolved — interrupt unblocked the wait
520+ // without the run settling.
521+ } ) ;
522+
465523 test ( "aborting the wait returns without cancelling workers" , async ( ) => {
466524 const gate = deferred < RunSubAgentResult > ( ) ;
467525 const deps = makeDeps ( async ( ) => gate . promise ) ;
0 commit comments