dsh-engram 0.7.1 → 0.7.4
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 +42 -5
- package/README.zh.md +30 -5
- package/docs/CONTEXT-GC-GUIDE.zh.md +3 -1
- package/docs/RELEASE-NOTES-v0.7.2.md +48 -0
- package/docs/RELEASE-NOTES-v0.7.3.md +30 -0
- package/docs/RELEASE-NOTES-v0.7.4.md +71 -0
- package/lib/boundary-prune.js +13 -0
- package/lib/capture.js +2 -1
- package/lib/client.js +1760 -1758
- package/lib/episode.js +10 -5
- package/lib/index-block.js +10 -4
- package/lib/index.js +42 -11
- package/lib/preference.js +2 -1
- package/lib/session-events.js +126 -0
- package/lib/todo-sink.js +3 -2
- package/lib/tools.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -264,8 +264,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
264
264
|
<!-- dsh-market compatibility block — keep labels bilingual and in sync with
|
|
265
265
|
docs/RELEASE-NOTES.TEMPLATE.md (market README convention) -->
|
|
266
266
|
|
|
267
|
-
- **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.7.
|
|
268
|
-
- **最后验证日期 / Last verified**: 2026-10-
|
|
267
|
+
- **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.7.2`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
|
|
268
|
+
- **最后验证日期 / Last verified**: 2026-10-20 — DSH `0.2.0` live composition (`dsh-context` + `dshmarket` + `dsh-engram`) arms L1 boundary prune; npm test 406/406
|
|
269
269
|
- **安装方式已验证 / Verified install**: `dsh plugin --profile web add dsh-engram`
|
|
270
270
|
|
|
271
271
|
> **Short version.** Every **published** release (`0.2.0` … `0.3.6`) supports
|
|
@@ -283,7 +283,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
283
283
|
| `0.5.1` | published | 同 `0.5.0` — 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
|
|
284
284
|
| `0.6.0` | published | 同 `0.5.0` — Context Ledger、BoundaryPrune/ResultPack 默认开 + 账本否决、JIT 推送、Context GC 改 opt-in | 同 `0.5.0` |
|
|
285
285
|
| `0.7.0` | published | 同 `0.5.0` — session episode、resume brief、entity pages/cards、revalidatable anchors + layered TTL | 同 `0.5.0` |
|
|
286
|
-
| `0.7.1` (
|
|
286
|
+
| `0.7.1` (npm) | published | 同 `0.5.0` — web-plane Context GC on DSH `0.2.0` declarative presets (14-space rows), bundle patch re-enables the host `tool-result-pruner`, compaction savings feed the Context Ledger | 同 `0.5.0` |
|
|
287
|
+
| `0.7.2` (本期 / this release) | prepared | 同 `0.5.0` — L1 boundary prune arms through `ctx.inject`, fixing the boot-ordering race where a pruner activating one tick after the plugin stayed dormant for the whole process | 同 `0.5.0` |
|
|
287
288
|
|
|
288
289
|
### Where the API family broke — `0.1.2-alpha.2`
|
|
289
290
|
|
|
@@ -333,7 +334,33 @@ drives mutations).
|
|
|
333
334
|
So: keep DSH on `0.1.1-rc.2` or older while running a release ≤ `0.3.6`, and
|
|
334
335
|
upgrade the plugin to `>=0.3.7` before moving DSH to `0.1.2-alpha.2`.
|
|
335
336
|
|
|
336
|
-
### Current release — `0.7.
|
|
337
|
+
### Current release — `0.7.2`
|
|
338
|
+
|
|
339
|
+
**L1 boundary prune was silently dormant on some profiles** — a boot-ordering
|
|
340
|
+
race, not a missing patch.
|
|
341
|
+
|
|
342
|
+
`BoundaryPrune` resolved DSH's `toolResultPruner` with a strict
|
|
343
|
+
`ctx.get("toolResultPruner")` at install time. On DSH `0.2.0` web profiles the
|
|
344
|
+
pruner's fiber activates **~100 ms after** the plugin (measured on the live
|
|
345
|
+
composition `dsh-context` + `dshmarket` + `dsh-engram`: `t0 strict=undefined /
|
|
346
|
+
loose=object`, strict resolves 100 ms later), so the strict lookup was empty,
|
|
347
|
+
`installBoundaryPrune` gave up, and L1 never armed for the life of the process —
|
|
348
|
+
taking the ledger's only prune-credit leg with it. The status snapshot also
|
|
349
|
+
reported that race as "row missing", pointing at the wrong fix.
|
|
350
|
+
|
|
351
|
+
- **Arm through `ctx.inject(["toolResultPruner"], …)`** — cordis runs the
|
|
352
|
+
callback the moment the service becomes active (and again after a reload), so
|
|
353
|
+
arming no longer depends on composition order; the durable status snapshot is
|
|
354
|
+
rewritten as soon as L1 is armed.
|
|
355
|
+
- **"Absent" and "late" now read differently** — `boundaryPruneAvailability`
|
|
356
|
+
falls back to a non-strict lookup: a disabled/missing row still says
|
|
357
|
+
`no toolResultPruner service … (the bundle patch must re-enable …)`, a
|
|
358
|
+
registered-but-inactive one says `registered but its fiber is not active yet`.
|
|
359
|
+
- **Verified** — the live bundle composition (with `dsh-context`) reproduces
|
|
360
|
+
`armed:false` in an isolated `DSH_HOME`; after the fix the same composition
|
|
361
|
+
reports `armed:true · threshold 8192`. `npm test` 406/406.
|
|
362
|
+
|
|
363
|
+
### Previous release — `0.7.1`
|
|
337
364
|
|
|
338
365
|
Web-plane Context GC on DSH `0.2.0`'s **declarative presets** — the preset
|
|
339
366
|
format changed shape (one `@deepseek-ai/dsh-agent-preset` declaration inside
|
|
@@ -578,7 +605,17 @@ After restart, inside the **native** DSH settings surface:
|
|
|
578
605
|
session events. Per-tool counts + a 14-day daily rollup are shown too.
|
|
579
606
|
Numbers are real, from real sessions — lift ESR proactivity by watching
|
|
580
607
|
this panel and tuning the injected prompt.
|
|
581
|
-
- **Settings →
|
|
608
|
+
- **Settings → Engram Memory → 设置 tab** — the config card, expanded by default
|
|
609
|
+
(DSH 0.2.1 dropped the `settings.plugin.item` slot, so the old
|
|
610
|
+
Settings → Plugins → Plugin configuration seat no longer renders). Same card,
|
|
611
|
+
same transport: title + one-line description + chevron, its ~12 options under
|
|
612
|
+
four groups — Capture & Search / Index / Lifecycle & GC / Security. Changes
|
|
613
|
+
apply to new sessions (frozen blocks stay stable); Discard / Save with an
|
|
614
|
+
"unsaved" badge on the header. It drives the namespace through the
|
|
615
|
+
plugin's own `/api/dsh-engram/settings` route (not the isLoopback-gated
|
|
616
|
+
scope), so it stays editable even through an operator-authorized tunnel.
|
|
617
|
+
- **Settings → Plugins → Plugin configuration → dsh-engram** (DSH ≤ 0.2.0 only,
|
|
618
|
+
legacy `settings.plugin.item` seat) — a collapsible
|
|
582
619
|
config card in the same style as the built-in "Shell / Agent loop / Web
|
|
583
620
|
search" cards: title + one-line description + chevron, collapsed by default,
|
|
584
621
|
click to expand/collapse. Open, its ~12 options render under four groups —
|
package/README.zh.md
CHANGED
|
@@ -166,8 +166,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
166
166
|
|
|
167
167
|
<!-- dsh-market 兼容信息块 —— 与 docs/RELEASE-NOTES.TEMPLATE.md 的市场 README 公约保持一致 -->
|
|
168
168
|
|
|
169
|
-
- **DSH 版本**:`>=0.1.2-alpha.2 <0.3.0-0`(本版 `0.7.
|
|
170
|
-
- **最后验证日期**:2026-10-
|
|
169
|
+
- **DSH 版本**:`>=0.1.2-alpha.2 <0.3.0-0`(本版 `0.7.2`;已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` —— 见下文矩阵)
|
|
170
|
+
- **最后验证日期**:2026-10-20 —— DSH `0.2.0` 实机组合(`dsh-context` + `dshmarket` + `dsh-engram`)验证 L1 边界剪枝武装;npm test 406/406 通过
|
|
171
171
|
- **安装方式已验证**:`dsh plugin --profile web add dsh-engram`
|
|
172
172
|
|
|
173
173
|
> **一句话结论**:所有**已真正发布**的版本(`0.2.0` … `0.3.6`)**只支持旧版
|
|
@@ -183,7 +183,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
183
183
|
| `0.5.1` | 已发布 | 同 `0.5.0` —— 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
|
|
184
184
|
| `0.6.0` | 已发布 | 同 `0.5.0` —— Context Ledger、BoundaryPrune/ResultPack 默认开 + 账本否决、JIT 推送、Context GC 改 opt-in | 同 `0.5.0` |
|
|
185
185
|
| `0.7.0` | 已发布 | 同 `0.5.0` —— 会话 episode、恢复简报、实体页/实体卡、可重验证锚点 + 分层 TTL | 同 `0.5.0` |
|
|
186
|
-
| `0.7.1
|
|
186
|
+
| `0.7.1`(npm) | 已发布 | 同 `0.5.0` —— web 平面 Context GC 适配 DSH `0.2.0` 声明式预设(14 空格缩进)、bundle patch 重新启用 host 平面 `tool-result-pruner`、压缩节省接入 Context Ledger | 同 `0.5.0` |
|
|
187
|
+
| `0.7.2`(本期 / this release) | 待发布 | 同 `0.5.0` —— L1 边界剪枝改经 `ctx.inject` 武装,修掉「pruner 行比插件晚激活一帧就永久休眠」的启动时序竞态 | 同 `0.5.0` |
|
|
187
188
|
|
|
188
189
|
### API 族断裂点:`0.1.2-alpha.2`
|
|
189
190
|
|
|
@@ -223,7 +224,25 @@ profile 条目 id(`engram`)为命名空间,不再需要任何“挂载”
|
|
|
223
224
|
所以:跑 ≤ `0.3.6` 的已发布版本时请把 DSH 保持在 `0.1.1-rc.2` 或更旧;升级
|
|
224
225
|
DSH 到 `0.1.2-alpha.2` 之前,先升级插件到 `>=0.3.7`。
|
|
225
226
|
|
|
226
|
-
### 当前发布版本 —— `0.7.
|
|
227
|
+
### 当前发布版本 —— `0.7.2`
|
|
228
|
+
|
|
229
|
+
修复 **L1 边界剪枝的启动时序竞态**(真机定位:组合里多挂两个 bundle 就复现)。
|
|
230
|
+
|
|
231
|
+
`BoundaryPrune` 在插件安装时用严格 `ctx.get("toolResultPruner")` 取宿主剪枝器;而 `0.2.0`
|
|
232
|
+
的 web profile 里,剪枝器的 fiber 比插件**晚激活约 100 ms**(实测:`dsh-context` +
|
|
233
|
+
`dshmarket` + `dsh-engram` 组合下 `t0 strict=undefined / loose=object`,100 ms 后 strict 才
|
|
234
|
+
拿到服务)。严格查找此时为空 → `installBoundaryPrune` 放弃 → **L1 整个进程生命周期都不武装**,
|
|
235
|
+
账本唯一的「剪枝节省」入账腿静默断掉;设备快照还会把这种"还没到"报成"行不存在",把人引向错误的排查方向。
|
|
236
|
+
|
|
237
|
+
- **改经 `ctx.inject(["toolResultPruner"], …)` 武装** — cordis 在服务真正激活那一刻回调
|
|
238
|
+
(重载后也会重新武装),不再赌安装顺序;武装成功后立刻重写状态快照。
|
|
239
|
+
- **区分「缺失」与「晚到」** — `boundaryPruneAvailability` 增加非严格查找:行被禁用/没装
|
|
240
|
+
报 `no toolResultPruner service … (the bundle patch must re-enable …)`,只是 fiber 未激活
|
|
241
|
+
报 `registered but its fiber is not active yet`。两种原因以前在快照里长得一模一样。
|
|
242
|
+
- **验证** — 用真实 profile 的 bundle 组合(含 `dsh-context`)在隔离 `DSH_HOME` 复现
|
|
243
|
+
`armed:false`,修复后同一组合 `armed:true · threshold 8192`;`npm test` 406/406。
|
|
244
|
+
|
|
245
|
+
### 上一发布版本 —— `0.7.1`
|
|
227
246
|
|
|
228
247
|
修复 **DSH `0.2.0` 声明式预设下的 web 平面 Context GC 接管**:旧版自动装配以
|
|
229
248
|
`agent.cordis.yml` 的 4 空格布局为锚,而 `0.2.0` 把预设换成
|
|
@@ -385,7 +404,13 @@ node scripts/setup-links.mjs # 把 @deepseek-ai 工作区包软链进 node_m
|
|
|
385
404
|
**平均命中/查询**;**detail 转化** = 命中召回后很快跟一次 engram_detail 的比例(会话内 8 事件窗口);失败数按工具记。
|
|
386
405
|
面板同时列出各工具调用计数与最近 14 天逐日滚动。这些是真实会话的真实数字——想提升 ESR 主动性,
|
|
387
406
|
就观察面板上 esr 占比并调整注入提示。
|
|
388
|
-
- **设置 →
|
|
407
|
+
- **设置 → Engram 记忆 → 「设置」tab** — 配置卡默认展开(DSH 0.2.1 去掉了
|
|
408
|
+
`settings.plugin.item` 槽位,旧的「插件 → 插件配置」位置不再渲染)。同一张卡、同一套传输:
|
|
409
|
+
标题 + 一行说明 + chevron,展开后 ~12 个选项分四组——捕获与检索 / 索引 / 生命周期与 GC /
|
|
410
|
+
安全。改动对新会话生效(已冻结的块保持不变);Discard / Save,标题栏带「未保存」徽标。
|
|
411
|
+
卡片走插件**自有** `/api/dsh-engram/settings` 路由(不经过 isLoopback 围栏),
|
|
412
|
+
经授权隧道访问 GUI 时也能改。
|
|
413
|
+
- **设置 → 插件 → 插件配置 → dsh-engram**(仅 DSH ≤ 0.2.0,旧 `settings.plugin.item` 座位)— 与内置「终端 / Agent 循环 / 网页搜索」同款的
|
|
389
414
|
**默认折叠卡片**:标题 + 一行描述 + 箭头,点击展开/收起;展开后常用 11 项 + 高级分组按
|
|
390
415
|
「捕获与检索 / 索引 / 生命周期与 GC / 安全」四个分组展示。改动对新建会话即时生效
|
|
391
416
|
(已冻结的块保持稳定);支持放弃修改 / 保存,有未保存改动时标题上出现「未保存」徽标。
|
|
@@ -195,7 +195,9 @@ Fetch the exact records that are still in the store:
|
|
|
195
195
|
| 日志 `dsh-compaction-basic unavailable` | 环境缺后端依赖 | 安装依赖;自动回退默认压缩,host 不崩 |
|
|
196
196
|
| 极小被驱逐片段(span 小于 checkpoint 开销)不压缩 | harness 收缩闸门对**任何**后端一视同仁 | 属正常,没必要为几十 token 起 checkpoint |
|
|
197
197
|
| 改配置后没变化 | web 行要重启才刷新 | 重启 dsh web |
|
|
198
|
-
| 遥测「节省 · 剪枝/压缩」一直是 0、净 token 恒负 | 两条入账腿都没触发:L1
|
|
198
|
+
| 遥测「节省 · 剪枝/压缩」一直是 0、净 token 恒负 | 两条入账腿都没触发:L1 拿不到 host 平面的 `toolResultPruner`(0.2.0 的 host 行被禁),压缩节省此前进不了账本 | 确认状态快照 `boundaryPrune.armed: true`(`npx dsh-engram status` 会打印);压缩在 0.7.1+ 按 `区间字符数 − checkpoint 字符数` 入账 |
|
|
199
|
+
| L1 状态报 `no toolResultPruner service …` 但 `--dump-config` 里行是启用的 | 行存在却被**运行时**关掉(如 `- id: tool-result-pruner, disabled: true` 的 profile override) | 删掉该 override;bundle patch 只负责重新启用出厂行 |
|
|
200
|
+
| L1 状态报 `registered but its fiber is not active yet` | 启动时序:剪枝器 fiber 比插件晚激活(v0.7.2 前会因此永久休眠) | 升到 0.7.2+(改经 `ctx.inject` 武装),然后重启 |
|
|
199
201
|
|
|
200
202
|
---
|
|
201
203
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
## dsh-engram v0.7.2
|
|
2
|
+
|
|
3
|
+
自 v0.7.1 以来:**修复 L1 边界剪枝的启动时序竞态**——此前在部分 profile 上 L1 整个进程
|
|
4
|
+
生命周期都不武装,账本的「剪枝节省」入账腿静默断掉,而状态快照把它报成"行不存在"。
|
|
5
|
+
|
|
6
|
+
### 根因(真机定位)
|
|
7
|
+
|
|
8
|
+
`BoundaryPrune` 在插件安装时用**严格** `ctx.get("toolResultPruner")` 取宿主剪枝器,拿不到
|
|
9
|
+
就 `log.warn` 后放弃。但 DSH `0.2.0` web profile 里 `tool-result-pruner` 行虽然由 bundle patch
|
|
10
|
+
重新启用,它的 fiber 却比插件**晚激活约 100 ms**:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
t0 strict=undefined loose=object ← 服务已注册,fiber 未激活
|
|
14
|
+
inject 100 ms 后 strict=object ← 服务激活
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
严格查找在 `t0` 为空 → `installBoundaryPrune` 直接返回 noop → **L1 永久休眠**(本次问题
|
|
18
|
+
只在组合里多挂 bundle 时出现:最小 profile 里剪枝器恰好先激活,所以此前的真机验证是绿的)。
|
|
19
|
+
|
|
20
|
+
### 修复
|
|
21
|
+
|
|
22
|
+
- **改经 `ctx.inject(["toolResultPruner"], callback)` 武装**:cordis 在服务真正激活那一刻
|
|
23
|
+
回调(插件重载后也会重新武装),武装顺序不再由 bundle 组合顺序决定;武装成功后立刻
|
|
24
|
+
重写持久化状态快照(首刷可能早于剪枝器激活)。
|
|
25
|
+
- **区分「缺失」与「晚到」**:`boundaryPruneAvailability` 增加非严格查找——
|
|
26
|
+
- 行被禁用/没装:`no toolResultPruner service in the host plane (the bundle patch must re-enable the tool-result-pruner row)`
|
|
27
|
+
- 只是 fiber 未激活:`toolResultPruner is registered but its fiber is not active yet (L1 arms when it activates)`
|
|
28
|
+
- **CLI 同步**:`npx dsh-engram status` 的 L1 行直接复用该 reason,未武装时打印「节省不会入账」告警。
|
|
29
|
+
|
|
30
|
+
### 验证
|
|
31
|
+
|
|
32
|
+
- 把真实 web profile(`dsh-context` + `dshmarket` + `dsh-engram`)克隆到隔离 `DSH_HOME`
|
|
33
|
+
复现 `armed:false`;换成修复后的代码,同一组合 `armed:true · threshold 8192`。
|
|
34
|
+
`dshmarket` 组合对照组一直 `armed:true`(说明差异来自激活顺序,不是组合内容)。
|
|
35
|
+
- 单测新增「registered-but-inactive 报 pending 而非 missing」一例;`npm test` 406/406,
|
|
36
|
+
`npm run typecheck` 干净。
|
|
37
|
+
|
|
38
|
+
### 升级步骤
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm publish # 或先 npm pack 检查产物
|
|
42
|
+
dsh plugin --profile web add dsh-engram@0.7.2
|
|
43
|
+
# 重启 dsh web 后确认:
|
|
44
|
+
npx dsh-engram status | head -6 # 期望「L1 边界剪枝:已武装(threshold 8192)」
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
> 升级不会回填历史账本:`avoidedChars` 从 0 开始累计,第一次边界剪枝/checkpoint 之后
|
|
48
|
+
> 「节省 · 剪枝/压缩」才会出现正数。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# dsh-engram v0.7.3
|
|
2
|
+
|
|
3
|
+
自 v0.7.2 以来:**设置卡搬到「Engram 记忆 → 设置」tab**——DSH 0.2.1 删掉了
|
|
4
|
+
`settings.plugin.item` 槽位,旧位置不再渲染,卡片在 GUI 里彻底不可见(宿主 API
|
|
5
|
+
`/api/dsh-engram/settings` 一直正常,只是没有挂载点)。
|
|
6
|
+
|
|
7
|
+
## 根因
|
|
8
|
+
|
|
9
|
+
`settings.plugin.item` 是 DSH ≤0.2.0 时代「插件 → 插件配置」tab 的插槽;`0.2.1-rc.2`
|
|
10
|
+
把插件配置改成按 entry-id 的通用表单(插件管理页里的行详情),旧插槽在运行时不再声明
|
|
11
|
+
(只剩 `dsh-client-ui-settings-models` 里的一份类型声明)。插件把卡片注册进这个槽位,
|
|
12
|
+
`ctx.slots.inject` 因此在浏览器里静默失败,卡片从未挂载——用户看到的
|
|
13
|
+
「Engram 记忆」页只有 记忆 / ESR / 注入预览 / 遥测 四个 tab。
|
|
14
|
+
|
|
15
|
+
## 改动
|
|
16
|
+
|
|
17
|
+
- 「Engram 记忆」页新增 **「设置」tab**,直接渲染同一张 `EngramConfigCard`(默认展开);
|
|
18
|
+
共享 `EngramScopeImpl`(`/api/dsh-engram/settings`)传输,读写落在同一份 DSH 设置文档,
|
|
19
|
+
写回后 loader 提交 volatile ref → 插件热同步 `resolved`(与之前完全一致)。
|
|
20
|
+
- `EngramConfigCard` 新增 `defaultOpen`:设置页里展开,旧槽位里保持折叠的旧行为。
|
|
21
|
+
- 保留 `settings.plugin.item` 注册(DSH ≤0.2.0 上仍可见),失败仍只 `console.warn`。
|
|
22
|
+
- 设置 tab 下隐藏顶部「工作区」筛选(该 view 与工作区无关)。
|
|
23
|
+
- 文档:README 中英改为「设置 → Engram 记忆 → 设置 tab」,并注明旧座位仅 DSH ≤0.2.0。
|
|
24
|
+
|
|
25
|
+
## 验证
|
|
26
|
+
|
|
27
|
+
`npm run typecheck` 干净;`npm test` 406/406;`npm run build:client` 重新产出
|
|
28
|
+
`lib/client.js`(设置 tab、`setView("config")`、`defaultOpen` 均在产物中);
|
|
29
|
+
`/api/dsh-engram/settings` 实测返回 `autoWebCompaction=true · gcReplacesCompaction=true ·
|
|
30
|
+
gcNarrative=true`(与 profile patch 一致,无「卡片说 false、实际 true」的分裂)。
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# dsh-engram v0.7.4
|
|
2
|
+
|
|
3
|
+
自 v0.7.3 以来:**修复「推送腿」在 DSH 0.2.x 上整条静默失效**。`[RECALL]` 启动召回、
|
|
4
|
+
会话 episode、`[RESUME]` 恢复简报、会话结束 todo 沉淀——四个 v0.6/v0.7 的招牌机制,
|
|
5
|
+
在真机上**一次都没有触发过**,而它们的单测全绿。
|
|
6
|
+
|
|
7
|
+
## 根因(宿主 API 漂移 + 静默归零,第二次)
|
|
8
|
+
|
|
9
|
+
DSH ≤0.1.x 把会话日志暴露成 `session.events`(一个冻结数组)。**DSH 0.2.x 删掉了这个
|
|
10
|
+
getter**——`Session.prototype` 现在只有 `eventAt` / `snapshotEvents` / `ownEvents` /
|
|
11
|
+
`deriveEventMessage`,宿主内部的同步全量读已被标记 deprecated,官方路径是
|
|
12
|
+
`ctx.sessionQuery.live(session)` 租约。
|
|
13
|
+
|
|
14
|
+
插件里 6 处 `Array.isArray(session.events)` 因此全部拿到 `[]`:
|
|
15
|
+
|
|
16
|
+
| 位置 | 后果 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| `index-block.firstUserMessageText` | 取不到首条用户消息 → 查询串为空 → `[RECALL]` 永不渲染 |
|
|
19
|
+
| 同上(`pendingRecall` 分支) | 每轮都「等下一轮再试」→ `[ENGRAM]` 块**永不缓存**,每轮重渲染;注入体积也不进账本(净收益被高估) |
|
|
20
|
+
| `episode.buildEpisode` | 永远返回 `null` → 0 条 episode → `[RESUME]` 永不触发 |
|
|
21
|
+
| `todo-sink.pendingTodosFromSession` | 永远读不到 `todo/write` → 会话结束不沉淀任何 ESR draft |
|
|
22
|
+
| `capture` / `tools` / `preference` 的 `seq` 戳 | 溯源恒为 `seq: 0`(可审计性的最小字段失效) |
|
|
23
|
+
|
|
24
|
+
真机数据(本机 store,286 条记忆):`kind` 分布里 **0 条 `episode`**、**0 条
|
|
25
|
+
`preference`**、只有 4 条带锚点——与「机制存在 ≠ 机制被调用」的旧教训完全一致。
|
|
26
|
+
单测之所以没发现:它们都 mock 了 `{ events: [...] }`,测的是旧宿主的形状。
|
|
27
|
+
|
|
28
|
+
## 修复
|
|
29
|
+
|
|
30
|
+
- 新增 **`lib/session-events.js`**:跨代际读取会话日志,按顺序取第一个可用路径
|
|
31
|
+
1. `session.events`(≤0.1.x 与所有单测替身)→ 2. `ctx.sessionQuery.live()` 租约
|
|
32
|
+
(≥0.2.x 官方路径,读完立即 dispose)→ 3. `session.snapshotEvents(0, seq)`
|
|
33
|
+
(无 ctx 时的兜底)→ 4. `[]`。
|
|
34
|
+
同时导出 `sessionEventsSource()`(`legacy` / `sessionQuery` / `snapshotEvents` /
|
|
35
|
+
`none`)与 `sessionSeq()`(溯源 seq,优先 `session.seq`)。
|
|
36
|
+
- 6 处读点全部改接:`firstUserMessageText`、`buildEpisode`、`pendingTodosFromSession`、
|
|
37
|
+
`episode` 写入的 seq、`capture` / `tools` / `preference` 的 seq。
|
|
38
|
+
- **不再无限重试**:`[RECALL]` 的 `pendingRecall` 现在只在「日志可读但首条用户消息还没
|
|
39
|
+
落地」时重试;日志彻底不可读时只告警一次并照常缓存 `[ENGRAM]` 块——恢复前缀稳定性,
|
|
40
|
+
也避免每轮重渲染。
|
|
41
|
+
- 新增一次性告警:`engram: this host exposes no readable session event log … —
|
|
42
|
+
[RECALL] / episode / todo-sink stay dormant`(把静默降级改成可观测)。
|
|
43
|
+
|
|
44
|
+
## 验证
|
|
45
|
+
|
|
46
|
+
- `test/session-events.test.mjs` 10 例:所有用例的 session 替身**故意不暴露 `.events`**
|
|
47
|
+
(只给 `seq` / `eventAt` / `snapshotEvents`,与 0.2.x 原型一致),覆盖 legacy /
|
|
48
|
+
lease(含 dispose 断言)/ 兜底 / lease 抛错 / 完全不可读 / seq 取值,以及
|
|
49
|
+
`[RECALL]` 取词、`buildEpisode`、`pendingTodosFromSession` 三条端到端回归。
|
|
50
|
+
一旦有人改回 `session.events`,这组用例会红而不是静默归零。
|
|
51
|
+
- `npm test` 416/416;`npm run typecheck` 干净。
|
|
52
|
+
- 交叉核对真机形状:`Session.prototype` 仅含 `eventAt/snapshotEvents/ownEvents/
|
|
53
|
+
deriveEventMessage`;真实会话文件里的 `user/message` 事件形状与读取逻辑一致
|
|
54
|
+
(`data.content[].text`)、`todo/write` 仍存在于 0.2.1。
|
|
55
|
+
- **未做实机重启验证**:修复要重启 `dsh web` 才生效,而本次修复是在同一进程里做的
|
|
56
|
+
(重启会终结当前会话)。验证方式:重启后新会话的系统提示里应出现 `[RECALL]`,
|
|
57
|
+
且 `/stats` 的 `recallInjection` 计数开始增长。
|
|
58
|
+
|
|
59
|
+
## 升级步骤
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# 插件走 file: 链接,改完代码重启 web 面即可
|
|
63
|
+
# (设置文档不需要迁移)
|
|
64
|
+
dsh web # 或在你原来的终端里 Ctrl-C 后重新 dsh --profile web
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## 由此改变的产品判断
|
|
68
|
+
|
|
69
|
+
本提案「拉取式被证伪」的实测(store 123 / recall 24 / detail 8)**有一部分是假的**:
|
|
70
|
+
推送腿当时根本没接线。重启后 1–2 周的账本与激活漏斗,才是「推送 vs 拉取」的第一份
|
|
71
|
+
干净数据——在它出来之前,不应据此再加新机制。
|
package/lib/boundary-prune.js
CHANGED
|
@@ -138,6 +138,12 @@ export function expectedSessionRequests(requestsSoFar, history, workspace, floor
|
|
|
138
138
|
* plugin cannot see it. The shipped bundle patch re-enables the host row; when
|
|
139
139
|
* a custom profile keeps it off, this reports why L1 stays dormant.
|
|
140
140
|
*
|
|
141
|
+
* A non-strict lookup separates two failure modes that look identical through a
|
|
142
|
+
* strict `ctx.get`: the row is **absent** (patch missing / disabled) versus
|
|
143
|
+
* **registered but not yet active** (the pruner's fiber activates a tick or two
|
|
144
|
+
* after this plugin on a full profile — L1 arms through `ctx.inject`, so this
|
|
145
|
+
* state resolves itself, while the absent row never will).
|
|
146
|
+
*
|
|
141
147
|
* @param {object} ctx - the host plugin context.
|
|
142
148
|
* @param {object} config - resolved engram config.
|
|
143
149
|
* @returns {{ armed: boolean, reason: string }}
|
|
@@ -146,6 +152,13 @@ export function boundaryPruneAvailability(ctx, config) {
|
|
|
146
152
|
if (config?.boundaryPrune === false) return { armed: false, reason: "disabled by config (boundaryPrune:false)" };
|
|
147
153
|
const pruner = ctx?.get?.("toolResultPruner");
|
|
148
154
|
if (!pruner || typeof pruner.pruneSession !== "function") {
|
|
155
|
+
const registered = ctx?.get?.("toolResultPruner", false);
|
|
156
|
+
if (registered !== undefined && registered !== null) {
|
|
157
|
+
return {
|
|
158
|
+
armed: false,
|
|
159
|
+
reason: "toolResultPruner is registered but its fiber is not active yet (L1 arms when it activates)",
|
|
160
|
+
};
|
|
161
|
+
}
|
|
149
162
|
return {
|
|
150
163
|
armed: false,
|
|
151
164
|
reason: "no toolResultPruner service in the host plane (the bundle patch must re-enable the tool-result-pruner row)",
|
package/lib/capture.js
CHANGED
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import { workspaceKey as workspaceKeyOf } from "./util.js";
|
|
24
|
+
import { sessionSeq } from "./session-events.js";
|
|
24
25
|
|
|
25
26
|
const GIT_MILESTONE_SIGNAL = 0.5;
|
|
26
27
|
const GIT_COMMIT_SIGNAL = 0.55;
|
|
@@ -226,7 +227,7 @@ export function makeCaptureHandler(store, config, log, stats) {
|
|
|
226
227
|
signal: entry.signal,
|
|
227
228
|
filePath: entry.filePath ?? null,
|
|
228
229
|
sessionId,
|
|
229
|
-
seq: agent.session
|
|
230
|
+
seq: sessionSeq(agent.session),
|
|
230
231
|
},
|
|
231
232
|
config,
|
|
232
233
|
)
|