From 0145f0cfe1c52857b4e13bdd44e985baaaeb9476 Mon Sep 17 00:00:00 2001 From: thzxx Date: Fri, 10 Jul 2026 21:47:41 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20memory=20replace/remove=20=E5=BD=92?= =?UTF-8?q?=E4=B8=80=E5=8C=96=E5=8C=B9=E9=85=8D+=E6=9C=80=E4=BD=8E?= =?UTF-8?q?=E9=95=BF=E5=BA=A6=E5=9B=9E=E9=80=80=E8=87=B35=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=95=E5=8F=B7=E5=B7=AE=E5=BC=82=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=88=A0=E9=99=A4=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/services/memory-service.ts | 30 ++++++++++++------------- src/renderer/services/tool-registry.ts | 2 +- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/renderer/services/memory-service.ts b/src/renderer/services/memory-service.ts index f72e473..3d570ba 100644 --- a/src/renderer/services/memory-service.ts +++ b/src/renderer/services/memory-service.ts @@ -530,12 +530,11 @@ export async function addEntry( /** 替换记忆(子串匹配) * M8: 使用写入锁串行化 - * M9: 要求 oldText 至少 5 个字符,减少误匹配 */ + * 要求 oldText 至少 5 个字符,减少误匹配 */ export async function replaceEntry(oldText: string, newContent: string): Promise<{ success: boolean; message: string }> { return withWriteLock(async () => { - // M4: 提高最小匹配长度到 8,减少误匹配 - if (!oldText || oldText.length < 8) { - return { success: false, message: 'old_text 不能为空且至少 8 个字符(提高精确度)' }; + if (!oldText || oldText.length < 5) { + return { success: false, message: 'old_text 不能为空且至少 5 个字符(提高精确度)' }; } if (!newContent || newContent.length < 2) { return { success: false, message: 'new_content 不能为空且至少 2 个字符' }; @@ -547,12 +546,12 @@ export async function replaceEntry(oldText: string, newContent: string): Promise } const entries = await loadAllEntries(); - // M9: 大小写不敏感匹配 - const oldTextLower = oldText.toLowerCase(); - const matches = entries.filter(e => e.content.toLowerCase().includes(oldTextLower)); + // 归一化匹配:统一全角/半角标点、空白、大小写,解决引号等字符差异 + const oldTextNorm = normalizeForDedup(oldText); + const matches = entries.filter(e => normalizeForDedup(e.content).includes(oldTextNorm)); if (matches.length === 0) { - return { success: false, message: `未找到包含 "${oldText.slice(0, 50)}" 的记忆` }; + return { success: false, message: `未找到包含 "${oldText.slice(0, 50)}" 的记忆。建议先调用 memory read_all 查看完整内容,再用精确的 old_text 重试` }; } if (matches.length > 1) { return { success: false, message: `匹配到 ${matches.length} 条记忆,请使用更精确的 old_text` }; @@ -579,21 +578,20 @@ export async function replaceEntry(oldText: string, newContent: string): Promise /** 删除记忆(子串匹配) * M8: 使用写入锁串行化 - * M4: 要求 oldText 至少 8 个字符,减少误匹配 */ + * 要求 oldText 至少 5 个字符,减少误匹配 */ export async function removeEntry(oldText: string): Promise<{ success: boolean; message: string }> { return withWriteLock(async () => { - // M4: 提高最小匹配长度到 8 - if (!oldText || oldText.length < 8) { - return { success: false, message: 'old_text 不能为空且至少 8 个字符(提高精确度)' }; + if (!oldText || oldText.length < 5) { + return { success: false, message: 'old_text 不能为空且至少 5 个字符(提高精确度)' }; } const entries = await loadAllEntries(); - // M9: 大小写不敏感匹配 - const oldTextLower = oldText.toLowerCase(); - const matches = entries.filter(e => e.content.toLowerCase().includes(oldTextLower)); + // 归一化匹配:统一全角/半角标点、空白、大小写,解决引号等字符差异 + const oldTextNorm = normalizeForDedup(oldText); + const matches = entries.filter(e => normalizeForDedup(e.content).includes(oldTextNorm)); if (matches.length === 0) { - return { success: false, message: `未找到包含 "${oldText.slice(0, 50)}" 的记忆` }; + return { success: false, message: `未找到包含 "${oldText.slice(0, 50)}" 的记忆。建议先调用 memory read_all 查看完整内容,再用精确的 old_text 重试` }; } if (matches.length > 1) { return { success: false, message: `匹配到 ${matches.length} 条记忆,请使用更精确的 old_text` }; diff --git a/src/renderer/services/tool-registry.ts b/src/renderer/services/tool-registry.ts index e3a94b2..c202797 100644 --- a/src/renderer/services/tool-registry.ts +++ b/src/renderer/services/tool-registry.ts @@ -378,7 +378,7 @@ CRITICAL: For add action, you MUST include both "type" (fact/preference/rule) an content: { type: 'string', description: '[add REQUIRED, replace] Memory text. Keep it concise (8-100 chars).' }, importance: { type: 'integer', description: '[add] Priority 1-10. Default: 5. Use 8+ for critical info.' }, tags: { type: 'array', items: { type: 'string' }, description: '[add] 2-5 keywords for search matching.' }, - old_text: { type: 'string', description: '[replace, remove REQUIRED] Unique substring to identify the entry. Must be ≥8 chars for precision.' }, + old_text: { type: 'string', description: '[replace, remove REQUIRED] Unique substring to identify the entry. Must be ≥5 chars. Use exact text from read_all for best results.' }, new_content: { type: 'string', description: '[replace REQUIRED] New text to replace with.' } } }