
























@@ -74,7 +74,7 @@ type RunPhaseIfTriggeredParams = {
7474const LIGHT_SLEEP_EVENT_TEXT = "__openclaw_memory_core_light_sleep__";
7575const REM_SLEEP_EVENT_TEXT = "__openclaw_memory_core_rem_sleep__";
7676const MEMORY_DAY_RE = /^\d{4}-\d{2}-\d{2}$/;
77-const DAILY_MEMORY_FILENAME_RE = /^(\d{4}-\d{2}-\d{2})\.md$/;
77+const DAILY_MEMORY_FILENAME_RE = /^(\d{4}-\d{2}-\d{2})(?:-[^/]+)?\.md$/i;
7878const DAILY_INGESTION_STATE_RELATIVE_PATH = path.join("memory", ".dreams", "daily-ingestion.json");
7979const DAILY_INGESTION_SCORE = 0.62;
8080const DAILY_INGESTION_MAX_SNIPPET_CHARS = 280;
@@ -385,12 +385,36 @@ type DailyIngestionBatch = {
385385results: MemorySearchResult[];
386386};
387387388+type DailyMemoryFile = {
389+fileName: string;
390+day: string;
391+};
392+388393type DailyIngestionFileState = {
389394mtimeMs: number;
390395size: number;
391396lastDreamingDayIngested?: string;
392397};
393398399+function parseDailyMemoryFileName(fileName: string): DailyMemoryFile | null {
400+const match = fileName.match(DAILY_MEMORY_FILENAME_RE);
401+const day = match?.[1];
402+return day ? { fileName, day } : null;
403+}
404+405+function compareDailyMemoryFilesByNewestDay(left: DailyMemoryFile, right: DailyMemoryFile): number {
406+const dayOrder = right.day.localeCompare(left.day);
407+return dayOrder !== 0 ? dayOrder : left.fileName.localeCompare(right.fileName);
408+}
409+410+function resolveWorkspaceMemoryRelativePath(workspaceDir: string, filePath: string): string {
411+const relativePath = path.relative(workspaceDir, filePath).replace(/\\/g, "/");
412+if (relativePath && relativePath !== ".." && !relativePath.startsWith("../")) {
413+return relativePath;
414+}
415+return `memory/${path.basename(filePath)}`;
416+}
417+394418type DailyIngestionState = {
395419version: 1;
396420files: Record<string, DailyIngestionFileState>;
@@ -1082,18 +1106,17 @@ async function collectDailyIngestionBatches(params: {
10821106const files = entries
10831107.filter((entry) => entry.isFile())
10841108.map((entry) => {
1085-const match = entry.name.match(DAILY_MEMORY_FILENAME_RE);
1086-if (!match) {
1109+const file = parseDailyMemoryFileName(entry.name);
1110+if (!file) {
10871111return null;
10881112}
1089-const day = match[1];
1090-if (!isDayWithinLookback(day, cutoffMs)) {
1113+if (!isDayWithinLookback(file.day, cutoffMs)) {
10911114return null;
10921115}
1093-return { fileName: entry.name, day };
1116+return file;
10941117})
1095-.filter((entry): entry is { fileName: string; day: string } => entry !== null)
1096-.toSorted((a, b) => b.day.localeCompare(a.day));
1118+.filter((entry): entry is DailyMemoryFile => entry !== null)
1119+.toSorted(compareDailyMemoryFilesByNewestDay);
1097112010981121const batches: DailyIngestionBatch[] = [];
10991122const nextFiles: Record<string, DailyIngestionFileState> = {};
@@ -1252,15 +1275,21 @@ export async function seedHistoricalDailyMemorySignals(params: {
12521275const resolved = normalizedPaths
12531276.map((filePath) => {
12541277const fileName = path.basename(filePath);
1255-const match = fileName.match(DAILY_MEMORY_FILENAME_RE);
1256-if (!match) {
1257-return { filePath, day: null as string | null };
1278+const file = parseDailyMemoryFileName(fileName);
1279+if (!file) {
1280+return { filePath, fileName, relativePath: "", day: null as string | null };
12581281}
1259-return { filePath, day: match[1] ?? null };
1282+return {
1283+ filePath,
1284+ fileName,
1285+relativePath: resolveWorkspaceMemoryRelativePath(params.workspaceDir, filePath),
1286+day: file.day,
1287+};
12601288})
12611289.toSorted((a, b) => {
12621290if (a.day && b.day) {
1263-return b.day.localeCompare(a.day);
1291+const dayOrder = b.day.localeCompare(a.day);
1292+return dayOrder !== 0 ? dayOrder : a.fileName.localeCompare(b.fileName);
12641293}
12651294if (a.day) {
12661295return -1;
@@ -1271,8 +1300,9 @@ export async function seedHistoricalDailyMemorySignals(params: {
12711300return a.filePath.localeCompare(b.filePath);
12721301});
127313021274-const valid = resolved.filter((entry): entry is { filePath: string; day: string } =>
1275-Boolean(entry.day),
1303+const valid = resolved.filter(
1304+(entry): entry is { filePath: string; fileName: string; relativePath: string; day: string } =>
1305+Boolean(entry.day),
12761306);
12771307const skippedPaths = resolved.filter((entry) => !entry.day).map((entry) => entry.filePath);
12781308const totalCap = Math.max(20, params.limit * 4);
@@ -1299,7 +1329,7 @@ export async function seedHistoricalDailyMemorySignals(params: {
12991329const results: MemorySearchResult[] = [];
13001330for (const chunk of chunks) {
13011331results.push({
1302-path: `memory/${entry.day}.md`,
1332+path: entry.relativePath,
13031333startLine: chunk.startLine,
13041334endLine: chunk.endLine,
13051335score: DAILY_INGESTION_SCORE,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。