mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 09:08:38 +00:00
test (memory/compaction): cover resolved memory flush prompt semantics
This commit is contained in:
@@ -8,7 +8,6 @@ import type { TemplateContext } from "../templating.js";
|
|||||||
import type { FollowupRun, QueueSettings } from "./queue.js";
|
import type { FollowupRun, QueueSettings } from "./queue.js";
|
||||||
import { loadSessionStore, saveSessionStore } from "../../config/sessions.js";
|
import { loadSessionStore, saveSessionStore } from "../../config/sessions.js";
|
||||||
import { onAgentEvent } from "../../infra/agent-events.js";
|
import { onAgentEvent } from "../../infra/agent-events.js";
|
||||||
import { DEFAULT_MEMORY_FLUSH_PROMPT } from "./memory-flush.js";
|
|
||||||
import { createMockTypingController } from "./test-helpers.js";
|
import { createMockTypingController } from "./test-helpers.js";
|
||||||
|
|
||||||
const runEmbeddedPiAgentMock = vi.fn();
|
const runEmbeddedPiAgentMock = vi.fn();
|
||||||
@@ -948,7 +947,7 @@ describe("runReplyAgent fallback reasoning tags", () => {
|
|||||||
|
|
||||||
it("enforces <final> during memory flush on fallback providers", async () => {
|
it("enforces <final> during memory flush on fallback providers", async () => {
|
||||||
runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedPiAgentParams) => {
|
runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedPiAgentParams) => {
|
||||||
if (params.prompt === DEFAULT_MEMORY_FLUSH_PROMPT) {
|
if (params.prompt?.includes("Pre-compaction memory flush.")) {
|
||||||
return { payloads: [], meta: {} };
|
return { payloads: [], meta: {} };
|
||||||
}
|
}
|
||||||
return { payloads: [{ text: "ok" }], meta: {} };
|
return { payloads: [{ text: "ok" }], meta: {} };
|
||||||
@@ -970,7 +969,9 @@ describe("runReplyAgent fallback reasoning tags", () => {
|
|||||||
|
|
||||||
const flushCall = runEmbeddedPiAgentMock.mock.calls.find(
|
const flushCall = runEmbeddedPiAgentMock.mock.calls.find(
|
||||||
([params]) =>
|
([params]) =>
|
||||||
(params as EmbeddedPiAgentParams | undefined)?.prompt === DEFAULT_MEMORY_FLUSH_PROMPT,
|
(params as EmbeddedPiAgentParams | undefined)?.prompt?.includes(
|
||||||
|
"Pre-compaction memory flush.",
|
||||||
|
),
|
||||||
)?.[0] as EmbeddedPiAgentParams | undefined;
|
)?.[0] as EmbeddedPiAgentParams | undefined;
|
||||||
|
|
||||||
expect(flushCall?.enforceFinalTag).toBe(true);
|
expect(flushCall?.enforceFinalTag).toBe(true);
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import type { TemplateContext } from "../templating.js";
|
|||||||
import type { GetReplyOptions } from "../types.js";
|
import type { GetReplyOptions } from "../types.js";
|
||||||
import type { FollowupRun, QueueSettings } from "./queue.js";
|
import type { FollowupRun, QueueSettings } from "./queue.js";
|
||||||
import * as sessions from "../../config/sessions.js";
|
import * as sessions from "../../config/sessions.js";
|
||||||
import { DEFAULT_MEMORY_FLUSH_PROMPT } from "./memory-flush.js";
|
|
||||||
import { createMockTypingController } from "./test-helpers.js";
|
import { createMockTypingController } from "./test-helpers.js";
|
||||||
|
|
||||||
type AgentRunParams = {
|
type AgentRunParams = {
|
||||||
@@ -949,7 +948,7 @@ describe("runReplyAgent memory flush", () => {
|
|||||||
const calls: Array<EmbeddedRunParams> = [];
|
const calls: Array<EmbeddedRunParams> = [];
|
||||||
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
||||||
calls.push(params);
|
calls.push(params);
|
||||||
if (params.prompt === DEFAULT_MEMORY_FLUSH_PROMPT) {
|
if (params.prompt?.includes("Pre-compaction memory flush.")) {
|
||||||
return { payloads: [], meta: {} };
|
return { payloads: [], meta: {} };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -1009,7 +1008,7 @@ describe("runReplyAgent memory flush", () => {
|
|||||||
const calls: Array<{ prompt?: string }> = [];
|
const calls: Array<{ prompt?: string }> = [];
|
||||||
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
||||||
calls.push({ prompt: params.prompt });
|
calls.push({ prompt: params.prompt });
|
||||||
if (params.prompt === DEFAULT_MEMORY_FLUSH_PROMPT) {
|
if (params.prompt?.includes("Pre-compaction memory flush.")) {
|
||||||
return { payloads: [], meta: {} };
|
return { payloads: [], meta: {} };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@@ -1031,7 +1030,11 @@ describe("runReplyAgent memory flush", () => {
|
|||||||
commandBody: "hello",
|
commandBody: "hello",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(calls.map((call) => call.prompt)).toEqual([DEFAULT_MEMORY_FLUSH_PROMPT, "hello"]);
|
expect(calls).toHaveLength(2);
|
||||||
|
expect(calls[0]?.prompt).toContain("Pre-compaction memory flush.");
|
||||||
|
expect(calls[0]?.prompt).toContain("Current time:");
|
||||||
|
expect(calls[0]?.prompt).toMatch(/memory\/\d{4}-\d{2}-\d{2}\.md/);
|
||||||
|
expect(calls[1]?.prompt).toBe("hello");
|
||||||
|
|
||||||
const stored = JSON.parse(await fs.readFile(storePath, "utf-8"));
|
const stored = JSON.parse(await fs.readFile(storePath, "utf-8"));
|
||||||
expect(stored[sessionKey].memoryFlushAt).toBeTypeOf("number");
|
expect(stored[sessionKey].memoryFlushAt).toBeTypeOf("number");
|
||||||
@@ -1141,7 +1144,7 @@ describe("runReplyAgent memory flush", () => {
|
|||||||
await seedSessionStore({ storePath, sessionKey, entry: sessionEntry });
|
await seedSessionStore({ storePath, sessionKey, entry: sessionEntry });
|
||||||
|
|
||||||
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
state.runEmbeddedPiAgentMock.mockImplementation(async (params: EmbeddedRunParams) => {
|
||||||
if (params.prompt === DEFAULT_MEMORY_FLUSH_PROMPT) {
|
if (params.prompt?.includes("Pre-compaction memory flush.")) {
|
||||||
params.onAgentEvent?.({
|
params.onAgentEvent?.({
|
||||||
stream: "compaction",
|
stream: "compaction",
|
||||||
data: { phase: "end", willRetry: false },
|
data: { phase: "end", willRetry: false },
|
||||||
|
|||||||
36
src/auto-reply/reply/memory-flush.test.ts
Normal file
36
src/auto-reply/reply/memory-flush.test.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { resolveMemoryFlushPromptForRun } from "./memory-flush.js";
|
||||||
|
|
||||||
|
describe("resolveMemoryFlushPromptForRun", () => {
|
||||||
|
const cfg = {
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
userTimezone: "America/New_York",
|
||||||
|
timeFormat: "12",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
it("replaces YYYY-MM-DD using user timezone and appends current time", () => {
|
||||||
|
const prompt = resolveMemoryFlushPromptForRun({
|
||||||
|
prompt: "Store durable notes in memory/YYYY-MM-DD.md",
|
||||||
|
cfg,
|
||||||
|
nowMs: Date.UTC(2026, 1, 16, 15, 0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(prompt).toContain("memory/2026-02-16.md");
|
||||||
|
expect(prompt).toContain("Current time:");
|
||||||
|
expect(prompt).toContain("(America/New_York)");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not append a duplicate current time line", () => {
|
||||||
|
const prompt = resolveMemoryFlushPromptForRun({
|
||||||
|
prompt: "Store notes.\nCurrent time: already present",
|
||||||
|
cfg,
|
||||||
|
nowMs: Date.UTC(2026, 1, 16, 15, 0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(prompt).toContain("Current time: already present");
|
||||||
|
expect((prompt.match(/Current time:/g) ?? []).length).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user