fix(memory-flush): ban timestamped variant files in default flush prompt (#34951)
Merged via squash. Prepared head SHA: efadda4988b460e6da07be72994d4951d64239d0 Co-authored-by: zerone0x <39543393+zerone0x@users.noreply.github.com> Co-authored-by: jalehman <550978+jalehman@users.noreply.github.com> Reviewed-by: @jalehman
This commit is contained in:
@@ -158,6 +158,7 @@ Docs: https://docs.openclaw.ai
|
||||
- TUI/webchat command-owner scope alignment: treat internal-channel gateway sessions with `operator.admin` as owner-authorized in command auth, restoring cron/gateway/connector tool access for affected TUI/webchat sessions while keeping external channels on identity-based owner checks. (from #35666, #35673, #35704) Thanks @Naylenv, @Octane0411, and @Sid-Qin.
|
||||
- Discord/inbound timeout isolation: separate inbound worker timeout tracking from listener timeout budgets so queued Discord replies are no longer dropped when listener watchdog windows expire mid-run. (#36602) Thanks @dutifulbob.
|
||||
- Memory/doctor SecretRef handling: treat SecretRef-backed memory-search API keys as configured, and fail embedding setup with explicit unresolved-secret errors instead of crashing. (#36835) Thanks @joshavant.
|
||||
- Memory/flush default prompt: ban timestamped variant filenames during default memory flush runs so durable notes stay in the canonical daily `memory/YYYY-MM-DD.md` file. (#34951) thanks @zerone0x.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { resolveMemoryFlushPromptForRun } from "./memory-flush.js";
|
||||
import { DEFAULT_MEMORY_FLUSH_PROMPT, resolveMemoryFlushPromptForRun } from "./memory-flush.js";
|
||||
|
||||
describe("resolveMemoryFlushPromptForRun", () => {
|
||||
const cfg = {
|
||||
@@ -36,3 +36,16 @@ describe("resolveMemoryFlushPromptForRun", () => {
|
||||
expect((prompt.match(/Current time:/g) ?? []).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("DEFAULT_MEMORY_FLUSH_PROMPT", () => {
|
||||
it("includes append-only instruction to prevent overwrites (#6877)", () => {
|
||||
expect(DEFAULT_MEMORY_FLUSH_PROMPT).toMatch(/APPEND/i);
|
||||
expect(DEFAULT_MEMORY_FLUSH_PROMPT).toContain("do not overwrite");
|
||||
});
|
||||
|
||||
it("includes anti-fragmentation instruction to prevent timestamped variant files (#34919)", () => {
|
||||
// Agents must not create YYYY-MM-DD-HHMM.md variants alongside the canonical file
|
||||
expect(DEFAULT_MEMORY_FLUSH_PROMPT).toContain("timestamped variant");
|
||||
expect(DEFAULT_MEMORY_FLUSH_PROMPT).toContain("YYYY-MM-DD.md");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,8 @@ export const DEFAULT_MEMORY_FLUSH_FORCE_TRANSCRIPT_BYTES = 2 * 1024 * 1024;
|
||||
export const DEFAULT_MEMORY_FLUSH_PROMPT = [
|
||||
"Pre-compaction memory flush.",
|
||||
"Store durable memories now (use memory/YYYY-MM-DD.md; create memory/ if needed).",
|
||||
"IMPORTANT: If the file already exists, APPEND new content only and do not overwrite existing entries.",
|
||||
"IMPORTANT: If the file already exists, APPEND new content only — do not overwrite existing entries.",
|
||||
"Do NOT create timestamped variant files (e.g., YYYY-MM-DD-HHMM.md); always use the canonical YYYY-MM-DD.md filename.",
|
||||
`If nothing to store, reply with ${SILENT_REPLY_TOKEN}.`,
|
||||
].join(" ");
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { captureFullEnv } from "../../test-utils/env.js";
|
||||
import type { DaemonActionResponse } from "./response.js";
|
||||
|
||||
const loadConfigMock = vi.hoisted(() => vi.fn());
|
||||
@@ -118,6 +119,7 @@ vi.mock("../../runtime.js", () => ({
|
||||
}));
|
||||
|
||||
const { runDaemonInstall } = await import("./install.js");
|
||||
const envSnapshot = captureFullEnv();
|
||||
|
||||
describe("runDaemonInstall", () => {
|
||||
beforeEach(() => {
|
||||
@@ -162,6 +164,12 @@ describe("runDaemonInstall", () => {
|
||||
isGatewayDaemonRuntimeMock.mockReturnValue(true);
|
||||
installDaemonServiceAndEmitMock.mockResolvedValue(undefined);
|
||||
service.isLoaded.mockResolvedValue(false);
|
||||
delete process.env.OPENCLAW_GATEWAY_TOKEN;
|
||||
delete process.env.CLAWDBOT_GATEWAY_TOKEN;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
envSnapshot.restore();
|
||||
});
|
||||
|
||||
it("fails install when token auth requires an unresolved token SecretRef", async () => {
|
||||
|
||||
@@ -68,6 +68,7 @@ describe("restartGatewayProcessWithFreshPid", () => {
|
||||
});
|
||||
|
||||
it("returns supervised when launchd/systemd hints are present", () => {
|
||||
clearSupervisorHints();
|
||||
process.env.LAUNCH_JOB_LABEL = "ai.openclaw.gateway";
|
||||
const result = restartGatewayProcessWithFreshPid();
|
||||
expect(result.mode).toBe("supervised");
|
||||
|
||||
Reference in New Issue
Block a user