Skip to content

Commit 5720c39

Browse files
authored
Merge d294e71 into bdd365a
2 parents bdd365a + d294e71 commit 5720c39

2 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/agents/subagent-registry.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3373,6 +3373,61 @@ describe("subagent registry seam flow", () => {
33733373
});
33743374
});
33753375

3376+
it("wakes a sessions_yield-paused parent when pending descendants settle", async () => {
3377+
mocks.loadSessionStore.mockReturnValue({
3378+
"agent:main:subagent:parent": {
3379+
sessionId: "sess-parent",
3380+
updatedAt: 1,
3381+
},
3382+
"agent:main:subagent:child": {
3383+
sessionId: "sess-child",
3384+
updatedAt: 1,
3385+
},
3386+
});
3387+
3388+
mod.addSubagentRunForTests({
3389+
runId: "run-yielded-parent",
3390+
childSessionKey: "agent:main:subagent:parent",
3391+
requesterSessionKey: "agent:main:main",
3392+
requesterDisplayKey: "main",
3393+
task: "yielded parent waiting on descendants",
3394+
cleanup: "keep",
3395+
createdAt: Date.parse("2026-06-26T02:17:00Z"),
3396+
startedAt: Date.parse("2026-06-26T02:18:00Z"),
3397+
endedAt: Date.parse("2026-06-26T02:19:00Z"),
3398+
pauseReason: "sessions_yield",
3399+
wakeOnDescendantSettle: true,
3400+
cleanupHandled: false,
3401+
cleanupCompletedAt: undefined,
3402+
});
3403+
3404+
mod.registerSubagentRun({
3405+
runId: "run-yielded-child-finished",
3406+
childSessionKey: "agent:main:subagent:child",
3407+
requesterSessionKey: "agent:main:subagent:parent",
3408+
requesterDisplayKey: "parent",
3409+
task: "descendant settles after yield",
3410+
cleanup: "keep",
3411+
});
3412+
3413+
await waitForFast(() => {
3414+
expect(mocks.runSubagentAnnounceFlow).toHaveBeenCalledTimes(2);
3415+
});
3416+
expectRecordFields(
3417+
getMockCallArg(mocks.runSubagentAnnounceFlow, 0, 0, "child finished announce"),
3418+
{ childRunId: "run-yielded-child-finished" },
3419+
"child finished announce params",
3420+
);
3421+
expectRecordFields(
3422+
getMockCallArg(mocks.runSubagentAnnounceFlow, 1, 0, "yielded parent wake announce"),
3423+
{
3424+
childRunId: "run-yielded-parent",
3425+
wakeOnDescendantSettle: true,
3426+
},
3427+
"yielded parent wake announce params",
3428+
);
3429+
});
3430+
33763431
it("loads runtime plugins before emitting killed subagent ended hooks", async () => {
33773432
const endedHookRunner = {
33783433
hasHooks: (hookName: string) => hookName === "subagent_ended",

src/agents/subagent-registry.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,9 @@ function resumeSubagentRun(runId: string) {
626626
if (typeof entry.endedAt === "number" && isDeliverySuspended(entry)) {
627627
return;
628628
}
629-
if (entry.pauseReason === "sessions_yield") {
629+
// Yielded runs stay paused until explicitly steered, except orchestrators
630+
// waiting on descendants: their settle retry must reach the wake path.
631+
if (entry.pauseReason === "sessions_yield" && entry.wakeOnDescendantSettle !== true) {
630632
return;
631633
}
632634
// Skip entries that have exhausted their retry budget or expired (#18264).

0 commit comments

Comments
 (0)