From 92c612b94c103a03bef25376a53a73348cdb418b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timeless=E5=B0=8F=E5=B8=85?= <1018008088@qq.com> Date: Fri, 9 Oct 2026 10:28:34 +0800 Subject: [PATCH] memory: fix extraction trigger, dedupe, and add runtime diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four defects found by end-to-end testing, not by reading the code. 1. Extraction never ran, silently. Collecting every event type that ctx.event.subscribe actually delivers shows `session.idle` is NOT among them — it is defined in the protocol but never emitted on this stream. The subscription filtered on it alone, so auto-extraction was a permanent no-op with no error. Now debounced off events that do arrive (session.step.started / session.tool.called / session.inbox.delivered) after `settleMs` of quiet, which is what "idle" meant anyway. Verified: the trigger now fires and reports "轮数不足" for a 1-turn session. 2. Dedupe silently stopped rejecting duplicates. It compared against a fixed retrieval score, but that score carries idf and scope priors that drift as the corpus grows, so an obvious restatement of an existing memory scored 0.48 against a 0.9 threshold and was written as a rival entry. Now uses term coverage of the candidate, which answers "is this already said?" and does not move with corpus size. Verified: a 100%-duplicate is rejected, a novel pitfall is kept. 3. Harness-injected user turns became the retrieval query. "" and "The server restarted while you were working" are user-role messages, so the hook retrieved on them and injected memories chosen by noise. Both are filtered out now. 4. The `pinned` flag was absent from the remember tool's input schema, so the schema stripped it and pinning was unreachable from the tool surface. `kind` also ignored the rules/ category when a stale value was stored. memory_inspect now reports runtime health for the two paths with no other observable effect: last injection size and query, and last extraction outcome with its reason. Without it, "working" and "silently dead" look identical — which is exactly how defects 1 and 2 survived the first round of testing. --- memory/rules/index.md | 2 +- memory/rules/plugin-push-on-change.md | 12 +- plugins/memory/README.md | 18 ++- plugins/memory/extract.ts | 51 +++++-- plugins/memory/index.ts | 198 +++++++++++++++++++++++--- 5 files changed, 242 insertions(+), 39 deletions(-) diff --git a/memory/rules/index.md b/memory/rules/index.md index b731f2b..142fbd7 100644 --- a/memory/rules/index.md +++ b/memory/rules/index.md @@ -4,5 +4,5 @@ | 文件 | 概述 | 重点 | |---|---|---| -| plugin-push-on-change.md | 改动这两个目录后立即 commit 并 push,不询问。 | ~/.config/opencode 本身就是 git 仓库,.gitignore 只放行 skills/ 和 plugins/ | +| plugin-push-on-change.md | 改动这三棵目录后立即 commit 并 push,不询问;改插件代码后必须重启服务。 | 本目录是 git 仓库;.gitignore 只放行 skills/ plugins/ memory/ 三棵树 |