dsh-engram 0.3.4 → 0.3.6
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/README.md +283 -27
- package/README.zh.md +184 -16
- package/cordis.patch.yml +6 -0
- package/docs/CONTEXT-GC-GUIDE.zh.md +192 -0
- package/docs/PROPOSAL-agentmemory.zh.md +108 -0
- package/docs/PROPOSAL-beads.zh.md +81 -0
- package/docs/PROPOSAL-contextgc.zh.md +188 -0
- package/docs/PROPOSAL-esrtrigger.zh.md +199 -0
- package/docs/PROPOSAL-hindsight.zh.md +156 -0
- package/lib/api.js +76 -2
- package/lib/capture.js +132 -4
- package/lib/client.js +45 -2
- package/lib/compaction.js +2 -18
- package/lib/context-gc.js +234 -2
- package/lib/goal-capture.js +89 -0
- package/lib/index-block.js +96 -1
- package/lib/index.js +233 -5
- package/lib/redact.js +48 -0
- package/lib/session-cjk.js +159 -0
- package/lib/settings.js +13 -0
- package/lib/status.js +57 -0
- package/lib/store.js +411 -6
- package/lib/todo-sink.js +146 -0
- package/lib/tools.js +98 -40
- package/lib/trigger.js +10 -8
- package/lib/usage.js +147 -5
- package/lib/web-provision.js +430 -0
- package/package.json +13 -2
- package/scripts/dsh-engram.mjs +268 -0
- package/scripts/engram-web-compaction.mjs +7 -0
- package/scripts/prepublish-check.mjs +106 -0
- package/scripts/setup-links.mjs +241 -0
package/README.zh.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> **[中文](README.zh.md) · [English](README.md) · [已交付 UI 控件清单](FEATURES.zh.md)**
|
|
4
4
|
|
|
5
|
+
[](https://github.com/skepsun/dsh-engram/actions/workflows/ci.yml)
|
|
6
|
+
|
|
5
7
|
为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 设计的极简长期记忆插件,融合了
|
|
6
8
|
[symbolic-index](https://github.com/skepsun/symbolic-index) 与 [pi-esr](https://github.com/skepsun/pi-esr) 的思想——
|
|
7
9
|
目标只有一个:**省 token**。
|
|
@@ -9,6 +11,12 @@
|
|
|
9
11
|
- **零 LLM 摄入** — 纯模式匹配从工具结果自动捕获有意义的事件(带书面 `-m` 提交信息的 git 里程碑、
|
|
10
12
|
关键文件编辑、反复出现的错误),另有显式 `engram_store`。热路径上没有任何模型调用,纯粹的操作
|
|
11
13
|
——`git push` / `git stash` / 无提交信息的 commit——刻意**从不记录**(见下方「自动捕获策略」)。
|
|
14
|
+
每条写入先过一道确定性**密钥脱敏器**——API key、JWT、`Bearer` token、私钥、AWS/Stripe/Slack/GitHub
|
|
15
|
+
token 与 `key=value` 形密钥一律替换为 `<REDACTED:…>` 标记,且在去重哈希 / 字符上限 / 落盘之前完成,
|
|
16
|
+
敏感内容永远进不了磁盘。**测试失败**用纯模式识别(`npm test` / `node --test` / vitest/pytest/jest
|
|
17
|
+
+ 失败行)自动捕获为 `tags:["error","test"]`、信号上调。DSH **goal 域打通**:completed/blocked 的
|
|
18
|
+
goal(`goal/change` 会话事件)自动沉淀为 `handoff`/`error` 记忆(`tag:goal`),目标结局不随会话消散
|
|
19
|
+
(读取面见 `GET /api/dsh-engram/goals`)。
|
|
12
20
|
- **符号索引 + 渐进披露** — 一个紧凑的 `[ENGRAM]` 块(默认预算 700 字符 ≈ 175 token;每条记忆一行)在
|
|
13
21
|
组装提示词时注入,并**按会话冻结**,让请求前缀字节稳定以复用 KV 缓存。模型需要细节时用
|
|
14
22
|
`engram_recall` / `engram_detail` 下钻,而不是把命中的原文灌进上下文。召回对内存池做
|
|
@@ -16,7 +24,25 @@
|
|
|
16
24
|
命中实体锚定的记忆时附带**实体邻域关系简表**(复用 esr_link:`node --rel--> node · conf%`);
|
|
17
25
|
与历史失败**高度同源**的新错误会**唤醒旧 error 记忆**(刷新 recency + 命中,向 promoteHits
|
|
18
26
|
爬升直至重回索引,失败不重复堆积);本地零命中时自动兜底到 **DSH 自带的跨会话全文索引**
|
|
19
|
-
(`ctx.sessionQuery`,按 cwd 过滤)——不另建 SQLite
|
|
27
|
+
(`ctx.sessionQuery`,按 cwd 过滤)——不另建 SQLite,完全复用宿主。当 FTS 兜底也返回空、
|
|
28
|
+
且查询含 **CJK 中文**(FTS5 中文分词整段只算一个 token)时,召回会对最近若干会话日志做
|
|
29
|
+
有界的**子串扫描**(zstd 解压 + LRU 缓存,限文件数与字节),追加命中会话的确定性
|
|
30
|
+
`# past sessions` 行。
|
|
31
|
+
- **会话启动自动召回(`autoRecallOnStart`,默认开)** — 纯拉取式设计有个被实证戳穿的盲区:
|
|
32
|
+
召回工具只交模型自觉,而真实会话里模型几乎从不主动调 `engram_recall`(实测 19 个会话数千次
|
|
33
|
+
工具调用只出现 ~5 次召回)。因此宿主在新会话**首次组装**时,用会话**首条用户消息**对工作区做
|
|
34
|
+
一次确定性 BM25 召回,把命中前 ≤3 条直接注入 `[RECALL]` 块(默认 700 字符预算,"少而准",
|
|
35
|
+
agentmemory 候选①)——相关记忆不依赖模型想起来就已在上下文里。纯规则、零 LLM、
|
|
36
|
+
纯读不 bump 命中;superseded 过期真相不占注入槽(仍可 `engram_detail` 重取);
|
|
37
|
+
与 `[ENGRAM]` 一起按会话冻结保持前缀稳定。
|
|
38
|
+
- **记忆间语义(supersede/contradict)** — `engram_store` 可选收 `supersedes` / `contradicts`
|
|
39
|
+
记忆 id(同工作区校验)。被 supersede 的「过期真相」在召回里**降级到尾部**、并从 `[ENGRAM]`
|
|
40
|
+
块中**剔除**(新陈述占行);被 contradicts 的记忆保留排序但标注 `· contradicted by <id>`。
|
|
41
|
+
旧行永不删除——可重取,只是排得诚实。可选 `autoSupersede` 配置(默认**关**)对"实体锚定 +
|
|
42
|
+
替换式更新(改用/不再/no longer/switched…)"自动打 supersedes;显式 `supersedes` 永远优先。
|
|
43
|
+
- **失败→解法闭环(零 LLM)** — error 记忆带 `cmd:` 签名标签;同命令随后跑通时自动沉淀
|
|
44
|
+
`procedure` 记忆(`fixed: <cmd> — N earlier failing runs now succeed`),并把旧 error
|
|
45
|
+
行打上 `resolved`(不影响其排序),召回因此浮出解法而不是过期失败。
|
|
20
46
|
- **ESR-lite 证据闭环** — `esr_task` / `esr_close` / `esr_link` 给任务一个 `draft → active → stable`
|
|
21
47
|
生命周期,其中 `stable` 必须要有真实证据(`artifact` / `evaluation` / `memory_ref`),把"缺什么"
|
|
22
48
|
摊在明面上,而不是让 agent 没有证据就宣布完成。可开 `verifyArtifact`(默认开):非 URL 的
|
|
@@ -36,6 +62,13 @@
|
|
|
36
62
|
**拉取**:`esr_status`(全量视图 + `since_revision` 增量短响应 + 派生 actionables)。
|
|
37
63
|
recorder 由 `tools/result` 订阅喂入(actionables 的数据源);P4 转化度量照常(`#suggest-*` 标记 +
|
|
38
64
|
10 分钟归因 + `GET /api/dsh-engram/triggerstats`)。纯规则、零 LLM。
|
|
65
|
+
- **会话结束 todo 自动沉淀(draft 兜底,`autoSinkTodosOnEnd` 默认开)** — 会话内 todo 仍是
|
|
66
|
+
轻量、随会话而逝的"工作记忆";但当会话在其**拆解边界**(`session/disposed`)关闭时仍挂着 pending
|
|
67
|
+
todo,这些待办会**自动转为该工作区的 ESR draft 任务**(名称=todo 原文、描述「源自会话计划」、
|
|
68
|
+
按已存在任务名去重、受 `maxTasksPerWorkspace` 上限约束),计划从此不静默蒸发。落到 **draft**
|
|
69
|
+
而非 active:不占 `[ESR]` 的 active 行、不产生证据义务,仍需刻意的 `esr_claim` / `esr_task`
|
|
70
|
+
推进才变 active——「进行中默认不写」的取舍不变,只把「收尾丢数据」的缺口补上。可关(profile
|
|
71
|
+
patch 或设置卡)。
|
|
39
72
|
- **记忆 GC(pi-esr 约束)** — 定时、机械、只归档的回收:TTL 过期记忆归档、超容量工作区淘汰低价值条目、
|
|
40
73
|
stable 任务超保留窗离开 `[ESR]` 表面、悬空链接边清理。工作集(active 任务引用 / 任务记忆 / 已入索引命中)
|
|
41
74
|
永不触碰;**不硬删任何东西**——归档条目保留 id、始终可重取。
|
|
@@ -57,12 +90,65 @@ MIT · node >= 22.19 · host 半边 + 浏览器半边合在一包
|
|
|
57
90
|
dsh-engram 补的是对 token 纪律真正重要的三个空白:
|
|
58
91
|
|
|
59
92
|
1. **写入路径没有模型** — 捕获是确定性的模式匹配。
|
|
60
|
-
2.
|
|
93
|
+
2. **提示词里不灌全文** — 只注入有界的符号索引 + 会话启动时自动召回的最相关 ≤3 条(预算内),
|
|
94
|
+
更深的检索按需进行("检索到≠灌全文")。
|
|
61
95
|
3. **诚实的任务闭环** — 没有证据就不能宣布 STABLE。
|
|
62
96
|
|
|
63
97
|
DSH 已经提供跨会话 FTS(`ctx.sessionQuery`)、存储(`ctx.storageDomain`)、提示词注入钩子和设置槽位;
|
|
64
98
|
dsh-engram 只是这些能力之上的一层薄组合层,而非重新实现。
|
|
65
99
|
|
|
100
|
+
## 安全模型
|
|
101
|
+
|
|
102
|
+
DSH 插件生态还很年轻、缺乏背书:没有官方目录、没有签名校验,且 harness 的读写权限三档**约束不了插件自身代码**。因此记忆插件面对的信任何题比工具更高——它趴在你的提示词前缀上,还替你在磁盘上写东西。dsh-engram 的模型,直说如下:
|
|
103
|
+
|
|
104
|
+
- **永远不联网。** 本插件没有出口 socket、没有遥测、没有更新探针。任何东西都不可能把会话带出本机。
|
|
105
|
+
- **无 shell、除一个存储文件外不碰文件系统。** 不执行命令、不碰任意路径。全部数据只落在一个 storage-domain 单元 `~/.dsh/storages/dsh_engram.json`(外加经 DSH 自身 `ctx.sessionQuery` 做的会话日志读取)。
|
|
106
|
+
- **密钥在落盘之前就被脱敏。** 每条写入路径——`engram_store`、自动捕获,以及本节的**导入/恢复**——都先把文本过一遍确定性的 `redactText` 规则引擎(API Key、JWT、`Bearer` token、私钥、`key=value` 密钥形态),*之后*才做去重哈希、字符上限与落盘。敏感文本永不落盘,召回时自然也不会有。
|
|
107
|
+
- **要做什么坏事,必须借你 harness 自己的权限。** 插件只通过你已信任的工具同款的 seam 向宿主"请求"做事;不扩沙箱策略、不拉高到 `danger-full-access`——你保持 profile 默认,engram 就只继承那些边界。
|
|
108
|
+
- **Web API 只读为主、loopback 栅栏。** `/api/dsh-engram` 下的 GUI 路由拒绝任何非回环调用方,除非你用 `trustedHosts` 显式放行某个主机名;即便放行,同源栅栏依然生效。
|
|
109
|
+
- **可核验。** `npm run dsh-engram -- doctor`(`scripts/dsh-engram.mjs doctor`)报告插件被配置去碰什么;整个 store 可检视、不透明的东西为零。如果对这一段有怀疑,要查的代码就是 `lib/redact.js`、`lib/store.js` 和本插件的 `cordis.patch.yml`。
|
|
110
|
+
|
|
111
|
+
这**不是**说它是个气闸:如果你的 profile 给了 agent `danger-full-access` 或 shell,agent 可以用——engram 是记忆层而不是沙箱。上面这句话的意思是:*dsh-engram 自己*不新增任何攻击面。
|
|
112
|
+
|
|
113
|
+
## 数据契约:导出 / 导入
|
|
114
|
+
|
|
115
|
+
记忆不该当人质。四张表(memories / tasks / links / entities)可以用一个稳定、带版本号的机器可读格式整体倒出再恢复——重装、换机,或者(写一层薄适配器之后)搬到别的 harness / MCP 端点 / Claude Code skill,语料都跟得走。契约是带自描述头的纯 JSON:
|
|
116
|
+
|
|
117
|
+
```http
|
|
118
|
+
GET /api/dsh-engram/export?workspace=/path/to/project # 单个工作区
|
|
119
|
+
GET /api/dsh-engram/export # 全部工作区
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```jsonc
|
|
123
|
+
{
|
|
124
|
+
"meta": { "format": "dsh-engram/export", "version": 1, "exportedAt": 1724…, "workspace": "/path/to/project" },
|
|
125
|
+
"memories": [ /* 全部行,含归档——备份不丢溯源 */ ],
|
|
126
|
+
"tasks": [ /* draft/active/stable + 归档 */ ],
|
|
127
|
+
"links": [ /* 类型化边 */ ],
|
|
128
|
+
"entities": [ /* 图节点 */ ]
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
恢复默认幂等、破坏性操作有门禁:
|
|
133
|
+
|
|
134
|
+
```http
|
|
135
|
+
POST /api/dsh-engram/import # body: { payload, mode, dryRun?, workspace?, confirm? }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- **`mode: "merge"`**(默认)— 只写 `id` 尚不存在的行,备份可以随便重复套用而不会重复;每行保留自己的 `workspace`。
|
|
139
|
+
- **`mode: "replace"`** — 先把目标 `workspace` 的四张表清空,再只恢复属于它的行。破坏性操作,因此 body 里还要求 `confirm: "restore"`。
|
|
140
|
+
- **`dryRun: true`** — 只算出完全相同的执行计划(会写什么 / 跳过什么),不写任何一行。
|
|
141
|
+
- **导入遵守与 `storeMemory` 相同的不可变约定**:记忆文本落盘前先过密钥脱敏;会破坏契约的行(缺 id/workspace、空文本、超 `maxMemoryChars`、merge 时 id 已存在、超工作区记忆上限)会被跳过并写进响应报告,而不是中止整批。
|
|
142
|
+
|
|
143
|
+
单工作区的恢复往返:
|
|
144
|
+
|
|
145
|
+
```sh
|
|
146
|
+
curl -s "http://127.0.0.1:3080/api/dsh-engram/export?workspace=$PWD" -o engram-backup.json
|
|
147
|
+
curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
148
|
+
-H "content-type: application/json" \
|
|
149
|
+
-d "{\"payload\": $(cat engram-backup.json), \"mode\": \"merge\"}"
|
|
150
|
+
```
|
|
151
|
+
|
|
66
152
|
## 安装
|
|
67
153
|
|
|
68
154
|
```sh
|
|
@@ -198,15 +284,20 @@ npm run eval # 离线召回 + 结构基准(确定性语料,跑真实 store/
|
|
|
198
284
|
|
|
199
285
|
| 工具 | 用途 | 类型 |
|
|
200
286
|
|---|---|---|
|
|
201
|
-
| `engram_store` | 显式存入一条记忆(kind、tags
|
|
202
|
-
| `engram_recall` | 工作区记忆的确定性关键词召回;可选 `search_sessions` 跨会话 FTS | 读 |
|
|
287
|
+
| `engram_store` | 显式存入一条记忆(kind、tags、可选实体锚点、可选 supersedes/contradicts id,可选 `source`/`conditions`) | 写 |
|
|
288
|
+
| `engram_recall` | 工作区记忆的确定性关键词召回;可选 `search_sessions` 跨会话 FTS;可选 `scope=global`/`recallScope` 跨工作区召回(带 `[W:<ws>]` 来源标记) | 读 |
|
|
203
289
|
| `engram_detail` | 一条记忆 id 的完整记录(来源、标签、命中数) | 读 |
|
|
204
290
|
| `esr_task` | 创建任务实体(draft → active) | 写 |
|
|
205
291
|
| `esr_close` | 按证据协议关闭任务(artifact + evaluation + memory_ref) | 写 |
|
|
206
292
|
| `esr_link` | 在两个实体之间添加类型化关系(迷你图) | 写 |
|
|
293
|
+
| `esr_dep` | 在任务间添加依赖边(blocks / relates-to / parent-of) | 写 |
|
|
294
|
+
| `esr_claim` | 原子认领任务(assignee + claimedAt,draft → active) | 写 |
|
|
295
|
+
| `esr_unclaim` | 释放已认领任务的 assignee | 写 |
|
|
207
296
|
| `esr_ready` | 列出可认领任务(无 blocker、无人认领) | 读 |
|
|
208
297
|
| `esr_status` | 拉取实时 ESR 状态 + 派生提示(`since_revision` 增量短响应) | 读 |
|
|
298
|
+
| `esr_node` | 创建/更新实体节点(稳定符号) | 写 |
|
|
209
299
|
| `esr_gc` | 运行本工作区的记忆 GC(`dry_run:true` 预览不落库) | 写 |
|
|
300
|
+
| `esr_model` | 工作区预计算心智模型(`brief`/`full`,`max_chars`) | 读 |
|
|
210
301
|
|
|
211
302
|
`[ESR]` 块是每会话冻结快照,绝不中途刷新——要最新状态调 `esr_status`。
|
|
212
303
|
|
|
@@ -243,15 +334,53 @@ BasicCompactionEngine` 只重写唯一的 `summarize()` 钩子,把摘要正文
|
|
|
243
334
|
tool-call/result 配对、token 定价全部复用基本引擎。任何错误 → 回退默认压缩,**永不破坏 compact**。
|
|
244
335
|
装配即注册 `compaction` 服务,卸载/reload engram 自动还回默认引擎。
|
|
245
336
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
337
|
+
> **收缩闸门(shrink gate)**:harness 拒绝任何不比被驱逐片段更小的 checkpoint(`summary is not
|
|
338
|
+
> smaller than the shadowed content`),否则压缩回滚、上下文永不缩小、最终触发模型侧溢出。Context GC
|
|
339
|
+
> 据此**自预测闸门**:用 host `tokenMeter` 复刻 harness 的 framing 估算(实测逐 token 一致),把指针
|
|
340
|
+
> 摘要/叙事体按被驱逐 span 的 token 预算动态**裁剪尾部**(指针头与工作集保留,细节仍在会话日志可
|
|
341
|
+
> 重取),保证 checkpoint 严格缩得更小、压缩真正提交——不出现"start 涨、summary 不涨"的假接管。
|
|
342
|
+
> 完整用法见 [`docs/CONTEXT-GC-GUIDE.zh.md`](docs/CONTEXT-GC-GUIDE.zh.md)(从 0 开始的使用教程)。
|
|
343
|
+
|
|
344
|
+
#### 启用入口(这一节就是答案:该功能开在哪)
|
|
345
|
+
|
|
346
|
+
Context GC 的装配在**两个平面**——web 现在**全部自动**,零配置:
|
|
347
|
+
|
|
348
|
+
- **host 平面(headless / TUI / base 型 profile)——开箱即用,无需任何配置**:
|
|
349
|
+
主插件 `lib/index.js` 在 `ctx.effect` 里直接
|
|
350
|
+
`mountCompactionEngine(ctx, resolved, { readWorkspace }) → new Engine()` 注册 `compaction` 服务;
|
|
351
|
+
配合插件 patch 禁用基座 `compaction-basic` 行,engram 即为该平面唯一 provider。
|
|
352
|
+
- `gcReplacesCompaction: true`(**默认**)→ `ContextGcEngine`(机械驱逐 + 重取指针);
|
|
353
|
+
- `gcReplacesCompaction: false` → 挂裸 `BasicCompactionEngine`(退化为 DSH 默认 LLM 摘要),
|
|
354
|
+
**`compaction` 服务永不缺席**。
|
|
355
|
+
- 关闭/开启:profile patch 里给 engram 行加 `config: { gcReplacesCompaction: false }`,或设置卡
|
|
356
|
+
「记忆 GC」区的 `gcNarrative` 关掉叙事。
|
|
357
|
+
- **preset 平面(web profile)——全自动,零配置,覆盖全部预设**:web 面把 compaction 放在 agent
|
|
358
|
+
preset 的 isolate realm(shipped 预设自挂 `compaction-basic`),host 条目进不去、profile patch 也
|
|
359
|
+
够不到预设文件(`mountPreset` 的 Include 不带 patches——已对源码核实)。所以插件在启动时
|
|
360
|
+
(`agentPresets` 服务就绪后)**自动改写每个仍处于出厂 stock 布局的预设**——默认预设 + 整张 roster
|
|
361
|
+
(shipped 根 + `~/.dsh/.agent-presets` 用户根,`standard`/`code`/`cordis` 和你自己的预设都覆盖):
|
|
362
|
+
把 `compaction` 组里的 `compaction-basic` 行换成 `dsh-engram/compaction`。这一自动装配是:
|
|
363
|
+
- **默认开**(`autoWebCompaction: true`,设置卡「记忆 GC」可关),幂等——已替换则跳过;
|
|
364
|
+
**关掉的含义**:只是在之后的启动时不再自动接管(headless/TUI/base 的 host 平面不受影响)——
|
|
365
|
+
它**不会**还原之前已接管的预设,要还原用 `npm run web-compaction:revert`;
|
|
366
|
+
- **逐预设判定,只碰 stock 布局**——用户自定义过 compaction 组的预设,以及根本没有 compaction 组的
|
|
367
|
+
预设(如 shipped `minimal`),一律不写、只记日志;
|
|
368
|
+
- **带备份 + 严格校验**:每个文件写前在旁边留 `agent.cordis.yml.engram.bak`(create-only,保留首次
|
|
369
|
+
原件),写后重读校验,任何一步可疑即回滚该文件;改写失败只 warn,该会话仍用 DSH 默认摘要,
|
|
370
|
+
**永不影响宿主**。
|
|
371
|
+
- **配置真实传导**:写进预设行的引擎配置来自设置卡/配置里的 `gcReplacesCompaction` 与
|
|
372
|
+
`gcNarrative`——改了这两个开关,下次启动会自动把已接管的行刷新成新配置(幂等重写),
|
|
373
|
+
所以**设置卡对 web 平面同样生效**,不再硬编码 true/true。
|
|
374
|
+
- 手动的完全等价物(预览 / 审计 / 卸载前回归,随 npm 包发布的 CLI,默认扫 shipped + 用户两个根、
|
|
375
|
+
可 `--file` 指定单个):
|
|
376
|
+
```bash
|
|
377
|
+
npx dsh-engram status # stock → 未动;wired → 已接管;custom → 不碰
|
|
378
|
+
npx dsh-engram doctor # status + 按缺口排序的下一步建议
|
|
379
|
+
npx dsh-engram enable # 等价于启动时自动装配(通常 no-op)
|
|
380
|
+
npx dsh-engram revert # 还原全部预设的 stock 行(卸载 dsh-engram 前先跑这个)
|
|
381
|
+
```
|
|
382
|
+
(仓库内 `npm run web-compaction:*` 是同一 CLI 的别名。)
|
|
383
|
+
替换后的 `compaction` 组形如:
|
|
255
384
|
```yaml
|
|
256
385
|
- id: compaction
|
|
257
386
|
name: cordis:group
|
|
@@ -263,14 +392,40 @@ tool-call/result 配对、token 定价全部复用基本引擎。任何错误
|
|
|
263
392
|
- id: engram-compaction # ← 替换原 compaction-basic
|
|
264
393
|
name: dsh-engram/compaction
|
|
265
394
|
config:
|
|
266
|
-
gcReplacesCompaction: true #
|
|
267
|
-
gcNarrative: true
|
|
395
|
+
gcReplacesCompaction: true # 来自设置;false=该 session 用默认 LLM 摘要
|
|
396
|
+
gcNarrative: true # 来自设置;false=纯机械无 LLM
|
|
268
397
|
- id: command-compact
|
|
269
398
|
name: '@deepseek-ai/dsh-command-compact'
|
|
270
399
|
- id: tool-result-pruner
|
|
271
400
|
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
272
401
|
# 原有配置保留
|
|
273
402
|
```
|
|
403
|
+
⚠️ **卸载前先 revert**:预设引用 `dsh-engram/compaction` 后,卸载 dsh-engram 会让该行悬空、
|
|
404
|
+
web 会话挂 loading。所以**卸载 engram 前**先 `npx dsh-engram revert`(还原全部预设,
|
|
405
|
+
或逐个恢复各自的 `.engram.bak`)。harness 大版本升级会覆盖 shipped 预设,悬空引用随之自愈。
|
|
406
|
+
|
|
407
|
+
#### 从 npm 安装后的第一印象(可感知 / 易引导 / 易配置)
|
|
408
|
+
|
|
409
|
+
- **自动**:装进 profile 后启动一次即可——host 平面由 `mountCompactionEngine` 直接接管;web 平面
|
|
410
|
+
由 `autoWebCompaction`(默认开)在启动时自动改写全部 stock 预设。**无需任何手动配置。**
|
|
411
|
+
- **可感知**:插件启动时把权威状态写到 `$DSH_HOME/engram/context-gc.status.json`
|
|
412
|
+
(`host` 平面模式 + `web` 平面每个预设的接管结果 + 生效配置)。随时
|
|
413
|
+
`npx dsh-engram status` 或 `npx dsh-engram doctor` 查看;web 记忆看板(ESR 任务看板)头部也有
|
|
414
|
+
一枚状态徽标("Context GC·主机 ·N 预设",来自 overview API)。启动日志也有两行关键确认:
|
|
415
|
+
`engram context-gc: compaction = Context GC …` 与 `engram web-provision: wired Context GC into preset …`。
|
|
416
|
+
- **易配置**:一个设置卡(「记忆 GC」区)管全部:`autoWebCompaction`(web 自动接管开关)、
|
|
417
|
+
`gcReplacesCompaction`(用 Context GC 还是回退默认摘要)、`gcNarrative`(叙事兜底开关)——
|
|
418
|
+
改动后 `dsh web` 重启生效,web 预设行会被自动刷新成新配置。
|
|
419
|
+
|
|
420
|
+
**验证是否生效**:`dsh web`(或对应 profile)重启后——
|
|
421
|
+
- host 平面(headless/TUI/base):启动日志出现
|
|
422
|
+
`engram context-gc: compaction = Context GC (mechanical eviction + re-fetch pointers)`;
|
|
423
|
+
- web 平面:日志出现
|
|
424
|
+
`engram web-provision: wired Context GC into preset "standard" (…); restart dsh web so sessions pick it up`
|
|
425
|
+
(每个被接管的预设一行);或 `npx dsh-engram status` 显示 `wired`;任意预设的会话内
|
|
426
|
+
`command-compact`/压力触发即走机械驱逐 + 重取指针。
|
|
427
|
+
- (若见 `… keeping the existing compaction service` 说明同域已有 provider、未替换成功;`web-provision … skipped (custom)`
|
|
428
|
+
说明某预设是自定义/无 compaction 布局、未被触碰;`dsh-compaction-basic unavailable` 说明环境缺依赖,自动回退默认压缩。)
|
|
274
429
|
|
|
275
430
|
## 自动捕获策略
|
|
276
431
|
|
|
@@ -307,7 +462,11 @@ ESR 操作协议(静态,每轮逐字节相同)
|
|
|
307
462
|
[ENGRAM] workspace: symbolic-index · 2 memories · 1 task(s) active · 0 links
|
|
308
463
|
[D] 06-18 Decided: use sqlite-vec for retrieval #a2331d87
|
|
309
464
|
[T] 06-18 Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref #tsk_8b26
|
|
310
|
-
drill:
|
|
465
|
+
drill: use [RECALL] below · engram_detail <id> (full record) · engram_recall <query> (more) · esr_task/esr_node/esr_link (work)
|
|
466
|
+
|
|
467
|
+
[RECALL] recall · 1 hit(s) · first msg: retrieval
|
|
468
|
+
- [D] 06-18 Decided: use sqlite-vec for retrieval upgrade #a2331d87 ×2
|
|
469
|
+
context: use above · engram_detail <id> · engram_recall <query>
|
|
311
470
|
|
|
312
471
|
[ESR] tasks: 1 active / 1 stable
|
|
313
472
|
- tsk_0d: Retrieval upgrade — ACTIVE · gap: artifact, evaluation, memory_ref
|
|
@@ -325,6 +484,11 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
|
|
|
325
484
|
`#` id 通过 `engram_detail` 取完整记录。工作区没有任务时,`[ESR]` 仍会渲染一行点名 `esr_task`/`esr_close`,
|
|
326
485
|
让机制对模型保持可见,而不是整体消失。
|
|
327
486
|
|
|
487
|
+
`[RECALL]`(会话启动自动召回,`autoRecallOnStart`)按会话首条消息对工作区做确定性 BM25 召回,
|
|
488
|
+
把命中前 `autoRecallLimit` 条注入,受 `autoRecallMaxChars` 字符预算约束;无命中或空工作区时不渲染。
|
|
489
|
+
它是一条**提示**而不是全文灌入——模型该把它当成"这条相关,可能需要用 `engram_detail` 看细节"。
|
|
490
|
+
纯读、不 bump 命中、superseded 过期真相不占槽位;随 `[ENGRAM]` 一起按会话冻结。
|
|
491
|
+
|
|
328
492
|
## 配置
|
|
329
493
|
|
|
330
494
|
默认值以 token 为优先;可通过 profile 补丁(`~/.dsh/profiles/web/cordis.patch.yml`)或 Web 配置卡片覆盖任意键:
|
|
@@ -334,6 +498,10 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
|
|
|
334
498
|
config:
|
|
335
499
|
autoCapture: true # 零 LLM 工具结果捕获
|
|
336
500
|
sessionSearch: true # engram_recall 也可对历史会话 FTS
|
|
501
|
+
recallScope: workspace # 召回范围:workspace(严格工作区隔离,默认)| global(可选跨工作区召回,带 [W:<ws>] 来源标记)
|
|
502
|
+
autoRecallOnStart: true # 会话启动自动召回:按首条消息注入 [RECALL] 块(false=回到纯拉取)
|
|
503
|
+
autoRecallLimit: 3 # [RECALL] 最多注入条数(少而准)
|
|
504
|
+
autoRecallMaxChars: 700 # [RECALL] 字符预算
|
|
337
505
|
autoCapturePerSession: 40
|
|
338
506
|
indexMaxLines: 12 # [ENGRAM] 行数上限
|
|
339
507
|
indexMaxChars: 700 # [ENGRAM] 字符上限(token 预算)
|
package/cordis.patch.yml
CHANGED
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
# dsh-engram from the profile re-arms the base row automatically.
|
|
15
15
|
# NOTE: with `gcReplacesCompaction:false`, dsh-engram still mounts a plain
|
|
16
16
|
# BasicCompactionEngine, so compaction never goes away while it is installed.
|
|
17
|
+
# The host-plane provider is mounted by `lib/index.js` (`mountCompactionEngine`);
|
|
18
|
+
# the WEB plane is auto-wired at boot (`autoWebCompaction`, default on): the
|
|
19
|
+
# plugin swaps the `compaction-basic` row for `dsh-engram/compaction` in every
|
|
20
|
+
# stock-layout preset — default + full roster (shipped + user roots; idempotent,
|
|
21
|
+
# backed up, never touches a custom or no-compaction preset; manual CLI
|
|
22
|
+
# `npm run web-compaction:status|enable|revert`).
|
|
17
23
|
- id: compaction-basic
|
|
18
24
|
disabled: true
|
|
19
25
|
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# dsh-engram Context GC — 从 0 开始的使用教程
|
|
2
|
+
|
|
3
|
+
> 适用范围:dsh web(preset 平面)+ headless/TUI/base(host 平面)。
|
|
4
|
+
> 一句话:**用「机械驱逐 + 重取指针」替代 DSH 自带的有损 LLM 全量摘要压缩。**
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. 这是什么
|
|
9
|
+
|
|
10
|
+
DSH 默认的上下文压缩(`compaction-basic`)在自动 / 手动 compact 时,把被驱逐的历史压成一段
|
|
11
|
+
**不可查询的散文摘要**——有损、且摘要本身还要烧 token。
|
|
12
|
+
|
|
13
|
+
dsh-engram 的 Context GC 把这一步换成:
|
|
14
|
+
|
|
15
|
+
1. **扫描**被驱逐轮次里的 provenance 锚——`engram_store`/`engram_recall`/`engram_detail`
|
|
16
|
+
回显的 `#记忆id`、`esr_*` 涉及的 `tsk_*`/`ent_*`、`file_path` 锚;
|
|
17
|
+
2. **指针摘要**——每条被驱逐类别都带显式重取调用(`engram_detail(id)` / `engram_recall(query)`
|
|
18
|
+
/ `[ESR]` 块 / `esr_ready`);active 工作集在摘要里**复述**、不驱逐;
|
|
19
|
+
3. **兜底叙事**——只有**无锚轮次**(纯对话/推理,没有任何可重取落点)才走 scoped LLM 摘要
|
|
20
|
+
(`gcNarrative`,默认开);关掉后整条路径**零 LLM**,无锚轮次截断原文保留。
|
|
21
|
+
|
|
22
|
+
触发时机跟 DSH 现有 compact 完全一致:**自动压力(约 80% 窗口阈值)→ context-overflow → 手动
|
|
23
|
+
`/compact`**。任何一步出错都会回退默认压缩,**永不破坏 compact、永不弄丢会话**。
|
|
24
|
+
|
|
25
|
+
### 两个平面
|
|
26
|
+
|
|
27
|
+
| 平面 | 覆盖 | 接管方式 |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| host 平面 | headless / TUI / base 型 profile | 插件启动时直接注册 `compaction` 服务为零配置 ContextGcEngine |
|
|
30
|
+
| web 平面 | dsh web 的 agent preset(shipped + 用户预设) | 启动时自动把 stock 预设 `compaction` 组的 `compaction-basic` 行换成 `dsh-engram/compaction` 行 |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. 前提
|
|
35
|
+
|
|
36
|
+
- 已安装 dsh(含 **dsh web**)与一个 web profile;
|
|
37
|
+
- dsh-engram 已作为 profile 依赖挂好(`link:/path/to/dsh-loom` 或 npm 包),profile patch 里有
|
|
38
|
+
`engram` 行;
|
|
39
|
+
- 后端依赖 `@deepseek-ai/dsh-compaction-basic` 可被解析(安装 engram 时自动链接);
|
|
40
|
+
- 记忆/任务侧已配置好 engram 存储域(`engram_store` 有可写域、ESR 可选)。
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 3. 从 0 安装并启用(3 步 + 1 条铁律)
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# ① 安装(源码开发方式;生产用 npm install dsh-engram)
|
|
48
|
+
cd /path/to/dsh-loom && npm link # 或 profile package.json 加 "dsh-engram": "link:..."
|
|
49
|
+
|
|
50
|
+
# ② 启动一次 dsh web —— 这一步做「自动装配」
|
|
51
|
+
# - host 平面:立即注册 Context GC 为 compaction 服务
|
|
52
|
+
# - web 平面:改写每个 stock 预设文件(compaction-basic 行 → dsh-engram/compaction 行,
|
|
53
|
+
# 每个文件旁留 agent.cordis.yml.engram.bak)
|
|
54
|
+
dsh web
|
|
55
|
+
|
|
56
|
+
# ③ 再重启一次 dsh web —— 让已接管的预设真正生效
|
|
57
|
+
dsh web
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**铁律:代码/预设改动后必须重启 dsh。** 运行中的进程把旧 `lib/*.js` 和旧预设行都缓存/装载在内存里,
|
|
61
|
+
磁盘上的修复与文件改写不会热生效;只有重启(host 开机自动装配默认 `autoWebCompaction:true`)才会
|
|
62
|
+
加载新代码并接管 web 预设。
|
|
63
|
+
|
|
64
|
+
> 也可以先手动预写再一次性重启:
|
|
65
|
+
> ```bash
|
|
66
|
+
> npx dsh-engram enable # 等价于启动时的自动装配(通常 no-op)
|
|
67
|
+
> npx dsh-engram status # 确认 preset 已 wired
|
|
68
|
+
> # 然后重启 dsh web 一次
|
|
69
|
+
> ```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 4. 验证是否生效
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx dsh-engram status # 每个预设显示 wired(已接管)/ stock(未动)/ custom(不碰)
|
|
77
|
+
npx dsh-engram doctor # status + 按缺口排序的下一步建议
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
启动日志的两行金标准:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
engram context-gc: compaction = Context GC (mechanical eviction + re-fetch pointers) # host
|
|
84
|
+
engram web-provision: wired Context GC into preset "standard" (…); restart dsh web … # web 每个预设一行
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
其他入口:
|
|
88
|
+
- 记忆看板头部状态徽标("Context GC · 主机 ·N 预设");
|
|
89
|
+
- 权威快照 `$DSH_HOME/engram/context-gc.status.json`。
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 5. 日常使用:它替你做掉了什么
|
|
94
|
+
|
|
95
|
+
在任意会话里照常对话、照常用工具即可。当 compact 触发(自动压力 / 溢出 / 手动 `/compact`),
|
|
96
|
+
落在会话里的 checkpoint 长这样:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
## Context GC — evicted detail is RE-FETCHABLE (do not re-derive)
|
|
100
|
+
|
|
101
|
+
Older conversation was evicted to free context. The detail is NOT lost: it lives in the engram memory
|
|
102
|
+
store and the ESR task store. Re-fetch ONLY when you actually need it, using the tools below.
|
|
103
|
+
|
|
104
|
+
Evicted 3 turns. 2 with re-fetchable provenance, 1 narrative-only.
|
|
105
|
+
|
|
106
|
+
### ESR task state
|
|
107
|
+
Reload the full graph with the [ESR] block / `esr_ready` — only re-fetch what you need.
|
|
108
|
+
- Active working set (still tracked in ESR):
|
|
109
|
+
- `tsk_act1` — migrate compaction engine
|
|
110
|
+
- 2 closed task(s) retained — details stay re-fetchable via the [ESR] block.
|
|
111
|
+
|
|
112
|
+
### engram memories (re-fetchable)
|
|
113
|
+
Fetch the exact records that are still in the store:
|
|
114
|
+
- `engram_detail(id: "8f7a2c4e-…")` [decision]
|
|
115
|
+
- Re-run recall: `engram_recall(query: "compaction shrink gate")`
|
|
116
|
+
|
|
117
|
+
### Narrative not captured elsewhere
|
|
118
|
+
(只有无锚轮次的 scoped 叙事;gcNarrative 关掉则为截断原文)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
指针类别速查:
|
|
122
|
+
|
|
123
|
+
| 被驱逐内容 | checkpoint 里留下的指针 |
|
|
124
|
+
|---|---|
|
|
125
|
+
| engram 记忆(含 auto-capture / recall 命中 `#xxxxxx`) | `engram_detail(id)` / `engram_recall(query/entity)` |
|
|
126
|
+
| ESR 任务 / 实体 / stable 任务 | `[ESR]` 块 / `esr_ready` / 实体 `ent_*` |
|
|
127
|
+
| 文件锚 | `filePath` 路径提示 |
|
|
128
|
+
| 无锚轮次(纯对话 / 推理) | `gcNarrative` 叙事(默认开)或截断原文(关闭后) |
|
|
129
|
+
| active 工作集 | **在摘要里复述,绝不驱逐** |
|
|
130
|
+
|
|
131
|
+
手动触发:`/compact` 命令(来自 `command-compact` 插件)。
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 6. 配置项
|
|
136
|
+
|
|
137
|
+
> 位置:dsh web 设置卡「记忆 GC」区 / profile patch 的 `engram` 行 `config:` / 配置 JSON。
|
|
138
|
+
|
|
139
|
+
| 键 | 默认 | 作用 |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| `autoWebCompaction` | `true` | 是否在启动时自动改写 stock 预设并接管 web 平面 |
|
|
142
|
+
| `gcReplacesCompaction` | `true` | `true`=用 Context GC;`false`=回退 DSH 默认 LLM 摘要(`compaction` 服务永不缺席) |
|
|
143
|
+
| `gcNarrative` | `true` | 无锚轮次是否走 scoped LLM 叙事;`false`=**纯机械、整条路径零 LLM** |
|
|
144
|
+
| `gcNarrativeMaxTokens` | `1024` | 叙事生成的最大 token 数 |
|
|
145
|
+
| `gcNarrativeMaxChars` | `4000` | 无锚轮次原文兜底的截断长度(字符) |
|
|
146
|
+
|
|
147
|
+
**改配置后要重启 dsh web**——web 预设行会在下次启动时被自动刷新成新配置(幂等重写)。
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## 7. 运维与卸载
|
|
152
|
+
|
|
153
|
+
| 命令 | 作用 |
|
|
154
|
+
|---|---|
|
|
155
|
+
| `npx dsh-engram status` | 查看 host + 每个预设的接管状态与生效配置 |
|
|
156
|
+
| `npx dsh-engram doctor` | status + 按缺口排序的下一步 |
|
|
157
|
+
| `npx dsh-engram enable` | 手动重跑启动时的自动装配(通常 no-op) |
|
|
158
|
+
| `npx dsh-engram revert` | 把全部预设还原成 stock `compaction-basic` 行 |
|
|
159
|
+
|
|
160
|
+
- 仓库内 `npm run web-compaction:*` 是同一 CLI 的别名。
|
|
161
|
+
- 每个被改写文件旁有 `agent.cordis.yml.engram.bak`(create-only,保留首次原件)。
|
|
162
|
+
- **卸载 dsh-engram 之前先 `npx dsh-engram revert`**——否则预设里的 `dsh-engram/compaction` 行会
|
|
163
|
+
悬空,web 会话挂 loading。
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 8. 排障速查
|
|
168
|
+
|
|
169
|
+
| 现象 | 原因 | 处理 |
|
|
170
|
+
|---|---|---|
|
|
171
|
+
| 自动压缩没触发,反而触发模型侧上下文溢出 | 运行中的进程还是**旧代码**(shrink-gate 回滚 bug) | **重启 dsh web** 加载修复(本教程最典型场景) |
|
|
172
|
+
| 手动 `/compact` 报 `manual compaction did not commit cleanly` | 旧 Context GC 代码缺 provider/model 落盘,commit 阶段被拒 | 同上:重启加载新代码 |
|
|
173
|
+
| 长会话自动压缩仍不提交(`start` 涨、`summary` 不涨) | 同上 / 或某些后端版本旧 | 重启;确认日志有 `compaction = Context GC` |
|
|
174
|
+
| 日志 `… keeping the existing compaction service` | 同域已有 compaction provider(基座行未禁 / 双 provider) | 检查 patch 与预设行,避免重复注册 |
|
|
175
|
+
| 日志 `web-provision … skipped (custom)` | 该预设是自定义/无 compaction 布局 | **设计如此**,不会碰 |
|
|
176
|
+
| 日志 `dsh-compaction-basic unavailable` | 环境缺后端依赖 | 安装依赖;自动回退默认压缩,host 不崩 |
|
|
177
|
+
| 极小被驱逐片段(span 小于 checkpoint 开销)不压缩 | harness 收缩闸门对**任何**后端一视同仁 | 属正常,没必要为几十 token 起 checkpoint |
|
|
178
|
+
| 改配置后没变化 | web 行要重启才刷新 | 重启 dsh web |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 9. FAQ
|
|
183
|
+
|
|
184
|
+
- **有损吗?** 锚定细节**无损**(全部可通过工具重取);只有无锚轮次走叙事/截断;所有原文仍留在
|
|
185
|
+
会话日志里,即使 checkpoint 被裁剪也能找回。
|
|
186
|
+
- **会不会更烧 token?** 默认叙事只覆盖无锚轮次;需要完全零 LLM 就开 `gcNarrative:false`。
|
|
187
|
+
- **和记忆面板 GC 什么关系?** 完全正交:面板 GC 管**存储有界**(TTL/超容量归档),Context GC 管
|
|
188
|
+
**上下文窗口**(compact 时驱逐)。
|
|
189
|
+
- **是强制的吗?** 不是。`gcReplacesCompaction:false` 即回退 DSH 默认 LLM 摘要。
|
|
190
|
+
- **什么时候触发?** 与默认 compact 完全一致:自动压力(约 80% 窗口阈值)→ 溢出 → 手动 `/compact`。
|
|
191
|
+
- **之前失败过的会话有没有被弄坏?** 没有。收紧闸门/commit 失败都会**整事务回滚**并写
|
|
192
|
+
`compaction/end`(含 error),不留半成品;修复后直接再 `/compact` 即可。
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# dsh-engram 方案候选 · 借自 agentmemory(会话去重 / retention / 自动遗忘)
|
|
2
|
+
|
|
3
|
+
> 依据:[rohitg00/agentmemory](https://github.com/rohitg00/agentmemory) 深度研究(TS + iii engine 的
|
|
4
|
+
> hook 驱动记忆流水线:54 MCP 工具 / 12 hooks / 0 外部 DB / 1600+ 测试)。
|
|
5
|
+
> **状态:已归档(研究报告 + 候选方案),未实施。** 实施与否待与用户确认。
|
|
6
|
+
> 约束:全部**纯规则 / 零向量 / 零 LLM 蒸馏 / 确定性单测 / host 等自然重启**。
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 研究报告摘要(详见对话经过与仓库)
|
|
11
|
+
|
|
12
|
+
agentmemory = 「coding agent 的持久记忆全流水线」:PostToolUse 自动捕获 → SHA-256 5min 去重 →
|
|
13
|
+
隐私过滤 → LLM 压缩 → 向量+BM25+知识图谱三索引 → SessionStart 按 token 预算注入。
|
|
14
|
+
|
|
15
|
+
核心模型:
|
|
16
|
+
1. **四层记忆巩固**(Working / Episodic / Semantic / Procedural),Ebbinghaus 遗忘曲线。
|
|
17
|
+
2. **Retention 数学**:`min(1, salience·exp(-λ·Δt) + σ·Σ(1/daysSinceAccess))`;
|
|
18
|
+
access-tracker 记 count/lastAt/recent[≤20];hot/warm/cold 分级。
|
|
19
|
+
3. **Auto-forget**:per-memory `forgetAfter` TTL、矛盾检测(0.9)、重要性逐出。
|
|
20
|
+
4. **检索**:BM25+向量+图谱 → RRF(k=60) 融合 + **session-diversified(每会话≤3 条)**;
|
|
21
|
+
superseded 版本移出检索路径;近重复 advisory `similarTo`。
|
|
22
|
+
5. **关系词汇**:`supersedes / extends / derives / contradicts / related`。
|
|
23
|
+
|
|
24
|
+
## 三个纯规则候选点(未实施)
|
|
25
|
+
|
|
26
|
+
| # | 候选 | 现状差距 | 落点 | 成本 |
|
|
27
|
+
|---|---|---|---|---|
|
|
28
|
+
| ① | **会话去重 recall**(session-diversified,每会话≤3) | auto-capture 单会话霸榜、他会话高相关被挤掉 | engram_recall 排序后按 sessionId 稳定去重,默认每会话 3 条(可配) | host ~25 行 |
|
|
29
|
+
| ② | **Retention 分数**(Ebbinghaus + 访问强化) | 现有 recency 仅单指数 `1+0.5·exp(-age/14)`,无访问增强 | 新增 `lib/retention.js` 纯函数;记忆加 `lastAccessAt`+`accessWindow`(recall 命中即记);bm25Rank recency 升级为 retention(evidenceBoost 保留);GC 逐出按 retention 排序 | host ~120 行 + GC 调整 |
|
|
30
|
+
| ③ | **Per-memory TTL + 显式 supersedes/contradicts** | 只有全局 expireDays;观察反证是计数而非可回查关系 | `storeMemory` 支持 `expiresAfter`(error 类默认短 TTL);esr_link 记忆层加 `contradicts`/`supersedes` 关系,superseded 检索降权 | host ~100 行 |
|
|
31
|
+
|
|
32
|
+
明确不做:embedding / MiniLM、图谱抽取、LLM 压缩、secrets 深度脱敏、coordination、git snapshots、
|
|
33
|
+
CJK segmenter。
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 外部实证(2026-08-22,AML 首届学术榜头部系统深挖 7 仓库 + 双 bench 实测)
|
|
38
|
+
|
|
39
|
+
来源:`research/aml_top_systems/SYNTHESIS.md`;实测:`research/personamem_bench/REPORT.md`、
|
|
40
|
+
`research/realdata_bench/REPORT.md`。
|
|
41
|
+
|
|
42
|
+
### 候选②(retention / recency)——实证修正
|
|
43
|
+
- 头部系统一致做法:recency 用**候选集内相对归一**(episodic:`+= weight*best*relative` 加法且刻意
|
|
44
|
+
轻微,注释"过重毁旧事实召回");Chrono/FlowGrid 均**意图门控**——仅查询带时间意图(now/current/
|
|
45
|
+
latest/recent/最近/目前…)才放大,且明确"只解近并列、不压过强词法证据"。
|
|
46
|
+
- 我们的双 bench 实测(rank.mjs 加 `recency-gated`/`full-gated` 变体):
|
|
47
|
+
- PersonaMem 32k:gated 30.2% R@5 < 无条件 32.1%(585 问句中 75% 无时间词,gold 铆会话尾部,
|
|
48
|
+
门控主动放弃数据红利,此语料无条件更优)。
|
|
49
|
+
- 真实库 self-recall:entity 查询全无时间词 → gated == plain(23.0%),无条件 +1.6pp(24.6)——
|
|
50
|
+
**同 entity 记忆里 updatedAt 更新的更接近"当前应记住的状态",实体查询隐含最新语义**。
|
|
51
|
+
- **结论**:对 dsh-engram(agent 工作记忆、实体/主题查询为主),**保持现状轻微无条件 recency
|
|
52
|
+
(lib/util.js 现公式:14 天 +18%、60 天 +1%)优于意图门控**;意图门控+放大仅适合"高频模板化
|
|
53
|
+
重复陈述"的对话记忆场景,若做则作为配置项(默认 off)。候选②的改动重心应从"改 recency 公式"
|
|
54
|
+
移到 **GC 逐出按 retention 排序 + lastAccessAt 访问强化**(保留不破坏现状的确定性收益面)。
|
|
55
|
+
|
|
56
|
+
### 候选③(TTL + supersedes/contradicts)——实证给出门控规格
|
|
57
|
+
- FlowGrid #8 的超前实现与消融(关键实证):
|
|
58
|
+
- 话题签名 containment(交集/较短者)≥0.5 + 时间更晚 → 新者 +4/旧者 −1;
|
|
59
|
+
链中间态不加不减;**只在查询含时间意图时生效**。
|
|
60
|
+
- **裸结构判定净负**(temporal|paraphrase +0.10,整体 MRR −0.026~−0.034):同话题无关后续提及
|
|
61
|
+
会误判为覆写;`require_update_cue`(新记录须带"改为/不再/replaced by/supersedes/最新口径…")
|
|
62
|
+
是修正方向,官方默认 disabled。
|
|
63
|
+
- 真实库情况:同 entity containment≥0.5 有 27 对、带 update-cue 仅 4 对,且多为"同一事件回顾"
|
|
64
|
+
而非"新状态替换旧状态" → 当前积累下无充分场景,原型无统计意义。
|
|
65
|
+
- **结论**:候选③若实施,规格 = temporal-intent 门控 + require_update_cue + 链中间态中性 +
|
|
66
|
+
**默认关、按配置开启**(FlowGrid 官方即默认 disabled)。在其产生可感知收益前(真实库积累更多
|
|
67
|
+
更新型记忆),优先级低于候选①②。
|
|
68
|
+
|
|
69
|
+
### 白捡机制(成本低,待并入候选或另立小项)
|
|
70
|
+
- 会话/实体二级 RRF(Refind:`1/(60+单条rank)+1/(60+会话rank)`)——有 sessionId/entity,可直接做。
|
|
71
|
+
- 相邻证据加成(FlowGrid:同会话 seq±1 也在候选 → +6;Chrono context 通道)。
|
|
72
|
+
- 日期/数字精确命中加成(FlowGrid W_DATE=45 / W_NUMBER=25 同级)。
|
|
73
|
+
- 时间戳/role 烘焙进证据文本(episodic,表示层,我们记忆已带 createdAt 可复用到 evidence 视图)。
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## AML 编程榜启示与实施顺序(2026-08-22 追加)
|
|
78
|
+
|
|
79
|
+
来源:`research/AML-coding-2026-08-21.md` + `research/aml-coding-2026-08-21.json`(58 条全量)。
|
|
80
|
+
|
|
81
|
+
### 榜单事实
|
|
82
|
+
- academic coding 43 条:**峰值 52.67 = 官方 `aml-memory-baseline` 自身**(8 个并列,疑似
|
|
83
|
+
baseline 模板克隆),**0 个提交超过**;其余 35 条在 46.00–52.33。industry 峰值 MemoraX 62.00
|
|
84
|
+
(返回量全榜最小 ~6K、搜索最快 1.8s)。官方对照 `no-memory-8000`(无记忆+8k 上下文)数值仅在网页端。
|
|
85
|
+
- 词法/简单方法全程不落下风:SQLite-FTS 50.00、Refind 50.00、FlowGrid 49.33 vs Mem0 48.67、
|
|
86
|
+
Hindsight 46.67;returnSize 与解决率无单调关系,但「返回极少+快」的 MemoraX 登顶、几乎不返回的
|
|
87
|
+
反而垫底。
|
|
88
|
+
|
|
89
|
+
### 对三候选的启示(证据纪律 > 检索魔法)
|
|
90
|
+
1. **① 会话去重 recall 升为最高优先级**:coding 榜最强提交「返回极少而准」+ textual 榜 RRF/去噪
|
|
91
|
+
惯例 →「少而准」是当前评测范式下的正收益;engram_recall 的会话去重直接落实这一纪律,成本最低。
|
|
92
|
+
2. **返回策略做成显式约束**:默认 topK/返回大小可控;证据带 provenance/时间/状态(episodic 烘焙
|
|
93
|
+
思路),服务下游"判断新旧",这是③的治理面,比 supersede 判定更优先。
|
|
94
|
+
3. **② retention 保持轻量化**:不改 recency 公式(实测无条件轻微更优);重心在 GC 逐出按
|
|
95
|
+
retention 排序 + lastAccessAt 访问强化(确定性收益面)。
|
|
96
|
+
4. **③ supersedes 维持门控规格且默认关**:真实库场景不足(27 对候选/4 对 cue),等积累;实施时
|
|
97
|
+
按 FlowGrid 门控规格(temporal-intent 门控 + require_update_cue + 链中间态中性)。
|
|
98
|
+
5. **不做向量/重排/复杂融合**:编码榜证明简单方法与复杂系统同带,增强预算花在证据组织上。
|
|
99
|
+
|
|
100
|
+
### 实施顺序(更新)
|
|
101
|
+
| 序 | 项 | 状态 |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| 1 | ① 会话去重 recall(每会话≤3,可配)| **下一实施项** |
|
|
104
|
+
| 2 | 返回控制 + 证据字段(provenance/时间戳)显式化 | 随①一并落地 |
|
|
105
|
+
| 3 | ② GC 按 retention 排序 + lastAccessAt 访问强化 | 之后 |
|
|
106
|
+
| 4 | ③ supersedes 门控规格(默认关)| 场景积累后评估 |
|
|
107
|
+
|
|
108
|
+
> 决策依据:不追榜单分数(coding 赛道区分度不足);以自建 bench(PersonaMem/真实库)为增强度量尺。
|