@@ -620,6 +620,105 @@ describe("killControlledSubagentRun", () => {
620620 } ) ;
621621 expect ( getSubagentRunByChildSessionKey ( leafSessionKey ) ?. endedAt ) . toBeTypeOf ( "number" ) ;
622622 } ) ;
623+
624+ it ( "does not cascade through a child session that moved to a newer parent" , async ( ) => {
625+ const oldParentSessionKey = "agent:main:subagent:old-parent" ;
626+ const newParentSessionKey = "agent:main:subagent:new-parent" ;
627+ const childSessionKey = "agent:main:subagent:shared-child" ;
628+ const leafSessionKey = `${ childSessionKey } :subagent:leaf` ;
629+
630+ addSubagentRunForTests ( {
631+ runId : "run-old-parent-current" ,
632+ childSessionKey : oldParentSessionKey ,
633+ controllerSessionKey : "agent:main:main" ,
634+ requesterSessionKey : "agent:main:main" ,
635+ requesterDisplayKey : "main" ,
636+ task : "old parent task" ,
637+ cleanup : "keep" ,
638+ createdAt : Date . now ( ) - 8_000 ,
639+ startedAt : Date . now ( ) - 7_000 ,
640+ endedAt : Date . now ( ) - 6_000 ,
641+ outcome : { status : "ok" } ,
642+ } ) ;
643+ addSubagentRunForTests ( {
644+ runId : "run-new-parent-current" ,
645+ childSessionKey : newParentSessionKey ,
646+ controllerSessionKey : "agent:main:main" ,
647+ requesterSessionKey : "agent:main:main" ,
648+ requesterDisplayKey : "main" ,
649+ task : "new parent task" ,
650+ cleanup : "keep" ,
651+ createdAt : Date . now ( ) - 5_000 ,
652+ startedAt : Date . now ( ) - 4_000 ,
653+ } ) ;
654+ addSubagentRunForTests ( {
655+ runId : "run-child-stale-old-parent" ,
656+ childSessionKey,
657+ controllerSessionKey : oldParentSessionKey ,
658+ requesterSessionKey : oldParentSessionKey ,
659+ requesterDisplayKey : oldParentSessionKey ,
660+ task : "stale shared child task" ,
661+ cleanup : "keep" ,
662+ createdAt : Date . now ( ) - 4_000 ,
663+ startedAt : Date . now ( ) - 3_500 ,
664+ endedAt : Date . now ( ) - 3_000 ,
665+ outcome : { status : "ok" } ,
666+ } ) ;
667+ addSubagentRunForTests ( {
668+ runId : "run-child-current-new-parent" ,
669+ childSessionKey,
670+ controllerSessionKey : newParentSessionKey ,
671+ requesterSessionKey : newParentSessionKey ,
672+ requesterDisplayKey : newParentSessionKey ,
673+ task : "current shared child task" ,
674+ cleanup : "keep" ,
675+ createdAt : Date . now ( ) - 2_000 ,
676+ startedAt : Date . now ( ) - 1_500 ,
677+ } ) ;
678+ addSubagentRunForTests ( {
679+ runId : "run-leaf-active" ,
680+ childSessionKey : leafSessionKey ,
681+ controllerSessionKey : childSessionKey ,
682+ requesterSessionKey : childSessionKey ,
683+ requesterDisplayKey : childSessionKey ,
684+ task : "leaf task" ,
685+ cleanup : "keep" ,
686+ createdAt : Date . now ( ) - 1_000 ,
687+ startedAt : Date . now ( ) - 900 ,
688+ } ) ;
689+
690+ const result = await killControlledSubagentRun ( {
691+ cfg : { } as OpenClawConfig ,
692+ controller : {
693+ controllerSessionKey : "agent:main:main" ,
694+ callerSessionKey : "agent:main:main" ,
695+ callerIsSubagent : false ,
696+ controlScope : "children" ,
697+ } ,
698+ entry : {
699+ runId : "run-old-parent-current" ,
700+ childSessionKey : oldParentSessionKey ,
701+ requesterSessionKey : "agent:main:main" ,
702+ requesterDisplayKey : "main" ,
703+ controllerSessionKey : "agent:main:main" ,
704+ task : "old parent task" ,
705+ cleanup : "keep" ,
706+ createdAt : Date . now ( ) - 8_000 ,
707+ startedAt : Date . now ( ) - 7_000 ,
708+ endedAt : Date . now ( ) - 6_000 ,
709+ outcome : { status : "ok" } ,
710+ } ,
711+ } ) ;
712+
713+ expect ( result ) . toEqual ( {
714+ status : "done" ,
715+ runId : "run-old-parent-current" ,
716+ sessionKey : oldParentSessionKey ,
717+ label : "old parent task" ,
718+ text : "old parent task is already finished." ,
719+ } ) ;
720+ expect ( getSubagentRunByChildSessionKey ( leafSessionKey ) ?. endedAt ) . toBeUndefined ( ) ;
721+ } ) ;
623722} ) ;
624723
625724describe ( "killAllControlledSubagentRuns" , ( ) => {
0 commit comments