From ef126f377b64a8a75eb58f49bc0f7e810eeda911 Mon Sep 17 00:00:00 2001 From: Sami Rusani Date: Sun, 12 Apr 2026 08:29:25 +0200 Subject: [PATCH] Fix cron sessionFile persistence --- .../isolated-agent.session-identity.test.ts | 19 +++++++++++++++++++ src/cron/isolated-agent.turn-test-helpers.ts | 5 ++++- src/cron/isolated-agent/run-executor.ts | 10 ++++++---- src/cron/isolated-agent/run.ts | 4 ++++ 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/cron/isolated-agent.session-identity.test.ts b/src/cron/isolated-agent.session-identity.test.ts index f2f345378a7..36df45280f4 100644 --- a/src/cron/isolated-agent.session-identity.test.ts +++ b/src/cron/isolated-agent.session-identity.test.ts @@ -15,6 +15,9 @@ import { runCronTurn, withTempHome, } from "./isolated-agent.turn-test-helpers.js"; +import { setupRunCronIsolatedAgentTurnSuite } from "./isolated-agent/run.suite-helpers.js"; + +setupRunCronIsolatedAgentTurnSuite(); describe("runCronIsolatedAgentTurn session identity", () => { beforeEach(() => { @@ -101,6 +104,22 @@ describe("runCronIsolatedAgentTurn session identity", () => { }); }); + it("passes sessionFile to isolated cron runs", async () => { + await withTempHome(async (home) => { + await runCronTurn(home, { + jobPayload: DEFAULT_AGENT_TURN_PAYLOAD, + }); + const call = vi.mocked(runEmbeddedPiAgent).mock.calls.at(-1)?.[0] as { + sessionFile?: string; + }; + + expect(call?.sessionFile).toContain( + path.join(home, ".openclaw", "agents", "main", "sessions"), + ); + expect(call?.sessionFile?.endsWith(".jsonl")).toBe(true); + }); + }); + it("starts a fresh session id for each cron run", async () => { await withTempHome(async (home) => { const storePath = await writeSessionStore(home, { lastProvider: "webchat", lastTo: "" }); diff --git a/src/cron/isolated-agent.turn-test-helpers.ts b/src/cron/isolated-agent.turn-test-helpers.ts index 18de2530ac7..8bdb413f2e2 100644 --- a/src/cron/isolated-agent.turn-test-helpers.ts +++ b/src/cron/isolated-agent.turn-test-helpers.ts @@ -60,7 +60,10 @@ export function expectEmbeddedProviderModel(expected: { provider: string; model: export async function readSessionEntry(storePath: string, key: string) { const raw = await fs.readFile(storePath, "utf-8"); - const store = JSON.parse(raw) as Record; + const store = JSON.parse(raw) as Record< + string, + { sessionId?: string; label?: string; sessionFile?: string } + >; return store[key]; } diff --git a/src/cron/isolated-agent/run-executor.ts b/src/cron/isolated-agent/run-executor.ts index 625fa73d1a1..9c84e79c351 100644 --- a/src/cron/isolated-agent/run-executor.ts +++ b/src/cron/isolated-agent/run-executor.ts @@ -67,10 +67,12 @@ export function createCronPromptExecutor(params: { abortSignal?: AbortSignal; abortReason: () => string; }) { - const sessionFile = resolveSessionTranscriptPath( - params.cronSession.sessionEntry.sessionId, - params.agentId, - ); + const sessionFile = + params.cronSession.sessionEntry.sessionFile?.trim() || + resolveSessionTranscriptPath(params.cronSession.sessionEntry.sessionId, params.agentId); + if (!params.cronSession.sessionEntry.sessionFile?.trim()) { + params.cronSession.sessionEntry.sessionFile = sessionFile; + } const cronFallbacksOverride = resolveCronFallbacksOverride({ cfg: params.cfg, job: params.job, diff --git a/src/cron/isolated-agent/run.ts b/src/cron/isolated-agent/run.ts index 593a9a94b83..bba5adbd9d8 100644 --- a/src/cron/isolated-agent/run.ts +++ b/src/cron/isolated-agent/run.ts @@ -18,6 +18,7 @@ import { } from "./helpers.js"; import { resolveCronModelSelection } from "./model-selection.js"; import { buildCronAgentDefaultsConfig } from "./run-config.js"; +import { resolveSessionTranscriptPath } from "./run-execution.runtime.js"; import { executeCronRun, type CronExecutionResult } from "./run-executor.js"; import { createPersistCronSessionEntry, @@ -272,6 +273,9 @@ async function prepareCronRunContext(params: { forceNew: input.job.sessionTarget === "isolated", }); const runSessionId = cronSession.sessionEntry.sessionId; + if (!cronSession.sessionEntry.sessionFile?.trim()) { + cronSession.sessionEntry.sessionFile = resolveSessionTranscriptPath(runSessionId, agentId); + } const runSessionKey = baseSessionKey.startsWith("cron:") ? `${agentSessionKey}:run:${runSessionId}` : agentSessionKey;