diff --git a/src/agents/cli-runner.reliability.test.ts b/src/agents/cli-runner.reliability.test.ts index ec71f60e14a..81adc6e2376 100644 --- a/src/agents/cli-runner.reliability.test.ts +++ b/src/agents/cli-runner.reliability.test.ts @@ -8,6 +8,7 @@ import { createReplyOperation, replyRunRegistry, } from "../auto-reply/reply/reply-run-registry.js"; +import type { OpenClawConfig } from "../config/types.openclaw.js"; import { getGlobalHookRunner } from "../plugins/hook-runner-global.js"; import { runPreparedCliAgent } from "./cli-runner.js"; import { @@ -18,6 +19,7 @@ import { } from "./cli-runner.test-support.js"; import { executePreparedCliRun } from "./cli-runner/execute.js"; import { resolveCliNoOutputTimeoutMs } from "./cli-runner/helpers.js"; +import { prepareCliRunContext } from "./cli-runner/prepare.js"; import * as sessionHistoryModule from "./cli-runner/session-history.js"; import { MAX_CLI_SESSION_HISTORY_MESSAGES } from "./cli-runner/session-history.js"; import type { PreparedCliRunContext } from "./cli-runner/types.js"; @@ -752,6 +754,55 @@ describe("runCliAgent reliability", () => { historySpy.mockRestore(); } }); + + it("builds fresh-session history reseed prompts from hook-mutated prompts", async () => { + const { dir, sessionFile } = createSessionFile({ + history: [{ role: "user", content: "earlier ask" }], + }); + const config: OpenClawConfig = { + agents: { + defaults: { + workspace: dir, + cliBackends: { + "codex-cli": { + command: "codex", + args: ["exec"], + output: "text", + input: "arg", + sessionMode: "existing", + }, + }, + }, + }, + }; + const hookRunner = { + hasHooks: vi.fn((hookName: string) => hookName === "before_prompt_build"), + runBeforePromptBuild: vi.fn(async () => ({ prependContext: "hook context" })), + runBeforeAgentStart: vi.fn(async () => undefined), + }; + mockGetGlobalHookRunner.mockReturnValue(hookRunner as never); + + try { + const context = await prepareCliRunContext({ + sessionId: "s1", + sessionFile, + workspaceDir: dir, + config, + prompt: "current ask", + provider: "codex-cli", + model: "gpt-5.4", + timeoutMs: 1_000, + runId: "run-history-hook", + }); + + expect(context.params.prompt).toBe("hook context\n\ncurrent ask"); + expect(context.openClawHistoryPrompt).toContain("User: earlier ask"); + expect(context.openClawHistoryPrompt).toContain("hook context"); + expect(context.openClawHistoryPrompt).toContain("current ask"); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } + }); }); describe("resolveCliNoOutputTimeoutMs", () => { diff --git a/src/agents/cli-runner/prepare.ts b/src/agents/cli-runner/prepare.ts index 1c1509c1e46..2b13ff0e0a1 100644 --- a/src/agents/cli-runner/prepare.ts +++ b/src/agents/cli-runner/prepare.ts @@ -259,16 +259,17 @@ export async function prepareCliRunContext( `cli session reset: provider=${params.provider} reason=${reusableCliSession.invalidatedReason}`, ); } - const openClawHistoryPrompt = buildCliSessionHistoryPrompt({ - messages: loadCliSessionHistoryMessages({ + let openClawHistoryMessages: unknown[] | undefined; + const loadOpenClawHistoryMessages = () => { + openClawHistoryMessages ??= loadCliSessionHistoryMessages({ sessionId: params.sessionId, sessionFile: params.sessionFile, sessionKey: params.sessionKey, agentId: params.agentId, config: params.config, - }), - prompt: params.prompt, - }); + }); + return openClawHistoryMessages; + }; const heartbeatPrompt = resolveHeartbeatPromptForSystemPrompt({ config: params.config, agentId: sessionAgentId, @@ -323,13 +324,7 @@ export async function prepareCliRunContext( try { const hookResult = await resolvePromptBuildHookResult({ prompt: params.prompt, - messages: loadCliSessionHistoryMessages({ - sessionId: params.sessionId, - sessionFile: params.sessionFile, - sessionKey: params.sessionKey, - agentId: params.agentId, - config: params.config, - }), + messages: loadOpenClawHistoryMessages(), hookCtx: { runId: params.runId, agentId: sessionAgentId, @@ -365,6 +360,12 @@ export async function prepareCliRunContext( cliBackendLog.warn(`cli prompt-build hook preparation failed: ${String(error)}`); } } + const openClawHistoryPrompt = reusableCliSession.sessionId + ? undefined + : buildCliSessionHistoryPrompt({ + messages: loadOpenClawHistoryMessages(), + prompt: preparedPrompt, + }); systemPrompt = applyPluginTextReplacements(systemPrompt, backendResolved.textTransforms?.input); const systemPromptReport = buildSystemPromptReport({ source: "run",