mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(agents): queued subagents falsely fail with 'lost active execution context' after 60s in the swarm queue (#123169)
* fix(agents): queued swarm collectors falsely killed after 60s waiting for a slot The subagent registry sweeper's stale-context reap treats 'no live gateway run context + 60s age' as proof a run died. Queued collectors intentionally have no run context until the swarm FIFO dispatches them, so any collector that waited more than a minute for a slot (or any queued row restored after a gateway restart) was terminated with a fabricated 'subagent run lost active execution context' error while the FIFO later launched the real turn anyway — burning the slot and tokens for a result already reported failed to the parent. Queued rows keep their real owners (scheduler dispatch, kill intents, restore settlement); exclude them from the stale-context reap. * refactor: compact the queued-collector guard to fit the sweeper max-lines cap
This commit is contained in:
committed by
GitHub
parent
f3db7fe511
commit
41fc4558de
@@ -364,9 +364,10 @@ export function createSubagentRegistrySweeper(params: {
|
||||
continue;
|
||||
}
|
||||
if (typeof entry.execution.endedAt !== "number") {
|
||||
const hasLiveRunContext = Boolean(getAgentRunContext(runId));
|
||||
// Queued collectors have no run context until FIFO dispatch; the scheduler owns them.
|
||||
const notStale = entry.execution.status === "queued" || getAgentRunContext(runId);
|
||||
const activeAgeMs = now - (entry.execution.startedAt ?? entry.createdAt);
|
||||
if (!hasLiveRunContext && activeAgeMs >= STALE_ACTIVE_SUBAGENT_GRACE_MS) {
|
||||
if (!notStale && activeAgeMs >= STALE_ACTIVE_SUBAGENT_GRACE_MS) {
|
||||
const orphanReason = resolveSubagentRunOrphanReason({ entry });
|
||||
if (orphanReason) {
|
||||
if (
|
||||
|
||||
@@ -277,6 +277,33 @@ describe("subagent registry archive behavior", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not reap a queued collector waiting for a swarm slot past the stale grace", async () => {
|
||||
// Queued collectors have no gateway run context until FIFO dispatch; the
|
||||
// stale-context reap must not fabricate a lost-context failure for them.
|
||||
const now = Date.now();
|
||||
addCanonicalSubagentRunForTests({
|
||||
runId: "run-queued-collector",
|
||||
childSessionKey: "agent:main:subagent:queued-collector",
|
||||
requesterSessionKey: "agent:main:main",
|
||||
requesterDisplayKey: "main",
|
||||
task: "wait for a swarm slot",
|
||||
cleanup: "keep",
|
||||
collect: true,
|
||||
createdAt: now - 120_000,
|
||||
execution: { status: "queued" },
|
||||
});
|
||||
|
||||
await mod.testing.sweepOnceForTests();
|
||||
|
||||
expect(mod.listSubagentRunsForRequester("agent:main:main")[0]).toMatchObject({
|
||||
runId: "run-queued-collector",
|
||||
execution: { status: "queued" },
|
||||
});
|
||||
expect(
|
||||
mod.listSubagentRunsForRequester("agent:main:main")[0]?.collectorCompletion,
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not archive an active run carrying an obsolete persisted deadline", async () => {
|
||||
vi.mocked(getAgentRunContext).mockReturnValue({} as never);
|
||||
const now = Date.now();
|
||||
|
||||
Reference in New Issue
Block a user