dsh-memu-memory 1.1.2 → 1.2.0
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 -6
- package/README.md +50 -5
- package/README.zh.md +49 -5
- package/docs/active-memory-ab.md +385 -0
- package/docs/binding-lifecycle.md +99 -0
- package/docs/contributing.md +6 -4
- package/docs/emotion-model-spec.md +281 -0
- package/docs/env-and-commands.md +13 -0
- package/docs/host-api.md +35 -3
- package/docs/memory-semantics.md +40 -11
- package/docs/recall-benchmark.md +238 -0
- package/docs/troubleshooting.md +395 -366
- package/lib/active-memory.js +165 -0
- package/lib/activity-log.js +190 -0
- package/lib/backup.js +1103 -0
- package/lib/binding-diagnostics.js +635 -0
- package/lib/client.js +728 -58
- package/lib/consolidation-ledger.js +347 -0
- package/lib/consolidation-receipt.js +284 -0
- package/lib/consolidation-snapshot.js +274 -0
- package/lib/consolidation-worker.js +115 -0
- package/lib/curator.js +81 -37
- package/lib/cycle.js +43 -6
- 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 +36 -0
- package/lib/inject.js +232 -103
- package/lib/local-embedding-entry.js +145 -0
- package/lib/local-embedding-manager.js +267 -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 +599 -57
- package/lib/memu-config.js +10 -22
- package/lib/memu.js +53 -19
- package/lib/mood.js +268 -39
- package/lib/paths.js +24 -0
- package/lib/preset-scope.js +1 -1
- package/lib/private.js +450 -29
- package/lib/prompts/private-consolidation.coding.md +1 -0
- package/lib/prompts/private-consolidation.md +1 -0
- package/lib/prompts/private-consolidation.mixed.md +1 -0
- package/lib/prompts/private-consolidation.rp.md +1 -0
- package/lib/prompts.js +4 -4
- package/lib/remote-summary.js +51 -25
- package/lib/rpc.js +54 -5
- package/lib/state.js +137 -172
- package/lib/tools.js +58 -7
- package/lib/vector-migration.js +878 -0
- package/lib/vector-profile.js +968 -0
- package/package.json +4 -2
- package/scripts/acceptance-local.mjs +7 -5
- package/scripts/active-memory-ab-live.mjs +655 -0
- package/scripts/active-memory-ab.mjs +1302 -0
- package/scripts/chain-matrix.mjs +537 -0
- package/scripts/check-all.mjs +29 -1
- 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/tests/activation.test.mjs +89 -0
- package/tests/active-memory-ab.test.mjs +745 -0
- package/tests/active-memory.test.mjs +129 -0
- package/tests/activity-log.test.mjs +126 -0
- package/tests/activity-wiring.test.mjs +103 -0
- package/tests/appendix-b.test.mjs +212 -0
- package/tests/appendix-b2.test.mjs +166 -0
- package/tests/audit-regression.test.mjs +272 -0
- package/tests/audit-safety.test.mjs +227 -0
- package/tests/backend-compensation.test.mjs +272 -0
- package/tests/backup.test.mjs +793 -0
- package/tests/binding-diagnostics.test.mjs +720 -0
- package/tests/browser.test.mjs +366 -0
- package/tests/client-render.test.mjs +892 -0
- package/tests/coalesce.test.mjs +113 -0
- package/tests/config.test.mjs +159 -0
- package/tests/consolidation-credential.test.mjs +320 -0
- package/tests/consolidation-fork.test.mjs +357 -0
- package/tests/consolidation-ledger.test.mjs +298 -0
- package/tests/consolidation-snapshot.test.mjs +321 -0
- package/tests/consolidation-value.test.mjs +89 -0
- package/tests/context-scope.test.mjs +40 -0
- package/tests/cue.test.mjs +44 -0
- package/tests/curator-probe.test.mjs +433 -0
- package/tests/curator.test.mjs +150 -0
- package/tests/cycle.test.mjs +411 -0
- package/tests/disclosure.test.mjs +231 -0
- package/tests/doc-drift.test.mjs +222 -0
- package/tests/embedding-catalog.test.mjs +266 -0
- package/tests/embedding-download.test.mjs +391 -0
- package/tests/embedding-runtime.test.mjs +389 -0
- package/tests/emotion-chain.test.mjs +84 -0
- package/tests/emotion-contract.test.mjs +445 -0
- package/tests/engine.test.mjs +35 -0
- package/tests/fixtures/active-memory-ab/README.md +56 -0
- package/tests/fixtures/active-memory-ab/cases/01-clean-dense-turn.json +351 -0
- package/tests/fixtures/active-memory-ab/cases/02-clean-thin-turn.json +122 -0
- package/tests/fixtures/active-memory-ab/cases/03-clean-starved-small.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/04-clean-large-thin.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/05-clean-half-step.json +166 -0
- package/tests/fixtures/active-memory-ab/cases/06-clean-duplicate-reread.json +197 -0
- package/tests/fixtures/active-memory-ab/cases/07-clean-recent-recall.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/08-global-relevant.json +111 -0
- package/tests/fixtures/active-memory-ab/cases/09-global-irrelevant-conflict.json +158 -0
- package/tests/fixtures/active-memory-ab/cases/10-no-human-turn.json +97 -0
- package/tests/fixtures/active-memory-ab/cases/11-clean-scale-100.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/12-clean-scale-1000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/13-clean-scale-5000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/14-clean-scale-20000.json +137 -0
- package/tests/fixtures/active-memory-ab/lead-ai-reviewed-reference.json +191 -0
- package/tests/fixtures/active-memory-ab/manifest.json +199 -0
- package/tests/fixtures/recall-bench/01-paraphrase.json +184 -0
- package/tests/fixtures/recall-bench/02-exact.json +153 -0
- package/tests/fixtures/recall-bench/03-negation.json +173 -0
- package/tests/fixtures/recall-bench/04-no-answer.json +162 -0
- package/tests/fixtures/recall-bench/05-conflict.json +194 -0
- package/tests/fixtures/recall-bench/06-boundary.json +273 -0
- package/tests/fixtures/recall-bench/07-secret.json +191 -0
- package/tests/fixtures/recall-bench/08-coding.json +164 -0
- package/tests/fixtures/recall-bench-gold-candidates/01-paraphrase.json +193 -0
- package/tests/fixtures/recall-bench-gold-candidates/02-exact.json +197 -0
- package/tests/fixtures/recall-bench-gold-candidates/03-negation.json +244 -0
- package/tests/fixtures/recall-bench-gold-candidates/04-no-answer.json +189 -0
- package/tests/fixtures/recall-bench-gold-candidates/05-conflict.json +245 -0
- package/tests/fixtures/recall-bench-gold-candidates/06-boundary.json +279 -0
- package/tests/fixtures/recall-bench-gold-candidates/07-secret.json +224 -0
- package/tests/fixtures/recall-bench-gold-candidates/08-coding.json +218 -0
- package/tests/fixtures/repetition-eval/01-zh-rp.json +93 -0
- package/tests/fixtures/repetition-eval/02-en.json +97 -0
- package/tests/fixtures/repetition-eval/03-code.json +91 -0
- package/tests/fixtures/repetition-eval/04-names.json +116 -0
- package/tests/fixtures/repetition-eval/05-user-quote.json +96 -0
- package/tests/fixtures/repetition-eval/06-agreement.json +86 -0
- package/tests/graph-view.test.mjs +187 -0
- package/tests/graph.test.mjs +77 -0
- package/tests/hook-order.test.mjs +72 -0
- package/tests/humanlike.test.mjs +232 -0
- package/tests/hybrid-recall.test.mjs +92 -0
- package/tests/inbound.test.mjs +393 -0
- package/tests/inject-guide.test.mjs +364 -0
- package/tests/inject.test.mjs +222 -0
- package/tests/injection-budget-settings.test.mjs +35 -0
- package/tests/injection-budget.test.mjs +64 -0
- package/tests/injection-chain.test.mjs +191 -0
- package/tests/loader-register.mjs +3 -0
- package/tests/loader.mjs +12 -0
- package/tests/local-embedding-entry.test.mjs +95 -0
- package/tests/local-embedding-manager.test.mjs +476 -0
- package/tests/local-embedding-protocol.test.mjs +95 -0
- package/tests/local-embedding-worker.test.mjs +346 -0
- package/tests/managed-memory.test.mjs +536 -0
- package/tests/managed-runtime.test.mjs +40 -0
- package/tests/media.test.mjs +132 -0
- package/tests/migration-payload.test.mjs +42 -0
- package/tests/mood.test.mjs +109 -0
- package/tests/multiprocess.test.mjs +29 -0
- package/tests/new-session-gate.test.mjs +361 -0
- package/tests/package-shipping.test.mjs +84 -0
- package/tests/preset-scope.test.mjs +212 -0
- package/tests/prompts.test.mjs +250 -0
- package/tests/react-snapshot.test.mjs +23 -0
- package/tests/recall-bench.test.mjs +306 -0
- package/tests/remote.test.mjs +140 -0
- package/tests/rename.test.mjs +30 -0
- package/tests/repetition-detector-snapshot.test.mjs +231 -0
- package/tests/repetition-eval-live.test.mjs +177 -0
- package/tests/repetition-eval.test.mjs +373 -0
- package/tests/salient-date.test.mjs +142 -0
- package/tests/settings-beat.test.mjs +221 -0
- package/tests/short-term.test.mjs +166 -0
- package/tests/sidebar-beat.test.mjs +208 -0
- package/tests/sidebar-refresh.test.mjs +123 -0
- package/tests/sidebar.test.mjs +70 -0
- package/tests/snippet.test.mjs +47 -0
- package/tests/source-kind.test.mjs +52 -0
- package/tests/state.test.mjs +150 -0
- package/tests/stats.test.mjs +112 -0
- package/tests/storage.test.mjs +125 -0
- package/tests/stubs/dsh-llm.js +5 -0
- package/tests/stubs/dsh-session.js +7 -0
- package/tests/stubs/dsh-tools.js +101 -0
- package/tests/tool-schema.test.mjs +73 -0
- package/tests/tools.test.mjs +184 -0
- package/tests/ui-defaults.test.mjs +57 -0
- package/tests/update-fields.test.mjs +138 -0
- package/tests/vector-migration.test.mjs +733 -0
- package/tests/vector-profile.test.mjs +425 -0
- package/tests/visibility-migration.test.mjs +152 -0
- package/tests/webui-auth.test.mjs +454 -0
- package/tests/webui.test.mjs +164 -0
- package/tests/windows-env.test.mjs +89 -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.
|
|
17
|
+
3. **记忆规则与动态记忆都走 plugin 消息**:当前版本不再注册 system prompt 段;静态 guide 在回合首步以 `<memory-guide rules="…">` 投放(`rulesKey` 处理切域/改稿/压缩丢失),动态记忆走独立 plugin 消息,保护 KV cache 并让注入可折叠。
|
|
18
18
|
4. **不每步注入**:普通回合首步注入;长工具回合只在出现尚未处理的真实人类消息批次时追加一次。工具日志、心跳不算人类消息。
|
|
19
19
|
5. **不自动删除记忆**:永久记忆移出 = 边缘化;删库必须显式确认;删会话默认只解绑。
|
|
20
20
|
6. **Python 不装进系统解释器 / 用户 site-packages**,只装 `engine/<version>/venv`,且 venv 里不留 pip(`--without-pip` 建,再用基础 Python 的 `pip --python` 指进去装)。
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
注入整段没了 → T3.13 日期语义错 / 看不见日期 → T3.14
|
|
48
48
|
保存成功但没变 / 字段改不回来 → T3.15 记忆凭空消失 / 侧边栏空 → T3.17
|
|
49
49
|
弹窗选了却两侧都勾上 → T3.16 聊很久一条记忆都没写 → T3.18
|
|
50
|
-
人格预设会话里完全没有记忆 → T3.19
|
|
50
|
+
人格预设会话里完全没有记忆 → T3.19 鉴权 401/403 说不清 → T3.20
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
---
|
|
@@ -61,7 +61,7 @@ node scripts/acceptance-local.mjs # 50/50
|
|
|
61
61
|
npm run check # node --check + i18n + package.json + 文档预算
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
-
**结果口径**:以 `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。
|
|
65
65
|
|
|
66
66
|
---
|
|
67
67
|
|
|
@@ -71,10 +71,12 @@ npm run check # node --check + i18n + package.json + 文
|
|
|
71
71
|
|---|---|
|
|
72
72
|
| `docs/troubleshooting.md` | §3 全部症状/落点/守卫 + 症状速查表 + 守卫索引表 + 附录(模块地图 §2.1、调用链 §2.2、数据铁律 §2.3、三种 exec 形状 §6.3、硬规则全文 §1) |
|
|
73
73
|
| `docs/contributing.md` | §4 改动流程(四步 / 验证三件套 / 连带清单 / 文档同步)+ §5 六个扩展点 + §10 提交前清单 |
|
|
74
|
-
| `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+折叠、预设工具面真机证据边界 |
|
|
75
75
|
| `docs/client-conventions.md` | §7:两个壳一份实现、颜色 token、控件纪律、数据与刷新、文案与结构 |
|
|
76
|
-
| `docs/memory-semantics.md` | §8
|
|
77
|
-
| `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 未证明改善重复回答率,事实词面完整性反而下降。证据文档已删除,不得据此宣称“已证明任何防复读技术无效”。
|
|
78
80
|
|
|
79
81
|
节号跨文件不变:看到「(§8.4)」就去 `docs/memory-semantics.md` 找 §8.4。
|
|
80
82
|
|
package/README.md
CHANGED
|
@@ -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. Mood is described by four components (joy / anger / sorrow / fear, summing to 1) plus arousal (intensity) and dominance (sense of control); a compound mood such as jealousy is a named mix of the four, not a new axis. Mood only reorders recall: it never enters the injected text and never rewrites a memory body. Gating is the OR of three independent conditions — the dominant share is >= 0.35, |arousal - 0.35| >= 0.1, or |dominance| >= 0.25; when none holds, both multipliers are exactly 1. Older entries carry no emotion and keep the old valence path; the four axes are never inferred back from valence. 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).
|
|
@@ -67,6 +67,34 @@ All screenshots are the real WebUI on isolated example data, not anyone's memori
|
|
|
67
67
|
- **Images are pointers and captions, not pretend vision.** Attachments are deduplicated by SHA-256, quota-limited and tiered; an image without a description is remembered as "received an image", never as a scene the model did not see.
|
|
68
68
|
- **Housekeeping happens in the background.** Consolidation runs in a seeded fork sub-session, never as an editable turn in your chat. Failed runs back off instead of reporting success.
|
|
69
69
|
|
|
70
|
+
### Active memory, measured
|
|
71
|
+
|
|
72
|
+
Idle consolidation is not "every quiet session gets a fork". Before a fork the plugin scores the evidence since the last cursor: human turns (`H`), content volume (`C`: human text, assistant text and deduped successful tool results, 2,000 characters per result) and effective tool work units (`U`), with `score = 0.35*min(H/3,2) + 0.45*min(C/4000,2) + 0.20*min(U/20,2)` (default threshold 0.8). A session idle for 15 minutes wakes below that score only when it is small; transcripts of 2,000+ events must earn their fork, because the host seeds the full prefix. A recent consolidation or a recent recall suppresses the idle fork.
|
|
73
|
+
|
|
74
|
+
More is not better: thin turns on a large transcript are skipped by the guard (about 37% fewer prompt tokens on the same scenarios, at the cost of roughly 1 in 22 labels arriving a little later), but once the unconsolidated range passes 600 events the check runs unconditionally, so decisions made early in a long session do not stay out of memory forever.
|
|
75
|
+
|
|
76
|
+
Four real long sessions from this machine were replayed read-only (no new chat) and their turns were counted:
|
|
77
|
+
|
|
78
|
+
| Session | Events | Turns | Score-qualified | Below threshold | Fresh human turns after cursor |
|
|
79
|
+
|---|---:|---:|---:|---:|---:|
|
|
80
|
+
| `62056bff…` | 5,913 | 12 | 6 | 6 | 0 |
|
|
81
|
+
| `adedb9ac…` | 5,766 | 23 | 16 | 7 | 0 |
|
|
82
|
+
| `e38a0de0…` | 85 | 2 | 0 | 2 | 0 |
|
|
83
|
+
| `edf7dc5c…` | 78 | 4 | 0 | 4 | 0 |
|
|
84
|
+
|
|
85
|
+
Below-threshold turns on the two small sessions can still wake through starvation; on the 2,000+ event sessions they do not. None of the four had new human input after its real cursor, so none would fork again immediately.
|
|
86
|
+
|
|
87
|
+
Provider-reported usage from real forks: one consolidation costs about **41k–217k input tokens** (including cache reads; it depends on memory-tool steps) and **0.8k–3.4k output**. At one 4-hour long session per day and 2–6 effective consolidations:
|
|
88
|
+
|
|
89
|
+
| Consolidations/day | Monthly input | Monthly output |
|
|
90
|
+
|---|---:|---:|
|
|
91
|
+
| 2 | ~5.6M | ~0.11M |
|
|
92
|
+
| 4 | ~11M | ~0.23M |
|
|
93
|
+
| 6 | ~17M | ~0.34M |
|
|
94
|
+
| 6 (worst measured fork each) | ~39M | ~0.7M |
|
|
95
|
+
|
|
96
|
+
For scale, the whole 4-hour session tree measured here consumed 132M input and 1.28M output in one day, so active-memory forks are about **0.2%–1%** of the total. These are token counts, not money; cache reads are usually billed at a lower rate. The exact figure depends on turn count, memory-tool steps and how often the session actually goes idle.
|
|
97
|
+
|
|
70
98
|
## One WebUI
|
|
71
99
|
|
|
72
100
|
The sidebar has exactly **one** entry: **MemU WebUI**. The memory wall and all settings live in the same navigation, with deep links such as `#/settings/memories`, `#/settings/folders` and `#/settings/stats`. The interface follows the browser locale (Chinese or English).
|
|
@@ -86,14 +114,18 @@ The locally bundled D3 force layout preserves positions and the camera across ba
|
|
|
86
114
|
| Libraries | Create, rename, archive, restore, explicitly delete libraries |
|
|
87
115
|
| Memory browser | Full-text editing, attachments, review queue, graph and bounded canvas, JSON/ZIP import/export |
|
|
88
116
|
| 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 |
|
|
117
|
+
| 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
118
|
| Stats | Daily activity, hit distribution, health, never-recalled shortlist, 7-day write/read ratio |
|
|
91
119
|
|
|
92
120
|
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
121
|
|
|
122
|
+
### Injection token budgets
|
|
123
|
+
|
|
124
|
+
`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.
|
|
125
|
+
|
|
94
126
|
### Domain Prompts
|
|
95
127
|
|
|
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.
|
|
128
|
+
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
129
|
|
|
98
130
|
| Domain | Memory focus |
|
|
99
131
|
|---|---|
|
|
@@ -176,7 +208,11 @@ What it does:
|
|
|
176
208
|
- if no usable Python/pip exists, uses a **pinned uv** runtime inside the plugin directory and leaves the system `PATH` untouched;
|
|
177
209
|
- downloads roughly 150 MB, runs a real smoke test, and keeps the previous version for rollback.
|
|
178
210
|
|
|
179
|
-
|
|
211
|
+
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.
|
|
212
|
+
|
|
213
|
+
`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.
|
|
214
|
+
|
|
215
|
+
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
216
|
|
|
181
217
|
## First run
|
|
182
218
|
|
|
@@ -288,7 +324,8 @@ the idle window starts from real message activity or the agent's return to idle.
|
|
|
288
324
|
- **No cloud sync, no accounts, no cross-device sync.** This is a local plugin with no server-side identity.
|
|
289
325
|
- **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
326
|
- **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.
|
|
291
|
-
- **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. `lib/preset-scope.js` attaches
|
|
327
|
+
- **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 an injection listener to that agent's own context, so **anchor and recall delivery works**. All conversations now receive the memory rules as one `<memory-guide rules="…">` plugin message on the first step of a turn; the plugin no longer registers a system-prompt section, and the message is replaced after a domain/prompt change or a compaction (`rulesKey` / `guideLost`). 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.
|
|
328
|
+
- **Consolidation worker (C 包, 2026-10-30).** An idle or manual pass now works from a *fixed snapshot*: it takes the public `sessionQuery.observeSession()` lease (falling back to `readSession()` when the host offers no lease), cuts at the last complete `turn/end`, and drops unpaired tool calls and half steps — a live transcript whose last turn is still open is **deferred**, never consolidated. A job is settled only by a structured completion receipt that is cross-checked against the library index (an id the library does not contain is not a success, and a rewrite of an existing id counts as an update, not a new memory). Checked / pending / in-flight ranges and a lease are persisted separately in `consolidation.json`, so a crash, a timeout or a failed turn leaves the range pending instead of looking consolidated. **Limits:** the worker still runs inside the parent preset's own system prompt — it receives an explicit "you are a background consolidation worker, not this character" brief, which reduces but does not remove persona carry-over, because the host has no public API to replace that prompt; and when the conversation's tool surface carries no `memu_private_remember` / `memu_private_update` (or exposes memory only through PTC), consolidation reports `unavailable` (`worker-tools-missing` / `worker-tools-ptc-only`) rather than forking a worker that could not write. The parent's library, scope, domain and memory context are re-checked before dispatch, on every worker tool call, and again before any result is credited.
|
|
292
329
|
- **"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.
|
|
293
330
|
- **Not in scope:** cloud MemU integration, source backfill for old entries, automatic repair of already-written v4 corruption.
|
|
294
331
|
|
|
@@ -310,6 +347,14 @@ With the preview running, use `npm run test:graph-browser -- http://127.0.0.1:77
|
|
|
310
347
|
|
|
311
348
|
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.
|
|
312
349
|
|
|
350
|
+
## Changelog
|
|
351
|
+
|
|
352
|
+
**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).
|
|
353
|
+
|
|
354
|
+
**1.1.2 (2026-10-29)**: anchor and recall delivery in agent-preset conversations; startup catch-up consolidation; panel TDZ crash fix.
|
|
355
|
+
|
|
356
|
+
Full notes: [`CHANGELOG.md`](CHANGELOG.md).
|
|
357
|
+
|
|
313
358
|
## Documentation
|
|
314
359
|
|
|
315
360
|
[`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
|
+
- **记忆会不均匀地淡。** 新近、访问次数、峰终、首因、习惯化、闪光灯记忆的准确度共同参与强度。情绪用四项构成(joy / anger / sorrow / fear,和为 1)加唤醒度 `arousal`(强度)与掌控感 `dominance` 描述;「嫉妒」这类复合情绪是四项的具名混合比例,不是新维度。情绪只影响召回排序:不进注入文本,也不改记忆正文。门控是三条独立条件的 OR——主导项占比 ≥ 0.35、`|arousal − 0.35| ≥ 0.1`、`|dominance| ≥ 0.25`;三条都不满足时两项乘数恒为 1。旧条目没有 emotion 时继续走原来的 valence 路径,不从旧 valence 反推四轴。一条生动但可能记错的记忆会显示「细节未必准」,而不是假装确定。
|
|
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` 才写,先备份)。
|
|
@@ -67,6 +67,34 @@
|
|
|
67
67
|
- **图片是指针加描述,不是假装能看图。** 附件按 SHA-256 去重、有配额、分三级留存;没有描述时只记「收到一张图片」,绝不编造画面。
|
|
68
68
|
- **整理在后台。** 整理跑在种子 fork 子会话里,不会在你的待发区多出一轮;失败退避重试,不伪记成功。
|
|
69
69
|
|
|
70
|
+
### 主动记忆:实测触发与月开销
|
|
71
|
+
|
|
72
|
+
空闲整理不是“每个安静会话都 fork”。进 fork 前会先给上次游标之后的证据打分:真人回合 `H`、内容量 `C`(真人文字 + 助手正文 + 去重后的成功工具结果,单结果最多 2000 字符)、有效工具工作单元 `U`,`score = 0.35*min(H/3,2) + 0.45*min(C/4000,2) + 0.20*min(U/20,2)`,默认门槛 0.8。空闲 15 分钟时,只有小会话能凭饥饿直接唤醒;2000 条事件以上的 transcript 必须分数达标,因为宿主会种完整前缀。近期整理过或注入过记忆的会话不 fork。
|
|
73
|
+
|
|
74
|
+
整理不是越勤越好:大 transcript 的薄回合会被守卫跳过(同一批用例上约 −37% prompt token,代价是被跳过的那几个用例里约 1/22 条标签晚一点进记忆),但待整理区间超过 600 事件时无条件是检查一次,避免长会话早期的决定永远进不了记忆。
|
|
75
|
+
|
|
76
|
+
用本机 4 个真实长会话做只读回放(不开新对话),统计合格回合:
|
|
77
|
+
|
|
78
|
+
| 会话 | 事件数 | 回合数 | 分数触发 | 未达分数 | 游标后新真人回合 |
|
|
79
|
+
|---|---:|---:|---:|---:|---:|
|
|
80
|
+
| `62056bff…` | 5,913 | 12 | 6 | 6 | 0 |
|
|
81
|
+
| `adedb9ac…` | 5,766 | 23 | 16 | 7 | 0 |
|
|
82
|
+
| `e38a0de0…` | 85 | 2 | 0 | 2 | 0 |
|
|
83
|
+
| `edf7dc5c…` | 78 | 4 | 0 | 4 | 0 |
|
|
84
|
+
|
|
85
|
+
两条小会话的未达分数回合仍可能因饥饿唤醒;2000 条事件以上的大会话不会。四个会话在真实游标之后都没有新的真人输入,因此不会立即再 fork。
|
|
86
|
+
|
|
87
|
+
从真实 fork 的 provider usage 汇总:一次整理约 **4.1 万~21.7 万 input tokens**(含缓存读,取决于记忆工具步数)+ **0.8k~3.4k output**。按每天一次 4 小时长会话、每天有效整理 2~6 次:
|
|
88
|
+
|
|
89
|
+
| 每天整理次数 | 每月 input | 每月 output |
|
|
90
|
+
|---|---:|---:|
|
|
91
|
+
| 2 次 | ~5.6M | ~0.11M |
|
|
92
|
+
| 4 次 | ~11M | ~0.23M |
|
|
93
|
+
| 6 次 | ~17M | ~0.34M |
|
|
94
|
+
| 6 次(都按实测最贵的单次) | ~39M | ~0.7M |
|
|
95
|
+
|
|
96
|
+
作为参照,今天这棵 4 小时会话树实测 132M input + 1.28M output/日,主动记忆整理约占 **0.2%~1%**。以上是 token 量,不是金额;缓存读通常按更低单价计费。实际取决于回合数、记忆工具步数和会话真正空闲的次数。
|
|
97
|
+
|
|
70
98
|
## 一个 WebUI
|
|
71
99
|
|
|
72
100
|
侧边栏只留**一个**入口:**MemU WebUI**。记忆墙与全部设置在同一套导航内,支持深链,如 `#/settings/memories`、`#/settings/folders`、`#/settings/stats`。
|
|
@@ -86,14 +114,18 @@
|
|
|
86
114
|
| 记忆库 | 新建、改名、归档、恢复、显式删除 |
|
|
87
115
|
| 记忆浏览 | 全文编辑、附件、复核池、有界图谱、JSON/ZIP 导入导出 |
|
|
88
116
|
| 全局记忆 | 分域全局记忆、证据、复核队列与独立 curator |
|
|
89
|
-
| 提示词 | 通用 / RP / Coding / Mixed 变体,覆盖与单项恢复;新会话默认 RP |
|
|
117
|
+
| 提示词 | 通用 / RP / Coding / Mixed 变体,覆盖与单项恢复;新会话默认 RP,并可在首次弹窗里直接选领域 |
|
|
90
118
|
| 统计 | 每日活跃、命中分布、库健康度、最久没被想起的 5 条、7 天写读比 |
|
|
91
119
|
|
|
92
120
|
设置项即时保存(250ms 防抖),跨窗口约 2.5 秒同步;工具调用或另一个窗口的写入也会被心跳发现。WebUI 优先在新标签页打开,被拦截时退回应用内 overlay,不卸载宿主 SPA。支持浅色、深色、减少动效与窄屏。
|
|
93
121
|
|
|
122
|
+
### 注入 token 预算
|
|
123
|
+
|
|
124
|
+
`anchorTokens` 与 `turnTokens` 分别约束锚点与召回内容(均默认 800)。`injectionTotalTokens` 限制整条 plugin 消息(默认 2000),不替代召回预算。
|
|
125
|
+
|
|
94
126
|
### 领域提示词
|
|
95
127
|
|
|
96
|
-
常驻指南、写入策略和整理提示词按当前会话领域选择;本地工具整理和远程 JSON 整理共用领域正文,各自使用实际支持的输出协议。新会话默认 RP;Coding、Mixed
|
|
128
|
+
常驻指南、写入策略和整理提示词按当前会话领域选择;本地工具整理和远程 JSON 整理共用领域正文,各自使用实际支持的输出协议。新会话默认 RP;Coding、Mixed 与自定义页保持启用,可按会话选择。新会话的记忆弹窗里也能直接选这四个记忆领域,在 RP 工作区里开写代码的对话不必事后再去侧边栏切换。
|
|
97
129
|
|
|
98
130
|
| 领域 | 记忆重点 |
|
|
99
131
|
|---|---|
|
|
@@ -176,7 +208,11 @@ npx --package dsh-memu-memory dsh-memu-memory-setup
|
|
|
176
208
|
- 没有可用 Python/pip 时,使用放在插件目录里的**锁定版本 uv**,不改系统 `PATH`;
|
|
177
209
|
- 下载约 150 MB,跑真实 smoke,并保留上一版本以便回滚。
|
|
178
210
|
|
|
179
|
-
|
|
211
|
+
默认 `memoryBackend="agent"` 使用词法召回,不调用 embedding 服务。启用向量库需选择 `memoryBackend="api"`,再以 `vectorSource="local"` 选择受管本地 embedding,或以 `vectorSource="api"` 选择已配置的兼容 embedding 端点(端点也可位于 localhost)。两种来源都接入 MemU 存储与检索;仅安装 MemU 引擎不会开启向量。
|
|
212
|
+
|
|
213
|
+
`memoryMode`(`local` / `cloud`)是 MemU 存储兼容设置,不是 embedding 开关或来源选择;保留 cloud 选项不意味着受管本地推理可被称为离线云存储。总结生成与向量路由独立:常规私有整理使用 Agent fork,显式远程总结动作使用其聊天端点,再经统一记忆写入路径提交。召回不使用 LLM 重排,也不会以 LLM 作为失败回退。精确记忆 id 仍走直达路径,插件不维护平行的向量数据库。
|
|
214
|
+
|
|
215
|
+
模型下载、进度展示与 profile 切换/迁移流程已有实现,但本轮未验证真实模型/runtime 下载及原生推理/切换全链路。candidate 或 `pending` artifact 不代表可用;在制品与校验门槛通过前,不应宣传为可下载或已就绪。
|
|
180
216
|
|
|
181
217
|
## 第一次使用
|
|
182
218
|
|
|
@@ -280,7 +316,7 @@ return { content: originalContent, meta: { ...originalMeta, memoryInbound: batch
|
|
|
280
316
|
- **没有云同步、账号或跨设备同步。** 这是本地插件,没有服务端身份。
|
|
281
317
|
- **没有视觉时:** 图片记忆只是「指针 + 人写的描述」。插件不会声称看过像素。
|
|
282
318
|
- **v4 污染会话:** 历史 `format v4 message requires a producer-owned source kind` 行只能诊断,不能改写;插件不会编辑私有会话文件。
|
|
283
|
-
- **人格预设(agent preset):** 预设(`i-am-yuike`、`yuike-standard` 等)自带 `cordis.yml`,会话的模型可见插件集只由那份清单决定,它的 scope 也不会把 `agent/pre-step`
|
|
319
|
+
- **人格预设(agent preset):** 预设(`i-am-yuike`、`yuike-standard` 等)自带 `cordis.yml`,会话的模型可见插件集只由那份清单决定,它的 scope 也不会把 `agent/pre-step` 送到本插件。运行时 `lib/preset-scope.js` 会把注入监听挂到该 agent 自己的 ctx 上,所以**锚点与召回的送达是能用的**。所有会话现在都通过回合首步的一条 `<memory-guide rules="…">` 插件消息接收记忆规则;插件不再注册 system prompt 段,规则在切域、改稿或压缩后由 `rulesKey`/`guideLost` 替换。**最终工具面**是第三件事,由该预设自己的清单与宿主 scope 决定——不能从「有没有列上本插件」推断,仓库里的观察既有「没有 `memu_*` 工具」,也有某些预设的工具链里存在 `memu_private_*`。**逐预设的真实工具名单仍需真机核实(W3)**;在那之前,别读成「预设都没有工具」,也别读成「列上插件就一定可用」。插件不会改任何人的预设文件。
|
|
284
320
|
- **相对日期在写入时结算:** 「今天 / 明天 / 后天 / today / tomorrow」加上一个月日落成带年份的日期;只说「下个月某天」的记忆不产生日期,也不替它编一个。已经按 `MM-DD` 写进去的旧条目不会被改写——这条只对新写入生效。
|
|
285
321
|
- **不在范围:** 云端 MemU 联调、旧条目的 source 回填、已写坏 v4 消息的自动修复。
|
|
286
322
|
|
|
@@ -302,6 +338,14 @@ node --import ./tests/loader-register.mjs scripts/preview.mjs --port 7789
|
|
|
302
338
|
|
|
303
339
|
测试包含一条真实引擎集成用例,未设置 `DSH_MEMU_TEST_ENGINE_PYTHON` 时按设计跳过;50 条自动验收全部通过。可选引擎已在隔离目录安装并跑通锁定 wheel 的 smoke;embedding 测试使用本机确定性服务,只证明协议可用,不证明语义质量。
|
|
304
340
|
|
|
341
|
+
## 更新日志
|
|
342
|
+
|
|
343
|
+
**1.1.3(2026-10-30)**:受管本地向量可用(运行时/模型下载、切换重建、进度与失败明细);活动日志与「日志」页;整理结果落到侧边栏按钮下方;归档/还原与列表刷新提速到毫秒级;日期漏填时从正文兜底;默认 topK 5/5;修复设置/WebUI 白屏。
|
|
344
|
+
|
|
345
|
+
**1.1.2(2026-10-29)**:人格预设会话的锚点与召回送达;启动补扫空闲整理;面板 TDZ 崩溃修复。
|
|
346
|
+
|
|
347
|
+
完整记录见 [`CHANGELOG.md`](CHANGELOG.md)。
|
|
348
|
+
|
|
305
349
|
## 文档
|
|
306
350
|
|
|
307
351
|
[`AGENTS.md`](AGENTS.md) 是给改这个仓库的人的索引:哪个问题去哪份文件。
|