dsh-memu-memory 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -5
- package/README.md +22 -5
- package/README.zh.md +21 -4
- package/docs/contributing.md +5 -3
- package/docs/env-and-commands.md +13 -0
- package/docs/host-api.md +35 -3
- package/docs/memory-semantics.md +41 -1
- package/docs/troubleshooting.md +395 -350
- package/lib/activity-log.js +190 -0
- package/lib/backup.js +1103 -0
- package/lib/binding-diagnostics.js +630 -0
- package/lib/client.js +703 -50
- package/lib/curator.js +81 -37
- package/lib/cycle.js +3 -0
- package/lib/embedding-catalog.js +763 -0
- package/lib/embedding-download.js +407 -0
- package/lib/embedding-runtime.js +710 -0
- package/lib/engine.js +2 -2
- package/lib/index.js +61 -4
- package/lib/inject.js +195 -49
- package/lib/local-embedding-entry.js +145 -0
- package/lib/local-embedding-manager.js +249 -0
- package/lib/local-embedding-protocol.js +173 -0
- package/lib/local-embedding-worker.js +652 -0
- package/lib/local-vector-service.js +283 -0
- package/lib/memory.js +385 -45
- package/lib/memu-config.js +10 -22
- package/lib/memu.js +53 -19
- package/lib/paths.js +24 -0
- package/lib/preset-scope.js +121 -0
- package/lib/private.js +139 -13
- package/lib/rpc.js +45 -4
- package/lib/state.js +109 -161
- package/lib/tools.js +9 -5
- package/lib/vector-migration.js +878 -0
- package/lib/vector-profile.js +941 -0
- package/package.json +3 -2
- package/scripts/acceptance-local.mjs +5 -4
- package/scripts/chain-matrix.mjs +527 -0
- package/scripts/check-all.mjs +19 -0
- package/scripts/check-doc-drift.mjs +353 -0
- package/scripts/diagnose-bindings.mjs +176 -0
- package/scripts/local-runtime-install.mjs +142 -0
- package/scripts/local-runtime-verify.mjs +56 -0
- package/scripts/local-vector-verify.mjs +93 -0
- package/scripts/recall-bench.mjs +813 -0
- package/scripts/repetition-ab-scenarios.mjs +93 -0
- package/scripts/repetition-detector-snapshot.mjs +314 -0
- package/scripts/repetition-eval-live.mjs +360 -0
- package/scripts/repetition-eval.mjs +702 -0
package/AGENTS.md
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
1. **不改 DSH 源码**,只用插件、公开 service、RPC、slot;只用公开扩展点。
|
|
16
16
|
2. **不让主 agent 写全局记忆**:全局只由 curator 写,主 agent 只读。
|
|
17
|
-
3. **动态记忆不进 system prompt**(静态 guide 可以):走独立 plugin 消息,保护 KV cache
|
|
17
|
+
3. **动态记忆不进 system prompt**(静态 guide 可以):走独立 plugin 消息,保护 KV cache 也让注入可折叠。`persona` 带 `complete: true` 的预设会丢弃本插件的 system prompt 段,这类会话的 guide 改由首步一条 `<memory-guide>` 消息投放(`withGuideMessage`,按 `binding.guideMessageAt` 只发一次,`lib/inject.js`)——仍然是 plugin 消息,不是把动态记忆写进 system prompt。
|
|
18
18
|
4. **不每步注入**:普通回合首步注入;长工具回合只在出现尚未处理的真实人类消息批次时追加一次。工具日志、心跳不算人类消息。
|
|
19
19
|
5. **不自动删除记忆**:永久记忆移出 = 边缘化;删库必须显式确认;删会话默认只解绑。
|
|
20
20
|
6. **Python 不装进系统解释器 / 用户 site-packages**,只装 `engine/<version>/venv`,且 venv 里不留 pip(`--without-pip` 建,再用基础 Python 的 `pip --python` 指进去装)。
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
注入整段没了 → T3.13 日期语义错 / 看不见日期 → T3.14
|
|
48
48
|
保存成功但没变 / 字段改不回来 → T3.15 记忆凭空消失 / 侧边栏空 → T3.17
|
|
49
49
|
弹窗选了却两侧都勾上 → T3.16 聊很久一条记忆都没写 → T3.18
|
|
50
|
+
人格预设会话里完全没有记忆 → T3.19 鉴权 401/403 说不清 → T3.20
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
---
|
|
@@ -60,7 +61,7 @@ node scripts/acceptance-local.mjs # 50/50
|
|
|
60
61
|
npm run check # node --check + i18n + package.json + 文档预算
|
|
61
62
|
```
|
|
62
63
|
|
|
63
|
-
**结果口径**:以 `node --test` 输出的 `ℹ tests / pass / fail / skipped`
|
|
64
|
+
**结果口径**:以 `node --test` 输出的 `ℹ tests / pass / fail / skipped` 为准。用例数变了先问「是不是我加的」,失败先问「是不是并发写了同一个库」——这仓库真会多个会话同时改它。测试数字只作**带日期快照**引用(2026-10-29 W7/W8 集成后实测 505 tests / 504 pass / 1 skipped;同日更早的 W7 为 493/492/1、W3–W9 为 463/462/1、W1/W2 为 409/408/1 与 392/391/1,321/327/333 原报告缺失、不可复核),不当成当前保证。提交前逐条对 `docs/contributing.md` §10。
|
|
64
65
|
|
|
65
66
|
---
|
|
66
67
|
|
|
@@ -70,10 +71,12 @@ npm run check # node --check + i18n + package.json + 文
|
|
|
70
71
|
|---|---|
|
|
71
72
|
| `docs/troubleshooting.md` | §3 全部症状/落点/守卫 + 症状速查表 + 守卫索引表 + 附录(模块地图 §2.1、调用链 §2.2、数据铁律 §2.3、三种 exec 形状 §6.3、硬规则全文 §1) |
|
|
72
73
|
| `docs/contributing.md` | §4 改动流程(四步 / 验证三件套 / 连带清单 / 文档同步)+ §5 六个扩展点 + §10 提交前清单 |
|
|
73
|
-
| `docs/host-api.md` | §6.1 / 6.2 / 6.4–6.
|
|
74
|
+
| `docs/host-api.md` | §6.1 / 6.2 / 6.4–6.8:embedding、workspaceRegistry、历史会话与标题、fork/followup、定时器、RPC+slot+折叠、预设工具面真机证据边界 |
|
|
74
75
|
| `docs/client-conventions.md` | §7:两个壳一份实现、颜色 token、控件纪律、数据与刷新、文案与结构 |
|
|
75
|
-
| `docs/memory-semantics.md` | §8
|
|
76
|
-
| `docs/env-and-commands.md` | §9:Windows 跑命令的 env、CRLF 补丁法、本地 link
|
|
76
|
+
| `docs/memory-semantics.md` | §8:三层、写入规则、全局记忆、注入(含预设会话首步 `<memory-guide>` 一次性投放)、提示词管理 |
|
|
77
|
+
| `docs/env-and-commands.md` | §9:Windows 跑命令的 env、CRLF 补丁法、本地 link、引擎安装与回滚、本地向量受管运行时的安装/状态命令(§9.5)、MemU CLI 事实 |
|
|
78
|
+
|
|
79
|
+
**W8(助手重复提示)已决定不做,不再重做。** 理由:120 次合成 A/B 未证明改善重复回答率,事实词面完整性反而下降。证据文档已删除,不得据此宣称“已证明任何防复读技术无效”。
|
|
77
80
|
|
|
78
81
|
节号跨文件不变:看到「(§8.4)」就去 `docs/memory-semantics.md` 找 §8.4。
|
|
79
82
|
|
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ It is **local-first by default**. The default `agent` backend stores full text i
|
|
|
30
30
|
> [!WARNING]
|
|
31
31
|
> **Early-stage software.** This plugin is still early and may contain unforeseen errors, bugs or breaking changes. Back up your data, and please [report an issue](https://github.com/Tkingxiao/dsh-memu-memory/issues) or send a pull request — feedback helps the project improve.
|
|
32
32
|
|
|
33
|
-
> **Status:** 1.1.
|
|
33
|
+
> **Status:** 1.1.2. The first public release was 1.0.0. The manual now lives in [`docs/`](docs/), with [`AGENTS.md`](AGENTS.md) as a short index. Back up `~/.dsh/dsh-memu-memory` before upgrades, and read [Compatibility & limits](#compatibility--limits) before storing data you cannot re-create.
|
|
34
34
|
|
|
35
35
|
## Screenshots
|
|
36
36
|
|
|
@@ -59,7 +59,7 @@ All screenshots are the real WebUI on isolated example data, not anyone's memori
|
|
|
59
59
|
- **Three layers, one timeline.** `short_term` drafts expire after 72 hours by default; `long_term` is the body of ordinary memory; `must_remember` needs a reason and a source, decays over 365 days with a 0.35 strength floor, and can be *marginalized* but never auto-deleted to make room.
|
|
60
60
|
- **Recall is a moment, not a dump.** The first turn after a session starts (or after compaction) gets an anchor block with budgets for pinned, core and global memory. After that, each user turn gets at most one recall. Deduplication and a token budget are enforced in code, not left to the prompt.
|
|
61
61
|
- **A date is either an anniversary or one day.** `MM-DD` recurs every year (a birthday); `YYYY-MM-DD` fires the day before and the day itself, then is spent. A memory that says "tomorrow" is stored as the dated form, so an appointment does not come back every year.
|
|
62
|
-
- **Memory fades unevenly.** Recency, access count,
|
|
62
|
+
- **Memory fades unevenly.** Recency, access count, peak and end effects, primacy, habituation and flashbulb accuracy feed one strength score. Arousal and mood congruence are conditional rather than always-on: both are off by default and only engage when the mood is far enough from flat (|valence| >= 0.15, or |arousal - 0.35| >= 0.1), so in a calm conversation both multipliers are exactly 1. A vivid memory can be more confident than it is accurate, and the UI says so.
|
|
63
63
|
- **Provenance is a fact, not a style.** Every entry carries `source` (`user_said` / `inferred` / `imagined` / `told`), `confidence`, `accuracy`, and disclosure rules. A vague recollection cannot impersonate a quote.
|
|
64
64
|
- **Contradictions wait.** A write that rewrites or contradicts an existing entry lands as `pending_review`: it is not injected, not recalled, and appears in a review queue until someone accepts or rejects it.
|
|
65
65
|
- **Secrets stay excluded.** `secret` visibility, group-chat channels, characters, worlds, branches and `knownBy` all constrain reads and edits. Automatic recall never injects a `secret` memory, and a `secret` is still readable by an explicit recall from the same folder — it hides a memory from the prompt, it is not a lock. What actually separates two conversations in one folder is the `context` scope (`channelId` / `characterId` / `worldId` / `branchId`); a blank scope on both sides means one shared scope, which is the point of a folder. The old `visibility: 'session'` level is gone — reading turns it into `shared` with its `context` untouched, and `node scripts/migrate-visibility.mjs` rewrites libraries that still store it (`--apply`, backs up first).
|
|
@@ -86,14 +86,18 @@ The locally bundled D3 force layout preserves positions and the camera across ba
|
|
|
86
86
|
| Libraries | Create, rename, archive, restore, explicitly delete libraries |
|
|
87
87
|
| Memory browser | Full-text editing, attachments, review queue, graph and bounded canvas, JSON/ZIP import/export |
|
|
88
88
|
| Global memory | Domain-scoped global memories, evidence, review queue and the separate curator |
|
|
89
|
-
| Prompts | General / RP / Coding / Mixed variants, overrides and per-key reset; new conversations start on RP |
|
|
89
|
+
| Prompts | General / RP / Coding / Mixed variants, overrides and per-key reset; new conversations start on RP and can pick a domain in the first-run prompt |
|
|
90
90
|
| Stats | Daily activity, hit distribution, health, never-recalled shortlist, 7-day write/read ratio |
|
|
91
91
|
|
|
92
92
|
Settings save as you change them (250 ms debounce), with about 2.5 s cross-window sync and a heartbeat for writes made by tools or another window. The WebUI opens in a new tab; when a popup is blocked it falls back to an in-app overlay without unloading the host SPA. Light, dark, reduced-motion and narrow layouts are supported.
|
|
93
93
|
|
|
94
|
+
### Injection token budgets
|
|
95
|
+
|
|
96
|
+
`anchorTokens` and `turnTokens` bound anchor and recall content independently (default 800 each). `injectionTotalTokens` caps the whole plugin message (default 2000); it does not replace the recall budget.
|
|
97
|
+
|
|
94
98
|
### Domain Prompts
|
|
95
99
|
|
|
96
|
-
Resident guidance, writing policies and consolidation prompts follow the current session domain. Local tools and remote JSON consolidation share the domain body, with separate supported output contracts. New conversations default to RP; Coding, Mixed and custom pages stay enabled and can be selected per conversation.
|
|
100
|
+
Resident guidance, writing policies and consolidation prompts follow the current session domain. Local tools and remote JSON consolidation share the domain body, with separate supported output contracts. New conversations default to RP; Coding, Mixed and custom pages stay enabled and can be selected per conversation. The new-conversation memory prompt also offers the four memory domains, so a coding session can be started in an RP workspace without remembering to change the sidebar afterwards.
|
|
97
101
|
|
|
98
102
|
| Domain | Memory focus |
|
|
99
103
|
|---|---|
|
|
@@ -176,7 +180,11 @@ What it does:
|
|
|
176
180
|
- if no usable Python/pip exists, uses a **pinned uv** runtime inside the plugin directory and leaves the system `PATH` untouched;
|
|
177
181
|
- downloads roughly 150 MB, runs a real smoke test, and keeps the previous version for rollback.
|
|
178
182
|
|
|
179
|
-
|
|
183
|
+
The default `memoryBackend="agent"` uses lexical recall and does not call an embedding service. To enable the vector library, choose `memoryBackend="api"`, then select `vectorSource="local"` for managed local embeddings or `vectorSource="api"` for a configured compatible embedding endpoint (which may itself run on localhost). Both sources feed MemU storage and retrieval; installing the MemU engine alone does not enable vectors.
|
|
184
|
+
|
|
185
|
+
`memoryMode` (`local` / `cloud`) is a MemU storage-compatibility setting, not the embedding switch or source selector; its cloud option is not a claim that managed local inference is offline cloud storage. Summary generation is configured independently of the vector route: ordinary private consolidation uses an Agent fork; an explicit remote-summary action uses its chat endpoint and commits through the same memory write path. Recall uses neither LLM reranking nor an LLM fallback. Exact memory ids still use the direct path; the plugin does not maintain a parallel vector database.
|
|
186
|
+
|
|
187
|
+
Managed model download, progress reporting and profile-switch/migration flows are implemented, but real model/runtime downloads and end-to-end native inference/switching have not been verified in this work. A candidate or `pending` artifact is not available for use; it must not be advertised as downloadable or ready until its artifact and validation gates pass.
|
|
180
188
|
|
|
181
189
|
## First run
|
|
182
190
|
|
|
@@ -288,6 +296,7 @@ the idle window starts from real message activity or the agent's return to idle.
|
|
|
288
296
|
- **No cloud sync, no accounts, no cross-device sync.** This is a local plugin with no server-side identity.
|
|
289
297
|
- **Images without vision:** without an optional caption/vision endpoint, an image memory is a pointer plus what a person wrote about it. The plugin does not claim to see pixels.
|
|
290
298
|
- **Poisoned v4 sessions:** historical `format v4 message requires a producer-owned source kind` rows can be diagnosed but not rewritten; the plugin never edits private session files.
|
|
299
|
+
- **Agent presets:** a conversation whose preset (`i-am-yuike`, `yuike-standard`, …) carries its own `cordis.yml` composes its model-facing plugins from that list alone, and its scope never delivers `agent/pre-step` to this plugin. At runtime `lib/preset-scope.js` attaches a second injection listener to that agent's own context, so **anchor and recall delivery works**; because a preset persona usually sets `complete: true`, system-prompt sections are dropped and the memory rules are delivered once as a `<memory-guide>` plugin message on the first step instead. The **final tool list** is a third, separate question: it follows the preset's own plugin list and the host scope, and it cannot be inferred from whether this plugin is listed — observations in this repo record both "no `memu_*` tools" and `memu_private_*` present in some presets' tool chains. **Per-preset tool availability still needs a real-host check (W3)**; until then do not read this as "presets have no tools", nor as "listing the plugin is enough". The plugin never edits anyone's preset files.
|
|
291
300
|
- **"Tomorrow" is resolved at write time.** A relative day (今天 / 明天 / 后天 / today / tomorrow) together with a month-day settles into one dated memory; a memory that only says "sometime next month" keeps no date rather than inventing one. A date that was already written as `MM-DD` is not rewritten — the fix applies to new writes.
|
|
292
301
|
- **Not in scope:** cloud MemU integration, source backfill for old entries, automatic repair of already-written v4 corruption.
|
|
293
302
|
|
|
@@ -309,6 +318,14 @@ With the preview running, use `npm run test:graph-browser -- http://127.0.0.1:77
|
|
|
309
318
|
|
|
310
319
|
The suite includes one real-engine integration case that is skipped unless `DSH_MEMU_TEST_ENGINE_PYTHON` is set; the 50 automated acceptance checks pass. The optional engine was installed and smoke-tested in an isolated directory with the pinned wheel; embedding tests use a local deterministic server, which proves the protocol, not semantic quality.
|
|
311
320
|
|
|
321
|
+
## Changelog
|
|
322
|
+
|
|
323
|
+
**1.1.3 (2026-10-30)**: managed local vectors are usable end to end (runtime/model download, switch-and-rebuild, progress with per-item failures); activity log with a Logs page; consolidation results move under the sidebar button; archive/restore and list refresh drop from seconds to milliseconds; a date written in the text is picked up when the field is empty; default topK 5/5; fixes the blank settings/WebUI panel (React #310).
|
|
324
|
+
|
|
325
|
+
**1.1.2 (2026-10-29)**: anchor and recall delivery in agent-preset conversations; startup catch-up consolidation; panel TDZ crash fix.
|
|
326
|
+
|
|
327
|
+
Full notes: [`CHANGELOG.md`](CHANGELOG.md).
|
|
328
|
+
|
|
312
329
|
## Documentation
|
|
313
330
|
|
|
314
331
|
[`AGENTS.md`](AGENTS.md) is the index for anyone changing this repo — which file answers
|
package/README.zh.md
CHANGED
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
- **三层,一条时间线。** `short_term` 草稿默认 72 小时到期;`long_term` 是记忆主体;`must_remember` 需要理由与来源,按 365 天半衰并带 0.35 强度地板,可以**边缘化**,但不会为腾名额被自动删除。
|
|
60
60
|
- **召回是一个瞬间,不是一次倾倒。** 新会话或压缩后的第一个回合得到锚点块(pin / core / global 分段预算);之后每个用户回合最多一次召回。去重与 token 预算由代码执行,不交给提示词自觉。
|
|
61
61
|
- **日期要么是纪念日,要么是一天。** `MM-DD` 每年复发(生日);`YYYY-MM-DD` 在前一天和当天各响一次,之后就算用过了。说「明天」的记忆存成带年份的日期,不会变成每年都冒出来的周年。
|
|
62
|
-
- **记忆会不均匀地淡。**
|
|
62
|
+
- **记忆会不均匀地淡。** 新近、访问次数、峰终、首因、习惯化、闪光灯记忆的准确度共同参与强度;唤醒度与情绪同调是**条件项**而不是恒常生效——默认关闭,只有情绪离平缓够远时(|valence| >= 0.15,或 |arousal - 0.35| >= 0.1)才打开,平缓对话里两项乘数恒为 1。一条生动但可能记错的记忆会显示「细节未必准」,而不是假装确定。
|
|
63
63
|
- **来源是事实,不是文风。** 每条记忆带 `source`(`user_said` / `inferred` / `imagined` / `told`)、`confidence`、`accuracy` 与说出口径。模糊的推断不能冒充原话。
|
|
64
64
|
- **矛盾先挂起。** 与已有记忆同题改写或说法相反的新条进入 `pending_review`:不注入、不召回,只出现在复核队列,等人或整理作业裁决。
|
|
65
65
|
- **秘密不进自动召回。** `secret`、群聊频道、角色、世界线、剧情分支与 `knownBy` 共同约束读写;`secret` 永远不会被自动注入,但同文件夹里**主动检索仍然读得到**——它挡的是「自己冒出来」,不是保险箱。真正把同一文件夹里的两段对话隔开的是 `context` 作用域(`channelId` / `characterId` / `worldId` / `branchId`);两边都没填就是同一个作用域,这正是「文件夹」的含义。旧的 `visibility: 'session'` 级别已删除:读到就按 `shared` 处理、`context` 原样保留,仍存着该级别的库用 `node scripts/migrate-visibility.mjs` 重写(`--apply` 才写,先备份)。
|
|
@@ -86,14 +86,18 @@
|
|
|
86
86
|
| 记忆库 | 新建、改名、归档、恢复、显式删除 |
|
|
87
87
|
| 记忆浏览 | 全文编辑、附件、复核池、有界图谱、JSON/ZIP 导入导出 |
|
|
88
88
|
| 全局记忆 | 分域全局记忆、证据、复核队列与独立 curator |
|
|
89
|
-
| 提示词 | 通用 / RP / Coding / Mixed 变体,覆盖与单项恢复;新会话默认 RP |
|
|
89
|
+
| 提示词 | 通用 / RP / Coding / Mixed 变体,覆盖与单项恢复;新会话默认 RP,并可在首次弹窗里直接选领域 |
|
|
90
90
|
| 统计 | 每日活跃、命中分布、库健康度、最久没被想起的 5 条、7 天写读比 |
|
|
91
91
|
|
|
92
92
|
设置项即时保存(250ms 防抖),跨窗口约 2.5 秒同步;工具调用或另一个窗口的写入也会被心跳发现。WebUI 优先在新标签页打开,被拦截时退回应用内 overlay,不卸载宿主 SPA。支持浅色、深色、减少动效与窄屏。
|
|
93
93
|
|
|
94
|
+
### 注入 token 预算
|
|
95
|
+
|
|
96
|
+
`anchorTokens` 与 `turnTokens` 分别约束锚点与召回内容(均默认 800)。`injectionTotalTokens` 限制整条 plugin 消息(默认 2000),不替代召回预算。
|
|
97
|
+
|
|
94
98
|
### 领域提示词
|
|
95
99
|
|
|
96
|
-
常驻指南、写入策略和整理提示词按当前会话领域选择;本地工具整理和远程 JSON 整理共用领域正文,各自使用实际支持的输出协议。新会话默认 RP;Coding、Mixed
|
|
100
|
+
常驻指南、写入策略和整理提示词按当前会话领域选择;本地工具整理和远程 JSON 整理共用领域正文,各自使用实际支持的输出协议。新会话默认 RP;Coding、Mixed 与自定义页保持启用,可按会话选择。新会话的记忆弹窗里也能直接选这四个记忆领域,在 RP 工作区里开写代码的对话不必事后再去侧边栏切换。
|
|
97
101
|
|
|
98
102
|
| 领域 | 记忆重点 |
|
|
99
103
|
|---|---|
|
|
@@ -176,7 +180,11 @@ npx --package dsh-memu-memory dsh-memu-memory-setup
|
|
|
176
180
|
- 没有可用 Python/pip 时,使用放在插件目录里的**锁定版本 uv**,不改系统 `PATH`;
|
|
177
181
|
- 下载约 150 MB,跑真实 smoke,并保留上一版本以便回滚。
|
|
178
182
|
|
|
179
|
-
|
|
183
|
+
默认 `memoryBackend="agent"` 使用词法召回,不调用 embedding 服务。启用向量库需选择 `memoryBackend="api"`,再以 `vectorSource="local"` 选择受管本地 embedding,或以 `vectorSource="api"` 选择已配置的兼容 embedding 端点(端点也可位于 localhost)。两种来源都接入 MemU 存储与检索;仅安装 MemU 引擎不会开启向量。
|
|
184
|
+
|
|
185
|
+
`memoryMode`(`local` / `cloud`)是 MemU 存储兼容设置,不是 embedding 开关或来源选择;保留 cloud 选项不意味着受管本地推理可被称为离线云存储。总结生成与向量路由独立:常规私有整理使用 Agent fork,显式远程总结动作使用其聊天端点,再经统一记忆写入路径提交。召回不使用 LLM 重排,也不会以 LLM 作为失败回退。精确记忆 id 仍走直达路径,插件不维护平行的向量数据库。
|
|
186
|
+
|
|
187
|
+
模型下载、进度展示与 profile 切换/迁移流程已有实现,但本轮未验证真实模型/runtime 下载及原生推理/切换全链路。candidate 或 `pending` artifact 不代表可用;在制品与校验门槛通过前,不应宣传为可下载或已就绪。
|
|
180
188
|
|
|
181
189
|
## 第一次使用
|
|
182
190
|
|
|
@@ -280,6 +288,7 @@ return { content: originalContent, meta: { ...originalMeta, memoryInbound: batch
|
|
|
280
288
|
- **没有云同步、账号或跨设备同步。** 这是本地插件,没有服务端身份。
|
|
281
289
|
- **没有视觉时:** 图片记忆只是「指针 + 人写的描述」。插件不会声称看过像素。
|
|
282
290
|
- **v4 污染会话:** 历史 `format v4 message requires a producer-owned source kind` 行只能诊断,不能改写;插件不会编辑私有会话文件。
|
|
291
|
+
- **人格预设(agent preset):** 预设(`i-am-yuike`、`yuike-standard` 等)自带 `cordis.yml`,会话的模型可见插件集只由那份清单决定,它的 scope 也不会把 `agent/pre-step` 送到本插件。运行时 `lib/preset-scope.js` 会把第二个注入监听挂到该 agent 自己的 ctx 上,所以**锚点与召回的送达是能用的**;而 `persona` 通常带 `complete: true`、会把 system prompt 段整段丢弃,因此记忆规则改为首步一次性投放 `<memory-guide>` 插件消息。**最终工具面**是第三件事,由该预设自己的清单与宿主 scope 决定——不能从「有没有列上本插件」推断,仓库里的观察既有「没有 `memu_*` 工具」,也有某些预设的工具链里存在 `memu_private_*`。**逐预设的真实工具名单仍需真机核实(W3)**;在那之前,别读成「预设都没有工具」,也别读成「列上插件就一定可用」。插件不会改任何人的预设文件。
|
|
283
292
|
- **相对日期在写入时结算:** 「今天 / 明天 / 后天 / today / tomorrow」加上一个月日落成带年份的日期;只说「下个月某天」的记忆不产生日期,也不替它编一个。已经按 `MM-DD` 写进去的旧条目不会被改写——这条只对新写入生效。
|
|
284
293
|
- **不在范围:** 云端 MemU 联调、旧条目的 source 回填、已写坏 v4 消息的自动修复。
|
|
285
294
|
|
|
@@ -301,6 +310,14 @@ node --import ./tests/loader-register.mjs scripts/preview.mjs --port 7789
|
|
|
301
310
|
|
|
302
311
|
测试包含一条真实引擎集成用例,未设置 `DSH_MEMU_TEST_ENGINE_PYTHON` 时按设计跳过;50 条自动验收全部通过。可选引擎已在隔离目录安装并跑通锁定 wheel 的 smoke;embedding 测试使用本机确定性服务,只证明协议可用,不证明语义质量。
|
|
303
312
|
|
|
313
|
+
## 更新日志
|
|
314
|
+
|
|
315
|
+
**1.1.3(2026-10-30)**:受管本地向量可用(运行时/模型下载、切换重建、进度与失败明细);活动日志与「日志」页;整理结果落到侧边栏按钮下方;归档/还原与列表刷新提速到毫秒级;日期漏填时从正文兜底;默认 topK 5/5;修复设置/WebUI 白屏。
|
|
316
|
+
|
|
317
|
+
**1.1.2(2026-10-29)**:人格预设会话的锚点与召回送达;启动补扫空闲整理;面板 TDZ 崩溃修复。
|
|
318
|
+
|
|
319
|
+
完整记录见 [`CHANGELOG.md`](CHANGELOG.md)。
|
|
320
|
+
|
|
304
321
|
## 文档
|
|
305
322
|
|
|
306
323
|
[`AGENTS.md`](AGENTS.md) 是给改这个仓库的人的索引:哪个问题去哪份文件。
|
package/docs/contributing.md
CHANGED
|
@@ -20,7 +20,7 @@ node scripts/acceptance-local.mjs # 50/50;视觉证据只证明本次已审
|
|
|
20
20
|
npm run check # node --check + i18n 键对齐 + package.json 可解析
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
**结果口径**:以 `node --test` 输出的 `ℹ tests / pass / fail / skipped`
|
|
23
|
+
**结果口径**:以 `node --test` 输出的 `ℹ tests / pass / fail / skipped` 为准。用例数变了先问「是不是我加的」,失败先问「是不是并发写了同一个库」——这仓库真会多个会话同时改它。文档里出现的测试数字一律当作**带日期的快照**:2026-10-29 实测 392 tests / 391 pass / 0 fail / 1 skipped(真实引擎用例按设计跳过);更早的 321 / 327 / 333 等是历史转述,原报告已缺失、不可复核,不能当作当前保证。
|
|
24
24
|
|
|
25
25
|
### 4.3 每类改动的连带清单
|
|
26
26
|
|
|
@@ -57,7 +57,7 @@ npm run check # node --check + i18n 键对齐 + package.j
|
|
|
57
57
|
|
|
58
58
|
### 5.1 新增一个模型工具
|
|
59
59
|
|
|
60
|
-
1. `lib/tools.js
|
|
60
|
+
1. `lib/tools.js`:实际走 `toolBase(name, description, parameters, execute, options)`(`lib/tools.js:43`),它包一层 `defineTool({ name, description, parameters, output: { schema, render }, timeoutMs, isConcurrencySafe, execute(args, exec) })`。字段名是 **`parameters`**(不是 `inputSchema`)、输出契约在 **`output.schema`**、`timeoutMs` 是**正数**(默认 60000);`execute` 拿 `(args, exec)`,会话 id 用 `exec.agent.session.header.id`(§6.3)。
|
|
61
61
|
2. **描述是给模型看的契约**:写清默认值、拒绝条件、返回形状——模型读不到代码。
|
|
62
62
|
3. 主 agent **不注册**全局写入类工具(§1.2)。
|
|
63
63
|
4. `lib/index.js` 注册;`README.md` 工具表加一行。
|
|
@@ -75,7 +75,9 @@ npm run check # node --check + i18n 键对齐 + package.j
|
|
|
75
75
|
|
|
76
76
|
### 5.3 新增一个 RPC 方法
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
<!-- rpc-method-count: 83 -->
|
|
79
|
+
|
|
80
|
+
1. `lib/rpc.js` 的 `switch` 加 case(共 83 个方法,按功能分组,别乱插)。
|
|
79
81
|
2. 返回**形状稳定**:客户端 `call()` 直接解构,列表类给 `{items, total}` 而不是裸数组。
|
|
80
82
|
3. `revisionOnly` 分支只回 `{revision, stamp}`、**不要求 sessionId**(三端轮询,设置页与独立页没会话)、**不塞业务数据**(每 2.5 秒一次);顺带 `noteMemoryBeat()`,`memu_status` 靠它分「没写」与「没人轮询」。
|
|
81
83
|
4. 写成功后 `bumpMemoryRevision()`/`notifyMemoryWrite()`(§7);能让 `state.json` 或索引落盘的写,`state.js` 自动记写事件供 `memu_status` 展示。
|
package/docs/env-and-commands.md
CHANGED
|
@@ -52,4 +52,17 @@ python -m memu commit payload.json --json --db <db>
|
|
|
52
52
|
|
|
53
53
|
`commit` payload:`{ recall_files: [{ name, track: memory, description, content }], resource: [], user: {} }`。
|
|
54
54
|
|
|
55
|
+
### 9.5 本地向量运行时(受管,2026-10-30)
|
|
56
|
+
|
|
57
|
+
**不再需要手工环境变量**:运行时(`onnxruntime-node` 1.31.1 + `onnxruntime-common` + `@huggingface/tokenizers`)由插件按 catalog pin 装进 `<dataDir>/downloads/embeddings/runtime/`,规格见 §14.13。`DSH_MEMU_EMBED_RUNTIME_DIR` 只剩「显式覆盖」用途:指向的目录里没有那三个包时会被忽略(`warn`)并回落到受管目录;也不需要 Ollama。
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
node scripts/local-runtime-install.mjs # 只读:打印 pin 的制品、状态、已装 checks
|
|
61
|
+
node scripts/local-runtime-install.mjs --download # 显式联网装(≈ 设置页「安装运行时」)
|
|
62
|
+
node scripts/local-runtime-install.mjs --download --cache <dir> # 用离线 tarball 装,仍按 pin 校验 bytes/sha256
|
|
63
|
+
node scripts/local-runtime-install.mjs --target <dir> --platform win32-x64 --id <modelId> --shallow
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
状态 `installed / absent / unsupported / downloading / verifying / installing / failed / cancelled`;`unsupported` = catalog 没 pin 该平台原生库(如 `darwin-x64`)。装失败只 `warn` + 回词法召回,不会自动改用云端 embedding。
|
|
67
|
+
|
|
55
68
|
---
|
package/docs/host-api.md
CHANGED
|
@@ -31,8 +31,9 @@
|
|
|
31
31
|
### 6.5 fork、followup 与「等它跑完」
|
|
32
32
|
|
|
33
33
|
- 会话 fork:`ctx.sessions.fork(source, boundary?, childSessionId?)`——**source 必须 live**,同步返回 `Session`,不自己启动 agent,没有 parent/delivery。错误码 `SESSION_NOT_FOUND | SESSION_NOT_LIVE | SESSION_ALREADY_EXISTS | INVALID_BOUNDARY`。
|
|
34
|
-
- 历史会话整理走**种子重建**:`sessionQuery.readSession(id)` → `{ session, events, inheritedEventCount }` → `buildForkSeed(events, lastSeq)`(`@deepseek-ai/dsh-session`,可选 peer,动态 import)→ `ctx.agents.create({ sessionId, meta: { cwd, parentSession, isSeeded, agentPreset }, seed, signal })` → `{ agent, dispose }`。
|
|
35
|
-
- `
|
|
34
|
+
- 历史会话整理走**种子重建**:`sessionQuery.readSession(id)` → `{ session, events, inheritedEventCount }` → `buildForkSeed(events, lastSeq)`(`@deepseek-ai/dsh-session`,可选 peer,动态 import)→ `ctx.agents.create({ sessionId, meta: { cwd, parentSession, isSeeded, agentPreset }, inheritedEventCount: lastSeq + 1, seed, agentOptions, signal })` → `{ agent, dispose }`。
|
|
35
|
+
- **fork 不继承父 Agent 的 options**:`agentOptions` 必须显式传顶层字段(不是 `meta`)。活跃会话取 `ctx.get("agents").get(id).session.requestHeader().config`;关闭会话取事件里最后一条 `request/header` 的 `data.header.config`。至少要有 `provider` / `model`(可带 `reasoningEffort`、`maxTokens`);两处都没有就不要创建 fork,否则标准预设会在首步因 `{{model}}` 无值而死。
|
|
36
|
+
- `agent.followup(msg)` 只入队并唤醒 driver,**返回 void**;`await agent.whenIdle()` 只表示 driver 停了,**不代表这一轮成功**。followup 前订阅 `ctx.on("session/event", (session, event) => ...)`,只认 `session === agent.session` 且 `event.type === "turn/end"`;`whenIdle` 后检查 `event.data.reason.kind === "completed"`,`error` / `aborted` / 没有 `turn/end` 都按失败处理,不能推进整理游标。fork 整理必须 `whenIdle` 后再 `dispose`。
|
|
36
37
|
- **followup 会把消息画在输入框上方**(可编辑/可删)——这就是「整理提示出现在待发栏」的原因。**v0.4 起所有整理走 fork(§3.11),后台作业一律不碰 followup**。
|
|
37
38
|
|
|
38
39
|
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
|
|
41
42
|
`ctx.schedule`(`@deepseek-ai/dsh-schedule`:create/list/catalog/history/delete/update,`every_seconds | daily | weekly | cron`,最小 60s)**绑定单个 sessionId、往该会话投递 prompt**、需要 sessionPersistence、且拒绝 subagent 会话——**不适合插件级全局清扫**。插件自己的清扫用 `ctx.interval`(cordis 随作用域回收),没有才退回 unref 的 `setInterval`。
|
|
42
43
|
|
|
43
|
-
事件:`ctx.on("agent/status", { agent, status })`,`AgentStatus = idle | running`;另有 `session/created`、`session/disposed`、`session/flush`;事件类型含 `turn/start`、`turn/end`(`step/*`、`user/message…`)与 `compaction/*`。**`turn/end` 不 await flush
|
|
44
|
+
事件:`ctx.on("agent/status", { agent, status })`,`AgentStatus = idle | running`;另有 `session/created`、`session/disposed`、`session/flush`;事件类型含 `turn/start`、`turn/end`(`step/*`、`user/message…`)与 `compaction/*`。**`turn/end` 不 await flush,不要在那里读存储;判 fork 成败只读事件对象本身。**
|
|
44
45
|
|
|
45
46
|
|
|
46
47
|
### 6.7 RPC、slot 与注入折叠
|
|
@@ -58,3 +59,34 @@ ctx.inject([sidebarRightTabs], ...) + ctx.slots.register({ name: sidebar.right.p
|
|
|
58
59
|
- producer label 就是 **kind 原文**(如 `plugin:dsh-memu-memory`),不可自定义。`form: recall` 只有在 `kind: session-reference` + `references[].label` 时才走专门的召回正文;本插件用 `recall` 只是拿一个折叠行,要一行可读的折叠摘要就用 `form: notice` + `source.summary`。
|
|
59
60
|
|
|
60
61
|
---
|
|
62
|
+
|
|
63
|
+
### 6.8 预设工具面与 guide 的真机证据边界(2026-10-29)
|
|
64
|
+
|
|
65
|
+
本节只记录**本轮可复核的真机事实**。证据来自本机 DSH Desktop `0.2.1-rc.3`(`resources/app.asar/package.json`)、插件 `1.1.2` 的 v4 会话日志;日志是多个 zstd frame 拼接,必须解完所有 frame 再计数。计数口径是**唯一 plugin 消息 id / `request/header.data.header.tools` 的实际工具名**,不是字符串出现次数,也不读取聊天正文。
|
|
66
|
+
|
|
67
|
+
#### 已证实:标准会话
|
|
68
|
+
|
|
69
|
+
- 标准会话 `session-<redacted-standard-a>`(`agentPreset: "standard"`,21 个非 session 事件):模型请求头 `request/header` 的工具表为 **82 个工具**,首尾两次一致;其中 `memu_*` 共 **10 个**:`memu_private_list`、`memu_private_recall`、`memu_private_remember`、`memu_private_update`、`memu_private_archive`、`memu_private_link`、`memu_private_unpin`、`memu_global_list`、`memu_global_recall`、`memu_status`。同一会话中 `===== memory anchor =====` 出现 1 次,锚点内是真实私有 id。
|
|
70
|
+
- 标准会话 `session-<redacted-standard-b>`(`agentPreset: "standard"`,本轮扫描时 1737 个非 session 事件):`<memory-guide>` 只对应 **1 个** plugin 消息 id(`<redacted-plugin-message-id>`),锚点 1 次。该 id 在多个快照/工具记录里重复出现是日志回放,不是重复投放。
|
|
71
|
+
- 因此“标准会话的工具表里有 `memu_*`”“标准会话 anchor/guide 只投放一次”是**已证实**;标准会话的 guide 走 system prompt 段,不必然出现 `<memory-guide>` 消息。
|
|
72
|
+
|
|
73
|
+
#### 仅机制 + mock:独立人格预设 `yuike`
|
|
74
|
+
|
|
75
|
+
- 预设来源:`~/.dsh/.agent-presets/yuike/agent.cordis.yml`,15,645 bytes,mtime `2026-10-20T16:33:05Z`,sha256 `a5a978ab5cf62d24b3061bef5560ba7abfb84a635b73d8500fd893fe0fa1422e`;32 个 `name:` 条目中 **0 处 `memu`**,即该 bundle **没有列入 `dsh-memu-memory`**。
|
|
76
|
+
- 本机 95 个持久会话里 **没有 `agentPreset: "yuike"` 的会话**;报告中的“yuike 会话只有 1 行空壳”也无法作为真实对话证据。另有 3 个 `agentPreset: "yuike-ptc"` 会话(来自另一份 `dsh-yuike-ptc` bundle),13 次带工具表的请求头均无 `memu_*`,且日志中 `<memory-guide>`、`<memory-anchor>`、`<memory-context` 均为 0;这只能说明那个**不同 preset** 的历史状态,不能替代 `yuike` 的真机验证。
|
|
77
|
+
- 结论:`yuike` 的 guide 投放、anchor 送达、最终工具面**均只有 `tests/inject-guide.test.mjs` / `tests/preset-scope.test.mjs` 的 fake agents/fiber 机制证据**,真实会话未验证;不得写成“yuike 已验证有/没有 `memu_*` 工具”。
|
|
78
|
+
|
|
79
|
+
#### 未验证:显式列入本插件的预设
|
|
80
|
+
|
|
81
|
+
- 本机 `~/.dsh/.agent-presets/` 只有 `yuike` 这一份 agent preset;没有任何预设 bundle 显式列入 `dsh-memu-memory`。因此“预设显式列出本插件时工具可用”只有 mock 证据,本机没有可核对的真实会话。
|
|
82
|
+
- `lib/preset-scope.js` 的 `agents.list()` 真机形状本轮未直接采样;代码兼容 `{ agent, owner, ctx }` record、裸 agent、以及 `agents.get(sessionId)?.ctx` 回退,三种形状由 `tests/preset-scope.test.mjs` 的 fake agents 覆盖。真实宿主若只返回裸 agent 且无 `agents.get()` 上下文,仍会走“无 ctx”日志分支,不能当作已适配成功。
|
|
83
|
+
|
|
84
|
+
#### 不可推断
|
|
85
|
+
|
|
86
|
+
- **不能从“预设类型”推断工具面。** 最终工具名单由该预设自己的 `cordis.yml` 清单和宿主 scope 决定;本插件只能补注入监听,不能挂载工具,也不修改别人的预设文件。
|
|
87
|
+
- **工具已注册 ≠ 已向当前模型暴露。** 上文的工具名单取自 `request/header.data.header.tools`;没有该字段或只有标题请求的会话,不能拿插件侧注册表冒充模型可见工具。
|
|
88
|
+
- **guide 有 `<memory-guide>` ≠ 有 `memu_*`。** 正文自带“若本会话的工具列表里没有 `memu_*` 工具,请忽略本段”,它只声明规则可用性,不证明工具存在。
|
|
89
|
+
|
|
90
|
+
复核方法:用 `zlib.zstdDecompressSync` 逐 frame 解压 `~/.dsh/sessions/<bucket>/<id>/session.v4.jsonl.zstd`;只统计 `request/header` 的工具名、`session.v4` 消息 id 和 `<memory-guide>`/`===== memory anchor =====` 标签。不要打印会话正文,不要把同一消息在快照中的重复出现计成多次投放。
|
|
91
|
+
|
|
92
|
+
---
|
package/docs/memory-semantics.md
CHANGED
|
@@ -28,12 +28,13 @@
|
|
|
28
28
|
|
|
29
29
|
### 8.4 注入
|
|
30
30
|
|
|
31
|
-
- 静态 guide
|
|
31
|
+
- 静态 guide 默认在 system prompt(按 domain 选变体);动态记忆走 plugin 消息。`persona` 带 `complete: true` 的预设会把 system prompt 段整段丢弃,这类会话改由**一次性消息**投放:`withGuideMessage`(`lib/inject.js:703`)按 `binding.guideMessageAt` 在**首步**追加一条 `<memory-guide>` 插件消息,会话内只发一次(`:708` 只在 `step === 1` 投放,`:719` 发完写 binding;fail-open,`:721`);投放的是静态规则,动态记忆仍然不进 system prompt。
|
|
32
32
|
- 首轮锚点 + 每用户回合最多一次;长工具回合仅有新的真实人类消息批次时追加一次,普通工具步骤不触发。私有优先、全局补充;冲突时私有胜。
|
|
33
33
|
- **`injectedIds` 只能记真正进入文本的条目**,否则从未展示的记忆被白白压制 8 轮。
|
|
34
34
|
- 锚点分段预算 pin 40% / core 30% / global 30%;pin 装不下时末尾明示「另有 N 条未展开」,**不静默丢弃**。
|
|
35
35
|
- 预算单位是**模型 token**不是字符:中文 ≈1 字符/token、英文 ≈3.4,一律走 `lib/budget.js`,**不要再用 `tokens * 3`**(英文口径,中文超支约 3 倍)。
|
|
36
36
|
- 压缩后下一条用户消息重注入锚点;子代理不注入。文件夹两开关都关 → 不注入(看 clamp 后生效值,不是 binding 原始值)。召回为空必须留信号(§1.10)。
|
|
37
|
+
- **召回排序的准确口径**:`privateWeighted`(`lib/memory.js:643`)只服务**私有召回流水线**(`privateRecall` 调用它);全局召回(`globalRecall`,`lib/memory.js:1526`)走 `localRecall`,不经过它。cue 会经 `cueRecall`(`lib/inject.js:124`)**间接**调用 `privateRecall`,所以**不能**概括成「cue 不走私有排序」。心境一致性与唤起窄化**默认关闭**(`moodEnabled: false`,`lib/memory.js:645`),只有 `|valence| ≥ 0.15` 或 `|arousal − 0.35| ≥ 0.1` 才打开(`lib/memory.js:1110`,阈值见 `:75` 与 `lib/mood.js:27`),平缓对话里两项乘数恒为 1。`privateRecall` 的 topK 兜底是「传入 topK → `settings.privateTopK`(默认 5)→ 4」(`lib/memory.js:1107`):引用 3 或 4 时必须说清是**设置默认值**还是**代码兜底值**,两个数不是同一个。
|
|
37
38
|
|
|
38
39
|
### 8.5 提示词管理
|
|
39
40
|
|
|
@@ -93,3 +94,42 @@
|
|
|
93
94
|
- 手动「整理这场对话」(RPC `generatePrivate`)带 `force: true`,跳过上面那道评估:用户已经决定了。
|
|
94
95
|
|
|
95
96
|
---
|
|
97
|
+
|
|
98
|
+
### 8.10 人格预设(agent preset)会话:注入要另挂,工具面按预设清单
|
|
99
|
+
|
|
100
|
+
预设会话的「模型可见插件集」不是 host composition,而是它自己那份 `cordis.yml`——整棵子树是独立 scope,`agent/pre-step` 只向自己的祖先冒泡,到不了部署级实例的监听器。所以预设会话最初的表现是「连 binding 都没有」,不是「写了没读到」。
|
|
101
|
+
|
|
102
|
+
插件侧的处理(`lib/preset-scope.js`):每 10 秒枚举 `ctx.get('agents').list()`,沿 `agent.ctx.fiber` 往上找本插件的 fiber——找不到(= 不在自己这棵树里)才在该 agent 自己的 ctx(`lib/preset-scope.js:71` 取 `raw?.ctx || agent?.ctx || agents.get(sessionId)?.ctx`)上补挂 `registerInjection(actx, { guide: false, guideMessage: true })`(`lib/preset-scope.js:79`)。**首参必须是这个 agent 自己的 ctx**,不是部署级实例的 ctx,否则绑定与注入会挂错会话。`guide: false` 只表示**不注册 system prompt 的 guide 段**(预设未列本插件时没有 `memu_*` 工具;即便列了,`persona` 的 `complete: true` 也会丢弃该段),规则改由 `guideMessage: true` 用一次性消息投放,正文自带「工具列表里没有 `memu_*` 就忽略本段」。同树的正常会话跳过,避免注入两遍;agent 消失就卸载。
|
|
103
|
+
|
|
104
|
+
**提示词怎么办**:`persona` 常带 `complete: true`——装配完成后它会被恢复为唯一的 system prompt 段,本插件 `systemPrompt.section()` 注册的 guide 会被整段丢弃(实测 RP 会话的 `system/message` 只有人格正文)。所以预设会话改用**消息**投放规则:首步追加一次 `<memory-guide>` 插件消息(`withGuideMessage`,按 `binding.guideMessageAt` 会话内只发一次),并注明「工具列表里没有 `memu_*` 就忽略本段」。工具确实存在的预设会话因此重新拿到主动性规则,而不是只有一个 anchor。
|
|
105
|
+
|
|
106
|
+
**边界要分三件事讲**:① **注入监听**——补挂到 agent 自己的 ctx 后,锚点与召回上下文能送达;② **guide 投放**——首步一条 `<memory-guide>` 消息,会话内只发一次,正文自己声明「没有工具就忽略」;③ **最终工具面**——由该预设自己的 `cordis.yml` 清单与宿主 scope 决定,本插件**不能**从「有没有列上它」推断出一定有或一定没有。历史记录里曾出现过某些 RP 会话工具链含 `memu_private_*`,但 2026-10-29 复核无法把它归到本机 `yuike` bundle(该 bundle 未列本插件,且本机无 `agentPreset=yuike` 的真机会话),只能保留为未复核历史观察;**逐预设的真实工具名单仍须真机核实(W3)**,核实前不要写成「只有注入、没有工具」,也不要反过来写成「列上插件就一定可用」。真要在没有工具的会话里写记忆,进一次标准会话仍是最直接的办法——但如果该预设确实列了本插件且工具注册成功,记忆可以直接在那个会话里写。**不要为了这个去改别人的人格插件**:预设文件属于它的维护者,插件只能在自己的 scope 里做适配。
|
|
107
|
+
|
|
108
|
+
### 8.11 全局整理的间接输入边界
|
|
109
|
+
|
|
110
|
+
`startGlobalCuration` 不直接读私有 index:curator 输入里的 `existing_global_index` 来自 `compactGlobalIndex()`,只含全局条目(`archived` 被滤掉、`pending_review` 保留,正文截 600 字符)。但同一份输入还包含每个会话经 `condenseEvents`(`lib/curator.js:27`)压缩后的转录,这条是**内容级**通路,不按 `visibility` 过滤:
|
|
111
|
+
|
|
112
|
+
- 保留:`source.kind === 'user'` 的用户原话、助手正文、工具调用参数(截 300 字符)、工具结果正文(截 400 字符)。`memu_private_recall` 的 secret 条目正是从工具结果进入转录的,助手也可能在正文里转述它。
|
|
113
|
+
- 丢弃:所有插件消息(`source.kind` 不是 `user`),包括自动锚点与自动召回注入。原因是来源类型,**不是因为条目带 `secret`**;即便构造一条带 secret 的自动注入消息,它也止步于转录之前(`secret` 本身并不会自动注入,这不是一条生产通路)。
|
|
114
|
+
- 唯一的字符串过滤是 `redactSecrets`(`lib/paths.js`):只遮 `sk-…`、`Bearer …`、`api_key=…`、URL 内嵌凭据这类**凭据形状**,不识别普通私密叙述,也不看 `visibility`;提交层同样只过这一道,不校验内容来源。
|
|
115
|
+
|
|
116
|
+
因此 **`secret` 不是保险箱**:能进入 curator prompt 的内容,理论上也能被模型抄进输出并落到全局 index。合成探针已证明到「输入通道存在」,未证明真实模型会照抄,也未证明真机发生过泄漏。本次**不新增**防泄漏、来源追踪或输入白名单,止于「探针 + 文档」;哪些层必须剥离什么、助手/用户转述如何处理、失败与重试是否同样拦截,属于强契约,留待用户决定后单独实施。
|
|
117
|
+
|
|
118
|
+
探针:`tests/curator-probe.test.mjs` 用六通道各自唯一的合成标记,逐层断言压缩转录 → 真实 curator prompt → 模拟输出 → 提交后的全局 index;只写 `os.tmpdir()` + `DSH_MEMU_HOME`,不读取真实私有库。
|
|
119
|
+
|
|
120
|
+
### 8.12 向量来源与受管召回(MemU 路径)
|
|
121
|
+
|
|
122
|
+
默认 `memoryBackend="agent"` 的有效路由是 `lexical`,不调用 embedding。启用向量库(`memoryBackend="api"`)后,`vectorSource="local"` 对应 `managed-local`,`vectorSource="api"` 对应 `remote-api`;API 来源也可配置 localhost 端点。两者复用 MemU 存储与检索,不维护平行向量数据库。`memoryMode`(`local` / `cloud`)仅保留 MemU 存储兼容语义,不是 embedding 开关,也不覆盖来源选择。旧 `hybridRecall` / `hybridRecallMode` 生产开关已移除。
|
|
123
|
+
|
|
124
|
+
总结生成与向量路由解耦:常规私有整理通过 Agent fork;显式远程总结动作调用配置的聊天端点,其产物同样经 `privateRemember` 提交。启用向量不自动启用远程总结;聊天/总结模型不参与召回重排,也不作为向量失败回退。
|
|
125
|
+
|
|
126
|
+
受管召回只在候选阶段把词法结果与 MemU semantic retrieve 结果按 RRF(k=60)融合:先按 `isMemoryEligible`、`visibleToSession`、自动召回的 `secret` 排除及 context/scope 过滤,再按 canonical id 去重与候选上限处理。显式与自动召回共用候选融合;`touchAccessMany` 仍只对显式召回执行。精确记忆 id 走直达路径,切库期间中止以避免混合两个库。
|
|
127
|
+
|
|
128
|
+
服务不可用时仅回退词法并保留可见错误信号;不暗切远端、不调用 LLM。真实 embedding 质量、延迟和跨模型收益仍需单独评测;W8(助手重复提示)已决定不做,结论与理由见 `AGENTS.md`。
|
|
129
|
+
|
|
130
|
+
模型下载、进度与 profile 切换/迁移已有实现,但真实模型/runtime 下载、原生推理及切换全链路在本轮仍未验证。candidate / `pending` artifact 不是可用制品,必须通过制品、校验与迁移门槛后才可进入可用/激活状态。
|
|
131
|
+
|
|
132
|
+
回归与管线测试:`tests/hybrid-recall.test.mjs` 仅保留 RRF、去重、稳定排序、资格过滤与候选上限等通用融合 helper 覆盖;managed vector 行为由 `tests/managed-memory.test.mjs` 覆盖。
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|