mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:30:42 +00:00
memory: block dreaming self-ingestion (#66852)
Merged via squash.
Prepared head SHA: 4742656a0d
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
committed by
GitHub
parent
5702ab695b
commit
0c4e0d7030
@@ -174,4 +174,58 @@ describe("buildSessionEntry", () => {
|
||||
expect(entry).not.toBeNull();
|
||||
expect(entry?.generatedByDreamingNarrative).toBe(true);
|
||||
});
|
||||
|
||||
it("does not flag ordinary transcripts that quote the dream-diary prompt", async () => {
|
||||
const jsonlLines = [
|
||||
JSON.stringify({
|
||||
type: "message",
|
||||
message: {
|
||||
role: "user",
|
||||
content:
|
||||
"Write a dream diary entry from these memory fragments:\n- Candidate: durable note",
|
||||
},
|
||||
}),
|
||||
JSON.stringify({
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "A drifting archive breathed in moonlight." },
|
||||
}),
|
||||
];
|
||||
const filePath = path.join(tmpDir, "dreaming-prompt-session.jsonl");
|
||||
await fs.writeFile(filePath, jsonlLines.join("\n"));
|
||||
|
||||
const entry = await buildSessionEntry(filePath);
|
||||
|
||||
expect(entry).not.toBeNull();
|
||||
expect(entry?.generatedByDreamingNarrative).toBeUndefined();
|
||||
expect(entry?.content).toContain(
|
||||
"User: Write a dream diary entry from these memory fragments:",
|
||||
);
|
||||
expect(entry?.content).toContain("Assistant: A drifting archive breathed in moonlight.");
|
||||
expect(entry?.lineMap).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it("does not flag transcripts when dreaming markers only appear mid-string", async () => {
|
||||
const jsonlLines = [
|
||||
JSON.stringify({
|
||||
type: "custom",
|
||||
customType: "note",
|
||||
data: {
|
||||
runId: "user-context-dreaming-narrative-light-1775894400455",
|
||||
},
|
||||
}),
|
||||
JSON.stringify({
|
||||
type: "message",
|
||||
message: { role: "user", content: "Keep the archive index updated." },
|
||||
}),
|
||||
];
|
||||
const filePath = path.join(tmpDir, "substring-marker-session.jsonl");
|
||||
await fs.writeFile(filePath, jsonlLines.join("\n"));
|
||||
|
||||
const entry = await buildSessionEntry(filePath);
|
||||
|
||||
expect(entry).not.toBeNull();
|
||||
expect(entry?.generatedByDreamingNarrative).toBeUndefined();
|
||||
expect(entry?.content).toContain("User: Keep the archive index updated.");
|
||||
expect(entry?.lineMap).toEqual([2]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ import { createSubsystemLogger } from "../../logging/subsystem.js";
|
||||
import { hashText } from "./internal.js";
|
||||
|
||||
const log = createSubsystemLogger("memory");
|
||||
const DREAMING_NARRATIVE_RUN_PREFIX = "dreaming-narrative-";
|
||||
|
||||
export type SessionFileEntry = {
|
||||
path: string;
|
||||
@@ -42,7 +43,39 @@ function isDreamingNarrativeBootstrapRecord(record: unknown): boolean {
|
||||
return false;
|
||||
}
|
||||
const runId = (candidate.data as { runId?: unknown }).runId;
|
||||
return typeof runId === "string" && runId.startsWith("dreaming-narrative-");
|
||||
return typeof runId === "string" && runId.startsWith(DREAMING_NARRATIVE_RUN_PREFIX);
|
||||
}
|
||||
|
||||
function hasDreamingNarrativeRunId(value: unknown): boolean {
|
||||
return typeof value === "string" && value.startsWith(DREAMING_NARRATIVE_RUN_PREFIX);
|
||||
}
|
||||
|
||||
function isDreamingNarrativeGeneratedRecord(record: unknown): boolean {
|
||||
if (isDreamingNarrativeBootstrapRecord(record)) {
|
||||
return true;
|
||||
}
|
||||
if (!record || typeof record !== "object" || Array.isArray(record)) {
|
||||
return false;
|
||||
}
|
||||
const candidate = record as {
|
||||
runId?: unknown;
|
||||
sessionKey?: unknown;
|
||||
data?: unknown;
|
||||
};
|
||||
if (
|
||||
hasDreamingNarrativeRunId(candidate.runId) ||
|
||||
hasDreamingNarrativeRunId(candidate.sessionKey)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
if (!candidate.data || typeof candidate.data !== "object" || Array.isArray(candidate.data)) {
|
||||
return false;
|
||||
}
|
||||
const nested = candidate.data as {
|
||||
runId?: unknown;
|
||||
sessionKey?: unknown;
|
||||
};
|
||||
return hasDreamingNarrativeRunId(nested.runId) || hasDreamingNarrativeRunId(nested.sessionKey);
|
||||
}
|
||||
|
||||
export async function listSessionFilesForAgent(agentId: string): Promise<string[]> {
|
||||
@@ -140,7 +173,7 @@ export async function buildSessionEntry(absPath: string): Promise<SessionFileEnt
|
||||
} catch {
|
||||
continue;
|
||||
}
|
||||
if (!generatedByDreamingNarrative && isDreamingNarrativeBootstrapRecord(record)) {
|
||||
if (!generatedByDreamingNarrative && isDreamingNarrativeGeneratedRecord(record)) {
|
||||
generatedByDreamingNarrative = true;
|
||||
}
|
||||
if (
|
||||
@@ -163,6 +196,9 @@ export async function buildSessionEntry(absPath: string): Promise<SessionFileEnt
|
||||
if (!text) {
|
||||
continue;
|
||||
}
|
||||
if (generatedByDreamingNarrative) {
|
||||
continue;
|
||||
}
|
||||
const safe = redactSensitiveText(text, { mode: "tools" });
|
||||
const label = message.role === "user" ? "User" : "Assistant";
|
||||
collected.push(`${label}: ${safe}`);
|
||||
|
||||
Reference in New Issue
Block a user