dsh-engram 0.6.0 → 0.7.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 +89 -27
- package/README.zh.md +71 -23
- package/docs/PROPOSAL-evolution.zh.md +25 -1
- package/docs/RELEASE-NOTES-v0.7.0.md +57 -0
- package/lib/anchor.js +124 -0
- package/lib/client.js +4 -0
- package/lib/entity-page.js +200 -0
- package/lib/episode.js +163 -0
- package/lib/index-block.js +74 -4
- package/lib/index.js +82 -1
- package/lib/settings.js +6 -0
- package/lib/store.js +48 -5
- package/lib/tools.js +25 -3
- 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.
|
|
268
|
-
- **最后验证日期 / Last verified**: 2026-10-19 —
|
|
267
|
+
- **DSH 版本 / DSH versions**: `>=0.1.2-alpha.2 <0.3.0-0` (本版 `0.7.0`; 已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` — 见下方矩阵)
|
|
268
|
+
- **最后验证日期 / Last verified**: 2026-10-19 — episode / entity pages / anchor revalidation,npm test 381/381 通过
|
|
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
|
|
@@ -281,7 +281,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
281
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
282
|
| `0.5.0` (npm) | published | **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` |
|
|
283
283
|
| `0.5.1` | published | 同 `0.5.0` — 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
|
|
284
|
-
| `0.6.0`
|
|
284
|
+
| `0.6.0` | published | 同 `0.5.0` — Context Ledger、BoundaryPrune/ResultPack 默认开 + 账本否决、JIT 推送、Context GC 改 opt-in | 同 `0.5.0` |
|
|
285
|
+
| `0.7.0` (本期 / this release) | published | 同 `0.5.0` — session episode、resume brief、entity pages/cards、revalidatable anchors + layered TTL | 同 `0.5.0` |
|
|
285
286
|
|
|
286
287
|
### Where the API family broke — `0.1.2-alpha.2`
|
|
287
288
|
|
|
@@ -315,7 +316,7 @@ the loader), and the settings form is keyed by the profile entry id (`engram`),
|
|
|
315
316
|
so nothing needs "mounting". `0.5.0` feature-detects the two generations in
|
|
316
317
|
`installEngramSettings`:
|
|
317
318
|
|
|
318
|
-
- DSH `≥0.1.7` / `0.2.x` — the
|
|
319
|
+
- DSH `≥0.1.7` / `0.2.x` — the 34 GUI knobs are the volatile `Config` fields
|
|
319
320
|
(`lib/settings.js` `makeEngineConfigSchema`, exported as `Config` from
|
|
320
321
|
`lib/index.js`); the card reads/writes entry `engram` through the same
|
|
321
322
|
`/api/dsh-engram/settings` HTTP route, and the `service.settings` seam
|
|
@@ -331,27 +332,29 @@ drives mutations).
|
|
|
331
332
|
So: keep DSH on `0.1.1-rc.2` or older while running a release ≤ `0.3.6`, and
|
|
332
333
|
upgrade the plugin to `>=0.3.7` before moving DSH to `0.1.2-alpha.2`.
|
|
333
334
|
|
|
334
|
-
### Current release — `0.
|
|
335
|
-
|
|
336
|
-
From
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
- **
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
- **
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
335
|
+
### Current release — `0.7.0`
|
|
336
|
+
|
|
337
|
+
From event records to **maintainable current truth**: sessions sediment an
|
|
338
|
+
episode at teardown, new sessions get a resume brief, `esr_node` becomes a
|
|
339
|
+
readable page, and file anchors make stale truth detectable.
|
|
340
|
+
|
|
341
|
+
- **Session episode** — zero-LLM digest at `session/disposed` (files / commands /
|
|
342
|
+
failures→fixed / decisions / open loops), never indexed, newest 20 per
|
|
343
|
+
workspace kept.
|
|
344
|
+
- **Resume brief** — the newest episode from the last 7 days is injected as a
|
|
345
|
+
`[RESUME]` line (≤240 chars + drill pointer) at session start.
|
|
346
|
+
- **Entity pages + cards** — `truth / timeline / open loops / conflicts /
|
|
347
|
+
relations`; up to 2 one-line cards in the index, full page via
|
|
348
|
+
`engram_detail(entity=…)`.
|
|
349
|
+
- **Revalidatable anchors** — file-backed memories record `mtime/size/sha256`;
|
|
350
|
+
a bounded revalidation at session start tags changed/missing sources `stale`
|
|
351
|
+
(dropped from index/truth, still re-fetchable).
|
|
352
|
+
- **Layered TTL** — preference/procedure permanent, episode 14d, error 60d,
|
|
353
|
+
others 180d.
|
|
354
|
+
- **Migration** — only new writes are anchored (no historical backfill);
|
|
355
|
+
restart `dsh web` after upgrading; an episode appears after one session ends,
|
|
356
|
+
the resume brief on the next new session. The `0.6.0` ledger / defaults / JIT
|
|
357
|
+
behaviour is unchanged.
|
|
355
358
|
|
|
356
359
|
The published `0.4.0` declared `>=0.1.2-alpha.2 <0.2.0-0` — which the semver
|
|
357
360
|
gate **rejects on every DSH `0.2.0-0` prerelease** (`<0.2.0-0` excludes
|
|
@@ -372,7 +375,7 @@ feature-detected legacy fallback).
|
|
|
372
375
|
`0.1.2-alpha.2` is the minimum version for this API family: host settings are
|
|
373
376
|
**feature-detected** — on DSH `≤0.1.5` they register the `dsh-engram`
|
|
374
377
|
namespace via `settings.installSection`; on `≥0.1.7` / `0.2.x` the form is the
|
|
375
|
-
plugin's `Config` with the
|
|
378
|
+
plugin's `Config` with the 34 GUI knobs marked `.volatile()` (entry id
|
|
376
379
|
`engram`). The browser settings card reads and writes through the plugin's own
|
|
377
380
|
HTTP route (`/api/dsh-engram/settings`, see Route B above) on both. The full
|
|
378
381
|
regression suite (npm test 329/329, incl. the new settings-v2 coverage for the
|
|
@@ -898,6 +901,60 @@ and silence when there is nothing relevant to point at:
|
|
|
898
901
|
remaining-requests ROI gate — today the 3-line budget plus the ledger are the
|
|
899
902
|
guardrails.
|
|
900
903
|
|
|
904
|
+
### Session episode + resume brief (v0.7-A/D)
|
|
905
|
+
|
|
906
|
+
- **episode** — at `session/disposed`, a zero-LLM digest of the event log: files
|
|
907
|
+
touched, commands run, failures that later recovered (`cmd×N→fixed`), written
|
|
908
|
+
commit subjects, and still-open todos. Written only when there is substance (a
|
|
909
|
+
bare `ls` session produces none); **never indexed**; the newest 20 per
|
|
910
|
+
workspace are kept and older ones archived.
|
|
911
|
+
- **resume brief** — at the first assembly of a new session, the newest episode
|
|
912
|
+
from the last 7 days is injected as a `[RESUME]` line (≤240 chars) plus an
|
|
913
|
+
`engram_detail <id>` pointer, frozen with `[ENGRAM]`/`[RECALL]`. No recent
|
|
914
|
+
episode → no line; returning to a project does not need a re-briefing.
|
|
915
|
+
- Settings: `episodeEnabled`, `resumeBriefEnabled` (both default on), plus
|
|
916
|
+
`episodeMaxPerWorkspace` / `resumeBriefMaxAgeDays` / `resumeBriefMaxChars`.
|
|
917
|
+
|
|
918
|
+
### Entity pages + entity cards (v0.7-B)
|
|
919
|
+
|
|
920
|
+
`esr_node` grows from a dot on the graph into a readable **page**: current
|
|
921
|
+
truth, timeline, open loops, conflicts and relations for one thing
|
|
922
|
+
(package / repo / service / bug…).
|
|
923
|
+
|
|
924
|
+
- **Entity card (in the index, default on)** — `[ENGRAM]` renders ONE line for
|
|
925
|
+
each active entity (anchored memories or open tasks), at most 2:
|
|
926
|
+
`[ENT] dsh-engram · package · 3 mem · 1 open · truth: … #id · page: engram_detail(entity="dsh-engram")`
|
|
927
|
+
Those entities' flat memory lines are not repeated; other entities stay in a
|
|
928
|
+
single `nodes:` line.
|
|
929
|
+
- **Full page (on drill)** — `engram_detail(entity="<name|id>")` returns
|
|
930
|
+
`truth / timeline / open loops / conflicts / relations`, with memory ids and
|
|
931
|
+
evidence gaps. A name with anchored memories but no registered node still
|
|
932
|
+
gets a virtual page.
|
|
933
|
+
- Pure, deterministic: preference leads `truth`, superseded rows never enter
|
|
934
|
+
it, conflicts are de-duplicated by unordered pair (`#a vs #b`).
|
|
935
|
+
- Settings `entityCardsEnabled` (default on); `entityCardsMax` /
|
|
936
|
+
`entityCardChars` tunable.
|
|
937
|
+
|
|
938
|
+
### Revalidatable anchors + layered TTL (v0.7-C)
|
|
939
|
+
|
|
940
|
+
"Treating the past as truth" is the strongest credibility critique against
|
|
941
|
+
memory plugins. v0.7 gives file-backed memories an **anchor**:
|
|
942
|
+
|
|
943
|
+
- on write, record `{path, mtimeMs, size, hash?}` (sha256 for files ≤256KB,
|
|
944
|
+
stat only for larger ones) in the memory row; relative paths resolve against
|
|
945
|
+
the workspace;
|
|
946
|
+
- at session start a bounded revalidation (≤40 rows) tags changed/missing
|
|
947
|
+
sources `stale`; the `[ENGRAM]` index and entity `truth` stop showing them,
|
|
948
|
+
but nothing is deleted — `engram_detail` still returns them and the entity
|
|
949
|
+
timeline marks `· stale`;
|
|
950
|
+
- **layered TTL**: `preference` / `procedure` permanent; `episode` 14 days;
|
|
951
|
+
`error` 60 days; everything else `expireDays` (180). Hard deletes still do not
|
|
952
|
+
exist — GC only archives.
|
|
953
|
+
- Settings: `anchorRevalidate` (default on), `episodeTtlDays`, `errorTtlDays`.
|
|
954
|
+
- **Not done**: the offline consolidation job (episode abstraction/merge) —
|
|
955
|
+
deterministic rules can only roll up, not abstract semantically; deferred
|
|
956
|
+
until v0.8 alongside playbooks, rather than shipping a lossy pseudo-merge.
|
|
957
|
+
|
|
901
958
|
## Auto-capture policy
|
|
902
959
|
|
|
903
960
|
Capture is deterministic and offline — it only sees tool *results*, never the
|
|
@@ -1011,6 +1068,11 @@ Defaults are token-conscious; override any key via the profile patch
|
|
|
1011
1068
|
gcNarrative: true # scoped LLM narrative for un-provenanced turns; false = fully mechanical (zero LLM)
|
|
1012
1069
|
autoWebCompaction: false # rewrite stock web presets (default off; explicit opt-in, revert with the CLI)
|
|
1013
1070
|
jitEnabled: true # JIT push: error recurrence / file focus / goal completion → one memory line
|
|
1071
|
+
episodeEnabled: true # session episode: zero-LLM digest at teardown (never indexed)
|
|
1072
|
+
resumeBriefEnabled: true # resume brief: newest episode from the last 7 days at session start
|
|
1073
|
+
entityCardsEnabled: true # entity card: one truth/tasks/drill line per active entity in the index
|
|
1074
|
+
anchorRevalidate: true # re-stat filePath anchors at session start (changed/missing → stale)
|
|
1075
|
+
episodeTtlDays: 14 # episode TTL (preference/procedure permanent; error 60d; others expireDays)
|
|
1014
1076
|
ledgerEnabled: true # Context Ledger: injected cost / prune savings / rewrite penalty → net tokens
|
|
1015
1077
|
ledgerCacheDiscount: 0.1 # cached-prefix price share; rewrites pay (1−discount)
|
|
1016
1078
|
engramIndexOrder: 40 # systemPrompt section order (before tools band)
|
|
@@ -1020,7 +1082,7 @@ Defaults are token-conscious; override any key via the profile patch
|
|
|
1020
1082
|
## Development
|
|
1021
1083
|
|
|
1022
1084
|
```sh
|
|
1023
|
-
npm test #
|
|
1085
|
+
npm test # 381 tests: core + web API + GC + usage-observability + Context GC + ESR triggers + BoundaryPrune + preference learning + Context Ledger + JIT push (node:test)
|
|
1024
1086
|
npm run eval # offline recall + structure benchmark (deterministic)
|
|
1025
1087
|
npm run build:client
|
|
1026
1088
|
```
|
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.
|
|
170
|
-
- **最后验证日期**:2026-10-19 ——
|
|
169
|
+
- **DSH 版本**:`>=0.1.2-alpha.2 <0.3.0-0`(本版 `0.7.0`;已发布的 `0.3.7`、`0.4.0` 仍声明旧的 `0.1.x` 范围 `>=0.1.2-alpha.2 <0.2.0-0` —— 见下文矩阵)
|
|
170
|
+
- **最后验证日期**:2026-10-19 —— episode / 实体页 / 锚点重验证,npm test 381/381 通过
|
|
171
171
|
- **安装方式已验证**:`dsh plugin --profile web add dsh-engram`
|
|
172
172
|
|
|
173
173
|
> **一句话结论**:所有**已真正发布**的版本(`0.2.0` … `0.3.6`)**只支持旧版
|
|
@@ -181,7 +181,8 @@ curl -s -X POST http://127.0.0.1:3080/api/dsh-engram/import \
|
|
|
181
181
|
| `0.3.7` / `0.4.0`(npm) | 已发布 | **新版 DSH,settings `installSection`** —— `>=0.1.2-alpha.2 <0.2.0-0` | `engines.dsh` + peers 同范围 |
|
|
182
182
|
| `0.5.0`(npm) | 已发布 | **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` |
|
|
183
183
|
| `0.5.1` | 已发布 | 同 `0.5.0` —— 会话扫描修复(`session.v<N>.jsonl.zstd`,issue #8)、数据导出/导入 GUI、替换/冲突可视化(issue #3) | 同 `0.5.0` |
|
|
184
|
-
| `0.6.0
|
|
184
|
+
| `0.6.0` | 已发布 | 同 `0.5.0` —— Context Ledger、BoundaryPrune/ResultPack 默认开 + 账本否决、JIT 推送、Context GC 改 opt-in | 同 `0.5.0` |
|
|
185
|
+
| `0.7.0`(本期 / this release) | 已发布 | 同 `0.5.0` —— 会话 episode、恢复简报、实体页/实体卡、可重验证锚点 + 分层 TTL | 同 `0.5.0` |
|
|
185
186
|
|
|
186
187
|
### API 族断裂点:`0.1.2-alpha.2`
|
|
187
188
|
|
|
@@ -208,7 +209,7 @@ HTTP 路由(`/api/dsh-engram/settings`,与记忆 viewer 同样的同源 fetc
|
|
|
208
209
|
profile 条目 id(`engram`)为命名空间,不再需要任何“挂载”调用。`0.5.0`
|
|
209
210
|
在 `installEngramSettings` 里对两代际做特性检测:
|
|
210
211
|
|
|
211
|
-
- DSH `≥0.1.7` / `0.2.x` ——
|
|
212
|
+
- DSH `≥0.1.7` / `0.2.x` —— 34 个 GUI 旋钮即 `Config` 的 volatile 字段
|
|
212
213
|
(`lib/settings.js` `makeEngineConfigSchema`,由 `lib/index.js` 导出为
|
|
213
214
|
`Config`);卡片仍走同一 `/api/dsh-engram/settings` HTTP 路由读写条目 `engram`,
|
|
214
215
|
`service.settings` 接缝在 `loader/volatile-update` 事件上把 `resolved`
|
|
@@ -221,23 +222,21 @@ profile 条目 id(`engram`)为命名空间,不再需要任何“挂载”
|
|
|
221
222
|
所以:跑 ≤ `0.3.6` 的已发布版本时请把 DSH 保持在 `0.1.1-rc.2` 或更旧;升级
|
|
222
223
|
DSH 到 `0.1.2-alpha.2` 之前,先升级插件到 `>=0.3.7`。
|
|
223
224
|
|
|
224
|
-
### 当前发布版本 —— `0.
|
|
225
|
+
### 当前发布版本 —— `0.7.0`
|
|
225
226
|
|
|
226
|
-
|
|
227
|
-
|
|
227
|
+
把「记忆」从**事件记录**推进到**可维护的当前真相**:会话结束自动沉淀 episode、
|
|
228
|
+
新会话给恢复简报、`esr_node` 升级为实体页、文件锚点让过期真相可被检测。
|
|
228
229
|
|
|
229
|
-
-
|
|
230
|
-
|
|
231
|
-
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
`
|
|
239
|
-
- `0.5.1` 的会话日志版本化修复(`session.v<N>.jsonl.zstd`,issue #8)与数据备份
|
|
240
|
-
GUI(issue #3)保持不变。
|
|
230
|
+
- **会话 episode**:`session/disposed` 零 LLM 生成紧凑纪要(文件/命令/失败→修复/
|
|
231
|
+
决策/未闭环),不进索引,每 workspace 保留 20 条。
|
|
232
|
+
- **恢复简报**:新会话注入最近 7 天最新 episode(`[RESUME]` ≤240 字符 + 下钻指针)。
|
|
233
|
+
- **实体页 + 实体卡**:`truth / timeline / open loops / conflicts / relations`;
|
|
234
|
+
索引前置最多 2 张实体卡,`engram_detail(entity=…)` 下钻。
|
|
235
|
+
- **可重验证锚点**:带 `filePath` 的记忆记录 `mtime/size/sha256`;会话启动有界
|
|
236
|
+
重验证,改动/缺失 → `stale`(不进索引/truth,仍可 detail 重取)。
|
|
237
|
+
- **分层 TTL**:preference/procedure 永久、episode 14 天、error 60 天、其余 180 天。
|
|
238
|
+
- **迁移**:只有新写入会落锚(不回溯历史);升级后重启 `dsh web`;episode 要等一个
|
|
239
|
+
会话结束,resume brief 在下一个新会话生效。`0.6.0` 的账本/默认值/JIT 保持不变。
|
|
241
240
|
|
|
242
241
|
已发布的 `0.4.0` 声明 `>=0.1.2-alpha.2 <0.2.0-0`——这个范围被 semver 门槛在
|
|
243
242
|
**所有 DSH `0.2.0-0` 预发布**上拒绝(`<0.2.0-0` 排除 `0.2.0-rc.x`),且其宿主设置端
|
|
@@ -255,13 +254,13 @@ Config** 模型(并带特性检测的旧代际回退)。
|
|
|
255
254
|
|
|
256
255
|
`0.1.2-alpha.2` 是这组 API 的最低版本:宿主设置注册按代际**特性检测**——DSH `≤0.1.5`
|
|
257
256
|
走 `settings.installSection` 注册 `dsh-engram` 命名空间;`≥0.1.7` / `0.2.x` 走插件
|
|
258
|
-
`Config`(
|
|
257
|
+
`Config`(34 个 GUI 旋钮标记为 `.volatile()`,条目 id `engram`)。浏览器设置卡在两代际
|
|
259
258
|
都经插件自有 HTTP 路由(`/api/dsh-engram/settings`,见上文 Route B)读写。完整回归
|
|
260
259
|
(npm test 329/329,含新增的 volatile-Config 模型 settings-v2 覆盖)在 DSH
|
|
261
260
|
`0.2.0-rc.2` 依赖集(cordis 4.0.4 + schemastery 3.18.4 + cosmokit,与全局 DSH CLI 同版本)
|
|
262
261
|
上通过;`.volatile()`/loader 热提交路径与 describe 侧投影已针对真实 `dsh-settings
|
|
263
262
|
0.2.0-rc.2` 工具函数验证;并在隔离的 `dsh 0.2.0-rc.2` profile 上完成了**真机启动烟测并
|
|
264
|
-
通过**:插件启动无版本范围拒绝、设置卡表单以条目 `engram` 对外提供(全部
|
|
263
|
+
通过**:插件启动无版本范围拒绝、设置卡表单以条目 `engram` 对外提供(全部 34 个 GUI
|
|
265
264
|
旋钮,含 `trustedHosts`)、`/api/dsh-engram/settings` 的 GET → PUT(mutate ops,
|
|
266
265
|
revision 0→1)→ unset 往返落盘并读回。旧的 `0.1.0-rc.7` 与 `0.1.1` API 图不在
|
|
267
266
|
本发布版本的兼容范围内。
|
|
@@ -392,7 +391,7 @@ npm run build:client
|
|
|
392
391
|
## 测试与评测
|
|
393
392
|
|
|
394
393
|
```sh
|
|
395
|
-
npm test #
|
|
394
|
+
npm test # 381 项单元测试(含 usage 滚动 / /stats 路由 / Context GC / ESR 触发 / BoundaryPrune / Context Ledger / JIT 推送)
|
|
396
395
|
npm run eval # 离线召回 + 结构基准(确定性语料,跑真实 store/recall 路径)
|
|
397
396
|
```
|
|
398
397
|
|
|
@@ -664,6 +663,50 @@ v0.6 增加按事件**推送**:三个确定性事件,命中才推、每次
|
|
|
664
663
|
- **尚未做**:resume brief(隔天继续)与「预计剩余请求不足时跳过推送」的显式 ROI 门——
|
|
665
664
|
当前靠 3 行硬预算 + 账本观测。
|
|
666
665
|
|
|
666
|
+
### 会话纪要 + 恢复简报(v0.7-A/D)
|
|
667
|
+
|
|
668
|
+
- **episode**:会话结束(`session/disposed`)时,用零 LLM 规则把事件日志压成一条紧凑纪要——
|
|
669
|
+
改过哪些文件、跑过哪些命令、哪些失败后修复(`cmd×N→fixed`)、git commit 的书面主题、
|
|
670
|
+
仍挂着的 todo。只在有实质内容时生成(纯 `ls` 会话不写);**永不进 `[ENGRAM]` 索引**;
|
|
671
|
+
每个 workspace 只保留最近 20 条,超出自动归档。
|
|
672
|
+
数据源全部是已有事件(`tool/call` 的 arguments、`tool/result`、`todo/write`),不调模型。
|
|
673
|
+
- **恢复简报**:新会话第一次组装时,取最近 7 天最新的 episode,注入 ≤240 字符的
|
|
674
|
+
`[RESUME]` 行 + `engram_detail <id>` 指针;与 `[ENGRAM]`/`[RECALL]` 一起按会话冻结。
|
|
675
|
+
没有近期 episode 就不注入——隔天继续项目时不用重新交代背景。
|
|
676
|
+
- 设置键:`episodeEnabled`、`resumeBriefEnabled`(均默认开),
|
|
677
|
+
`episodeMaxPerWorkspace` / `resumeBriefMaxAgeDays` / `resumeBriefMaxChars` 可调。
|
|
678
|
+
|
|
679
|
+
### 实体页 + 实体卡(v0.7-B)
|
|
680
|
+
|
|
681
|
+
`esr_node` 从「图上的点」升级成**可读的页**:对一个实体(package / repo / 服务 / bug…)
|
|
682
|
+
聚合当前真相、时间线、未闭环任务、冲突与关系。
|
|
683
|
+
|
|
684
|
+
- **实体卡(索引内,默认开)**:`[ENGRAM]` 为活跃实体(有锚定记忆或未闭环任务)
|
|
685
|
+
渲染一行,最多 2 张:
|
|
686
|
+
`[ENT] dsh-engram · package · 3 mem · 1 open · truth: … #id · page: engram_detail(entity="dsh-engram")`
|
|
687
|
+
这些实体的平铺记忆行不再重复(真相由卡片承载);其余实体仍列在 `nodes:` 一行。
|
|
688
|
+
- **完整页(按需下钻)**:`engram_detail(entity="<name|id>")` 返回
|
|
689
|
+
`truth / timeline / open loops / conflicts / relations` 五段,带 memory id 与证据缺口;
|
|
690
|
+
没有注册节点但有记忆锚定的名字也会生成虚拟页。
|
|
691
|
+
- 纯函数、确定性排序:preference 排在 truth 最前,superseded 旧真相不进 truth,
|
|
692
|
+
冲突按无序对去重(`#a vs #b`)。
|
|
693
|
+
- 设置键 `entityCardsEnabled`(默认开);`entityCardsMax` / `entityCardChars` 可调。
|
|
694
|
+
|
|
695
|
+
### 可重验证锚点 + 分层 TTL(v0.7-C)
|
|
696
|
+
|
|
697
|
+
「把过去当真相」是记忆插件最大的可信度问题。v0.7 给带 `filePath` 的记忆加**锚点**:
|
|
698
|
+
|
|
699
|
+
- 写入时记录 `{path, mtimeMs, size, hash?}`(≤256KB 的文件存 sha256,大文件只存 stat),
|
|
700
|
+
落盘在记忆行的 `anchor` 字段;相对路径按 workspace 解析为绝对路径。
|
|
701
|
+
- 会话启动时做一次**有界重验证**(最多 40 条):文件缺失/改动 → 记忆打 `stale` 标签;
|
|
702
|
+
`[ENGRAM]` 索引与实体页 `truth` **不再自动展示**它,但**不删除**——`engram_detail`
|
|
703
|
+
仍可重取,实体页 timeline 会标 `· stale`。
|
|
704
|
+
- **分层 TTL**:`preference` / `procedure` 永久;`episode` 默认 14 天;`error` 默认 60 天;
|
|
705
|
+
其余按 `expireDays`(默认 180 天)。真正删除仍只发生在 GC 的归档(不硬删)。
|
|
706
|
+
- 设置键:`anchorRevalidate`(默认开)、`episodeTtlDays`、`errorTtlDays`。
|
|
707
|
+
- **未做**:离线「巩固任务」(episode 抽象/合并)——确定性规则只能做 rollup,不是语义抽象;
|
|
708
|
+
在没有证据前不引入,留到 v0.8 与 playbook 一起考虑。
|
|
709
|
+
|
|
667
710
|
## 自动捕获策略
|
|
668
711
|
|
|
669
712
|
捕获是确定性、离线的——只看到工具*结果*,从不看对话本身。什么会被记录成一条记忆:
|
|
@@ -763,6 +806,11 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
|
|
|
763
806
|
gcReplacesCompaction: false # Context GC:接管 DSH 自动 compact(默认关=宿主 LLM 压缩;true=opt-in 指针摘要)
|
|
764
807
|
gcNarrative: true # 无锚轮次走 scoped LLM 叙事;false=纯机械(零 LLM)
|
|
765
808
|
jitEnabled: true # JIT 推送:错误复发/文件焦点/goal 完成时推一行已有记忆
|
|
809
|
+
episodeEnabled: true # 会话纪要:结束时零 LLM 生成 episode(不进索引,供恢复简报)
|
|
810
|
+
resumeBriefEnabled: true # 恢复简报:新会话注入最近 7 天最新 episode
|
|
811
|
+
entityCardsEnabled: true # 实体卡:[ENGRAM] 为活跃实体渲染一行真相 + 任务 + 下钻指针
|
|
812
|
+
anchorRevalidate: true # 会话启动重验证 filePath 锚点(改动/缺失 → stale,不进索引/truth)
|
|
813
|
+
episodeTtlDays: 14 # episode TTL(preference/procedure 永久,error 60 天,其余 expireDays)
|
|
766
814
|
ledgerEnabled: true # Context Ledger:注入成本/剪枝节省/前缀重写罚金 → 净 token
|
|
767
815
|
ledgerCacheDiscount: 0.1 # 缓存折价:重写按 (1−0.1) 计罚金;0.1 = 命中只付 10%
|
|
768
816
|
autoWebCompaction: false # web 预设自动改写(默认关;开启需显式确认,可用 revert 还原)
|
|
@@ -774,7 +822,7 @@ promote: 2 pending todo(s) vs 1 ESR task(s) — esr_task(name="…") #suggest-pr
|
|
|
774
822
|
## 开发
|
|
775
823
|
|
|
776
824
|
```sh
|
|
777
|
-
npm test #
|
|
825
|
+
npm test # 381 个测试:核心 + Web API + GC + Context GC + ESR 触发 + Context Ledger + JIT(node:test)
|
|
778
826
|
npm run build:client
|
|
779
827
|
```
|
|
780
828
|
|
|
@@ -343,7 +343,7 @@ net : avoided − injected − rewrites×(1−cacheDiscount)
|
|
|
343
343
|
- **状态**:已实现(2026-10-19)——`lib/ledger.js`(纯函数 + 原子落盘 + delta flush)、
|
|
344
344
|
`test/ledger.test.mjs` 12 例、`/stats` 与 `/overview` 的 `ledger` 字段、
|
|
345
345
|
`ledgerEnabled` / `ledgerCacheDiscount` 两个设置键、GUI 遥测页账本面板 +
|
|
346
|
-
概览「上下文净 token」卡;`npm test`
|
|
346
|
+
概览「上下文净 token」卡;`npm test` 381/381。
|
|
347
347
|
- 反事实基线:同一会话关闭机制时的 avoided 由 oracle 离线算,账本只报「实际发生」。
|
|
348
348
|
|
|
349
349
|
**B. 自适应默认(`boundaryPrune: "auto"`)**
|
|
@@ -424,6 +424,13 @@ conflicts : contradicts 边 + 待裁决标记
|
|
|
424
424
|
- 注入时只给**实体卡**(≤3 行:truth 首行 + open loops 数 + 更新时间),
|
|
425
425
|
详情走 `engram_detail`/页——继续渐进披露。
|
|
426
426
|
- 索引从「平铺行」升级为「实体卡 + 少量独立事实」,同样 700c 预算内信息密度更高。
|
|
427
|
+
- **状态(2026-10-19)**:**B 已实现**——`lib/entity-page.js`
|
|
428
|
+
(`buildEntityPage` / `resolveEntity` / `renderEntityCard` / `renderEntityPage`);
|
|
429
|
+
`selectEntityCards` 在 `[ENGRAM]` 前置最多 2 张实体卡(truth 首条 + mem/open 计数 +
|
|
430
|
+
`engram_detail(entity=…)` 指针),并把这些实体的平铺记忆行从索引中去重;
|
|
431
|
+
`engram_detail` 新增可选 `entity` 参数返回完整页(truth/timeline/open loops/
|
|
432
|
+
conflicts/relations);`entityCardsEnabled` 默认开。`test/entity-page.test.mjs` 7 例。
|
|
433
|
+
**C(锚点重验证 / 分层 TTL / 巩固任务)仍未做**。
|
|
427
434
|
|
|
428
435
|
**C. 巩固任务(可离线)**
|
|
429
436
|
|
|
@@ -438,12 +445,29 @@ conflicts : contradicts 边 + 待裁决标记
|
|
|
438
445
|
召回/索引前抽查;锚点失效 → 自动降权并标 `stale`,而不是继续当真相。
|
|
439
446
|
- `expireDays` 从「整条过期」改为「分层 TTL」:episode 短、fact 长、preference 永久。
|
|
440
447
|
|
|
448
|
+
- **状态(2026-10-19)**:**C 的锚点 + 分层 TTL 已实现**——`lib/anchor.js`
|
|
449
|
+
(`makeFileAnchor` / `anchorStatus` / `memoryIsStale` / `collectStaleAnchors`),
|
|
450
|
+
记忆行新增 `anchor` 字段(path/mtimeMs/size/hash?/at;≤256KB 存 sha256);
|
|
451
|
+
会话启动时有界重验证(≤40 条),改动/缺失 → 打 `stale` 标签,索引与实体 truth
|
|
452
|
+
不再展示、timeline 标 `· stale`、`engram_detail` 仍可重取;分层 TTL:
|
|
453
|
+
preference/procedure 永久、episode 14d、error 60d、其余 expireDays。
|
|
454
|
+
`test/anchor.test.mjs` 6 例。**离线巩固任务(episode 抽象/合并)未做**:
|
|
455
|
+
纯规则只能 rollup、不是语义抽象,在没有证据前不引入(与 v0.8 playbook 一起考虑)。
|
|
456
|
+
|
|
441
457
|
**D. Resume Brief(隔天继续)**
|
|
442
458
|
|
|
443
459
|
打开旧会话/同 workspace 新会话时,注入 ≤5 行:上次停在哪、未闭环任务、
|
|
444
460
|
最近的失败与修复、下一步建议。这是本项目对「73% 请求在长会话」最直接的产品回答,
|
|
445
461
|
也是与宿主 checkpoint 的差异化(宿主存状态,我们存**意义**)。
|
|
446
462
|
|
|
463
|
+
- **状态(2026-10-19)**:**A + D 已实现**——`lib/episode.js` 的 `buildEpisode()`
|
|
464
|
+
在 `session/disposed` 生成零 LLM 纪要(文件/命令/失败→修复/决策/未闭环,仅实质会话写入,
|
|
465
|
+
永不进索引,每 workspace 保留 20 条);`renderResumeBrief()` 在新会话注入最近 7 天
|
|
466
|
+
最新 episode(`[RESUME]` ≤240 字符 + `engram_detail` 指针);设置键
|
|
467
|
+
`episodeEnabled` / `resumeBriefEnabled`;`test/episode.test.mjs` 9 例。
|
|
468
|
+
**B(实体页)/ C(锚点重验证、分层 TTL)待做**——它们需要 schema 迁移与索引渲染改造,
|
|
469
|
+
留到下一轮。
|
|
470
|
+
|
|
447
471
|
**门:**
|
|
448
472
|
|
|
449
473
|
- 跨会话问答集(自建 40 题 + LongMemEval 子集)Hit@3 提升 ≥ 20%;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## dsh-engram v0.7.0
|
|
2
|
+
|
|
3
|
+
自 v0.6.0 以来:把「记忆」从**事件记录**推进到**可维护的当前真相**——会话结束自动沉淀
|
|
4
|
+
episode、新会话给恢复简报、`esr_node` 升级为实体页、文件锚点让过期真相可被检测。
|
|
5
|
+
|
|
6
|
+
### 功能
|
|
7
|
+
|
|
8
|
+
- **会话 episode(v0.7-A)** — `session/disposed` 时用零 LLM 规则把事件日志压成一条紧凑
|
|
9
|
+
纪要:改过哪些文件、跑过哪些命令、哪些失败后修复(`cmd×N→fixed`)、git commit 主题、
|
|
10
|
+
仍挂着的 todo。只在有实质内容时写(纯 `ls` 会话不写),**永不进 `[ENGRAM]` 索引**,
|
|
11
|
+
每个 workspace 保留最近 20 条。
|
|
12
|
+
- **恢复简报(v0.7-D)** — 新会话第一次组装时,取最近 7 天最新的 episode,注入
|
|
13
|
+
≤240 字符的 `[RESUME]` 行 + `engram_detail` 指针;与 `[ENGRAM]`/`[RECALL]` 一起按会话冻结。
|
|
14
|
+
没有近期 episode 就不注入。
|
|
15
|
+
- **实体页 + 实体卡(v0.7-B)** — `esr_node` 升级为可读页面:`truth`(preference 优先、
|
|
16
|
+
superseded 剔除)/ `timeline` / `open loops`(active 任务 + 证据缺口)/ `conflicts`
|
|
17
|
+
(无序对去重)/ `relations`。`[ENGRAM]` 为活跃实体前置最多 2 张一行卡
|
|
18
|
+
(truth 首条 + mem/open + 下钻指针),被代表的实体不再重复平铺行;
|
|
19
|
+
`engram_detail(entity="<name|id>")` 返回完整页。
|
|
20
|
+
- **可重验证锚点(v0.7-C)** — 带 `filePath` 的记忆在写入时记录
|
|
21
|
+
`{path, mtimeMs, size, hash?}`(≤256KB 存 sha256);会话启动时有界重验证(≤40 条),
|
|
22
|
+
文件改动/缺失 → 打 `stale` 标签,索引与实体 truth 不再展示,timeline 标注 `· stale`,
|
|
23
|
+
`engram_detail` 仍可重取(不删除)。
|
|
24
|
+
- **分层 TTL(v0.7-C)** — `preference` / `procedure` 永久;`episode` 14 天;`error` 60 天;
|
|
25
|
+
其余按 `expireDays`(默认 180 天)。仍然只有 GC 归档、没有硬删。
|
|
26
|
+
|
|
27
|
+
### 兼容性说明
|
|
28
|
+
|
|
29
|
+
- 存储 schema 只**新增**字段:`memories.anchor`(nullable,默认 null)与新的 memory kind
|
|
30
|
+
`episode`。旧数据读取自动补默认值,无需迁移;真实实例冒烟用 256 条既有记忆验证通过。
|
|
31
|
+
- 只有**新写入**且带 `filePath` 的记忆会落锚;既有记忆不会被回溯锚定(避免一次性把历史
|
|
32
|
+
事实全部标 stale)。需要时可后续加显式 backfill 命令。
|
|
33
|
+
- 新增设置键(均默认开):`episodeEnabled`、`resumeBriefEnabled`、`entityCardsEnabled`、
|
|
34
|
+
`anchorRevalidate`;隐藏可调 `episodeMaxPerWorkspace`、`resumeBriefMaxAgeDays`、
|
|
35
|
+
`resumeBriefMaxChars`、`entityCardsMax`、`entityCardChars`、`episodeTtlDays`、
|
|
36
|
+
`errorTtlDays`。GUI 旋钮总数 34。
|
|
37
|
+
- 升级后需重启 `dsh web`;episode 要等一个会话结束、resume brief 在下一个新会话生效。
|
|
38
|
+
|
|
39
|
+
### 其他
|
|
40
|
+
|
|
41
|
+
- 测试 **381/381**(新增 episode 9 例、entity 7 例、anchor 6 例);`npm run eval` BENCH PASS;
|
|
42
|
+
`npm run typecheck` 通过;`lib/client.js` 重建。
|
|
43
|
+
- 文档:中英 README(episode / 实体页 / 锚点三节)、`docs/PROPOSAL-evolution.zh.md`
|
|
44
|
+
(v0.7 A/B/C/D 状态)、设置卡新增「会话纪要 / 恢复简报 / 实体卡」开关。
|
|
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 0.2.0-rc.2`
|
|
56
|
+
- **最后验证日期**:2026-10-19
|
|
57
|
+
- **安装方式已验证**:`dsh plugin --profile web add dsh-engram`
|
package/lib/anchor.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-engram revalidatable file anchors (PROPOSAL-evolution §4 v0.7-C).
|
|
3
|
+
*
|
|
4
|
+
* "The past is treated as truth" is the strongest critique against memory
|
|
5
|
+
* plugins: a fact written last week may describe code that changed yesterday.
|
|
6
|
+
* An anchor makes staleness DETECTABLE instead of trusted:
|
|
7
|
+
*
|
|
8
|
+
* { path, mtimeMs, size, hash?, at }
|
|
9
|
+
*
|
|
10
|
+
* - `makeFileAnchor` records the file's identity when a memory is written
|
|
11
|
+
* (sha256 for small files, mtime+size for every file — cheap default);
|
|
12
|
+
* - `anchorStatus` re-stats (and re-hashes when a hash exists) and returns
|
|
13
|
+
* `valid | changed | missing`;
|
|
14
|
+
* - `collectStaleAnchors` scans a bounded set of active memories so the index
|
|
15
|
+
* / entity truth can drop rows whose source moved, and the caller can tag
|
|
16
|
+
* them `stale` (never deleted — still re-fetchable via engram_detail).
|
|
17
|
+
*
|
|
18
|
+
* Zero LLM, fail-contained: any filesystem error reads as "missing", never
|
|
19
|
+
* throws into a render path.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { createHash } from "node:crypto";
|
|
23
|
+
import { readFileSync, statSync } from "node:fs";
|
|
24
|
+
import path from "node:path";
|
|
25
|
+
|
|
26
|
+
const DEFAULT_MAX_HASH_BYTES = 256 * 1024;
|
|
27
|
+
|
|
28
|
+
function hashFile(file, size) {
|
|
29
|
+
try {
|
|
30
|
+
return createHash("sha256").update(readFileSync(file)).digest("hex").slice(0, 32);
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function absolute(filePath, baseDir) {
|
|
37
|
+
const raw = String(filePath ?? "").trim();
|
|
38
|
+
if (raw.length === 0) return "";
|
|
39
|
+
if (path.isAbsolute(raw)) return raw;
|
|
40
|
+
return typeof baseDir === "string" && baseDir.length > 0 ? path.resolve(baseDir, raw) : path.resolve(raw);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Build an anchor for an existing file, or null when it cannot be stat'ed.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} filePath file path as stored on the memory
|
|
47
|
+
* @param {object} [opts]
|
|
48
|
+
* @param {string} [opts.baseDir] directory for relative paths (the workspace)
|
|
49
|
+
* @param {number} [opts.now]
|
|
50
|
+
* @param {number} [opts.maxHashBytes] hash only files up to this size
|
|
51
|
+
*/
|
|
52
|
+
export function makeFileAnchor(filePath, { baseDir = "", now = Date.now(), maxHashBytes = DEFAULT_MAX_HASH_BYTES } = {}) {
|
|
53
|
+
const abs = absolute(filePath, baseDir);
|
|
54
|
+
if (abs.length === 0) return null;
|
|
55
|
+
try {
|
|
56
|
+
const stat = statSync(abs);
|
|
57
|
+
if (!stat.isFile()) return null;
|
|
58
|
+
return {
|
|
59
|
+
path: abs,
|
|
60
|
+
mtimeMs: stat.mtimeMs,
|
|
61
|
+
size: stat.size,
|
|
62
|
+
hash: stat.size <= maxHashBytes ? hashFile(abs, stat.size) : null,
|
|
63
|
+
at: now,
|
|
64
|
+
};
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Revalidate one anchor: `valid` | `changed` | `missing` (`none` when absent).
|
|
72
|
+
*/
|
|
73
|
+
export function anchorStatus(anchor) {
|
|
74
|
+
if (anchor === null || anchor === void 0 || typeof anchor.path !== "string" || anchor.path.length === 0) {
|
|
75
|
+
return "none";
|
|
76
|
+
}
|
|
77
|
+
let stat;
|
|
78
|
+
try {
|
|
79
|
+
stat = statSync(anchor.path);
|
|
80
|
+
} catch {
|
|
81
|
+
return "missing";
|
|
82
|
+
}
|
|
83
|
+
if (!stat.isFile()) return "missing";
|
|
84
|
+
if (stat.size !== anchor.size || stat.mtimeMs !== anchor.mtimeMs) {
|
|
85
|
+
// mtime can survive content changes only in exotic cases; when a hash was
|
|
86
|
+
// recorded, let it decide before declaring the file changed.
|
|
87
|
+
if (typeof anchor.hash !== "string") return "changed";
|
|
88
|
+
const hash = hashFile(anchor.path, stat.size);
|
|
89
|
+
return hash === anchor.hash ? "valid" : "changed";
|
|
90
|
+
}
|
|
91
|
+
if (typeof anchor.hash === "string") {
|
|
92
|
+
const hash = hashFile(anchor.path, stat.size);
|
|
93
|
+
return hash === anchor.hash ? "valid" : "changed";
|
|
94
|
+
}
|
|
95
|
+
return "valid";
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Is this memory's source still the same file it was written against? */
|
|
99
|
+
export function memoryIsStale(memory) {
|
|
100
|
+
if (memory === null || typeof memory !== "object") return false;
|
|
101
|
+
const status = anchorStatus(memory.anchor);
|
|
102
|
+
return status === "changed" || status === "missing";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Bounded scan of active anchored memories whose source moved/vanished.
|
|
107
|
+
* Returns [{ id, status, path }] and never throws.
|
|
108
|
+
*/
|
|
109
|
+
export function collectStaleAnchors(store, workspace, { limit = 40 } = {}) {
|
|
110
|
+
if (store === null || typeof store.listMemories !== "function") return [];
|
|
111
|
+
const cap = Number.isFinite(limit) && limit > 0 ? Math.trunc(limit) : 40;
|
|
112
|
+
const rows = store.listMemories(workspace, 200);
|
|
113
|
+
const out = [];
|
|
114
|
+
for (const memory of rows) {
|
|
115
|
+
if (out.length >= cap) break;
|
|
116
|
+
if (memory?.anchor === null || memory?.anchor === void 0) continue;
|
|
117
|
+
if (Array.isArray(memory.tags) && memory.tags.includes("stale")) continue;
|
|
118
|
+
const status = anchorStatus(memory.anchor);
|
|
119
|
+
if (status === "changed" || status === "missing") {
|
|
120
|
+
out.push({ id: memory.id, status, path: memory.anchor.path });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
package/lib/client.js
CHANGED
|
@@ -2714,6 +2714,7 @@ function signedTokens(n) {
|
|
|
2714
2714
|
}
|
|
2715
2715
|
var KIND_COLORS2 = {
|
|
2716
2716
|
preference: "#b45309",
|
|
2717
|
+
episode: "#0e7490",
|
|
2717
2718
|
decision: "#2563eb",
|
|
2718
2719
|
error: "#dc2626",
|
|
2719
2720
|
procedure: "#7c3aed",
|
|
@@ -3703,6 +3704,9 @@ var COMMON_FIELDS = [
|
|
|
3703
3704
|
{ key: "resultPack", label: "\u7ED3\u679C\u5F52\u6863\u53EC\u56DE", hint: "ResultPack L2\uFF1A\u526A\u6389\u7684\u4E2D\u6BB5\u8131\u654F\u5F52\u6863\uFF0C\u8282\u70B9\u5C3E\u90E8\u9644 handle\uFF0C\u6A21\u578B\u53EF\u7528 result_recall(callId) \u6309\u9875\u53EC\u56DE\uFF08\u5B8C\u6574 ObservationPack\uFF1B\u9ED8\u8BA4\u5F00\uFF0C\u4FDD\u8BC1\u9ED8\u8BA4\u526A\u679D\u65E0\u635F\uFF1B\u9700\u4E0E\u8FB9\u754C\u526A\u679D\u4E00\u8D77\u5F00\uFF09", kind: "bool" },
|
|
3704
3705
|
{ key: "autoRecallOnStart", label: "\u4F1A\u8BDD\u542F\u52A8\u81EA\u52A8\u53EC\u56DE", hint: "\u65B0\u4F1A\u8BDD\u6309\u9996\u6761\u6D88\u606F\u81EA\u52A8\u628A\u6700\u76F8\u5173\u8BB0\u5FC6\u6CE8\u5165 [RECALL] \u5757\uFF08\u65E0\u9700\u6A21\u578B\u60F3\u8D77\u8C03 engram_recall\uFF09\uFF1B\u5173\u6389=\u56DE\u5230\u7EAF\u62C9\u53D6", kind: "bool" },
|
|
3705
3706
|
{ key: "jitEnabled", label: "JIT \u63A8\u9001", hint: "\u9519\u8BEF\u590D\u53D1 / \u6587\u4EF6\u7126\u70B9 / goal \u5B8C\u6210\u65F6\uFF0C\u628A\u5DF2\u6709\u8BB0\u5FC6\u538B\u6210\u4E00\u884C\u63A8\u8FDB\u4E0A\u4E0B\u6587\uFF08append-only\u3001\u6BCF\u4F1A\u8BDD\u22643 \u884C\u3001\u65E0\u547D\u4E2D\u6C89\u9ED8\uFF1B\u6BCF\u6B21\u63A8\u9001\u6309\u524D\u7F00\u91CD\u5199\u8BA1\u5165\u8D26\u672C\uFF09", kind: "bool" },
|
|
3707
|
+
{ key: "episodeEnabled", label: "\u4F1A\u8BDD\u7EAA\u8981", hint: "\u4F1A\u8BDD\u7ED3\u675F\u65F6\u7528\u96F6 LLM \u89C4\u5219\u751F\u6210\u4E00\u6761 episode\uFF08\u6587\u4EF6/\u547D\u4EE4/\u5931\u8D25\u2192\u4FEE\u590D/\u51B3\u7B56/\u672A\u95ED\u73AF\uFF09\uFF0C\u4E0D\u8FDB\u7D22\u5F15\uFF0C\u4F9B\u6062\u590D\u7B80\u62A5\u4F7F\u7528\uFF1B\u6BCF workspace \u4FDD\u7559\u6700\u8FD1 20 \u6761", kind: "bool" },
|
|
3708
|
+
{ key: "resumeBriefEnabled", label: "\u6062\u590D\u7B80\u62A5", hint: "\u65B0\u4F1A\u8BDD\u542F\u52A8\u65F6\u6CE8\u5165\u6700\u8FD1 7 \u5929\u7684\u6700\u65B0 episode\uFF08\u2264240 \u5B57\u7B26 + engram_detail \u6307\u9488\uFF09\uFF0C\u9694\u5929\u7EE7\u7EED\u4E0D\u7528\u91CD\u65B0\u4EA4\u4EE3\u80CC\u666F", kind: "bool" },
|
|
3709
|
+
{ key: "entityCardsEnabled", label: "\u5B9E\u4F53\u5361", hint: "[ENGRAM] \u7D22\u5F15\u4E3A\u6D3B\u8DC3\u5B9E\u4F53\uFF08\u6709\u951A\u5B9A\u8BB0\u5FC6\u6216\u672A\u95ED\u73AF\u4EFB\u52A1\uFF09\u6E32\u67D3\u4E00\u884C\u300C\u5F53\u524D\u771F\u76F8 + \u6253\u5F00\u4EFB\u52A1 + engram_detail(entity=\u2026) \u6307\u9488\u300D\uFF0C\u6700\u591A 2 \u5F20\uFF0C\u66FF\u4EE3\u8FD9\u4E9B\u5B9E\u4F53\u7684\u5E73\u94FA\u8BB0\u5FC6\u884C", kind: "bool" },
|
|
3706
3710
|
{ key: "maxRecallPerSession", label: "\u6BCF\u4F1A\u8BDD\u53BB\u91CD\u4E0A\u9650", hint: "recall \u6BCF\u4F1A\u8BDD\u6700\u591A\u4FDD\u7559 N \u6761\uFF08\u8DE8\u4F1A\u8BDD\u53BB\u91CD\uFF09", kind: "num", min: 1, max: 10 },
|
|
3707
3711
|
{ key: "expireDays", label: "TTL\uFF08\u5929\uFF09", hint: "0 = \u4E0D\u8FC7\u671F", kind: "num", min: 0, max: 3650 },
|
|
3708
3712
|
{ key: "indexMaxChars", label: "\u7D22\u5F15\u5B57\u7B26\u4E0A\u9650", hint: "[ENGRAM] \u5757 token \u9884\u7B97", kind: "num", min: 0, max: 4e3 }
|