fix: finalize deferred subagent expiry cleanup

This commit is contained in:
Tak Hoffman 2026-03-24 01:11:28 -05:00
parent 5dc42dfb17
commit 5e9ea804d4
No known key found for this signature in database
2 changed files with 76 additions and 3 deletions

View File

@ -288,4 +288,62 @@ describe("subagent registry seam flow", () => {
.find((entry) => entry.runId === "run-resume-delete"),
).toBeUndefined();
});
it("finalizes expired delete-mode parents when descendant cleanup retriggers deferred announce handling", async () => {
mocks.loadSessionStore.mockReturnValue({
"agent:main:subagent:parent": {
sessionId: "sess-parent",
updatedAt: 1,
},
"agent:main:subagent:child": {
sessionId: "sess-child",
updatedAt: 1,
},
});
mod.addSubagentRunForTests({
runId: "run-parent-expired",
childSessionKey: "agent:main:subagent:parent",
requesterSessionKey: "agent:main:main",
requesterDisplayKey: "main",
task: "expired parent cleanup",
cleanup: "delete",
createdAt: Date.parse("2026-03-24T11:50:00Z"),
startedAt: Date.parse("2026-03-24T11:50:30Z"),
endedAt: Date.parse("2026-03-24T11:51:00Z"),
cleanupHandled: false,
cleanupCompletedAt: undefined,
});
mod.registerSubagentRun({
runId: "run-child-finished",
childSessionKey: "agent:main:subagent:child",
requesterSessionKey: "agent:main:subagent:parent",
requesterDisplayKey: "parent",
task: "descendant settles",
cleanup: "keep",
});
await vi.waitFor(() => {
expect(
mod
.listSubagentRunsForRequester("agent:main:main")
.find((entry) => entry.runId === "run-parent-expired"),
).toBeUndefined();
});
expect(mocks.runSubagentAnnounceFlow).toHaveBeenCalledTimes(1);
expect(mocks.runSubagentAnnounceFlow).toHaveBeenCalledWith(
expect.objectContaining({
childRunId: "run-child-finished",
}),
);
await vi.waitFor(() => {
expect(mocks.onSubagentEnded).toHaveBeenCalledWith({
childSessionKey: "agent:main:subagent:parent",
reason: "deleted",
workspaceDir: undefined,
});
});
});
});

View File

@ -1174,9 +1174,24 @@ function retryDeferredCompletedAnnounces(excludeRunId?: string) {
// stay pending while descendants run for a long time.
const endedAgo = now - (entry.endedAt ?? now);
if (entry.expectsCompletionMessage !== true && endedAgo > ANNOUNCE_EXPIRY_MS) {
logAnnounceGiveUp(entry, "expiry");
entry.cleanupCompletedAt = now;
persistSubagentRuns();
if (!beginSubagentCleanup(runId)) {
continue;
}
void finalizeResumedAnnounceGiveUp({
runId,
entry,
reason: "expiry",
}).catch((error) => {
defaultRuntime.log(
`[warn] Subagent expiry finalize failed during deferred retry for run ${runId}: ${String(error)}`,
);
const current = subagentRuns.get(runId);
if (!current || current.cleanupCompletedAt) {
return;
}
current.cleanupHandled = false;
persistSubagentRuns();
});
continue;
}
resumedRuns.delete(runId);