diff --git a/CHANGELOG.md b/CHANGELOG.md index ccd9a3ba663..60d5a147112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Docs: https://docs.openclaw.ai - Agents/sandbox: preserve existing workspace file modes when sandbox edits atomically replace files, so 0644 files do not collapse to 0600 after Write/Edit/apply_patch. Fixes #44077. Thanks @patosullivan. - Agents/models: keep legacy CLI runtime model refs such as `claude-cli/*` in the configured allowlist after canonical runtime migration, so cron `payload.model` overrides keep working. Fixes #75753. Thanks @RyanSandoval. - Gateway/watch: keep colored subsystem log prefixes in the managed tmux pane even when the parent shell exports `NO_COLOR`, while preserving explicit `FORCE_COLOR=0` opt-out. Thanks @vincentkoc. +- Agents/compaction: submit a non-empty runtime-event marker for pre-compaction memory flush turns, so strict Anthropic providers no longer reject the silent flush as an empty user message. Fixes #75305. Thanks @sableassistant3777-source. - Plugin SDK: re-export `isPrivateIpAddress` from `plugin-sdk/ssrf-runtime`, restoring source-checkout builds for SearXNG and Firecrawl private-network guards. Thanks @vincentkoc. - CLI/directory: report unsupported directory operations for installed channel plugins instead of prompting to reinstall the plugin when it lacks a directory adapter. Fixes #75770. Thanks @lawong888. - Web search/SearXNG: show the JSON API `search.formats` prerequisite during SearXNG setup before prompting for the base URL. Supersedes #65592. Thanks @evanpaul14. diff --git a/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts b/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts index 6a6c5241eee..eca6a3d8969 100644 --- a/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts +++ b/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.test.ts @@ -111,7 +111,7 @@ describe("resolvePromptSubmissionSkipReason", () => { ).toBeNull(); }); - it("allows blank prompt on runtimeOnly turns", () => { + it("skips blank prompt on runtimeOnly turns", () => { expect( resolvePromptSubmissionSkipReason({ prompt: "", @@ -119,7 +119,7 @@ describe("resolvePromptSubmissionSkipReason", () => { runtimeOnly: true, imageCount: 0, }), - ).toBeNull(); + ).toBe("empty_prompt_history_images"); }); it("treats undefined runtimeOnly as a visible user submission", () => { diff --git a/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts b/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts index ef04a02d180..ce77c5388fa 100644 --- a/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts +++ b/src/agents/pi-embedded-runner/run/attempt.prompt-helpers.ts @@ -244,9 +244,6 @@ export function resolvePromptSubmissionSkipReason(params: { imageCount: number; runtimeOnly?: boolean; }): PromptSubmissionSkipReason | null { - if (params.runtimeOnly) { - return null; - } if (params.prompt.trim().length > 0 || params.imageCount > 0) { return null; } diff --git a/src/agents/pi-embedded-runner/run/runtime-context-prompt.test.ts b/src/agents/pi-embedded-runner/run/runtime-context-prompt.test.ts index 736169527b8..d3a02204d31 100644 --- a/src/agents/pi-embedded-runner/run/runtime-context-prompt.test.ts +++ b/src/agents/pi-embedded-runner/run/runtime-context-prompt.test.ts @@ -55,7 +55,7 @@ describe("runtime context prompt submission", () => { transcriptPrompt: "", }), ).toEqual({ - prompt: "", + prompt: "Continue the OpenClaw runtime event.", runtimeContext: "internal event", runtimeOnly: true, runtimeSystemContext: expect.stringContaining("internal event"), diff --git a/src/agents/pi-embedded-runner/run/runtime-context-prompt.ts b/src/agents/pi-embedded-runner/run/runtime-context-prompt.ts index 218c777a304..8111214eaef 100644 --- a/src/agents/pi-embedded-runner/run/runtime-context-prompt.ts +++ b/src/agents/pi-embedded-runner/run/runtime-context-prompt.ts @@ -6,6 +6,8 @@ import { } from "../../internal-runtime-context.js"; export { OPENCLAW_RUNTIME_CONTEXT_CUSTOM_TYPE }; +const OPENCLAW_RUNTIME_EVENT_USER_PROMPT = "Continue the OpenClaw runtime event."; + type RuntimeContextSession = { sendCustomMessage: ( message: { @@ -54,7 +56,7 @@ export function resolveRuntimeContextPromptParts(params: { if (!prompt) { return runtimeContext ? { - prompt: "", + prompt: OPENCLAW_RUNTIME_EVENT_USER_PROMPT, runtimeContext, runtimeOnly: true, runtimeSystemContext: buildRuntimeEventSystemContext(runtimeContext), diff --git a/src/auto-reply/reply/agent-runner-memory.test.ts b/src/auto-reply/reply/agent-runner-memory.test.ts index 223e03900a0..04f35fcc42b 100644 --- a/src/auto-reply/reply/agent-runner-memory.test.ts +++ b/src/auto-reply/reply/agent-runner-memory.test.ts @@ -160,6 +160,7 @@ describe("runMemoryFlushIfNeeded", () => { }; expect(flushCall.prompt).toContain("Pre-compaction memory flush."); expect(flushCall.transcriptPrompt).toBe(""); + expect(flushCall.prompt).not.toBe(flushCall.transcriptPrompt); expect(flushCall.memoryFlushWritePath).toMatch(/^memory\/\d{4}-\d{2}-\d{2}\.md$/); expect(flushCall.silentExpected).toBe(true); expect(refreshQueuedFollowupSessionMock).toHaveBeenCalledWith({