dsh-hypatia-auto-memory 1.1.1 → 2.0.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
@@ -205,6 +205,16 @@ agent/created ──▶ rules/taboos inject()
205
205
  long. Cascade is the exception: it keeps thinking (it is compressing sixteen
206
206
  summaries, not filling a shape) and pays for it in the same allowance.
207
207
 
208
+ A route's `reasoningEffort` overrides all of that. Set it to a level the model
209
+ declares and every call on that route is sent that level — the allowance
210
+ follows, because anything other than `off` shares the cap with the answer. The
211
+ vocabulary is the adapter's own (the settings card offers exactly what the
212
+ model declares: `off`, `low`, `high`, `max` on `llm-deepseek`), and a value the
213
+ route does not declare is **dropped with one warning** rather than sent: the
214
+ core rejects an undeclared effort before any provider I/O, so sending it would
215
+ turn a profile typo into a task that retries and then fails permanently. Leave
216
+ the field out to keep the per-purpose policy above.
217
+
208
218
  - **Cascade** archives sixteen unarchived tier-N summaries into one tier-(N+1)
209
219
  entry, using hypatia's own `$not-summaried` (which anti-joins on
210
220
  `statement.tail` and orders `created_at ASC`, giving FIFO batching for free).
@@ -357,7 +367,26 @@ takes whichever seat exists and moves between them without ever appearing twice
357
367
  save, without a profile reload. Stored as the plugin entry's `config:` in the
358
368
  profile patch; a pre-0.1.7 `settings.yaml` section is imported once on first
359
369
  launch. All fields optional, defaults shown. A blank consolidation route is
360
- refused on save; a duplicate one is dropped at runtime with a warning:
370
+ refused on save; a duplicate one is dropped at runtime with a warning.
371
+
372
+ **`consolidation.models` is a priority order, not a rotation.** A task's first
373
+ attempt takes the first route, and each retry degrades to the next one, reusing
374
+ the last route past the end. Two consequences are worth knowing: the chain a
375
+ task can reach is `min(queue.maxAttempts, models.length)` long — with the
376
+ default `maxAttempts: 3` a fourth and later route is never used — and each
377
+ downgrade costs one `queue.retryDelayMs` (5 s), because it happens on a retry
378
+ rather than inside one attempt. This replaced a round-robin that used every
379
+ selected route regardless of preference; reorder the list, or use the card's
380
+ ↑/↓ buttons, to change which route is preferred.
381
+
382
+ **Each route may also set a thinking level.** `reasoningEffort` names an
383
+ adapter-owned level — the settings card offers exactly what the model declares,
384
+ which on `llm-deepseek` is `off`/`low`/`high`/`max`. Omitting it keeps the
385
+ per-purpose policy described under *Consolidator* above; setting it overrides
386
+ that policy for every call on that route, and the output cap grows to pay for
387
+ it. A level the model does not declare is dropped at call time with one warning
388
+ instead of being sent, because the core rejects an undeclared effort before any
389
+ provider I/O.
361
390
 
362
391
  ```yaml
363
392
  hypatia-auto-memory:
@@ -373,8 +402,12 @@ hypatia-auto-memory:
373
402
  toolLedger: false # off by default; true records a compact tool-call ledger
374
403
  consolidation:
375
404
  enabled: true
376
- # Each attempt, including a retry, rotates to the next selected route.
405
+ # PRIORITY order: every consolidation tries the first route, and a retry
406
+ # degrades to the next one (see the note above).
377
407
  models: [] # select one or more { provider, model } routes
408
+ # Each route may also carry `reasoningEffort: <level>` — a thinking level the
409
+ # card offers from what the model declares (off/low/high/max on deepseek).
410
+ # Omit it to keep the per-purpose policy.
378
411
  maxInputTokens: 16000 # transcript cap (chars/4 estimate)
379
412
  maxOutputTokens: 2000
380
413
  timeoutMs: 120000
@@ -389,8 +422,8 @@ hypatia-auto-memory:
389
422
  batchSize: 16 # entries per tier before archiving one tier up
390
423
  queue:
391
424
  concurrency: 1 # parallel sessions
392
- maxAttempts: 3
393
- retryDelayMs: 5000
425
+ maxAttempts: 3 # retries per task; also caps the model fallback chain
426
+ retryDelayMs: 5000 # and the delay before the next route is tried
394
427
  # NOT a batching knob. Spans are cut at turn/end; for a turn still running
395
428
  # this long, the next step/end flushes what is complete so far.
396
429
  flushWindowMs: 120000
@@ -474,14 +507,19 @@ now only projects plugin Config forms.)
474
507
  5. Which model a background call actually ran on is recorded per attempt in
475
508
  `~/.dsh/storages/hypatia_auto_memory_diag.json` (`tables.model_calls`,
476
509
  newest first by `seq`, bounded to 100). The settings list is not the answer:
477
- one process-local cursor rotates through `consolidation.models` across every
478
- span summary, adjudication and cascade call, so consecutive attempts
479
- alternate. `outcome` is `pending` (in flight, or the process died mid-call),
480
- `ok` (a usable result was produced), `incomplete` (the call settled without
481
- one — output cap, abort, unparseable reply) or `error` (the call threw); in
482
- the last two the cursor was consumed and nothing was stored. `detail` is a
483
- finish kind, a fixed label, or the provider's message, capped at 200
484
- characters — never message content and never model output.
510
+ `consolidation.models` is a priority order, and one task's rows walk it —
511
+ the first attempt names the head, a retry names the next route down, which
512
+ is how a fallback is confirmed to have happened. `effort` is what the call
513
+ actually SENT, which is not the configured value when the route refused it;
514
+ `outputTokens` / `reasoningTokens` are the route's own usage report, and they
515
+ are what says whether the cap went to the answer or to the reasoning (both 0
516
+ when the route reports no usage). `outcome` is `pending` (in flight, or the
517
+ process died mid-call), `ok` (a usable result was produced), `incomplete`
518
+ (the call settled without one — output cap, abort, unparseable reply) or
519
+ `error` (the call threw); in the last two the attempt was spent and nothing
520
+ was stored. `detail` is a finish kind, a fixed label, or the provider's
521
+ message, capped at 200 characters — never message content and never model
522
+ output.
485
523
  6. `hypatia backfill --status` reports the shelf's embedding debt. With a
486
524
  current hypatia, logging a turn adds nothing to it; only summaries and work
487
525
  units are pending until the next flush. `hypatia scope list --count` shows
@@ -500,7 +538,7 @@ now only projects plugin Config forms.)
500
538
  | 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 |
501
539
  | Logging works, no summaries | `consolidation.models` is empty or invalid — one warning at first trigger |
502
540
  | Summaries but no `sum2-*` | Fewer than `cascade.batchSize` unarchived tier-1 summaries in that project yet |
503
- | 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 |
541
+ | 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 — a route whose `reasoningEffort` names a real level instead gets that 1024 plus the thinking allowance. 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 |
504
542
  | `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 |
505
543
  | 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). A deferred consolidation is re-queued by the next startup's backfill, so it does not wait for its session to be opened again |
506
544
  | 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 |
@@ -512,7 +550,8 @@ now only projects plugin Config forms.)
512
550
  | 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 |
513
551
  | The agent's own `hypatia` write still asks for approval | `autoApprove: false`, 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 |
514
552
  | 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 |
515
- | 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 |
553
+ | Can't tell which model actually ran | The list is a priority order, so a task's first attempt names the head of `consolidation.models` and a retry names the route it degraded to. Each attempt lands in `~/.dsh/storages/hypatia_auto_memory_diag.json` (`model_calls`) with purpose, provider/model, the `effort` actually sent, outcome, duration and the route's own token split — reading one task's rows top-down is how a fallback is confirmed, and `effort` is how a configured thinking level is confirmed to have been honoured. 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 |
554
+ | A configured `reasoningEffort` seems to do nothing | The route does not declare that level, so the call drops it rather than risk the core's `UNSUPPORTED_REASONING_EFFORT`. One warning names the route, the value and what the route does declare; `model_calls.effort` then reads empty for those attempts. The card offers exactly the levels the model advertises, so this normally only happens after editing the profile by hand or pointing the route at a different model |
516
555
  | 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 |
517
556
  | 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 |
518
557
 
package/README.zh-CN.md CHANGED
@@ -163,6 +163,13 @@ agent/created ──▶ rules/taboos inject()
163
163
  正是工作单元让回复变长。Cascade 是例外:它保留 thinking(它是在压缩十六条摘要,不是
164
164
  在填一个形状),并用同一份余量来支付。
165
165
 
166
+ 路由上的 `reasoningEffort` 覆盖以上全部策略。把它设成该模型声明过的档位,这条路由上的
167
+ 每次调用都会带上它,预算余量也随之生效(任何非 `off` 的档位都与正文共用上限)。档位
168
+ 词表属于适配器自己(设置卡片只列出该模型声明的档位:`llm-deepseek` 上是
169
+ `off`/`low`/`high`/`max`);而**路由没有声明的值会被丢弃并记一条警告**,不会发出去——
170
+ 核心会在任何 provider I/O 之前拒绝未声明的档位,发出去等于把一处配置笔误变成反复重试
171
+ 后永久失败的任务。留空即保持上面的按用途策略。
172
+
166
173
  - **Cascade** 把十六个未归档的 tier-N 摘要归档为一条 tier-(N+1) 条目,用 hypatia 自带
167
174
  的 `$not-summaried`(它对 `statement.tail` 做反连接并按 `created_at ASC` 排序,
168
175
  免费得到 FIFO 分批)。这就是协议的 log₁₆(n) 归档:每一层只压缩上一层已经蒸馏过的
@@ -273,7 +280,20 @@ agent/created ──▶ rules/taboos inject()
273
280
  下面每个字段保存即生效,无需重载 profile。配置以插件条目 `config:`
274
281
  的形式存进 profile patch;0.1.7 之前的 `settings.yaml` 段落会在首次启动时被一次性导入。
275
282
  所有字段可选,展示的是默认值。空白的巩固路由在保存时就被拒绝;重复的路由在运行时被丢弃
276
- 并记一条警告:
283
+ 并记一条警告。
284
+
285
+ **`consolidation.models` 是优先级顺序,不是轮换。** 一个任务的第一次尝试走第一条路由,
286
+ 之后每次重试降级到下一条,超出列表长度时复用最后一条。两个需要知道的后果:一个任务能触达
287
+ 的备选链长度是 `min(queue.maxAttempts, models.length)`——默认 `maxAttempts: 3` 时第四条
288
+ 及以后的路由永远不会被用到;而每降一级要等一个 `queue.retryDelayMs`(5 秒),因为降级发生
289
+ 在下一次重试,而不是同一次尝试内部。这是对原先「不管偏好、把所有已选路由轮流用完」的替换;
290
+ 改变偏好就重排列表,或直接用卡片上的 ↑/↓ 按钮。
291
+
292
+ **每条路由还可以设置思考程度。** `reasoningEffort` 取一个适配器私有的档位——设置卡片只
293
+ 列出该模型声明的那些,`llm-deepseek` 上是 `off`/`low`/`high`/`max`。留空即保持上文
294
+ *Consolidator* 里那套按用途策略;设了它就会覆盖该路由上所有调用的策略,输出上限也随之
295
+ 变大来支付这份思考。模型没有声明的档位会在调用时被丢弃并记一条警告,而不是发出去——核心
296
+ 会在任何 provider I/O 之前拒绝未声明的档位。
277
297
 
278
298
  ```yaml
279
299
  hypatia-auto-memory:
@@ -289,8 +309,10 @@ hypatia-auto-memory:
289
309
  toolLedger: false # 默认不写工具调用台账;true 才为有内容的助手消息记录
290
310
  consolidation:
291
311
  enabled: true
292
- # 每次尝试(含重试)轮换到下一条已选路由。
312
+ # 优先级顺序:每次整合先用第一条路由,重试才降级到下一条(见上文说明)。
293
313
  models: [] # 选择一条或多条 { provider, model } 路由
314
+ # 每条路由还可以带 `reasoningEffort: <档位>`——卡片只列出该模型声明的档位
315
+ # (deepseek 上是 off/low/high/max)。留空即保持按用途策略。
294
316
  maxInputTokens: 16000 # transcript 上限(chars/4 估算)
295
317
  maxOutputTokens: 2000
296
318
  timeoutMs: 120000
@@ -305,8 +327,8 @@ hypatia-auto-memory:
305
327
  batchSize: 16 # 归档上一层之前,每层的条目数
306
328
  queue:
307
329
  concurrency: 1 # 并行会话数
308
- maxAttempts: 3
309
- retryDelayMs: 5000
330
+ maxAttempts: 3 # 每个任务的重试次数;同时决定模型备选链能走多深
331
+ retryDelayMs: 5000 # 也是换到下一条路由前的等待时间
310
332
  # 不是分批旋钮。span 在 turn/end 切分;对一个跑这么久的 turn,
311
333
  # 下一个 step/end 会把已完成的部分刷出。
312
334
  flushWindowMs: 120000
@@ -374,12 +396,16 @@ shelf 清单本来就不是配置,而设置域现在只投影插件的 Config
374
396
  4. 检查路由告警:没选 `models` 的巩固只记录一次告警,其余时间静默。
375
397
  5. 后台调用实际用了哪个模型,逐次记在
376
398
  `~/.dsh/storages/hypatia_auto_memory_diag.json`(`tables.model_calls`,按 `seq`
377
- 倒序,上限 100 条)。设置卡片里的列表不是答案:一个进程内游标被 span 摘要、
378
- 裁决和 cascade 三者共用,所以相邻几次调用是轮流换模型的。`outcome` 为
379
- `pending`(在飞行中,或进程中途死了)、`ok`(产出了可用结果)、`incomplete`
380
- (调用结束了但没产出——撞输出上限、被中止、回复解析不出来)或 `error`(调用本身
381
- 抛错);后两种都消耗了游标且没有写入任何条目。`detail` 是 finish kind、固定标签
382
- 或 provider 的错误消息,截断到 200 字符——绝不放消息正文,也绝不放模型输出。
399
+ 倒序,上限 100 条)。设置卡片里的列表不是答案:`consolidation.models` 是优先级顺序,
400
+ 同一个任务的几行会沿它往下走——第一次尝试是队首那条,重试是降级后的下一条,这也正是
401
+ 确认「备选确实被用上了」的方式。`effort` 是这次调用**实际发出**的档位——路由拒绝了
402
+ 配置值时它就不是配置值;`outputTokens` / `reasoningTokens` 来自路由自己上报的用量,
403
+ 它们才说明输出上限是被正文吃掉的还是被推理吃掉的(路由不上报用量时两者都是 0)。
404
+ `outcome` 为 `pending`(在飞行中,或进程中途死了)、
405
+ `ok`(产出了可用结果)、`incomplete`(调用结束了但没产出——撞输出上限、被中止、回复
406
+ 解析不出来)或 `error`(调用本身抛错);后两种都花掉了一次尝试且没有写入任何条目。
407
+ `detail` 是 finish kind、固定标签或 provider 的错误消息,截断到 200 字符——绝不放消息
408
+ 正文,也绝不放模型输出。
383
409
  6. `hypatia backfill --status` 报告 shelf 的嵌入债务。用当前的 hypatia,记录一个
384
410
  turn 不会增加债务;只有摘要和工作单元在下一次 flush 前处于待处理。`hypatia scope
385
411
  list --count` 显示在用的 scope——本项目 `msg-*` 条目所带的那个,就是会话种子读取
@@ -397,7 +423,7 @@ shelf 清单本来就不是配置,而设置域现在只投影插件的 Config
397
423
  | 条目只在 turn 结束后才出现 | 设计如此:span 在 `turn/end` 切分,或当 turn 跑得比 `flushWindowMs` 久时在第一个 `step/end` 切分,所以条目不会缺它自己的工具结果 |
398
424
  | 有记录,没摘要 | `consolidation.models` 为空或无效——首次触发时告警一次 |
399
425
  | 有摘要但没有 `sum2-*` | 该项目里未归档的 tier-1 摘要还不足 `cascade.batchSize` 条 |
400
- | 工作单元没有关系 | 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>` 指向它已有的文件 |
426
+ | 工作单元没有关系 | shelf 没有嵌入模型(`similar` 失败),所有候选都超过了 `dedupMaxDistance`,或裁决调用本身没有产出裁决——`model_calls` 里表现为 `incomplete` / `max-tokens`,也就是开启了思考的路由把整个输出预算花在推理上、还没开始作答就撞了上限。现在裁决会先确认适配器声明了 `off`,再对该路由请求 `reasoningEffort: 'off'`;对无法接受它的路由则把上限提到 1024——而路由的 `reasoningEffort` 若指定了真实档位,拿到的就是这 1024 再加上思考余量。自 hypatia #19 起,本地模型在 `~/.hypatia/models/<org>/<name>`(或 Hugging Face 缓存)里找,不再挨着 shelf:一个以前能回答 `similar`、现在说 `is not installed` 的 shelf,需要 `hypatia model install <model>`,或 `hypatia model register <model> <dir>` 指向它已有的文件 |
401
427
  | `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` 边保留向量 |
402
428
  | 任务处于 `deferred` 状态 | live store 和 persistence 都没能提供它的会话。不是错误:它不消耗尝试次数,一旦二者之一能提供就运行。通常 storage 立即回答——只有组合里没有 `sessionPersistence`,或它的读取失败(日志里找 `could not be read`)时才会持久化这个状态。被 deferred 的巩固任务会在下次启动时被 backfill 重新入队,所以它不必等会话被重新打开 |
403
429
  | 任务处于 `failed` 状态 | 一次 hypatia 或模型错误在 `maxAttempts` 之后持久化了。失败的 `log-message` 记录在下次启动时被修剪,因为水位会重新推导它们的范围;其它类型保留供检查——删掉一条好让下一个触发器重新创建它 |
@@ -409,7 +435,8 @@ shelf 清单本来就不是配置,而设置域现在只投影插件的 Config
409
435
  | 手动乱改后出现重复 `msg-*` | 在 hypatia 里删掉该条目,并在 state domain 里把该会话的 `lastLoggedSeq` 调低——回填会重新创建它一次 |
410
436
  | Agent 自己的 `hypatia` 写入仍要审批 | `autoApprove: false`、命令在引号外有管道/重定向/串联、或首词不是 `binaries` 之一——按设计只回答纯调用。读取根本不会走到审批,所以那里没有要修的 |
411
437
  | Agent 拿到了一份教它手动记录消息的记忆协议 | 另一个插件先注册了 `hypatia-memory`(profile 里还有 `dsh-hypatia`),或磁盘上有 `hypatia-memory`——通常是 `hypatia skill install --agent codex` 写的 `~/.agents/skills/hypatia-memory`。Agent 预设会在比插件更近的一层加载磁盘技能,所以它在会话里胜出,尽管技能中心可能列出本插件。删掉启动告警指出的那份拷贝 |
412
- | 不知道实际用了哪个模型 | 设计上就是轮流的: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` 行表示调用仍在进行中,或进程在调用中途死了:记录在调用前先落盘、调用结束后回填 |
438
+ | 不知道实际用了哪个模型 | 列表是优先级顺序:一个任务的第一次尝试就是 `consolidation.models` 的队首,重试则是它降级到的那条。每次尝试都落在 `~/.dsh/storages/hypatia_auto_memory_diag.json`(`model_calls`),带 purpose、provider/model、**实际发出的 `effort`**、outcome、耗时以及路由自己上报的 token 拆分——把同一个任务的几行按序读下来,就能确认备选确实被用上了,而 `effort` 是确认配置的思考档位真的生效了的依据。usage ledger 答不了这个问题——它只折算 Agent 的 turn(`assistant/message`),看不见插件直连的 `llm.stream`。`pending` 行表示调用仍在进行中,或进程在调用中途死了:记录在调用前先落盘、调用结束后回填 |
439
+ | 配了 `reasoningEffort` 却像没生效 | 该路由没有声明这个档位,于是调用把它丢掉了,以免撞上核心的 `UNSUPPORTED_REASONING_EFFORT`。会有一条警告点名路由、值和该路由实际声明的档位,此后这些尝试的 `model_calls.effort` 是空的。卡片只提供模型声明的档位,所以这通常只发生在手改 profile、或把这条路由换成了别的模型之后 |
413
440
  | 启动告警从不出现在终端 | `dsh web` 不挂日志导出器,所以插件任何级别的日志行都没地方去;控制台导出器的默认阈值也会丢掉警告(warn 是 2 级,高于 info 的 1 级)。临时挂一个 logger,如 `dsh-logbook` 或 `dsh-boot-doctor` 来读它们 |
414
441
  | 项目 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)显示每种在用的拼写及其条目数 |
415
442