Skip to content

Commit 545febd

Browse files
committed
fix(memory): allow localized heading memories
1 parent 5f3c215 commit 545febd

2 files changed

Lines changed: 33 additions & 11 deletions

File tree

extensions/memory-core/src/short-term-promotion.test.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,8 @@ describe("short-term promotion", () => {
11511151
"```",
11521152
"|",
11531153
"[]",
1154+
"## Tagesnotizen",
1155+
"## Notes",
11541156
"## Tagesnotizen\n-\n\n## Entscheidungen\n-",
11551157
"## Tagesnotizen\n## Entscheidungen",
11561158
"## Tagesnotizen - ## Entscheidungen -",
@@ -1170,6 +1172,8 @@ describe("short-term promotion", () => {
11701172
expect(testing.isUnpromotableShortTermSnippet("- ## Decision move backups to S3")).toBe(false);
11711173
expect(testing.isUnpromotableShortTermSnippet("## API keys rotated")).toBe(false);
11721174
expect(testing.isUnpromotableShortTermSnippet("- ## VPN outage fix")).toBe(false);
1175+
expect(testing.isUnpromotableShortTermSnippet("## Prod outage")).toBe(false);
1176+
expect(testing.isUnpromotableShortTermSnippet("## 修复备份轮换")).toBe(false);
11731177
});
11741178

11751179
it("does not record placeholder-only grounded candidates for promotion", async () => {
@@ -1212,7 +1216,7 @@ describe("short-term promotion", () => {
12121216
await writeDailyMemoryNote(workspaceDir, "2026-04-18", [
12131217
"## Tagesnotizen",
12141218
"- ## Entscheidungen",
1215-
"- ## VPN outage fix",
1219+
"- ## 修复备份轮换",
12161220
]);
12171221
await fs.writeFile(
12181222
resolveShortTermRecallStorePath(workspaceDir),
@@ -1222,7 +1226,7 @@ describe("short-term promotion", () => {
12221226
updatedAt: "2026-04-18T10:00:00.000Z",
12231227
entries: {
12241228
placeholder: entry("- ## Entscheidungen", 2),
1225-
durable: entry("- ## VPN outage fix", 3),
1229+
durable: entry("- ## 修复备份轮换", 3),
12261230
},
12271231
},
12281232
null,
@@ -1238,7 +1242,7 @@ describe("short-term promotion", () => {
12381242
minUniqueQueries: 0,
12391243
});
12401244
expect(ranked).toHaveLength(1);
1241-
expect(ranked[0]?.snippet).toBe("- ## VPN outage fix");
1245+
expect(ranked[0]?.snippet).toBe("- ## 修复备份轮换");
12421246

12431247
const applied = await applyShortTermPromotions({
12441248
workspaceDir,
@@ -1250,7 +1254,7 @@ describe("short-term promotion", () => {
12501254

12511255
expect(applied.applied).toBe(1);
12521256
const memoryText = await fs.readFile(path.join(workspaceDir, "MEMORY.md"), "utf-8");
1253-
expect(memoryText).toContain("- ## VPN outage fix");
1257+
expect(memoryText).toContain("- ## 修复备份轮换");
12541258
expect(memoryText).not.toContain("- ## Entscheidungen");
12551259
});
12561260
});

extensions/memory-core/src/short-term-promotion.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,27 @@ function isContaminatedDreamingSnippet(raw: string): boolean {
319319
return hasNarrativeLead && hasConfidence && hasEvidence && hasStatus && hasRecalls;
320320
}
321321

322+
// Known empty daily-note section headings; arbitrary single headings should remain promotable.
323+
const MARKDOWN_SKELETON_HEADING_BODIES = new Set([
324+
"aufgaben",
325+
"daily notes",
326+
"decisions",
327+
"entscheidungen",
328+
"notes",
329+
"tasks",
330+
"tagesnotizen",
331+
"todo",
332+
"todos",
333+
]);
334+
335+
function normalizeMarkdownSkeletonHeadingBody(raw: string): string {
336+
return raw
337+
.replace(/[-*+>`_[\](){}|~.,;!?]+/g, " ")
338+
.replace(/\s+/g, " ")
339+
.trim()
340+
.toLowerCase();
341+
}
342+
322343
function isMarkdownSkeletonSnippet(raw: string): boolean {
323344
const nonEmptyLines = raw
324345
.split(/\r?\n/)
@@ -341,14 +362,11 @@ function isMarkdownSkeletonSnippet(raw: string): boolean {
341362
hasPlaceholderLine = true;
342363
continue;
343364
}
344-
const headingWords =
345-
headingBody.replace(/#{1,6}\s*/g, " ").match(/[\p{L}\p{N}][\p{L}\p{N}'-]*/gu) ?? [];
346-
// Short single headings are usually template scaffolding; three or more words carry memory text.
347-
if (/:\s*\S/.test(headingBody) || headingWords.length >= 3) {
348-
return false;
365+
if (MARKDOWN_SKELETON_HEADING_BODIES.has(normalizeMarkdownSkeletonHeadingBody(headingBody))) {
366+
hasPlaceholderLine = true;
367+
continue;
349368
}
350-
hasPlaceholderLine = true;
351-
continue;
369+
return false;
352370
}
353371
return false;
354372
}

0 commit comments

Comments
 (0)