From 0942ecb54f6d9f4fd523c0155c473a9b049ca757 Mon Sep 17 00:00:00 2001 From: Artale <117890364+arosstale@users.noreply.github.com> Date: Sat, 14 Feb 2026 02:10:17 +0100 Subject: [PATCH] fix(cron): use job config for cleanup instead of hardcoded "keep" (openclaw#15427) thanks @arosstale Verified: - pnpm install --frozen-lockfile - pnpm build - pnpm check - pnpm test Co-authored-by: arosstale <117890364+arosstale@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com> --- CHANGELOG.md | 1 + ...onse-has-heartbeat-ok-but-includes.test.ts | 60 +++++++++++++++++++ src/cron/isolated-agent/run.ts | 2 +- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02a621e22b9..9be74e7ef52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Docs: https://docs.openclaw.ai - Onboarding/CLI: restore terminal state without resuming paused `stdin`, so onboarding exits cleanly after choosing Web UI and the installer returns instead of appearing stuck. - Auth/OpenAI Codex: share OAuth login handling across onboarding and `models auth login --provider openai-codex`, keep onboarding alive when OAuth fails, and surface a direct OAuth help note instead of terminating the wizard. (#15406, follow-up to #14552) Thanks @zhiluo20. - Cron: add regression coverage for announce-mode isolated jobs so runs that already report `delivered: true` do not enqueue duplicate main-session relays, including delivery configs where `mode` is omitted and defaults to announce. (#15737) Thanks @brandonwise. +- Cron: honor `deleteAfterRun` in isolated announce delivery by mapping it to subagent announce cleanup mode, so cron run sessions configured for deletion are removed after completion. (#15368) Thanks @arosstale. - Onboarding/Providers: add vLLM as an onboarding provider with model discovery, auth profile wiring, and non-interactive auth-choice validation. (#12577) Thanks @gejifeng. - Onboarding/Providers: preserve Hugging Face auth intent in auth-choice remapping (`tokenProvider=huggingface` with `authChoice=apiKey`) and skip env-override prompts when an explicit token is provided. (#13472) Thanks @Josephrp. - OpenAI Codex/Spark: implement end-to-end `gpt-5.3-codex-spark` support across fallback/thinking/model resolution and `models list` forward-compat visibility. (#14990, #15174) Thanks @L-U-C-K-Y, @loiie45e. diff --git a/src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts b/src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts index 07965726229..dcb3a98dab1 100644 --- a/src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts +++ b/src/cron/isolated-agent.delivers-response-has-heartbeat-ok-but-includes.test.ts @@ -205,6 +205,66 @@ describe("runCronIsolatedAgentTurn", () => { expect(res.status).toBe("ok"); expect(runSubagentAnnounceFlow).toHaveBeenCalledTimes(1); + const announceArgs = vi.mocked(runSubagentAnnounceFlow).mock.calls[0]?.[0] as + | { cleanup?: "keep" | "delete" } + | undefined; + expect(announceArgs?.cleanup).toBe("keep"); + expect(deps.sendMessageTelegram).not.toHaveBeenCalled(); + }); + }); + + it("passes cleanup=delete to announce flow when job.deleteAfterRun is true", async () => { + await withTempHome(async (home) => { + const storePath = await writeSessionStore(home); + const deps: CliDeps = { + sendMessageWhatsApp: vi.fn(), + sendMessageTelegram: vi.fn().mockResolvedValue({ + messageId: "t1", + chatId: "123", + }), + sendMessageDiscord: vi.fn(), + sendMessageSignal: vi.fn(), + sendMessageIMessage: vi.fn(), + }; + vi.mocked(runEmbeddedPiAgent).mockResolvedValue({ + payloads: [{ text: "HEARTBEAT_OK 🦞" }], + meta: { + durationMs: 5, + agentMeta: { sessionId: "s", provider: "p", model: "m" }, + }, + }); + + const cfg = makeCfg(home, storePath); + cfg.agents = { + ...cfg.agents, + defaults: { + ...cfg.agents?.defaults, + heartbeat: { ackMaxChars: 0 }, + }, + }; + + const res = await runCronIsolatedAgentTurn({ + cfg, + deps, + job: { + ...makeJob({ + kind: "agentTurn", + message: "do it", + }), + deleteAfterRun: true, + delivery: { mode: "announce", channel: "telegram", to: "123" }, + }, + message: "do it", + sessionKey: "cron:job-1", + lane: "cron", + }); + + expect(res.status).toBe("ok"); + expect(runSubagentAnnounceFlow).toHaveBeenCalledTimes(1); + const announceArgs = vi.mocked(runSubagentAnnounceFlow).mock.calls[0]?.[0] as + | { cleanup?: "keep" | "delete" } + | undefined; + expect(announceArgs?.cleanup).toBe("delete"); expect(deps.sendMessageTelegram).not.toHaveBeenCalled(); }); }); diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index ed4434ef13e..aa97828f2b1 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -598,7 +598,7 @@ export async function runCronIsolatedAgentTurn(params: { requesterDisplayKey: announceSessionKey, task: taskLabel, timeoutMs, - cleanup: "keep", + cleanup: params.job.deleteAfterRun ? "delete" : "keep", roundOneReply: synthesizedText, waitForCompletion: false, startedAt: runStartedAt,