dsh-engram 0.4.0 → 0.5.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/README.md +134 -17
- package/README.zh.md +103 -15
- package/docs/PROPOSAL-resultpack.zh.md +7 -3
- package/docs/RELEASE-NOTES-v0.5.0.md +58 -0
- package/lib/api.js +19 -6
- package/lib/boundary-prune.js +113 -13
- package/lib/client.js +12 -0
- package/lib/index-block.js +27 -5
- package/lib/index.js +181 -5
- package/lib/pack-telemetry.js +115 -0
- package/lib/preference.js +276 -0
- package/lib/result-pack.js +276 -0
- package/lib/settings.js +115 -31
- package/lib/store.js +1 -0
- package/lib/tools.js +2 -1
- package/package.json +8 -7
- package/scripts/prepublish-check.mjs +7 -4
package/README.md
CHANGED
|
@@ -23,6 +23,21 @@ with one goal: **save tokens**.
|
|
|
23
23
|
integration**: a completed or blocked goal (`goal/change` session event)
|
|
24
24
|
auto-sediments as a `handoff`/`error` memory (`tag:goal`), so the outcome of
|
|
25
25
|
a goal survives its session (see the `GET /api/dsh-engram/goals` read surface).
|
|
26
|
+
- **User-correction / preference learning (`autoCapturePreferences`, default on,
|
|
27
|
+
zero LLM)** — the lesson that "when the AI makes a mistake and gets corrected,
|
|
28
|
+
that lesson should persist" ([correx](https://github.com/ozoz5/correx),
|
|
29
|
+
[PAHF](https://arxiv.org/abs/2602.16173), Mem0 preference extraction): a
|
|
30
|
+
`session/event` listener watches `user/message` and turns deterministic
|
|
31
|
+
correction/preference cues into a dedicated `preference` memory kind —
|
|
32
|
+
Chinese (`不要用X`, `改用X`, `以后统一用X`…) and English (`don't use X`,
|
|
33
|
+
`switch to X`, `prefer X`, `never use X`…) patterns, three directions
|
|
34
|
+
(`avoid` / `switch-to` / `prefer`), with interrogative/one-shot-instruction/
|
|
35
|
+
memory-tool-meta-talk filters to keep false positives out. `preference`
|
|
36
|
+
memories outrank every other kind in the `[ENGRAM]` block (`[R]` prefix) so a
|
|
37
|
+
standing user rule is the first line the model sees each session; per-session
|
|
38
|
+
cap + recent-window dedup mirror the auto-capture discipline. Zero LLM, zero
|
|
39
|
+
embeddings, deterministic and pure — extracted clauses are bounded, and every
|
|
40
|
+
write still goes through the secret redactor.
|
|
26
41
|
- **Symbolic index + progressive disclosure** — a compact `[ENGRAM]` block (default
|
|
27
42
|
budget 700 chars ≈ 175 tokens; one line per memory) is injected at prompt
|
|
28
43
|
assembly and **frozen per session**, keeping the request prefix byte-stable for
|
|
@@ -51,6 +66,12 @@ with one goal: **save tokens**.
|
|
|
51
66
|
Pure rule, zero LLM, pure read (never bumps `hits`); superseded stale truth does
|
|
52
67
|
not occupy an injection slot (still fetchable via `engram_detail`); frozen per
|
|
53
68
|
session together with `[ENGRAM]` for prefix stability.
|
|
69
|
+
- **Read-path activation (D)** — a hit whose one-line preview is truncated
|
|
70
|
+
(>140 chars) carries a `…` marker and the block's trailing guidance names that
|
|
71
|
+
concrete id: `#<id> truncated — engram_detail <id> (full) · engram_recall <query>`.
|
|
72
|
+
So the model knows the full record is one deterministic `engram_detail` call
|
|
73
|
+
away instead of assuming the preview is the whole memory (proven gap in real
|
|
74
|
+
use: 66 sessions, zero `engram_detail` calls — the detail path was invisible).
|
|
54
75
|
- **Memory-to-memory semantics** — `engram_store` accepts optional
|
|
55
76
|
`supersedes` / `contradicts` memory ids (validated against the same
|
|
56
77
|
workspace). A superseded ("stale truth") memory is demoted to the tail of
|
|
@@ -243,8 +264,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
243
264
|
<!-- dsh-market compatibility block — keep labels bilingual and in sync with
|
|
244
265
|
docs/RELEASE-NOTES.TEMPLATE.md (market README convention) -->
|
|
245
266
|
|
|
246
|
-
- **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.
|
|
247
|
-
- **最后验证日期 / Last verified**: 2026-
|
|
267
|
+
- **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.5.0`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
|
|
268
|
+
- **最后验证日期 / Last verified**: 2026-10-15 — 设置模型迁移(entry-id volatile Config,兼容 DSH `0.2.x`)落地,npm test 329/329 通过;真实 `dsh 0.2.0-rc.2` 隔离 profile 运行烟测通过(见下方“当前发布”)
|
|
248
269
|
- **安装方式已验证 / Verified install**: `dsh plugin --profile web add dsh-engram`
|
|
249
270
|
|
|
250
271
|
> **Short version.** Every **published** release (`0.2.0` … `0.3.6`) supports
|
|
@@ -257,7 +278,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
257
278
|
| dsh-engram release | Status | DSH support | Declared via |
|
|
258
279
|
| --- | --- | --- | --- |
|
|
259
280
|
| `0.2.0` … `0.3.6` (npm, GitHub v0.3.3–v0.3.6) | published | **old DSH only** — `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2` | peers `@deepseek-ai/dsh-*@^0.1.0-rc.7` |
|
|
260
|
-
| `0.3.7`
|
|
281
|
+
| `0.3.7` / `0.4.0` (npm) | published | **new DSH, settings `installSection`** — `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.2.0-0` |
|
|
282
|
+
| `0.5.0` (本期 / this release) | pre-release | **DSH `0.1.2-alpha.2` … `<0.3.0-0`** — 设置卡迁移到 entry-id volatile Config(`0.1.7+`/`0.2.x`),`≤0.1.5` 自动回退 `installSection` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.3.0-0` |
|
|
261
283
|
|
|
262
284
|
### Where the API family broke — `0.1.2-alpha.2`
|
|
263
285
|
|
|
@@ -282,36 +304,72 @@ HTTP route (`/api/dsh-engram/settings`, same-origin fetch like the memory
|
|
|
282
304
|
viewer), so the card is generation-agnostic on both sides of the
|
|
283
305
|
`0.1.2-alpha.2` boundary.
|
|
284
306
|
|
|
307
|
+
**One more settings break, at `0.1.7` / `0.2.0`** — and the reason `0.4.0` was
|
|
308
|
+
not actually loadable on the current DSH: `@deepseek-ai/dsh-settings` **removed
|
|
309
|
+
`settings.installSection` again** in `0.1.7-alpha.2` (and keeps it removed in
|
|
310
|
+
`0.2.x`). The new settings model is **entry-keyed**: editable fields are
|
|
311
|
+
`.volatile()` fields of the plugin's own `Config` (validated + hot-committed by
|
|
312
|
+
the loader), and the settings form is keyed by the profile entry id (`engram`),
|
|
313
|
+
so nothing needs "mounting". `0.5.0` feature-detects the two generations in
|
|
314
|
+
`installEngramSettings`:
|
|
315
|
+
|
|
316
|
+
- DSH `≥0.1.7` / `0.2.x` — the 27 GUI knobs are the volatile `Config` fields
|
|
317
|
+
(`lib/settings.js` `makeEngineConfigSchema`, exported as `Config` from
|
|
318
|
+
`lib/index.js`); the card reads/writes entry `engram` through the same
|
|
319
|
+
`/api/dsh-engram/settings` HTTP route, and the `service.settings` seam
|
|
320
|
+
re-syncs `resolved` on `loader/volatile-update` so card edits land live on
|
|
321
|
+
new sessions.
|
|
322
|
+
- DSH `≤0.1.5` — the legacy `settings.installSection` namespace (`dsh-engram`)
|
|
323
|
+
is registered as before; nothing changes.
|
|
324
|
+
|
|
325
|
+
The declared range `>=0.1.2-alpha.2 <0.3.0-0` covers both, and the HTTP wire
|
|
326
|
+
namespace stays `dsh-engram` on both generations (the seam's active namespace
|
|
327
|
+
drives mutations).
|
|
328
|
+
|
|
285
329
|
So: keep DSH on `0.1.1-rc.2` or older while running a release ≤ `0.3.6`, and
|
|
286
330
|
upgrade the plugin to `>=0.3.7` before moving DSH to `0.1.2-alpha.2`.
|
|
287
331
|
|
|
288
|
-
### Current release — `0.
|
|
332
|
+
### Current release — `0.5.0`
|
|
289
333
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
`
|
|
334
|
+
The published `0.4.0` declared `>=0.1.2-alpha.2 <0.2.0-0` — which the semver
|
|
335
|
+
gate **rejects on every DSH `0.2.0-0` prerelease** (`<0.2.0-0` excludes
|
|
336
|
+
`0.2.0-rc.x`), and its host settings half still called the `installSection`
|
|
337
|
+
API that `dsh-settings 0.1.7+` removed. `0.5.0` fixes **both**: the range
|
|
338
|
+
opens to `<0.3.0-0` (verified against DSH's own `includePrerelease` check, so
|
|
339
|
+
`0.2.0-rc.2` and the whole `0.2.x` line pass), and the settings card is
|
|
340
|
+
migrated onto the entry-id **volatile Config** model described above (with a
|
|
341
|
+
feature-detected legacy fallback).
|
|
293
342
|
|
|
294
343
|
| Component | Supported range |
|
|
295
344
|
| --- | --- |
|
|
296
|
-
| DSH runtime / host / client package family | `>=0.1.2-alpha.2 <0.
|
|
345
|
+
| DSH runtime / host / client package family | `>=0.1.2-alpha.2 <0.3.0-0` |
|
|
297
346
|
| `@deepseek-ai/cordis` | `^4.0.2` |
|
|
298
347
|
| `@deepseek-ai/schemastery` | `^3.18.2` |
|
|
299
348
|
| Node.js | `>=22.19.0` |
|
|
300
349
|
|
|
301
|
-
`0.1.2-alpha.2` is the minimum version for this API family: host settings
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
`
|
|
306
|
-
|
|
307
|
-
|
|
350
|
+
`0.1.2-alpha.2` is the minimum version for this API family: host settings are
|
|
351
|
+
**feature-detected** — on DSH `≤0.1.5` they register the `dsh-engram`
|
|
352
|
+
namespace via `settings.installSection`; on `≥0.1.7` / `0.2.x` the form is the
|
|
353
|
+
plugin's `Config` with the 27 GUI knobs marked `.volatile()` (entry id
|
|
354
|
+
`engram`). The browser settings card reads and writes through the plugin's own
|
|
355
|
+
HTTP route (`/api/dsh-engram/settings`, see Route B above) on both. The full
|
|
356
|
+
regression suite (npm test 329/329, incl. the new settings-v2 coverage for the
|
|
357
|
+
volatile-Config model) passes against the DSH `0.2.0-rc.2` dependency set
|
|
358
|
+
(cordis 4.0.4 + schemastery 3.18.4 + cosmokit, matching the global DSH CLI).
|
|
359
|
+
The `.volatile()`/loader hot-commit path and the describe-side projection were
|
|
360
|
+
verified against the real `dsh-settings 0.2.0-rc.2` utilities, and a full
|
|
361
|
+
real-machine boot smoke on an isolated `dsh 0.2.0-rc.2` profile **passed**:
|
|
362
|
+
the plugin boots with no version-range denial, the settings card form is
|
|
363
|
+
served for entry `engram` (all 27 GUI knobs, incl. `trustedHosts`), and a
|
|
364
|
+
GET → PUT (`mutate` ops, revision 0→1) → unset round trip on
|
|
365
|
+
`/api/dsh-engram/settings` lands in the profile row and reads back. The older
|
|
308
366
|
`0.1.0-rc.7` and `0.1.1` API graphs are outside this release's compatibility
|
|
309
367
|
range.
|
|
310
368
|
|
|
311
369
|
To install the DSH version used for validation:
|
|
312
370
|
|
|
313
371
|
```sh
|
|
314
|
-
npm install --global @deepseek-ai/dsh@0.
|
|
372
|
+
npm install --global @deepseek-ai/dsh@0.2.0-rc.2
|
|
315
373
|
dsh --version
|
|
316
374
|
```
|
|
317
375
|
|
|
@@ -705,9 +763,59 @@ later request. The two switches are independent.
|
|
|
705
763
|
simply never trigger (no boundary → no prune, zero side effects); the
|
|
706
764
|
corpus-wide dry run activates on 38% of sessions. If the pruner service is
|
|
707
765
|
absent the mechanism disables itself with one log line.
|
|
766
|
+
- **Boundary sources**: todo-progress completion and goal terminal events
|
|
767
|
+
(default), plus an optional **request-count cadence**
|
|
768
|
+
(`boundaryPruneIdleCadence`, default 0/off) — the "step idle" source that
|
|
769
|
+
covers the ~62% of sessions which never touch todo/goal (recon:
|
|
770
|
+
`eval/recon-idle-boundary.mjs`; +85% saved chars at cadence 50 in the
|
|
771
|
+
counterfactual `eval/simulate-idle-cadence.mjs`), still repayment-gated.
|
|
772
|
+
- **Threshold override**: `boundaryPruneThresholdChars` (default 0 → host's
|
|
773
|
+
8192). Set e.g. 2048 with smaller retained edges
|
|
774
|
+
(`boundaryPruneHeadChars`/`boundaryPruneTailChars`) to prune earlier —
|
|
775
|
+
T2048+small-edges lands 2.4× the first-prune savings of the host default on
|
|
776
|
+
the real corpus (10.14M vs 4.23M chars). Lowering the threshold is safe with
|
|
777
|
+
`resultPack` on, which archives the removed middles.
|
|
708
778
|
- Default **off**: `boundaryPrune: false`. When on, the log shows
|
|
709
779
|
`engram boundary-prune (todo @N reqs): pruned …`.
|
|
710
780
|
|
|
781
|
+
### ResultPack L2 (archive + `result_recall`, default OFF)
|
|
782
|
+
|
|
783
|
+
BoundaryPrune makes pruning lossless: the removed middle of every pruned
|
|
784
|
+
tool result is redacted (same rules as the memory write path) and archived to
|
|
785
|
+
`~/.dsh/engram/resultpack/<callId>.json`, and the pruned surface node gets a
|
|
786
|
+
tail handle — `[middle archived: result_recall(<callId>) 可取]` — so the model
|
|
787
|
+
knows the full result is one step away. `result_recall(callId, offset?)`
|
|
788
|
+
returns the archived middle in paged text blocks (progressive disclosure, the
|
|
789
|
+
same philosophy as `[ENGRAM]` → `engram_detail`, and the complete
|
|
790
|
+
ObservationPack pattern from SoL-Pi mechanism ③).
|
|
791
|
+
|
|
792
|
+
- **Lossless by construction**: L1 pruning shrinks the replay; L2 keeps the
|
|
793
|
+
original recoverable on demand — the "model rereads a pruned result" failure
|
|
794
|
+
mode goes to zero.
|
|
795
|
+
- **Scoped cost**: archives live outside the memory domain (big blobs never
|
|
796
|
+
bloat the domain JSON or the [ENGRAM] index); retention is a mtime sweep
|
|
797
|
+
(`resultPackRetentionDays`, default 7) riding the same GC cadence.
|
|
798
|
+
- **Self-disabling**: L2 without `boundaryPrune` has nothing to archive, so it
|
|
799
|
+
registers no tool and emits one warning.
|
|
800
|
+
- Default **off**: `resultPack: false` (must be on together with
|
|
801
|
+
`boundaryPrune: true`). When active the log shows
|
|
802
|
+
`engram result-pack enabled: result_recall(callId, offset) registered`.
|
|
803
|
+
|
|
804
|
+
### Activation telemetry (SoL-Pi M15/C13)
|
|
805
|
+
|
|
806
|
+
Mechanisms must be provably activating, and dormant ones are off by default.
|
|
807
|
+
`/api/dsh-engram/stats` (and the GUI overview) now answer
|
|
808
|
+
`activation: { boundaryPrune, recall }`:
|
|
809
|
+
|
|
810
|
+
- `boundaryPrune` — cumulative, durable record of real BoundaryPrune fires
|
|
811
|
+
(fires / prunedResults / charsRemoved / byKind todo|goal|step / lastFire),
|
|
812
|
+
written to `~/.dsh/engram/boundary-prune.status.json` on every landed prune,
|
|
813
|
+
independent of `resultPack`.
|
|
814
|
+
- `recall` — the injection leg of the recall funnel: how many `[RECALL]`
|
|
815
|
+
blocks actually made it into sessions (`recall-injections.json`), closing
|
|
816
|
+
the loop already measured from session logs (engram_recall queries → hits →
|
|
817
|
+
engram_detail follows) so you can see injection→query→detail activation.
|
|
818
|
+
|
|
711
819
|
## Auto-capture policy
|
|
712
820
|
|
|
713
821
|
Capture is deterministic and offline — it only sees tool *results*, never the
|
|
@@ -790,6 +898,15 @@ Defaults are token-conscious; override any key via the profile patch
|
|
|
790
898
|
- id: engram
|
|
791
899
|
config:
|
|
792
900
|
autoCapture: true # zero-LLM tool-result capture
|
|
901
|
+
autoCapturePreferences: true # zero-LLM user-correction/preference capture (prefer/avoid/switch-to cues)
|
|
902
|
+
preferenceCapturePerSession: 8 # per-session preference memory cap
|
|
903
|
+
boundaryPrune: false # ResultPack L1: prune stale over-threshold tool results at todo/goal boundaries (default OFF)
|
|
904
|
+
boundaryPruneThresholdChars: 0 # threshold override (0 = host 8192; e.g. 2048 prunes earlier)
|
|
905
|
+
boundaryPruneHeadChars: 0 # retained head under an override (0 = host 4096)
|
|
906
|
+
boundaryPruneTailChars: 0 # retained tail under an override (0 = host 1024)
|
|
907
|
+
boundaryPruneIdleCadence: 0 # request-count boundary for todo/goal-less sessions (0 = event-only)
|
|
908
|
+
resultPack: false # ResultPack L2: archive pruned middles + result_recall paged recall (default OFF; needs L1 on)
|
|
909
|
+
resultPackRetentionDays: 7 # archive retention days (mtime sweep on the GC cadence)
|
|
793
910
|
sessionSearch: true # engram_recall may also FTS past sessions
|
|
794
911
|
recallScope: workspace # recall scope: "workspace" (strict isolation, default) | "global" (opt-in cross-workspace recall with [W:<ws>] origin markers)
|
|
795
912
|
autoRecallOnStart: true # session-start auto recall (false = back to pure pull)
|
|
@@ -816,7 +933,7 @@ Defaults are token-conscious; override any key via the profile patch
|
|
|
816
933
|
## Development
|
|
817
934
|
|
|
818
935
|
```sh
|
|
819
|
-
npm test #
|
|
936
|
+
npm test # 291 tests: core + web API + GC + usage-observability + Context GC + ESR triggers + BoundaryPrune + preference learning (node:test)
|
|
820
937
|
npm run eval # offline recall + structure benchmark (deterministic)
|
|
821
938
|
npm run build:client
|
|
822
939
|
```
|
package/README.zh.md
CHANGED
|
@@ -17,6 +17,15 @@
|
|
|
17
17
|
+ 失败行)自动捕获为 `tags:["error","test"]`、信号上调。DSH **goal 域打通**:completed/blocked 的
|
|
18
18
|
goal(`goal/change` 会话事件)自动沉淀为 `handoff`/`error` 记忆(`tag:goal`),目标结局不随会话消散
|
|
19
19
|
(读取面见 `GET /api/dsh-engram/goals`)。
|
|
20
|
+
- **用户纠正/偏好学习(`autoCapturePreferences`,默认开,零 LLM)** — 「AI 犯错被纠正后,教训要留存」
|
|
21
|
+
([correx](https://github.com/ozoz5/correx)、[PAHF](https://arxiv.org/abs/2602.16173)、Mem0 偏好提取):
|
|
22
|
+
一个 `session/event` 监听器盯 `user/message`,用确定性纠正/偏好句式把用户话语沉淀为独立的
|
|
23
|
+
`preference` 记忆 kind——中文(`不要用X`、`改用X`、`以后统一用X`…)与英文(`don't use X`、
|
|
24
|
+
`switch to X`、`prefer X`、`never use X`…)模式,三种方向(`avoid` / `switch-to` / `prefer`),
|
|
25
|
+
并带疑问句 / 一次性操作指令 / 记忆工具元话语过滤器抑制误报。`preference` 记忆在 `[ENGRAM]`
|
|
26
|
+
块里**压过其它所有 kind**(`[R]` 前缀),让用户的长期规则成为每会话模型看到的第一行;
|
|
27
|
+
每会话上限 + 近期窗口去重与自动捕获同纪律。零 LLM、零向量、确定性纯函数——提取片段有界,
|
|
28
|
+
每条写入依旧先过密钥脱敏器。
|
|
20
29
|
- **符号索引 + 渐进披露** — 一个紧凑的 `[ENGRAM]` 块(默认预算 700 字符 ≈ 175 token;每条记忆一行)在
|
|
21
30
|
组装提示词时注入,并**按会话冻结**,让请求前缀字节稳定以复用 KV 缓存。模型需要细节时用
|
|
22
31
|
`engram_recall` / `engram_detail` 下钻,而不是把命中的原文灌进上下文。召回对内存池做
|
|
@@ -35,6 +44,10 @@
|
|
|
35
44
|
agentmemory 候选①)——相关记忆不依赖模型想起来就已在上下文里。纯规则、零 LLM、
|
|
36
45
|
纯读不 bump 命中;superseded 过期真相不占注入槽(仍可 `engram_detail` 重取);
|
|
37
46
|
与 `[ENGRAM]` 一起按会话冻结保持前缀稳定。
|
|
47
|
+
- **读路径激活(D)** — 命中条目的单行预览被截断(>140 字符)时带 `…` 标记,且块尾
|
|
48
|
+
引导行点名该具体 id:`#<id> truncated — engram_detail <id> (full) · engram_recall <query>`。
|
|
49
|
+
模型由此知道完整记录就在一次确定性 `engram_detail` 之后,而不是以为预览就是全文
|
|
50
|
+
(实证盲区:66 个会话 0 次 `engram_detail`——下钻路径此前对模型不可见)。
|
|
38
51
|
- **记忆间语义(supersede/contradict)** — `engram_store` 可选收 `supersedes` / `contradicts`
|
|
39
52
|
记忆 id(同工作区校验)。被 supersede 的「过期真相」在召回里**降级到尾部**、并从 `[ENGRAM]`
|
|
40
53
|
块中**剔除**(新陈述占行);被 contradicts 的记忆保留排序但标注 `· contradicted by <id>`。
|
|
@@ -153,8 +166,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
153
166
|
|
|
154
167
|
<!-- dsh-market 兼容信息块 —— 与 docs/RELEASE-NOTES.TEMPLATE.md 的市场 README 公约保持一致 -->
|
|
155
168
|
|
|
156
|
-
- **DSH 版本**:`>=0.1.2-alpha.2 <0.
|
|
157
|
-
- **最后验证日期**:2026-
|
|
169
|
+
- **DSH 版本**:`>=0.1.2-alpha.2 <0.3.0-0`(本版 `0.5.0`;已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` —— 见下文矩阵)
|
|
170
|
+
- **最后验证日期**:2026-10-15 —— 设置模型迁移(entry-id volatile Config,兼容 DSH `0.2.x`)落地,npm test 329/329 通过;真实 `dsh 0.2.0-rc.2` 隔离 profile 运行烟测通过(见下文“当前发布”)
|
|
158
171
|
- **安装方式已验证**:`dsh plugin --profile web add dsh-engram`
|
|
159
172
|
|
|
160
173
|
> **一句话结论**:所有**已真正发布**的版本(`0.2.0` … `0.3.6`)**只支持旧版
|
|
@@ -165,7 +178,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
165
178
|
| dsh-engram 发布版本 | 状态 | 支持的 DSH | 声明方式 |
|
|
166
179
|
| --- | --- | --- | --- |
|
|
167
180
|
| `0.2.0` … `0.3.6`(npm 全量 + GitHub v0.3.3–v0.3.6) | 已发布 | **仅旧版** —— `0.1.0-rc.7` / `0.1.0-rc.8` / `0.1.1-rc.1` / `0.1.1-rc.2` | peers `@deepseek-ai/dsh-*@^0.1.0-rc.7` |
|
|
168
|
-
| `0.3.7
|
|
181
|
+
| `0.3.7` / `0.4.0`(npm) | 已发布 | **新版 DSH,settings `installSection`** —— `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers 同范围 |
|
|
182
|
+
| `0.5.0`(本期 / this release) | 预发布 | **DSH `0.1.2-alpha.2` … `<0.3.0-0`** —— 设置卡迁移到 entry-id volatile Config(`0.1.7+`/`0.2.x`),`≤0.1.5` 自动回退 `installSection` | `engines.dsh` + peers `>=0.1.2-alpha.2 <0.3.0-0` |
|
|
169
183
|
|
|
170
184
|
### API 族断裂点:`0.1.2-alpha.2`
|
|
171
185
|
|
|
@@ -185,33 +199,59 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
185
199
|
HTTP 路由(`/api/dsh-engram/settings`,与记忆 viewer 同样的同源 fetch)读写
|
|
186
200
|
`dsh-engram` settings namespace,因此在 `0.1.2-alpha.2` 分界线两侧都是代际无关的。
|
|
187
201
|
|
|
202
|
+
**`0.1.7` / `0.2.0` 还有一次 settings 断裂**——`0.4.0` 在最新 DSH 上启动被拒的
|
|
203
|
+
真正原因:`@deepseek-ai/dsh-settings` 在 `0.1.7-alpha.2` **再次移除了
|
|
204
|
+
`settings.installSection`**(`0.2.x` 一路保留)。新设置模型是**条目式**的:可编辑字段
|
|
205
|
+
是插件自身 `Config` 的 `.volatile()` 字段(由 loader 校验并热提交),设置表单以
|
|
206
|
+
profile 条目 id(`engram`)为命名空间,不再需要任何“挂载”调用。`0.5.0`
|
|
207
|
+
在 `installEngramSettings` 里对两代际做特性检测:
|
|
208
|
+
|
|
209
|
+
- DSH `≥0.1.7` / `0.2.x` —— 27 个 GUI 旋钮即 `Config` 的 volatile 字段
|
|
210
|
+
(`lib/settings.js` `makeEngineConfigSchema`,由 `lib/index.js` 导出为
|
|
211
|
+
`Config`);卡片仍走同一 `/api/dsh-engram/settings` HTTP 路由读写条目 `engram`,
|
|
212
|
+
`service.settings` 接缝在 `loader/volatile-update` 事件上把 `resolved`
|
|
213
|
+
重新同步,卡片编辑对新会话即时生效。
|
|
214
|
+
- DSH `≤0.1.5` —— 照旧注册旧 `settings.installSection` 命名空间(`dsh-engram`)。
|
|
215
|
+
|
|
216
|
+
声明范围 `>=0.1.2-alpha.2 <0.3.0-0` 同时覆盖两代际;HTTP wire 命名空间在两代际都保持
|
|
217
|
+
`dsh-engram`(由接缝的活动命名空间驱动写入)。
|
|
218
|
+
|
|
188
219
|
所以:跑 ≤ `0.3.6` 的已发布版本时请把 DSH 保持在 `0.1.1-rc.2` 或更旧;升级
|
|
189
220
|
DSH 到 `0.1.2-alpha.2` 之前,先升级插件到 `>=0.3.7`。
|
|
190
221
|
|
|
191
|
-
### 当前发布版本 —— `0.
|
|
222
|
+
### 当前发布版本 —— `0.5.0`
|
|
192
223
|
|
|
193
|
-
|
|
194
|
-
`
|
|
224
|
+
已发布的 `0.4.0` 声明 `>=0.1.2-alpha.2 <0.2.0-0`——这个范围被 semver 门槛在
|
|
225
|
+
**所有 DSH `0.2.0-0` 预发布**上拒绝(`<0.2.0-0` 排除 `0.2.0-rc.x`),且其宿主设置端
|
|
226
|
+
仍在调用 `dsh-settings 0.1.7+` 已移除的 `installSection` API。`0.5.0`
|
|
227
|
+
**两处都修复**:范围放宽到 `<0.3.0-0`(用 DSH 自身的 `includePrerelease` 检查验证过,
|
|
228
|
+
`0.2.0-rc.2` 及整个 `0.2.x` 线都放行);设置卡迁移到上面描述的 entry-id **volatile
|
|
229
|
+
Config** 模型(并带特性检测的旧代际回退)。
|
|
195
230
|
|
|
196
231
|
| 组件 | 适配版本 |
|
|
197
232
|
| --- | --- |
|
|
198
|
-
| DSH runtime / host / client 包族 | `>=0.1.2-alpha.2 <0.
|
|
233
|
+
| DSH runtime / host / client 包族 | `>=0.1.2-alpha.2 <0.3.0-0` |
|
|
199
234
|
| `@deepseek-ai/cordis` | `^4.0.2` |
|
|
200
235
|
| `@deepseek-ai/schemastery` | `^3.18.2` |
|
|
201
236
|
| Node.js | `>=22.19.0` |
|
|
202
237
|
|
|
203
|
-
`0.1.2-alpha.2` 是这组 API
|
|
204
|
-
`settings.installSection
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
238
|
+
`0.1.2-alpha.2` 是这组 API 的最低版本:宿主设置注册按代际**特性检测**——DSH `≤0.1.5`
|
|
239
|
+
走 `settings.installSection` 注册 `dsh-engram` 命名空间;`≥0.1.7` / `0.2.x` 走插件
|
|
240
|
+
`Config`(27 个 GUI 旋钮标记为 `.volatile()`,条目 id `engram`)。浏览器设置卡在两代际
|
|
241
|
+
都经插件自有 HTTP 路由(`/api/dsh-engram/settings`,见上文 Route B)读写。完整回归
|
|
242
|
+
(npm test 329/329,含新增的 volatile-Config 模型 settings-v2 覆盖)在 DSH
|
|
243
|
+
`0.2.0-rc.2` 依赖集(cordis 4.0.4 + schemastery 3.18.4 + cosmokit,与全局 DSH CLI 同版本)
|
|
244
|
+
上通过;`.volatile()`/loader 热提交路径与 describe 侧投影已针对真实 `dsh-settings
|
|
245
|
+
0.2.0-rc.2` 工具函数验证;并在隔离的 `dsh 0.2.0-rc.2` profile 上完成了**真机启动烟测并
|
|
246
|
+
通过**:插件启动无版本范围拒绝、设置卡表单以条目 `engram` 对外提供(全部 27 个 GUI
|
|
247
|
+
旋钮,含 `trustedHosts`)、`/api/dsh-engram/settings` 的 GET → PUT(mutate ops,
|
|
248
|
+
revision 0→1)→ unset 往返落盘并读回。旧的 `0.1.0-rc.7` 与 `0.1.1` API 图不在
|
|
209
249
|
本发布版本的兼容范围内。
|
|
210
250
|
|
|
211
251
|
如需按验证版本安装 DSH:
|
|
212
252
|
|
|
213
253
|
```sh
|
|
214
|
-
npm install --global @deepseek-ai/dsh@0.
|
|
254
|
+
npm install --global @deepseek-ai/dsh@0.2.0-rc.2
|
|
215
255
|
dsh --version
|
|
216
256
|
```
|
|
217
257
|
|
|
@@ -333,7 +373,7 @@ npm run build:client
|
|
|
333
373
|
## 测试与评测
|
|
334
374
|
|
|
335
375
|
```sh
|
|
336
|
-
npm test #
|
|
376
|
+
npm test # 311 项单元测试(含 usage 滚动 / /stats 路由 / Context GC / ESR 触发 / BoundaryPrune)
|
|
337
377
|
npm run eval # 离线召回 + 结构基准(确定性语料,跑真实 store/recall 路径)
|
|
338
378
|
```
|
|
339
379
|
|
|
@@ -518,9 +558,48 @@ Context GC 管「压缩的摘要内容」,BoundaryPrune 管「确定性剪枝
|
|
|
518
558
|
workspace 历史先验 + 超过后 ×2 外推(有界乐观),长会话不会被挡死。
|
|
519
559
|
- **诚实激活面**:goal=0 且无 todo 推进的会话天然不触发(无边界不剪,零副作用);
|
|
520
560
|
全量干跑 77 会话激活 38%。pruner 服务缺席即自动禁用并打一条日志。
|
|
561
|
+
- **边界源**:默认 todo 完成推进 / goal 终态事件;可选**空闲步数边界**
|
|
562
|
+
(`boundaryPruneIdleCadence`,默认 0=关)——覆盖约 62% 从不动 todo/goal 的
|
|
563
|
+
会话(侦察:`eval/recon-idle-boundary.mjs`;反事实:`eval/simulate-idle-cadence.mjs`
|
|
564
|
+
显示 cadence 50 时节省 +85%),仍受偿还门约束。
|
|
565
|
+
- **阈值覆盖**:`boundaryPruneThresholdChars`(默认 0=宿主 8192)。设为 2048
|
|
566
|
+
并配更小保留边缘(`boundaryPruneHeadChars`/`boundaryPruneTailChars`)可更早
|
|
567
|
+
开剪——T2048+小边缘在真实语料上首剪节省是宿主默认的 2.4 倍(10.14M vs 4.23M
|
|
568
|
+
字符)。降阈值在 `resultPack` 开启时安全(被剪中段有归档兜底)。
|
|
521
569
|
- 默认**关**:`boundaryPrune: false`。开启后启动日志出现
|
|
522
570
|
`engram boundary-prune (todo @N reqs): pruned …`。
|
|
523
571
|
|
|
572
|
+
### ResultPack L2(结果归档 + `result_recall`,默认关)
|
|
573
|
+
|
|
574
|
+
让 BoundaryPrune 剪枝**无损**:每个被剪工具结果的被移除中段,按与记忆写入
|
|
575
|
+
相同的规则脱敏后归档到 `~/.dsh/engram/resultpack/<callId>.json`,并在剪枝
|
|
576
|
+
节点尾部追加 handle——`[middle archived: result_recall(<callId>) 可取]`——
|
|
577
|
+
模型知道完整结果就在一步之遥。`result_recall(callId, offset?)` 按页返回
|
|
578
|
+
归档中段(渐进披露,与 `[ENGRAM]` → `engram_detail` 同一哲学,也是 SoL-Pi
|
|
579
|
+
机制③ ObservationPack 的完整形态)。
|
|
580
|
+
|
|
581
|
+
- **构造性无损**:L1 剪掉的是重放、L2 保留的是可随时取回的原文——「模型回头
|
|
582
|
+
找被剪结果」的失败模式归零。
|
|
583
|
+
- **成本受控**:归档在记忆域之外(大块内容永远不会撑大 domain JSON 或
|
|
584
|
+
[ENGRAM] 索引);保留期 `resultPackRetentionDays`(默认 7 天)按 mtime 清理,
|
|
585
|
+
搭 GC 同一节奏。
|
|
586
|
+
- **自我禁用**:只开 L2 不开 L1 将无内容可归档,故不注册工具并打一条警告。
|
|
587
|
+
- 默认**关**:`resultPack: false`(须与 `boundaryPrune: true` 同开)。开启后
|
|
588
|
+
启动日志出现 `engram result-pack enabled: result_recall(callId, offset) registered`。
|
|
589
|
+
|
|
590
|
+
### 激活遥测(SoL-Pi M15/C13)
|
|
591
|
+
|
|
592
|
+
机制必须可证明在激活,休眠机制默认关。`/api/dsh-engram/stats`(以及 GUI
|
|
593
|
+
overview)现在返回 `activation: { boundaryPrune, recall }`:
|
|
594
|
+
|
|
595
|
+
- `boundaryPrune`——BoundaryPrune 真实 fire 的累计持久记录(fires /
|
|
596
|
+
prunedResults / charsRemoved / byKind todo|goal|step / lastFire),每次剪枝
|
|
597
|
+
落盘到 `~/.dsh/engram/boundary-prune.status.json`,与 `resultPack` 无关。
|
|
598
|
+
- `recall`——召回漏斗的**注入腿**:实际进过会话的 `[RECALL]` 块数量
|
|
599
|
+
(`recall-injections.json`),与从 session log 已统计的另一端
|
|
600
|
+
(engram_recall 查询 → 命中 → engram_detail 下钻)闭合,可看到
|
|
601
|
+
注入→查询→下钻的完整激活。
|
|
602
|
+
|
|
524
603
|
## 自动捕获策略
|
|
525
604
|
|
|
526
605
|
捕获是确定性、离线的——只看到工具*结果*,从不看对话本身。什么会被记录成一条记忆:
|
|
@@ -591,6 +670,15 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
|
|
|
591
670
|
- id: engram
|
|
592
671
|
config:
|
|
593
672
|
autoCapture: true # 零 LLM 工具结果捕获
|
|
673
|
+
autoCapturePreferences: true # 零 LLM 用户纠正/偏好捕获(prefer/avoid/switch-to 句式)
|
|
674
|
+
preferenceCapturePerSession: 8 # 每会话偏好记忆条数上限
|
|
675
|
+
boundaryPrune: false # ResultPack L1:todo/goal 边界剪掉超阈值旧工具结果(默认关)
|
|
676
|
+
boundaryPruneThresholdChars: 0 # 阈值覆盖(0=宿主 8192;如 2048 可更早开剪)
|
|
677
|
+
boundaryPruneHeadChars: 0 # 覆盖时的保留头部(0=宿主 4096)
|
|
678
|
+
boundaryPruneTailChars: 0 # 覆盖时的保留尾部(0=宿主 1024)
|
|
679
|
+
boundaryPruneIdleCadence: 0 # 空闲步数边界(0=仅事件边界;覆盖无 todo/goal 会话)
|
|
680
|
+
resultPack: false # ResultPack L2:剪掉的中段脱敏归档 + result_recall 按页召回(默认关,须与 L1 同开)
|
|
681
|
+
resultPackRetentionDays: 7 # 归档保留天数(mtime 清理,走 GC 节奏)
|
|
594
682
|
sessionSearch: true # engram_recall 也可对历史会话 FTS
|
|
595
683
|
recallScope: workspace # 召回范围:workspace(严格工作区隔离,默认)| global(可选跨工作区召回,带 [W:<ws>] 来源标记)
|
|
596
684
|
autoRecallOnStart: true # 会话启动自动召回:按首条消息注入 [RECALL] 块(false=回到纯拉取)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> 依据:[SoL-Pi](https://nvlabs.github.io/SoL-Pi/) 四幸存机制之二(ObservationPack:归档载荷、上下文留 handle+摘录、按页召回)
|
|
4
4
|
> 与提案池 C11「Reduce tool output before its first prompt insertion」/ C23「Build observation packs before paying for full bodies」。
|
|
5
5
|
> 数据:[Oracle Analysis](./ORACLE-ANALYSIS.zh.md)(97 真实会话、13.9K 请求、15.0K 工具调用)。
|
|
6
|
-
> **状态:L1 已实现(`lib/boundary-prune.js`,默认关;L0 见 §6,全量干跑见 §6.1)。L2
|
|
6
|
+
> **状态:L1 已实现(`lib/boundary-prune.js`,默认关;L0 见 §6,全量干跑见 §6.1)。L2 已实现(`lib/result-pack.js`,默认关)。**
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -56,6 +56,8 @@ L1 剪掉的中段今天直接丢弃(仅 session 日志保留原文,模型取不
|
|
|
56
56
|
- 注册 `result_recall(callId, offset?)` 工具,按页返回归档中段 —— 与 [ENGRAM] 渐进披露同一哲学:索引行→详情下钻;
|
|
57
57
|
- 剪枝结果尾部追加一行 handle:`[middle pruned: result_recall(callId) 可取]`,模型可自主决定是否下钻(M3 遥测将能看到激活率)。
|
|
58
58
|
|
|
59
|
+
> **已实现(2026-09-23,§8)**:实现细节与设计中两处修正——①归档落 `~/.dsh/engram/resultpack/<callId>.json`(独立文件而非域表,大块内容不撑 domain JSON);②handle 走宿主 surface-replace 协议(`session.append("tool/result", …, surfaceOp replace)`),replay-safe 零 LLM;脱敏先于持久化。17 项单测 + L1→L2 钩子 3 项 + 进程内端到端(归档→分页→缺档)验证通过。
|
|
60
|
+
|
|
59
61
|
### L3 · 上游提案(严格 C11)
|
|
60
62
|
|
|
61
63
|
向 DSH 提 PR:ToolRuntime 开放 per-tool 可扩展 finalizeContent 链(或"结果归档 transport")。附上 oracle 数据(96% 集中在三个工具、top-10 占 46%)作为动机。
|
|
@@ -128,8 +130,10 @@ L1 剪掉的中段今天直接丢弃(仅 session 日志保留原文,模型取不
|
|
|
128
130
|
|
|
129
131
|
## 8. 后续
|
|
130
132
|
|
|
131
|
-
-
|
|
132
|
-
-
|
|
133
|
+
- ~~**L2**~~ **已实现**(2026-09-23, `lib/result-pack.js`):pruned 中段归档 + `result_recall` 按页召回 + handle 行;默认关(`resultPack`,须与 `boundaryPrune` 同开),保留 7 天走 GC;T2048 阈值与 L2 绑定,**现已满足开低阈值的归档前提**。
|
|
134
|
+
- ~~**激活遥测**~~ **已实现**(2026-09-23):`/stats` 与 GUI overview 返回 `activation: { boundaryPrune, recall }` —— BoundaryPrune fire 每次落盘 `~/.dsh/engram/boundary-prune.status.json`(fires/prunedResults/charsRemoved/byKind,与 resultPack 无关),[RECALL] 注入计数落盘 `recall-injections.json`,与 session-log 已统计的 recall 漏斗(查询→命中→detail 下钻)闭合(SoL-Pi M15/C13)。
|
|
135
|
+
- ~~**step 空转边界**~~ **已实现**(2026-09-23):`boundaryPruneIdleCadence`(默认 0=关)——请求计数边界,覆盖无 todo/goal 会话。侦察 105 会话:65 个无边界、含 5.23M over-threshold 暴露(38%);反事实仿真(cadence 50):激活面 36→64 会话、首剪节省 4.23M→7.84M(+85%),仍受偿还门约束。
|
|
136
|
+
- **T2048 落地**(2026-09-23):`boundaryPruneThresholdChars`/`HeadChars`/`TailChars`(默认 0=宿主)——插件以 `Object.create(pruner)` 原型克隆宿主 pruner 实例、仅覆盖 config,宿主不变。真实语料干跑:T2048 H1024/T256 首剪 10.14M vs 宿主默认 4.23M(+2.4x)。
|
|
133
137
|
- **上游提案(L3)**:ToolRuntime 开放 finalizeContent 链,附 oracle 数据。
|
|
134
138
|
|
|
135
139
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
## dsh-engram v0.5.0
|
|
2
|
+
|
|
3
|
+
DSH 0.2.x 兼容修复版:`0.1.7` 起 `@deepseek-ai/dsh-settings` 移除了
|
|
4
|
+
`settings.installSection`,设置卡改为**条目式 volatile Config** 模型;本版本把设置
|
|
5
|
+
绑定迁移到新模型(entry-id `engram`),并把声明范围修到能覆盖 DSH `0.2.x` 全系,
|
|
6
|
+
使插件在最新 DSH 上恢复加载与设置卡读写。
|
|
7
|
+
|
|
8
|
+
### 功能
|
|
9
|
+
|
|
10
|
+
- **DSH ≥0.1.7 / 0.2.x 设置模型支持** — 插件 `Config`(`lib/index.js` 导出的
|
|
11
|
+
`Config`)声明全部 48 个 DEFAULTS 键;27 个 GUI 旋钮为 `.volatile()` 字段,
|
|
12
|
+
设置表单由 DSH 以 profile 条目 id `engram` 对外提供,卡片编辑经
|
|
13
|
+
`loader/volatile-update` **热提交**到运行配置(新会话即时生效,已冻结块保持
|
|
14
|
+
冻结——插件既有契约)。其余键普通声明,profile patch 里的内部旋钮不再被校验丢弃。
|
|
15
|
+
- **双代际特性检测** — `installEngramSettings` 自动识别宿主:DSH `≤0.1.5`
|
|
16
|
+
回退旧的 `settings.installSection` 命名空间(`dsh-engram`),行为与 0.4.0 完全
|
|
17
|
+
一致;`≥0.1.7` / `0.2.x` 走新模型(无挂载调用)。HTTP wire 命名空间两代际都保持
|
|
18
|
+
`dsh-engram`,**客户端 bundle 零改动**。
|
|
19
|
+
|
|
20
|
+
### 修复
|
|
21
|
+
|
|
22
|
+
- **版本范围**:`engines.dsh` + 5 个 `@deepseek-ai/dsh-*` peer 从
|
|
23
|
+
`>=0.1.2-alpha.2 <0.2.0-0` 修正为 `>=0.1.2-alpha.2 <0.3.0-0`——原范围把
|
|
24
|
+
DSH `0.2.0-rc.x` 全部排除(semver 预发布窗口),插件在最新 DSH 上被兼容门槛拒绝。
|
|
25
|
+
新范围已用 DSH 自身的 `includePrerelease` 检查实测:`0.2.0-rc.2` 与整个 `0.2.x`
|
|
26
|
+
线放行,`0.3.0-0` 拒绝。
|
|
27
|
+
- **宿主设置崩溃**:移除对已不存在的 `settings.installSection` 的无条件调用
|
|
28
|
+
(其在 `dsh-settings 0.1.7-alpha.2` 起被删除),改为特性检测。
|
|
29
|
+
- **`boundaryPruneThresholdChars` 默认 `null` → `0`**:与设置卡长期使用的
|
|
30
|
+
“0=用宿主 8192” 语义一致(`0` 与 `null` 在剪枝判定中等价),并让 describe 的
|
|
31
|
+
表单值完整包含该键。
|
|
32
|
+
|
|
33
|
+
### 其他
|
|
34
|
+
|
|
35
|
+
- 测试 329/329 通过(新增 `test/settings-v2.test.mjs` 6 个用例,覆盖 volatile
|
|
36
|
+
Config 校验/解包/热同步与两代际安装路径;`test/api.test.mjs` 随 ns 语义更新)。
|
|
37
|
+
- settings 投影与写路径针对真实 `dsh-settings 0.2.0-rc.2` 工具函数
|
|
38
|
+
(`volatileForm`/`projectForm`/`isVolatilePath`/`plainConfig`)验证;
|
|
39
|
+
真实 cordis 4.0.4 集成验证 Config 校验与热提交。
|
|
40
|
+
- **真机烟测通过**(隔离 profile,`dsh 0.2.0-rc.2`,`--port 3099`):插件启动无
|
|
41
|
+
版本拒绝、`/api/dsh-engram/settings` 提供 27 键表单、
|
|
42
|
+
GET → PUT(mutate,revision 0→1)→ unset 往返落盘并读回。
|
|
43
|
+
- `scripts/prepublish-check.mjs` 随新导出面与 peer 范围更新,`prepublishOnly`
|
|
44
|
+
在 0.2.x peer 集上通过。
|
|
45
|
+
|
|
46
|
+
## DSH 版本支持
|
|
47
|
+
|
|
48
|
+
- **支持的 DSH 范围**:>=0.1.2-alpha.2 <0.3.0-0
|
|
49
|
+
- **peer 声明**:
|
|
50
|
+
- `@deepseek-ai/dsh-compaction`: `>=0.1.2-alpha.2 <0.3.0-0`
|
|
51
|
+
- `@deepseek-ai/dsh-compaction-basic`: `>=0.1.2-alpha.2 <0.3.0-0`
|
|
52
|
+
- `@deepseek-ai/dsh-llm`: `>=0.1.2-alpha.2 <0.3.0-0`
|
|
53
|
+
- `@deepseek-ai/dsh-settings`: `>=0.1.2-alpha.2 <0.3.0-0`
|
|
54
|
+
- `@deepseek-ai/dsh-storage-domain`: `>=0.1.2-alpha.2 <0.3.0-0`
|
|
55
|
+
- **验证版本**:`dsh-v0.2.0-rc.2`(全局 DSH CLI,并针对真实
|
|
56
|
+
`dsh-settings` / `cordis` / `schemastery` 依赖集)
|
|
57
|
+
- **最后验证日期**:2026-10-15
|
|
58
|
+
- **安装方式已验证**:`dsh plugin --profile web add dsh-engram`
|
package/lib/api.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import { uuid, shortId } from "./util.js";
|
|
14
14
|
import { collectToolCounts, collectUsageStats } from "./usage.js";
|
|
15
|
-
import { SETTINGS_NS } from "./settings.js";
|
|
15
|
+
import { SETTINGS_NS, WIRE_SETTINGS_NS, LEGACY_SETTINGS_NS } from "./settings.js";
|
|
16
16
|
|
|
17
17
|
/** Route family prefix (kept in sync with the client half). */
|
|
18
18
|
export const API_PREFIX = "/api/dsh-engram";
|
|
@@ -160,8 +160,9 @@ export function makeEngramRoutes(service) {
|
|
|
160
160
|
writeJson(res, 200, {
|
|
161
161
|
...summary,
|
|
162
162
|
indexes,
|
|
163
|
-
captures: service.captureStats ?? { total: 0, git: 0, file: 0, error: 0 },
|
|
163
|
+
captures: service.captureStats ?? { total: 0, git: 0, file: 0, error: 0, preference: 0 },
|
|
164
164
|
gc: service.gcStats ?? { lastRun: 0, archivedMemories: 0, archivedTasks: 0, removedLinks: 0 },
|
|
165
|
+
activation: service.packTelemetry ? service.packTelemetry() : { boundaryPrune: null, recall: null },
|
|
165
166
|
compaction: service.compactionStatus ?? { host: "unknown", web: { action: "unknown", presets: [] } },
|
|
166
167
|
config: service.config ?? {},
|
|
167
168
|
anonymous: {
|
|
@@ -512,6 +513,10 @@ export function makeEngramRoutes(service) {
|
|
|
512
513
|
recallHitsPerQuery: queries > 0 ? +(hitsTotal / queries).toFixed(3) : null,
|
|
513
514
|
detailFollowRate: queries > 0 ? +(detailFollows / queries).toFixed(4) : null,
|
|
514
515
|
},
|
|
516
|
+
// SoL-Pi activation telemetry: the durable BoundaryPrune / ResultPack
|
|
517
|
+
// activation record (fires actually landed on this profile) + the
|
|
518
|
+
// [RECALL] injection-funnel leg (blocks actually injected into sessions).
|
|
519
|
+
activation: service.packTelemetry ? service.packTelemetry() : { boundaryPrune: null, recall: null },
|
|
515
520
|
});
|
|
516
521
|
};
|
|
517
522
|
|
|
@@ -561,8 +566,13 @@ export function makeEngramRoutes(service) {
|
|
|
561
566
|
// Normalize both onto the HTTP contract {namespaces:[...]} the client uses.
|
|
562
567
|
const payload = settings.describe();
|
|
563
568
|
const namespaces = Array.isArray(payload) ? payload : (payload?.namespaces ?? []);
|
|
564
|
-
|
|
565
|
-
|
|
569
|
+
// The seam carries the ACTIVE namespace — entry id `engram` on DSH
|
|
570
|
+
// ≥0.1.7 / 0.2.x, legacy `dsh-engram` on ≤0.1.5. The view is re-labelled
|
|
571
|
+
// onto the stable WIRE_SETTINGS_NS the client card filters on, so the
|
|
572
|
+
// shipped client works unchanged across generations.
|
|
573
|
+
const activeNs = settings.ns ?? SETTINGS_NS;
|
|
574
|
+
const view = namespaces.find((n) => n && (n.ns === activeNs || n.ns === LEGACY_SETTINGS_NS));
|
|
575
|
+
writeJson(res, 200, view ? { namespaces: [{ ...view, ns: WIRE_SETTINGS_NS }] } : { namespaces: [] });
|
|
566
576
|
} catch (error) {
|
|
567
577
|
writeError(res, 500, String(error?.message ?? error));
|
|
568
578
|
}
|
|
@@ -586,10 +596,13 @@ export function makeEngramRoutes(service) {
|
|
|
586
596
|
return writeError(res, 400, "body must provide ops (array of {op,path[,value]}) or patch (object)");
|
|
587
597
|
}
|
|
588
598
|
try {
|
|
599
|
+
// Drive the seam's ACTIVE namespace (entry id `engram` on DSH ≥0.1.7 /
|
|
600
|
+
// 0.2.x, legacy `dsh-engram` on ≤0.1.5), never the wire label.
|
|
601
|
+
const activeNs = settings.ns ?? SETTINGS_NS;
|
|
589
602
|
if (Array.isArray(ops)) {
|
|
590
|
-
await settings.mutate(
|
|
603
|
+
await settings.mutate(activeNs, ops, expectedRevision);
|
|
591
604
|
} else {
|
|
592
|
-
await settings.update(
|
|
605
|
+
await settings.update(activeNs, patch, expectedRevision);
|
|
593
606
|
}
|
|
594
607
|
writeJson(res, 200, { ok: true });
|
|
595
608
|
} catch (error) {
|