Skip to content

Commit 3e76526

Browse files
clawsweeper[bot]yetvalTakhoffman
authored
fix(agents): preserve run-mode keep subagents past session sweep TTL (#83132) (#83226)
Summary: - The PR exempts run-mode `cleanup: "keep"` subagent registry entries from the session-mode sweep TTL, adds focused regression coverage, and records the fix in the changelog. - Reproducibility: yes. Current main source shows a run-mode keep entry has no `archiveAtMs` and then matches ... ; the linked source PR also provides before/after terminal proof against a real persisted `runs.json` path. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(agents): preserve run-mode keep subagents past session sweep TTL … Validation: - ClawSweeper review passed for head 32faf5c. - Required merge gates passed before the squash merge. Prepared head SHA: 32faf5c Review: #83226 (comment) Co-authored-by: yetval <yetvald@gmail.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
1 parent fb028ca commit 3e76526

3 files changed

Lines changed: 31 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai
3838
- QA-Lab: make mock parity dispatch provider-aware for source discovery and subagent scenarios so OpenAI and Anthropic lanes no longer share identical canned plans. Fixes #64879. Thanks @100yenadmin.
3939
- QA-Lab: stop returning Control UI bearer tokens from unauthenticated bootstrap payloads and bind Docker harness ports to loopback-only host addresses. (#66355) Thanks @pgondhi987.
4040
- Mac app: avoid a SwiftUI metadata crash when rendering the Cron Jobs settings pane.
41+
- Agents/subagents: preserve run-mode keep subagent registry entries past the session sweep TTL, so kept subagent runs remain visible after cleanup completes. Fixes #83132. (#83168) Thanks @yetval.
4142
- Agents/OpenAI streams: yield via `setTimeout(0)` instead of `setImmediate` between bursty Responses chunks so abort timers can fire during the yield, keeping cancel-on-timeout responsive on hot streams. Refs #82462.
4243
- CLI/config: send SecretRef diagnostics to stderr so JSON command stdout remains parseable.
4344
- CLI/plugins: ship the bundled memory CLI as a package entry so package-installed `openclaw memory` commands register correctly.

src/agents/subagent-registry.test.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,33 @@ describe("subagent registry seam flow", () => {
767767
expect(run?.cleanupCompletedAt).toBeTypeOf("number");
768768
});
769769

770+
it("preserves run-mode keep entries past SESSION_RUN_TTL_MS sweep", async () => {
771+
mod.registerSubagentRun({
772+
runId: "run-keep-survives-ttl",
773+
childSessionKey: "agent:main:subagent:child",
774+
requesterSessionKey: "agent:main:main",
775+
requesterDisplayKey: "main",
776+
task: "keep me past the session ttl",
777+
cleanup: "keep",
778+
spawnMode: "run",
779+
});
780+
781+
await waitForFast(() => {
782+
const run = mod
783+
.listSubagentRunsForRequester("agent:main:main")
784+
.find((entry) => entry.runId === "run-keep-survives-ttl");
785+
expect(run?.cleanupCompletedAt).toBeTypeOf("number");
786+
});
787+
788+
vi.setSystemTime(new Date(Date.parse("2026-03-24T12:00:00Z") + 10 * 60_000));
789+
await mod.__testing.sweepOnceForTests();
790+
791+
const run = mod
792+
.listSubagentRunsForRequester("agent:main:main")
793+
.find((entry) => entry.runId === "run-keep-survives-ttl");
794+
expect(run?.runId).toBe("run-keep-survives-ttl");
795+
});
796+
770797
it("retries completion hooks before resuming ended cleanup", async () => {
771798
mocks.ensureRuntimePluginsLoaded.mockRejectedValueOnce(new Error("runtime unavailable"));
772799

src/agents/subagent-registry.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,8 +863,9 @@ async function sweepSubagentRuns() {
863863
}
864864
}
865865

866-
// Session-mode runs have no archiveAtMs — apply absolute TTL after cleanup completes.
867-
// Use cleanupCompletedAt (not endedAt) to avoid interrupting deferred cleanup flows.
866+
if (!entry.archiveAtMs && entry.cleanup === "keep" && entry.spawnMode !== "session") {
867+
continue;
868+
}
868869
if (!entry.archiveAtMs) {
869870
if (
870871
typeof entry.cleanupCompletedAt === "number" &&

0 commit comments

Comments
 (0)