mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 21:30:44 +00:00
memory: avoid rereading skipped dreaming transcripts
This commit is contained in:
@@ -720,6 +720,92 @@ describe("memory-core dreaming phases", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not reread unchanged dreaming-generated transcripts after checkpointing skip state", async () => {
|
||||
const workspaceDir = await createDreamingWorkspace();
|
||||
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
|
||||
vi.stubEnv("OPENCLAW_STATE_DIR", path.join(workspaceDir, ".state"));
|
||||
const sessionsDir = resolveSessionTranscriptsDirForAgent("main");
|
||||
await fs.mkdir(sessionsDir, { recursive: true });
|
||||
const transcriptPath = path.join(sessionsDir, "dreaming-narrative.jsonl");
|
||||
await fs.writeFile(
|
||||
transcriptPath,
|
||||
[
|
||||
JSON.stringify({
|
||||
type: "custom",
|
||||
customType: "openclaw:bootstrap-context:full",
|
||||
data: {
|
||||
runId: "dreaming-narrative-light-1775894400455",
|
||||
sessionId: "dream-session-1",
|
||||
},
|
||||
}),
|
||||
JSON.stringify({
|
||||
type: "message",
|
||||
message: {
|
||||
role: "user",
|
||||
timestamp: "2026-04-05T18:01:00.000Z",
|
||||
content: [
|
||||
{ type: "text", text: "Write a dream diary entry from these memory fragments." },
|
||||
],
|
||||
},
|
||||
}),
|
||||
].join("\n") + "\n",
|
||||
"utf-8",
|
||||
);
|
||||
const mtime = new Date("2026-04-05T18:05:00.000Z");
|
||||
await fs.utimes(transcriptPath, mtime, mtime);
|
||||
|
||||
const { beforeAgentReply } = createHarness(
|
||||
{
|
||||
agents: {
|
||||
defaults: {
|
||||
workspace: workspaceDir,
|
||||
},
|
||||
list: [{ id: "main", workspace: workspaceDir }],
|
||||
},
|
||||
plugins: {
|
||||
entries: {
|
||||
"memory-core": {
|
||||
config: {
|
||||
dreaming: {
|
||||
enabled: true,
|
||||
phases: {
|
||||
light: {
|
||||
enabled: true,
|
||||
limit: 20,
|
||||
lookbackDays: 7,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
workspaceDir,
|
||||
);
|
||||
|
||||
try {
|
||||
await beforeAgentReply(
|
||||
{ cleanedBody: "__openclaw_memory_core_light_sleep__" },
|
||||
{ trigger: "heartbeat", workspaceDir },
|
||||
);
|
||||
|
||||
const readFileSpy = vi.spyOn(fs, "readFile");
|
||||
await beforeAgentReply(
|
||||
{ cleanedBody: "__openclaw_memory_core_light_sleep__" },
|
||||
{ trigger: "heartbeat", workspaceDir },
|
||||
);
|
||||
|
||||
expect(readFileSpy.mock.calls.some(([target]) => String(target) === transcriptPath)).toBe(
|
||||
false,
|
||||
);
|
||||
readFileSpy.mockRestore();
|
||||
} finally {
|
||||
vi.restoreAllMocks();
|
||||
vi.unstubAllEnvs();
|
||||
}
|
||||
});
|
||||
|
||||
it("dedupes reset/deleted session archives instead of double-ingesting", async () => {
|
||||
const workspaceDir = await createDreamingWorkspace();
|
||||
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
|
||||
|
||||
@@ -739,10 +739,7 @@ async function collectSessionIngestionBatches(params: {
|
||||
mtimeMs: Math.floor(Math.max(0, stat.mtimeMs)),
|
||||
size: Math.floor(Math.max(0, stat.size)),
|
||||
};
|
||||
const cursorAtEnd =
|
||||
previous !== undefined &&
|
||||
previous.lineCount > 0 &&
|
||||
previous.lastContentLine >= previous.lineCount;
|
||||
const cursorAtEnd = previous !== undefined && previous.lastContentLine >= previous.lineCount;
|
||||
const unchanged =
|
||||
Boolean(previous) &&
|
||||
previous.mtimeMs === fingerprint.mtimeMs &&
|
||||
|
||||
@@ -39,6 +39,7 @@ const PHASE_SIGNAL_REM_BOOST_MAX = 0.09;
|
||||
const PHASE_SIGNAL_HALF_LIFE_DAYS = 14;
|
||||
const DREAMING_TRANSCRIPT_PROMPT_LINE_RE =
|
||||
/\[[^\]]*dreaming-narrative[^\]]*]\s*Write a dream diary entry from these memory fragments:?/i;
|
||||
const DREAMING_DIFF_PREFIX_RE = /@@\s*-\d+(?:,\d+)?\s+[-*+]\s+/iy;
|
||||
const inProcessShortTermLocks = new Map<string, Promise<void>>();
|
||||
const ensuredShortTermDirs = new Map<string, Promise<void>>();
|
||||
|
||||
@@ -240,10 +241,10 @@ function normalizeSnippet(raw: string): string {
|
||||
function consumeDreamingLeadPrefix(snippet: string): string {
|
||||
let index = 0;
|
||||
while (index < snippet.length) {
|
||||
const remaining = snippet.slice(index);
|
||||
const diffMatch = /^@@\s*-\d+(?:,\d+)?\s+[-*+]\s+/i.exec(remaining);
|
||||
DREAMING_DIFF_PREFIX_RE.lastIndex = index;
|
||||
const diffMatch = DREAMING_DIFF_PREFIX_RE.exec(snippet);
|
||||
if (diffMatch) {
|
||||
index += diffMatch[0].length;
|
||||
index = DREAMING_DIFF_PREFIX_RE.lastIndex;
|
||||
continue;
|
||||
}
|
||||
const char = snippet[index];
|
||||
|
||||
Reference in New Issue
Block a user