mirror of https://github.com/openclaw/openclaw.git
fix: finalize resumed subagent cleanup give-ups
This commit is contained in:
parent
a2d3b9f317
commit
c3744fbfc4
|
|
@ -26,6 +26,8 @@ const mocks = vi.hoisted(() => ({
|
|||
ensureRuntimePluginsLoaded: vi.fn(),
|
||||
ensureContextEnginesInitialized: vi.fn(),
|
||||
resolveContextEngine: vi.fn(),
|
||||
onSubagentEnded: vi.fn(async () => {}),
|
||||
runSubagentEnded: vi.fn(async () => {}),
|
||||
resolveAgentTimeoutMs: vi.fn(() => 1_000),
|
||||
}));
|
||||
|
||||
|
|
@ -114,6 +116,10 @@ describe("subagent registry seam flow", () => {
|
|||
updatedAt: 1,
|
||||
},
|
||||
});
|
||||
mocks.getGlobalHookRunner.mockReturnValue(null);
|
||||
mocks.resolveContextEngine.mockResolvedValue({
|
||||
onSubagentEnded: mocks.onSubagentEnded,
|
||||
});
|
||||
mocks.callGateway.mockImplementation(async (request: { method?: string }) => {
|
||||
if (request.method === "agent.wait") {
|
||||
return {
|
||||
|
|
@ -235,4 +241,50 @@ describe("subagent registry seam flow", () => {
|
|||
.find((entry) => entry.runId === "run-delete-give-up"),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("finalizes retry-budgeted completion delete runs during resume", async () => {
|
||||
const endedHookRunner = {
|
||||
hasHooks: (hookName: string) => hookName === "subagent_ended",
|
||||
runSubagentEnded: mocks.runSubagentEnded,
|
||||
};
|
||||
mocks.getGlobalHookRunner.mockReturnValue(endedHookRunner as never);
|
||||
mocks.restoreSubagentRunsFromDisk.mockImplementation(
|
||||
((params: { runs: Map<string, unknown>; mergeOnly?: boolean }) => {
|
||||
params.runs.set("run-resume-delete", {
|
||||
runId: "run-resume-delete",
|
||||
childSessionKey: "agent:main:subagent:child",
|
||||
requesterSessionKey: "agent:main:main",
|
||||
requesterDisplayKey: "main",
|
||||
task: "resume delete retry budget",
|
||||
cleanup: "delete",
|
||||
createdAt: Date.parse("2026-03-24T11:58:00Z"),
|
||||
startedAt: Date.parse("2026-03-24T11:59:00Z"),
|
||||
endedAt: Date.parse("2026-03-24T11:59:30Z"),
|
||||
expectsCompletionMessage: true,
|
||||
announceRetryCount: 3,
|
||||
lastAnnounceRetryAt: Date.parse("2026-03-24T11:59:40Z"),
|
||||
});
|
||||
return 1;
|
||||
}) as never,
|
||||
);
|
||||
|
||||
mod.initSubagentRegistry();
|
||||
await Promise.resolve();
|
||||
await Promise.resolve();
|
||||
|
||||
expect(mocks.runSubagentAnnounceFlow).not.toHaveBeenCalled();
|
||||
expect(mocks.runSubagentEnded).toHaveBeenCalledTimes(1);
|
||||
await vi.waitFor(() => {
|
||||
expect(mocks.onSubagentEnded).toHaveBeenCalledWith({
|
||||
childSessionKey: "agent:main:subagent:child",
|
||||
reason: "deleted",
|
||||
workspaceDir: undefined,
|
||||
});
|
||||
});
|
||||
expect(
|
||||
mod
|
||||
.listSubagentRunsForRequester("agent:main:main")
|
||||
.find((entry) => entry.runId === "run-resume-delete"),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -712,9 +712,11 @@ function resumeSubagentRun(runId: string) {
|
|||
}
|
||||
// Skip entries that have exhausted their retry budget or expired (#18264).
|
||||
if ((entry.announceRetryCount ?? 0) >= MAX_ANNOUNCE_RETRY_COUNT) {
|
||||
logAnnounceGiveUp(entry, "retry-limit");
|
||||
entry.cleanupCompletedAt = Date.now();
|
||||
persistSubagentRuns();
|
||||
void finalizeResumedAnnounceGiveUp({
|
||||
runId,
|
||||
entry,
|
||||
reason: "retry-limit",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (
|
||||
|
|
@ -722,9 +724,11 @@ function resumeSubagentRun(runId: string) {
|
|||
typeof entry.endedAt === "number" &&
|
||||
Date.now() - entry.endedAt > ANNOUNCE_EXPIRY_MS
|
||||
) {
|
||||
logAnnounceGiveUp(entry, "expiry");
|
||||
entry.cleanupCompletedAt = Date.now();
|
||||
persistSubagentRuns();
|
||||
void finalizeResumedAnnounceGiveUp({
|
||||
runId,
|
||||
entry,
|
||||
reason: "expiry",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1080,6 +1084,30 @@ async function finalizeSubagentCleanup(
|
|||
}, deferredDecision.resumeDelayMs).unref?.();
|
||||
}
|
||||
|
||||
async function finalizeResumedAnnounceGiveUp(params: {
|
||||
runId: string;
|
||||
entry: SubagentRunRecord;
|
||||
reason: "retry-limit" | "expiry";
|
||||
}) {
|
||||
params.entry.wakeOnDescendantSettle = undefined;
|
||||
params.entry.fallbackFrozenResultText = undefined;
|
||||
params.entry.fallbackFrozenResultCapturedAt = undefined;
|
||||
const shouldDeleteAttachments =
|
||||
params.entry.cleanup === "delete" || !params.entry.retainAttachmentsOnKeep;
|
||||
if (shouldDeleteAttachments) {
|
||||
await safeRemoveAttachmentsDir(params.entry);
|
||||
}
|
||||
const completionReason = resolveCleanupCompletionReason(params.entry);
|
||||
await emitCompletionEndedHookIfNeeded(params.entry, completionReason);
|
||||
logAnnounceGiveUp(params.entry, params.reason);
|
||||
completeCleanupBookkeeping({
|
||||
runId: params.runId,
|
||||
entry: params.entry,
|
||||
cleanup: params.entry.cleanup,
|
||||
completedAt: Date.now(),
|
||||
});
|
||||
}
|
||||
|
||||
async function emitCompletionEndedHookIfNeeded(
|
||||
entry: SubagentRunRecord,
|
||||
reason: SubagentLifecycleEndedReason,
|
||||
|
|
|
|||
Loading…
Reference in New Issue