dsh-hypatia-auto-memory 0.3.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 CHANGED
@@ -43,7 +43,8 @@ dsh plugin --profile web add dsh-hypatia-auto-memory
43
43
 
44
44
  Repeat for other profiles (desktop, dsh-tui). Restart the profile after install.
45
45
 
46
- The browser settings card is pre-built in `lib/client.js` and shipped with the
46
+ The browser half — the settings card and the conversation's Memory tab — is
47
+ pre-built in `lib/client.js` and shipped with the
47
48
  package. If you edit `src/client/*`, run `npm install && npm run build` in this
48
49
  directory to regenerate it; while `pnpm run dev:web` is active in the DSH
49
50
  checkout, client-plugin changes reload without a full page refresh.
@@ -253,6 +254,49 @@ agent/session-start ──▶ rules/taboos inject()
253
254
  in agent sessions — presets load disk skills in a nearer layer — so it is
254
255
  reported with its directory.
255
256
 
257
+ - **The conversation's Memory tab** is the read face of everything above. It sits
258
+ beside the **Chat** and **Trajectory** tabs (a `conversation.view` entry with
259
+ id `memory`, ordered after Trajectory) and shows, for the session it is bound
260
+ to, three things. **Status**: the logging and consolidation watermarks, the
261
+ pending token backlog, whether the `session-<id>` node exists, and any task
262
+ that exhausted its attempts together with the error that stopped it.
263
+ **Span summaries**: the `sum-<session>-<from>-<to>` entries consolidation
264
+ produced, with their archive tier. **Work units**: the `wu-*` entries derived
265
+ from those summaries, reached through the `derivedFrom` edges — their names are
266
+ content-addressed, so the edge is the only way to find them. Bodies render
267
+ through the shell's own `MarkdownText`, so a summary reads like assistant
268
+ Markdown elsewhere in the GUI.
269
+
270
+ Raw `msg-*` entries are deliberately **not** shown: they hold the conversation
271
+ verbatim, the reader just wrote them, and the agent is the right reader for
272
+ them.
273
+
274
+ The data arrives over a session-scoped, read-only HTTP route this plugin
275
+ registers on the DSH web server, `/api/dsh-hypatia-auto-memory/session`: status
276
+ from the in-memory state tables on every poll, the shelf content only when it
277
+ can have changed (on open, on a session switch, on a manual refresh, and when
278
+ consolidation advances the session's watermark), cached for 15 s in between.
279
+ Two channels were rejected on the way here. A **session projection** would be
280
+ the best shape, but the event that would drive it cannot be written from
281
+ outside this repository: `Session.append` offers no way to set the envelope's
282
+ `ignorable` marker, and the persistence read path refuses a session log
283
+ carrying an unknown event type without it — so a custom event would break
284
+ session reload. A **settings namespace** can be written safely but is
285
+ root-scoped: the Host cannot know which session the browser is showing, so it
286
+ would have to ship every session's data, and publishing means disposing and
287
+ re-creating the owning fiber, because `settings.register` refuses a duplicate
288
+ namespace and has no way to update a registered `base`.
289
+
290
+ The route is not one of the composed app's authenticated routes — a route a
291
+ plugin registers never is — so it authenticates itself the way
292
+ `dsh-hypatia-ui`'s does: the socket must be loopback, the `Host` must be a
293
+ loopback name (`localhost`, `127.x`, `[::1]`), and the request same-origin. A
294
+ browser tab on this page passes all three; a page on another origin fails the
295
+ last even from the same machine, and a DNS-rebound page fails the `Host` check.
296
+ `~/.dsh/storages/hypatia_auto_memory.json` and
297
+ `hypatia_auto_memory_diag.json` remain the durable record; the tab is a view of
298
+ the same facts, not a replacement for them.
299
+
256
300
  ## Configuration
257
301
 
258
302
  Settings namespace `hypatia-auto-memory` (edit `settings.yaml` or Web
@@ -350,19 +394,34 @@ changes. No card claims it, so it renders nowhere; nothing ever writes to it.
350
394
  ## Operations checklist
351
395
 
352
396
  1. After a turn ends, entries appear within seconds:
353
- `hypatia knowledge-get msg-<sessionId>-<n>` (`n` counts messages, from 0)
397
+ `hypatia knowledge-get msg-<sessionId>-<n>` (`n` counts messages, from 0).
398
+ The conversation's **Memory** tab answers the same question without a CLI,
399
+ and adds what the CLI cannot show: the watermarks themselves.
354
400
  2. Watermarks live in the state domain; failed tasks stay in the `tasks`
355
- table with their last error for inspection.
401
+ table with their last error for inspection. Both are what the Memory tab
402
+ reads; refresh it after changing the shelf, since the tab's snapshot is
403
+ keyed to the shelf this run is writing to.
356
404
  3. Restart mid-write is safe: messages already stored are skipped
357
405
  (get-before-create); uncovered ranges are re-enqueued from watermarks.
358
406
  4. To check the route warning: consolidation with no selected `models`
359
407
  logs a one-time warning and otherwise stays silent.
360
- 5. `hypatia backfill --status` reports the shelf's embedding debt. With a
408
+ 5. Which model a background call actually ran on is recorded per attempt in
409
+ `~/.dsh/storages/hypatia_auto_memory_diag.json` (`tables.model_calls`,
410
+ newest first by `seq`, bounded to 100). The settings list is not the answer:
411
+ one process-local cursor rotates through `consolidation.models` across every
412
+ span summary, adjudication and cascade call, so consecutive attempts
413
+ alternate. `outcome` is `pending` (in flight, or the process died mid-call),
414
+ `ok` (a usable result was produced), `incomplete` (the call settled without
415
+ one — output cap, abort, unparseable reply) or `error` (the call threw); in
416
+ the last two the cursor was consumed and nothing was stored. `detail` is a
417
+ finish kind, a fixed label, or the provider's message, capped at 200
418
+ characters — never message content and never model output.
419
+ 6. `hypatia backfill --status` reports the shelf's embedding debt. With a
361
420
  current hypatia, logging a turn adds nothing to it; only summaries and work
362
421
  units are pending until the next flush. `hypatia scope list --count` shows
363
422
  the scopes in use — the one this project's `msg-*` entries carry is the one
364
423
  the session seed reads.
365
- 6. Uninstall: `dsh plugin --profile web remove dsh-hypatia-auto-memory` —
424
+ 7. Uninstall: `dsh plugin --profile web remove dsh-hypatia-auto-memory` —
366
425
  hypatia entries themselves are left in `~/.hypatia/`.
367
426
 
368
427
  ## Failure modes
@@ -374,7 +433,7 @@ changes. No card claims it, so it renders nowhere; nothing ever writes to it.
374
433
  | Entries appear only after a turn finishes | By design: spans are cut at `turn/end`, or at the first `step/end` once a turn has run longer than `flushWindowMs`, so an entry never lacks its own tool results |
375
434
  | Logging works, no summaries | `consolidation.models` is empty or invalid — one warning at first trigger |
376
435
  | Summaries but no `sum2-*` | Fewer than `cascade.batchSize` unarchived tier-1 summaries in that project yet |
377
- | Work units have no relationships | No embedding model on the shelf (`similar` fails), or every candidate was beyond `dedupMaxDistance`. Since hypatia #19 the local model is looked up in `~/.hypatia/models/<org>/<name>` (or the Hugging Face cache), no longer beside the shelf: a shelf that used to answer `similar` and now says `is not installed` needs `hypatia model install <model>`, or `hypatia model register <model> <dir>` pointing at the files it already has |
436
+ | Work units have no relationships | No embedding model on the shelf (`similar` fails), every candidate was beyond `dedupMaxDistance`, or the adjudication call itself produced no verdict — `model_calls` shows that as `incomplete` / `max-tokens`, which is what a thinking-enabled route does when it spends the whole output budget on reasoning before answering. The call now asks a route for `reasoningEffort: 'off'` once the adapter advertises it, and carries a 1024-token cap for routes that cannot honour it. Since hypatia #19 the local model is looked up in `~/.hypatia/models/<org>/<name>` (or the Hugging Face cache), no longer beside the shelf: a shelf that used to answer `similar` and now says `is not installed` needs `hypatia model install <model>`, or `hypatia model register <model> <dir>` pointing at the files it already has |
378
437
  | `similar` still returns `msg-*` rows | They were written before this plugin opted the log layer out of embedding, or by a hypatia without `--no-embed`. Retract the knowledge vectors once with `embedding.skip_tags = ["message"]` in the shelf's `shelf.toml` followed by `hypatia backfill` (a binary older than the key refuses to open the shelf, so upgrade every binary sharing it first). Do not add `session` to that list: `skip_tags` matches any entry carrying the tag, and knowledge people write about sessions carries it too — one such entry lost its vector on the shelf this was tried on. The plugin's own `session-*` nodes are few and now opt out per write. Statements have no tags and no update command, so `belongTo` / `summary` edges written before keep their vectors |
379
438
  | Task in `deferred` state | Neither the live store nor persistence could supply its session. Not an error: it spends no attempts and runs as soon as one of them can. Normally storage answers immediately — the state persists only when `sessionPersistence` is absent from the composition, or its read failed (look for `could not be read` in the log) |
380
439
  | Task in `failed` state | A hypatia or model error persisted after `maxAttempts`. Failed `log-message` records are pruned at the next startup, since the watermark re-derives their range; other kinds are kept for inspection — delete one to let the next trigger re-create it |
@@ -386,6 +445,7 @@ changes. No card claims it, so it renders nowhere; nothing ever writes to it.
386
445
  | Duplicate `msg-*` after weird manual edits | Delete the entry in hypatia and lower `lastLoggedSeq` for that session in the state domain — backfill recreates it once |
387
446
  | The agent's own `hypatia` write still asks for approval | `autoApprove: false` (needs a profile reload to change), the command pipes/redirects/chains outside quotes, or its first word is not one of `binaries` — only plain calls are answered, by design. Reads never reach approval at all, so nothing to fix there |
388
447
  | The agent got a memory protocol that tells it to log messages by hand | Another plugin registered `hypatia-memory` first (`dsh-hypatia` still in the profile), or a `hypatia-memory` exists on disk — typically `~/.agents/skills/hypatia-memory`, written by `hypatia skill install --agent codex`. Agent presets load disk skills in a layer nearer than plugins, so it wins in sessions even though the skill center may list this plugin. Remove the copy the startup warning names |
448
+ | Can't tell which model actually ran | By design the choice rotates: one process-local cursor is shared by span summaries, adjudication and cascade, so consecutive calls alternate through `consolidation.models`. Each attempt lands in `~/.dsh/storages/hypatia_auto_memory_diag.json` (`model_calls`) with purpose, provider/model, outcome and duration. The usage ledger cannot answer this — it folds agent turns (`assistant/message`) and never sees a plugin's direct `llm.stream`. A `pending` row means the call is still in flight, or the process died mid-call: the row is written before the call and settled after it |
389
449
  | Startup warnings never appear in the terminal | `dsh web` mounts no log exporter, so plugin log lines of any level go nowhere; the console exporter's default threshold would also drop warnings (warn is level 2, above info's 1). Mount a logger such as `dsh-logbook` or `dsh-boot-doctor` temporarily to read them |
390
450
  | Project scope looks wrong | Scope = basename of the session cwd's git top level (`git rev-parse --show-toplevel`), or of the cwd itself when git finds no work tree or cannot answer (not installed, a repo it refuses as unsafe). A `rev-parse` slower than 3 s leaves that one session on the cwd's own name. Two same-named checkouts share a scope by design; a linked worktree is scoped by its own directory, not the main checkout's; git resolves symlinks, so a checkout opened through a link named differently from its target gets the target's name. A name hypatia would rewrite is normalized first: a session at `/` is scoped `/`, commas become `_`, surrounding whitespace goes. Entries written before these fixes stay where they were stored: a subdirectory session's under that directory's name (`repo/src` wrote under `src` — the git root was never read), a session at `/` with no scope, `a,b` under both `a` and `b`, `foo,` under `foo` and global. Padded names were stored trimmed, which is what the query now asks for. Nothing migrates them; `knowledge-update --scopes` moves one entry and keeps its `created_at`. `hypatia scope list --count` (hypatia #30) shows every spelling in use and how many entries each holds |
391
451
 
@@ -482,11 +542,12 @@ dsh-hypatia-auto-memory/
482
542
  │ ├── writer.js # idempotent get-before-create writes
483
543
  │ ├── consolidator.js # thresholds, prompt, llm.stream, validation
484
544
  │ ├── cascade.js # log₁₆(n) hierarchical summary archive
545
+ │ ├── model-log.js # bounded record of which model each attempt ran on
485
546
  │ ├── recall.js # rules/taboos preload at session start
486
547
  │ ├── auto-approve.js # approves the agent's own plain bash hypatia calls
487
548
  │ ├── skills.js # bundled skill registration (never shadows another provider)
488
549
  │ ├── status.js # counters + structured logging
489
- │ └── client/ # browser settings card
550
+ │ └── client/ # settings card + Memory tab
490
551
  │ ├── index.tsx # client plugin entry + slot registration
491
552
  │ ├── SettingsCard.tsx
492
553
  │ ├── shelves.ts # shelf dropdown choices from the inventory namespace
package/README.zh-CN.md CHANGED
@@ -38,9 +38,10 @@ dsh plugin --profile web add dsh-hypatia-auto-memory
38
38
 
39
39
  对其它 profile(desktop、dsh-tui)重复以上步骤。安装后重启 profile。
40
40
 
41
- 浏览器设置卡片预构建在 `lib/client.js` 中,随包发布。如果你改了 `src/client/*`,
42
- 在本目录运行 `npm install && npm run build` 重新生成它;当 DSH checkout 里
43
- `pnpm run dev:web` 处于运行状态时,client-plugin 的改动无需整页刷新即可热更新。
41
+ 浏览器半——设置卡片与会话里的记忆标签页——预构建在 `lib/client.js` 中,随包发布。如果
42
+ 你改了 `src/client/*`,在本目录运行 `npm install && npm run build` 重新生成它;当 DSH
43
+ checkout 里 `pnpm run dev:web` 处于运行状态时,client-plugin 的改动无需整页刷新即可
44
+ 热更新。
44
45
 
45
46
  **替换 `dsh-hypatia`:** 把它从 profile 移除并重启。
46
47
 
@@ -199,6 +200,36 @@ agent/session-start ──▶ rules/taboos inject()
199
200
  登记上去但在 Agent 会话里仍胜出——预设会在更近的一层加载磁盘技能——所以会连同目录
200
201
  一起报告。
201
202
 
203
+ - **会话里的「记忆」标签页**是上述一切的读取面。它和 **对话**、**轨迹** 并排(一个
204
+ `conversation.view` 注册项,id 为 `memory`,排序在轨迹之后),对当前会话显示三块
205
+ 内容。**状态**:记录水位、整合水位、待整合 token、`session-<id>` 节点是否存在,以及
206
+ 用尽重试次数的任务和拦住它的那条错误。**跨度摘要**:整合产出的
207
+ `sum-<session>-<from>-<to>` 条目及其归档层级。**工作单元**:由这些摘要派生的 `wu-*`
208
+ 条目——它们通过 `derivedFrom` 边找到,因为名字是内容寻址的,不携带会话信息。正文用
209
+ 外壳自带的 `MarkdownText` 渲染,所以摘要读起来和 GUI 里其它地方的助手 Markdown
210
+ 一致。
211
+
212
+ 原始 `msg-*` 条目**故意不显示**:它是对话原文,读的人刚刚写过,而正确的读者是
213
+ Agent。
214
+
215
+ 数据经由本插件注册在 DSH web 服务器上的、会话作用域的只读 HTTP 路由
216
+ `/api/dsh-hypatia-auto-memory/session` 到达浏览器:状态每次轮询都从内存中的状态表
217
+ 现算,shelf 内容只在可能变化时才读(打开时、切换会话时、手动刷新时,以及整合推进了
218
+ 该会话水位时),其间缓存 15 秒。路上否掉了两条通道。**session projection** 形态最
219
+ 合适,但驱动它的事件在本仓库之外写不出来:`Session.append` 没有任何途径设置信封的
220
+ `ignorable` 标记,而持久化读取路径会拒绝一个带着未知事件类型、又没有该标记的会话
221
+ 日志——所以自定义事件会破坏会话重载。**设置命名空间**能安全写入,但它是根作用域的:
222
+ 宿主无法知道浏览器正在看哪个会话,只能把每个会话的数据都发出去;而且发布意味着销毁
223
+ 并重建持有它的 fiber,因为 `settings.register` 拒绝重名命名空间,也没有任何途径更新
224
+ 已注册的 `base`。
225
+
226
+ 这条路由不属于组合应用自己那批已鉴权的路由——插件注册的路由从来都不是——所以它像
227
+ `dsh-hypatia-ui` 那样自鉴权:socket 必须是回环,`Host` 必须是回环名(`localhost`、
228
+ `127.x`、`[::1]`),请求必须同源。本页面里的浏览器标签三条都满足;另一来源的页面
229
+ 即便同机也会在最后一条上失败,DNS 重绑定的页面会在 `Host` 检查上失败。
230
+ `~/.dsh/storages/hypatia_auto_memory.json` 和 `hypatia_auto_memory_diag.json` 仍是
231
+ 持久记录;标签页是同一批事实的视图,不是它们的替代品。
232
+
202
233
  ## 配置
203
234
 
204
235
  设置命名空间 `hypatia-auto-memory`(编辑 `settings.yaml` 或 Web 设置;所有字段可选,
@@ -287,16 +318,28 @@ rules/taboos 预载、启动清理。设置卡片把它做成 `hypatia list` 所
287
318
  ## 运维清单
288
319
 
289
320
  1. 一个 turn 结束后,条目在几秒内出现:
290
- `hypatia knowledge-get msg-<sessionId>-<n>`(`n` 从 0 开始数消息)
291
- 2. 水位在 state domain 里;失败的任务连同最后一次错误留在 `tasks` 表里供检查。
321
+ `hypatia knowledge-get msg-<sessionId>-<n>`(`n` 从 0 开始数消息)。
322
+ 会话里的**记忆**标签页不用敲 CLI 就能回答同一个问题,并且能给出 CLI 看不到的东西:
323
+ 水位本身。
324
+ 2. 水位在 state domain 里;失败的任务连同最后一次错误留在 `tasks` 表里供检查。这两者
325
+ 就是记忆标签页读的内容;换过 shelf 后要刷新它,因为它读的快照对应本次运行正在写入
326
+ 的那个 shelf。
292
327
  3. 写入中途重启是安全的:已存储的消息被跳过(get-before-create);未覆盖的范围从
293
328
  水位重新排队。
294
329
  4. 检查路由告警:没选 `models` 的巩固只记录一次告警,其余时间静默。
295
- 5. `hypatia backfill --status` 报告 shelf 的嵌入债务。用当前的 hypatia,记录一个
330
+ 5. 后台调用实际用了哪个模型,逐次记在
331
+ `~/.dsh/storages/hypatia_auto_memory_diag.json`(`tables.model_calls`,按 `seq`
332
+ 倒序,上限 100 条)。设置卡片里的列表不是答案:一个进程内游标被 span 摘要、
333
+ 裁决和 cascade 三者共用,所以相邻几次调用是轮流换模型的。`outcome` 为
334
+ `pending`(在飞行中,或进程中途死了)、`ok`(产出了可用结果)、`incomplete`
335
+ (调用结束了但没产出——撞输出上限、被中止、回复解析不出来)或 `error`(调用本身
336
+ 抛错);后两种都消耗了游标且没有写入任何条目。`detail` 是 finish kind、固定标签
337
+ 或 provider 的错误消息,截断到 200 字符——绝不放消息正文,也绝不放模型输出。
338
+ 6. `hypatia backfill --status` 报告 shelf 的嵌入债务。用当前的 hypatia,记录一个
296
339
  turn 不会增加债务;只有摘要和工作单元在下一次 flush 前处于待处理。`hypatia scope
297
340
  list --count` 显示在用的 scope——本项目 `msg-*` 条目所带的那个,就是会话种子读取
298
341
  的那个。
299
- 6. 卸载:`dsh plugin --profile web remove dsh-hypatia-auto-memory`——hypatia 条目
342
+ 7. 卸载:`dsh plugin --profile web remove dsh-hypatia-auto-memory`——hypatia 条目
300
343
  本身留在 `~/.hypatia/`。
301
344
 
302
345
  ## 故障模式
@@ -308,7 +351,7 @@ rules/taboos 预载、启动清理。设置卡片把它做成 `hypatia list` 所
308
351
  | 条目只在 turn 结束后才出现 | 设计如此:span 在 `turn/end` 切分,或当 turn 跑得比 `flushWindowMs` 久时在第一个 `step/end` 切分,所以条目不会缺它自己的工具结果 |
309
352
  | 有记录,没摘要 | `consolidation.models` 为空或无效——首次触发时告警一次 |
310
353
  | 有摘要但没有 `sum2-*` | 该项目里未归档的 tier-1 摘要还不足 `cascade.batchSize` 条 |
311
- | 工作单元没有关系 | shelf 没有嵌入模型(`similar` 失败),或所有候选都超过了 `dedupMaxDistance`。自 hypatia #19 起,本地模型在 `~/.hypatia/models/<org>/<name>`(或 Hugging Face 缓存)里找,不再挨着 shelf:一个以前能回答 `similar`、现在说 `is not installed` 的 shelf,需要 `hypatia model install <model>`,或 `hypatia model register <model> <dir>` 指向它已有的文件 |
354
+ | 工作单元没有关系 | shelf 没有嵌入模型(`similar` 失败),所有候选都超过了 `dedupMaxDistance`,或裁决调用本身没有产出裁决——`model_calls` 里表现为 `incomplete` / `max-tokens`,也就是开启了思考的路由把整个输出预算花在推理上、还没开始作答就撞了上限。现在裁决会先确认适配器声明了 `off`,再对该路由请求 `reasoningEffort: 'off'`;对无法接受它的路由则把上限提到 1024。自 hypatia #19 起,本地模型在 `~/.hypatia/models/<org>/<name>`(或 Hugging Face 缓存)里找,不再挨着 shelf:一个以前能回答 `similar`、现在说 `is not installed` 的 shelf,需要 `hypatia model install <model>`,或 `hypatia model register <model> <dir>` 指向它已有的文件 |
312
355
  | `similar` 仍返回 `msg-*` 行 | 它们是在本插件让日志层退出嵌入之前写的,或由一个没有 `--no-embed` 的 hypatia 写的。在 shelf 的 `shelf.toml` 里用 `embedding.skip_tags = ["message"]` 加一次 `hypatia backfill` 一次性收回知识向量(比该 key 旧的二进制会拒绝打开 shelf,所以先升级所有共享它的二进制)。不要把 `session` 加进那个列表:`skip_tags` 匹配任何带该 tag 的条目,而人们写的关于会话的知识也带它——在试过的 shelf 上就有一条这样的条目丢了向量。插件自己的 `session-*` 节点很少,现在已逐次写入退出。三元组没有 tags 也没有 update 命令,所以之前写的 `belongTo` / `summary` 边保留向量 |
313
356
  | 任务处于 `deferred` 状态 | live store 和 persistence 都没能提供它的会话。不是错误:它不消耗尝试次数,一旦二者之一能提供就运行。通常 storage 立即回答——只有组合里没有 `sessionPersistence`,或它的读取失败(日志里找 `could not be read`)时才会持久化这个状态 |
314
357
  | 任务处于 `failed` 状态 | 一次 hypatia 或模型错误在 `maxAttempts` 之后持久化了。失败的 `log-message` 记录在下次启动时被修剪,因为水位会重新推导它们的范围;其它类型保留供检查——删掉一条好让下一个触发器重新创建它 |
@@ -320,6 +363,7 @@ rules/taboos 预载、启动清理。设置卡片把它做成 `hypatia list` 所
320
363
  | 手动乱改后出现重复 `msg-*` | 在 hypatia 里删掉该条目,并在 state domain 里把该会话的 `lastLoggedSeq` 调低——回填会重新创建它一次 |
321
364
  | Agent 自己的 `hypatia` 写入仍要审批 | `autoApprove: false`(改动需重载 profile)、命令在引号外有管道/重定向/串联、或首词不是 `binaries` 之一——按设计只回答纯调用。读取根本不会走到审批,所以那里没有要修的 |
322
365
  | Agent 拿到了一份教它手动记录消息的记忆协议 | 另一个插件先注册了 `hypatia-memory`(profile 里还有 `dsh-hypatia`),或磁盘上有 `hypatia-memory`——通常是 `hypatia skill install --agent codex` 写的 `~/.agents/skills/hypatia-memory`。Agent 预设会在比插件更近的一层加载磁盘技能,所以它在会话里胜出,尽管技能中心可能列出本插件。删掉启动告警指出的那份拷贝 |
366
+ | 不知道实际用了哪个模型 | 设计上就是轮流的:span 摘要、裁决、cascade 共用一个进程内游标,所以相邻调用在 `consolidation.models` 里交替。每次尝试都落在 `~/.dsh/storages/hypatia_auto_memory_diag.json`(`model_calls`),带 purpose、provider/model、outcome 和耗时。usage ledger 答不了这个问题——它只折算 Agent 的 turn(`assistant/message`),看不见插件直连的 `llm.stream`。`pending` 行表示调用仍在进行中,或进程在调用中途死了:记录在调用前先落盘、调用结束后回填 |
323
367
  | 启动告警从不出现在终端 | `dsh web` 不挂日志导出器,所以插件任何级别的日志行都没地方去;控制台导出器的默认阈值也会丢掉警告(warn 是 2 级,高于 info 的 1 级)。临时挂一个 logger,如 `dsh-logbook` 或 `dsh-boot-doctor` 来读它们 |
324
368
  | 项目 scope 看起来不对 | Scope = 会话 cwd 的 git 顶层目录的 basename(`git rev-parse --show-toplevel`);git 找不到工作树或答不上(未安装、或某 repo 被判定不安全)时,则是 cwd 本身的 basename。一次慢于 3 秒的 `rev-parse` 会让那个会话留在 cwd 自己的名字上。两个同名 checkout 按设计共享 scope;linked worktree 按它自己的目录而非主 checkout 的目录定 scope;git 会解析符号链接,所以通过一个与目标不同名的链接打开的 checkout 会得到目标的名字。一个会被 hypatia 改写的名字会先归一化:位于 `/` 的会话定 scope 为 `/`,逗号变 `_`,去掉首尾空白。这些修复之前写的条目留在原处:子目录会话写在那个目录名下(`repo/src` 写在 `src` 下——git 根从未被读取)、位于 `/` 的会话无 scope、`a,b` 同时写在 `a` 和 `b` 下、`foo,` 写在 `foo` 和全局下。带空白的名字被去空白存储,这也正是查询现在所请求的。没有任何东西迁移它们;`knowledge-update --scopes` 可移动单条并保留其 `created_at`。`hypatia scope list --count`(hypatia #30)显示每种在用的拼写及其条目数 |
325
369
 
@@ -394,11 +438,12 @@ dsh-hypatia-auto-memory/
394
438
  │ ├── writer.js # 幂等 get-before-create 写入
395
439
  │ ├── consolidator.js # 阈值、prompt、llm.stream、校验
396
440
  │ ├── cascade.js # log₁₆(n) 分层摘要归档
441
+ │ ├── model-log.js # 每次尝试实际用了哪个模型的有界记录
397
442
  │ ├── recall.js # 会话启动时的 rules/taboos 预载
398
443
  │ ├── auto-approve.js # 批准 Agent 自己的纯 bash hypatia 调用
399
444
  │ ├── skills.js # 随包技能注册(从不遮蔽其它提供者)
400
445
  │ ├── status.js # 计数器 + 结构化日志
401
- │ └── client/ # 浏览器设置卡片
446
+ │ └── client/ # 设置卡片 + 记忆标签页
402
447
  │ ├── index.tsx # client 插件入口 + slot 注册
403
448
  │ ├── SettingsCard.tsx
404
449
  │ ├── shelves.ts # 来自清单命名空间的 shelf 下拉选项