@zooique/memora 5.1.0 → 5.3.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +107 -4
  2. package/README.en.md +6 -2
  3. package/README.md +6 -2
  4. package/dist/agent/agent.d.ts +42 -2
  5. package/dist/agent/agent.d.ts.map +1 -1
  6. package/dist/agent/agent.js +61 -3
  7. package/dist/agent/agent.js.map +1 -1
  8. package/dist/agent/assembler.d.ts.map +1 -1
  9. package/dist/agent/assembler.js +7 -0
  10. package/dist/agent/assembler.js.map +1 -1
  11. package/dist/agent/constants.d.ts +49 -0
  12. package/dist/agent/constants.d.ts.map +1 -1
  13. package/dist/agent/constants.js +49 -0
  14. package/dist/agent/constants.js.map +1 -1
  15. package/dist/agent/contextManager.d.ts +31 -3
  16. package/dist/agent/contextManager.d.ts.map +1 -1
  17. package/dist/agent/contextManager.js +39 -2
  18. package/dist/agent/contextManager.js.map +1 -1
  19. package/dist/agent/loop.d.ts +14 -7
  20. package/dist/agent/loop.d.ts.map +1 -1
  21. package/dist/agent/loop.js +43 -18
  22. package/dist/agent/loop.js.map +1 -1
  23. package/dist/agent/managers/llmCaller.d.ts.map +1 -1
  24. package/dist/agent/managers/llmCaller.js +14 -1
  25. package/dist/agent/managers/llmCaller.js.map +1 -1
  26. package/dist/agent/managers/sessionManager.d.ts.map +1 -1
  27. package/dist/agent/managers/sessionManager.js +1 -0
  28. package/dist/agent/managers/sessionManager.js.map +1 -1
  29. package/dist/agent/managers/toolCallHelpers.d.ts.map +1 -1
  30. package/dist/agent/managers/toolCallHelpers.js +3 -0
  31. package/dist/agent/managers/toolCallHelpers.js.map +1 -1
  32. package/dist/agent/messageHistory.d.ts +86 -16
  33. package/dist/agent/messageHistory.d.ts.map +1 -1
  34. package/dist/agent/messageHistory.js +203 -65
  35. package/dist/agent/messageHistory.js.map +1 -1
  36. package/dist/agent/seed/orchestrator.d.ts +2 -1
  37. package/dist/agent/seed/orchestrator.d.ts.map +1 -1
  38. package/dist/agent/seed/orchestrator.js +48 -17
  39. package/dist/agent/seed/orchestrator.js.map +1 -1
  40. package/dist/agent/seed/prepare.d.ts +3 -1
  41. package/dist/agent/seed/prepare.d.ts.map +1 -1
  42. package/dist/agent/seed/prepare.js +10 -2
  43. package/dist/agent/seed/prepare.js.map +1 -1
  44. package/dist/agent/sessionStateMachine.d.ts +3 -0
  45. package/dist/agent/sessionStateMachine.d.ts.map +1 -1
  46. package/dist/agent/sessionStateMachine.js.map +1 -1
  47. package/dist/agent/textSanitize.d.ts +1 -1
  48. package/dist/agent/textSanitize.js +1 -1
  49. package/dist/agent/types.d.ts +9 -0
  50. package/dist/agent/types.d.ts.map +1 -1
  51. package/dist/index.d.ts +4 -2
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +11 -4
  54. package/dist/index.js.map +1 -1
  55. package/dist/llm/factory.d.ts +21 -0
  56. package/dist/llm/factory.d.ts.map +1 -1
  57. package/dist/llm/factory.js +4 -1
  58. package/dist/llm/factory.js.map +1 -1
  59. package/dist/llm/openaiCompatible.d.ts +8 -1
  60. package/dist/llm/openaiCompatible.d.ts.map +1 -1
  61. package/dist/llm/openaiCompatible.js +26 -0
  62. package/dist/llm/openaiCompatible.js.map +1 -1
  63. package/dist/llm/provider.d.ts +65 -0
  64. package/dist/llm/provider.d.ts.map +1 -1
  65. package/dist/llm/provider.js +10 -0
  66. package/dist/llm/provider.js.map +1 -1
  67. package/dist/memory/gcService.d.ts +8 -4
  68. package/dist/memory/gcService.d.ts.map +1 -1
  69. package/dist/memory/gcService.js.map +1 -1
  70. package/dist/memory/inMemoryRoundStore.d.ts +8 -3
  71. package/dist/memory/inMemoryRoundStore.d.ts.map +1 -1
  72. package/dist/memory/inMemoryRoundStore.js +19 -10
  73. package/dist/memory/inMemoryRoundStore.js.map +1 -1
  74. package/dist/memory/inMemorySessionStore.d.ts.map +1 -1
  75. package/dist/memory/inMemorySessionStore.js +11 -0
  76. package/dist/memory/inMemorySessionStore.js.map +1 -1
  77. package/dist/memory/roundStore.d.ts +84 -11
  78. package/dist/memory/roundStore.d.ts.map +1 -1
  79. package/dist/memory/roundStore.js +18 -0
  80. package/dist/memory/roundStore.js.map +1 -1
  81. package/dist/memory/sessionStore.d.ts +8 -0
  82. package/dist/memory/sessionStore.d.ts.map +1 -1
  83. package/dist/memory/sessionStore.js.map +1 -1
  84. package/dist/utils/time.d.ts +24 -4
  85. package/dist/utils/time.d.ts.map +1 -1
  86. package/dist/utils/time.js +32 -4
  87. package/dist/utils/time.js.map +1 -1
  88. package/docs/memora-api-reference.md +14 -4
  89. package/docs/memora-/346/216/245/345/205/245/346/214/207/345/215/227.md +45 -17
  90. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -8,10 +8,53 @@
8
8
  >
9
9
  > 本文件 2026-10-19 起按 `CHLOG-TRIM-1` 精简:只记「改了什么 + 为什么 + 对消费者的影响」;逐批拍板过程、变异验证收据、台账叙事的 SSOT 在仓库台账 `tasks/待完成任务.md` 对应 ID 条目(npm 包不含),此处只留 ID 锚保交叉引用。
10
10
 
11
+ ## [5.3.0] · 2026-10-31
12
+
13
+ ### Added(内核)
14
+
15
+ - **`Agent.currentRoundId()`**(`INTERRUPT-SETTLE-1`):读当前在途轮次 id(`''` = 无在途轮),与 loop 层同源同值、不缓存副本。**为什么**:`TurnState.waiting` 投影**不含** roundId(ask 挂起时轮身份从快照里消失),而 ask 期停止收场需要轮身份做归属(折叠区归属 / 容器底栏时间与复制/分叉/删除 / 分叉锚点);缺它时宿主 `settleRoundFooter` 首行 `if (!roundId) return` 直接早退,中断轮底栏整块不出现(真机 2026-10-31 实证)。**对消费者**:纯新增成员,零既有签名变更、零行为变化;放弃动作走独立的 `abandonTurn()` 读口(见下),轮身份与放弃结果互不耦合、两个读口各管一件事。
16
+
17
+ - **`Agent.abandonTurn()`**(`TURN-EXISTENCE-1` · ADR-044 二/三刀):主动放弃当前在途轮的单点原语——① `cancelAsk()` 取消在途提问(只动进程内 `pendingAsk`,保 tool 配对不变量);② `appendInterrupted` 中断收场落盘(盘面得一条诚实的中断记录,失败降级告警不抛);③ 清当前暂停检查点并以结果作 `boolean` 返回(宿主据此提示「检查点已清理」;无检查点返回 `false`)。**为什么**:停止一个停在 ask / 长循环的轮此前没有内核原语,「放弃」语义散在宿主各处。**对消费者**:纯新增成员,零既有签名变更、零删除。
18
+ - **导出 `isRoundSuccessful`**(`METRICS-OWNER-1` 缓冲 · `INTERRUPT-SETTLE-1` 顺手修):「轮是否成功收场」判据单点(盘面 `status === 'complete'` 投影),与既有 `isRoundSettled` 同文件同族挂出。**为什么**:宿主 `metrics.success` 原为宿主私有口径(`!aborted && !paused`),会把内核 failed 收场(盘面 `interrupted`)误标成功;判据收口内核后宿主不再自写状态比较。**对消费者**:需要「成功/失败」口径的面直接消费该函数,勿再自写 `status` 比较(与 `isRoundSettled` 同一条禁令)。
19
+ - **导出 `isWithinLocalDay`**(`E2E-TZ-SALVAGE-1`):本地日期 ↔ UTC 时间戳换算判据单点(本地日区间 `[D 00:00, D+1 00:00)` → UTC 比较)。**为什么**:会话 ID 用本地日期、轮 `createdAt` 用 UTC 的双口径换算此前内核与宿主各写一份(宿主那份写错即漏打捞,见 Fixed)。**对消费者**:任何「按本地日过滤 UTC 时间戳」的面复用同一函数,不另立换算。
20
+ - **`AskQuestion` 增可选 `askCallId`**(`ASK-BATCH-IDENTITY-1` · ADR-043):多问批次每题的身份 = 对应 `ask_user` 工具调用 id,由 `parseAskCalls` 按序单点填入(第 i 题 ↔ 第 i 个 toolCallId,与 `pendingAsk.toolCallIds` 同序同源,零新增状态),并随 `onPendingQuestion` / `question_pending` chunk / `takeAnsweredAsk` 快照贯通到落盘链路。**为什么**:运行时行 id(宿主自造)与盘面行 id(内核装配)两个产地、永不相遇,「实时行-重放行」配对只靠时序巧合。**对消费者**:纯新增可选字段,零既有签名变更;不做身份配对者可忽略。
21
+
22
+ ### Fixed(内核)
23
+
24
+ - **ask_user 整批空问题不再挂起**(`ASK-QGUARD-1`):`question` 空 / 纯空白的整批调用此前照常挂起等用户作答,只能干等 ask 超时(默认 30 分钟)。现整批空当场拒收:以明确错误回喂 tool result,让模型同轮重问。不变量保持:整批逐条回填 tool 消息(配对不变量不破);`askCountThisTurn` 不计未发出的提问(askLimit 语义是防打扰,空问题不构成打扰)。**对消费者**:行为变更——全空批次立即收到错误而非静默等待;含至少一个非空问题的混合批仍正常挂起(混合批里的空问题单列 `ASK-MIXED-BATCH-1` 观察中)。
25
+ - **在途提问崩溃前落盘**(`E2E-ASK-LOSS-1`):AI 已提问、用户未答时进程死亡 ⇒ 问题文本此前**完全丢失**(盘上轮只有 user 消息,重启只剩「没有问题的中断」,真杀进程实测)。现提问在挂起前随轮落盘,重启后收场转化出逐题 `unanswered` 记录——「问了什么、给了什么候选项」重启可回看。**对消费者**:自实现 `IRoundStore` 者无需改接口(落盘走既有 `pendingAsk` 字段);崩溃重启后提问不再丢。
26
+ - **多问批次逐题落盘**(`ASK-MULTI-Q-1`):作答 / 超时 / 批次内跳过三形态每题各落一条持久记录——作答题 `question-answer` + 各自答案、跳过题 `unanswered` + `[ASK_ABORTED]` 占位(与 LLM 收到的 tool result 同构)、超时整批 `timeout` + 超时通知。此前落盘只取首问,Q2..N 的问题与候选项只存活在内存。**对消费者**:重启回放多题批次可见完整 N 条问答对;`takeAnsweredAsk` 返回元素结构扩宽(成员名不动,旧读者结构兼容)。
27
+ - **凌晨崩溃轮打捞的时区口径**(`E2E-TZ-SALVAGE-1`):会话 ID 用本地日期、轮 `createdAt` 用 UTC ⇒ 本地 00:00–08:00 创建的中断轮打捞不到(UTC+8 下每天 8 小时窗口静默丢轮)。换算判据收敛为单点 `isWithinLocalDay`(见 Added),内核 `inMemoryRoundStore` 与宿主 `WorkspaceRoundStore` 同一函数同判据(单侧改 = 分叉,已被测试钉死)。**对消费者**:打捞过滤如自行实现,复用该单点,勿再手写换算。
28
+ - **未收场轮不再「凭空消失」**(`TURN-EXISTENCE-1` · ADR-044 一/四刀):轮的存在性不再绑死「收场」——建轮即入会话视图(此前一轮要等收场才可见;ask 超时等停滞轮在会话视图不可见、重启后也不被当「需打捞的中断轮」,用户体感「说过的话凭空消失」而盘上仍在,真机 2026-10-31 实证);ask 超时兜底去相位化(停滞轮有确定性收场兜底);孤儿判据口径随之收窄。**对消费者**:自实现会话视图 / 回收判定者将看到轮在创建期即出现;`Round.refCount` 语义以 `roundStore.ts` 注释为准。
29
+
30
+ ## [5.2.0] · 2026-10-29
31
+
32
+ > **本区归属**:仅**内核**变更;SemVer 定档**随本区收口复核**——本区现有三批:①**文档 + 测试守卫**(**运行时代码零变更、公开面零变更**),含**三件契约守卫增量**(公开面 diff 快照 / 可达成员面冻结表 / 随包接入指南一致性,封住三处「消费者可感知的契约变更会静默通过」的真实漏洞)与**一件文本卫生守卫**(全仓 U+FFFD 乱码扫描);②**一处运行时行为修复**(`ISessionStore.loadMessages` 的附件契约补齐,见 Fixed 小节,**公开面零变更、零签名变更**);③**一处运行时功能项**(图片输入内核面,见 Added 小节——`ImageRef` / `ImageResolver` / `imageTokens` 三导出与三个 `attachments?` 字段在 5.1.0 中均不存在,**公开面纯新增、零删除、零既有签名变更**)。③ 使本区按 SemVer 定档 **minor(5.2.0)**——与 2026-10-27 拍板的版本号自洽;①②单看是 patch,被③吸收。
33
+ > **收据与拍板过程**:见仓库台账(npm 包不含)ID 锚 `RUNTIME-TIER-1`(运行时门槛)/ `PUB-SNAPSHOT-1`(公开面快照守卫)/ `PUB-REACHABLE-1`(可达成员面守卫)/ `GUIDE-AUDIT-1`(接入指南核查)/ `GUIDE-GUARD-1`(接入指南守卫)/ `ONBOARD-MIN-1`(最小接入面叙事)/ `FFFD-GUARD-1`(全仓乱码清零与扫描守卫)/ `IMG-1`(图片内核面)/ `IMG-3`(能力位透传链)。
34
+ > **发版纪律**:本区标题日期须在打 tag 前改为实际发布日(`scripts/verify-changelog-version.mjs` 挂 `release.yml` 校验;已发布 tarball 不可变,见 `RELEASE-CHLOG-DATE-1`)。
35
+
36
+ ### Added(内核)
37
+
38
+ - **公开面 diff 守卫「向 E」**(`PUB-SNAPSHOT-1`):`publicApiSurfaceGuard.test.ts` 新增公开面 ↔ **冻结快照**(2026-10-27 冻结,计数以快照数组自身为准)逐位对账——删除或改名任一 `src/index.ts` 导出即红。**为什么**:原向 A/B/C/D 全部从「现存集合」出发迭代,符号一旦被删就不再被任何闸门检查——**任何被删除的导出都会全库静默**(实测:删 `isRoundSettled`,它**宿主真实消费**但不挂文档承诺面 ⇒ 仅向 E 变红、其余全绿)。**对消费者**:零运行时行为变化;此后删除公开导出必走「清算 README / 手册承诺与全部消费方 → major」的显式流程。新增导出仍先过向 A,同批补进快照(快照注释写明二选一更新纪律,不存在「改断言让它绿」的第三选项)。
39
+ - **可达成员面守卫**(`PUB-REACHABLE-1`):`publicMemberSurfaceGuard.test.ts` 新增「可达成员面」层——冻结**经已登记符号的公开 getter 返回、但未挂 `src/index.ts` 导出面**的类的公开成员清单(实测 **7 类型 / 133 成员** = `AgentLoop` / `ToolExecutor` / `MessageHistory` / `SkillManager` / `SecurityGuard` / `WorkProjectionManager` / `TextPolishManager`),增删即红。**为什么**:该守卫原只遍历**导出符号** ⇒ 不挂导出面的类完全不在射程——`SecurityGuard` 虽未从包入口导出,但 `Agent.get security` 返回它,消费者(宿主设置面板 / 装配层)**真实在调** `agent.security.setConfirmWrites(...)` 等方法,而 5.1.0 新增的 `requestToolCallConfirmation` 也在该面上 ⇒ **删改这些方法此前任何闸门都不红**(消费侧仅 TS 编译期拦截)。**对消费者**:零运行时行为变化;此后这类「经公开 getter 可达」的方法增删同样必走审查(新增 = 真能力还是谎报?删除 = 纠谎还是误删?),不再静默。冻结范围经三轮收紧(排除 TS 内置类型 / 内部协作对象 / 零消费类型),避免「为完整性而完整性」给内部实现上枷锁。
40
+ - **随包接入指南一致性守卫**(`GUIDE-GUARD-1`):`integrationGuideGuard.test.ts` 把 `docs/memora-接入指南.md`(**随包发布**、22 个可照抄的 TS 代码块)纳入机检——① 代码块 `import` 的符号必须存在于 `src/index.ts` 导出面;② 代码块与行内 `agent.X` 必须是 `Agent` 公开成员(**解析 `extends` 链**,故 `agent.on` 不假红);③ 文档**自称「接口全集」**时示例类必须实现接口全部必需成员;④ 扫描面归零即红(防路径漂移导致恒绿)。**为什么**:该文档此前**不在任何文档守卫射程**(既有守卫只对账 README 与 API 手册),两处真伤因此长期存活——示例里的 `appendMessage` **内核全仓不存在**(`ISessionStore` 有 11 个必需方法,示例只写 3 个 ⇒ 消费者照抄必编译失败)、`agent.projects` 僵尸引用(该 getter 已于 5.0.0 随项目层退役)。**对消费者**:零运行时行为变化;此后该指南的 API 引用与「照抄可编译」承诺随内核一起被机检。判据全部**实时读源码**(不建冻结表 ⇒ 无第二份真源);**历史留痕**(明写「已移除 / 已退役」的表述)与**合法节选**示例均豁免,不误伤正确写法。
41
+ - **全仓 U+FFFD 乱码清零 + 替换字符扫描守卫**(`FFFD-GUARD-1`):新增 `src/__tests__/replacementCharGuard.test.ts`——对全仓十二种文本后缀(含 `.trae` / `.github` 等隐藏目录)扫 U+FFFD 替换字符,判据为「零违例 + 扫描面下限断言(防空集假绿)+ 判据探针自检 + 与 `scan:phrase` 排除集的逐元素同源契约(防双写漂移)」;同批清零 **4 处存量乱码**(内核 `textSanitize.ts` 生产注释、宿主 `chatView.ts` 注释、仓库台账与方案文档各 1 处——生产注释**随编译进 dist .js 出货**,见 `package.json` 构建无 `removeComments`)。**为什么**:乱码是「没有任何测试会红」的伤(读者肉眼可见、机器不报错,与措辞折叠同族),4 处经 git 溯源均 **born corrupt**(入仓即带、原文不可从 VCS 恢复,只能语义重构),此前无任何闸门扫描此类损坏。**对消费者**:dist 注释里一处乱码的文本修复(零运行时行为变化);此后文本文件混入替换字符在测试闸门即红。
42
+ - **图片输入(多模态用户输入)内核面**(`IMG-1` / `IMG-3`):公开面**纯新增**——① `ImageRef`(宿主采集侧构造的图片引用:`sha256` / `mime` / `width` / `height` / `bytes` / 必填 `name`);② `ImageResolver`(宿主持有的**运行时回调**,把 `ImageRef` 物化为 `{url}` 或 `{text}` 占位文案——内核零外部 IO,回调不可持久化、不进任何配置 DTO);③ `imageTokens`(单图 token 估算**单点公式**,入参只要宽高子集,宿主入口限额直接复用,不各写一份数学);④ `Message` / `RoundMessage` / `SessionMessage` 各增可选 `attachments` 字段(随 `loadMessages` 恢复链带回,见 Fixed 小节);⑤ `ProviderConfig` 增 `supportsVision`(缺省 `false`——「声称看得见图却看不懂」比「坦承不支持」危害更大)与 `imageResolver`;⑥ `Agent.chat` / `AgentLoop.processUserInput` 增可选 `attachments` 参(仅流式入口承载)。带图请求发往未声明 `supportsVision` 的模型时**一级门禁 fail-closed 明确拒绝**(读**路由后** provider,非配置快照);resolver 未命中的图推**可见占位文本块**,绝不静默丢。**为什么**:多模态输入的内核契约与执行面——OpenAI `image_url` 形态序列化、token 计量与占用环复用同一公式、无附件请求体**字节级不变**(快照守门)。**对消费者**:不用图片的既有代码零影响(`attachments` 不带即字段不存在);要用图须三件齐备——模型声明 `supportsVision` + 注入 `imageResolver` + 调 `chat()` 时传 `attachments`。
43
+
44
+ ### Fixed(内核)
45
+
46
+ - **`ISessionStore.loadMessages` 的附件契约补齐:历史图片随轮恢复,并按窗口衰减**(`IMG-2` 断点B):`ISessionStore.loadMessages` 的 JSDoc 新增契约句——user 消息**必须**带 `attachments`,且经 `LOOP_CONSTANTS.RETAIN_IMAGE_ROUNDS` 窗口衰减;内核 `InMemorySessionStore.loadMessages` 与宿主 `WorkspaceSessionStore.loadMessages` 同批落地,两实现与 `messageHistory.loadRoundBasedMessages` **同判据同构**(`当前索引 − 消息索引 < 4`,索引一律 `roundIds.indexOf(round.id)` 取位——`getByIds` 会跳过缺失轮,用返回数组下标必错位)。**为什么**:本方法是内核 `restoreHistory` 的**唯一上游**,此前只透传 `role / content / timestamp / roundId`,漏掉了 5.0.0 起就存在于 `RoundMessage` 的 `attachments` ⇒ **重启宿主后历史图片全灭**(模型只见纯文本,连 D7 占位都没有;真机验收实锤)。**对消费者**:`loadMessages` 返回的 user 消息此后**会带** `attachments`(仅窗口内轮次)——自行实现 `ISessionStore` 的消费者不补该字段不会有任何报错,但历史图对其模型不可见;不需要该行为者可忽略该字段。**零签名变更、零公开面变更**;`RETAIN_IMAGE_ROUNDS` 仍是单点常量(其注释已同步登记**四个消费点**:三处窗口衰减 + 一处预读量)。
47
+
48
+ ### Changed(内核 · 文档)
49
+
50
+ - **运行时门槛双档口径**(`RUNTIME-TIER-1`):README 中英各三处对齐(「运行时要求」声明块 / 技术栈表行 / IMemoryStorage 表行)——包门槛 Node.js ≥ 22.0.0(与 `package.json#engines` 同源,**engines 刻意不收紧**,2026-10-16 A1 拍板);SQLite 落盘工厂 `createNodeSqliteStorage`(`node:sqlite`)需 **Node ≥ 22.13**(22.13 起免 `--experimental-sqlite` 标志)。低于 22.13 时包可正常加载、内存存储照常可用,仅调用该工厂抛「需 Node ≥22.13」的 `NOT_AVAILABLE` 明确错误,**不会静默失败**。**对消费者**:npm 安装面此前只见 22.0.0 门槛、不知第二档能力线,现补齐双档事实。
51
+ - **最小接入面叙事**(`ONBOARD-MIN-1`):README 中英边界声明后各增一段——构造 `Agent` 必填仅 **`projectPath` / `provider` / `dataDir` 三项**(`dataDir` 无缺省值,与 API 手册 §〇.5 同口径);`storage` 缺省为内置内存实现(对话与记忆闭环照常,仅不持久化),`sessionStore` / `roundStore` / `tracer` 与五个外部工具 provider(`web_search` / `web_fetch` / `run_code` / `search_project` / 环境上报)均可选,不配只是不启用对应能力、不阻塞启动。**对消费者**:纠正「接入需自实现一整套存储/会话接口」的错觉——要落盘直接用内置 `createNodeSqliteStorage` 工厂,无需自实现存储接口。
52
+
11
53
  ## [5.1.0] · 2026-10-25
12
54
 
13
- > **本区归属**:仅**内核**变更;SemVer = **minor**(零删除 / 零既有签名变更;**行为变化共三处、均为修复方向、不构成破坏性**:① 脚本族执行面按正文裁决,命中黑名单/恒弹清单的执行行为收紧;② 写侧护栏判据改为「无进展」(`write_loop` 只计整文件覆盖与连续失败写,增量写不再计数);③ `task_table_update` 不再被跨轮幂等跳过(防回喂旧任务表)。三者均见 Fixed 区)。公开面**分两层**:① **包入口符号面**增量 = **仅** `ToolDefinition` 加可选字段 `confirmPolicy`(类型面)——`SecurityGuard` 类与 `SCRIPT_READ_MAX_LEN` 均**未**从包入口 `src/index.ts` 导出;② **公开成员面**零新增(`publicMemberSurfaceGuard` 成员表未增元素),但 `agent.security` 本就是公开成员,其新增方法 `requestToolCallConfirmation(toolName, summary, needConfirm)` 对消费者**可达**(文档见 `docs/memora-api-reference.md` §2.6)。宿主侧 MCP 消费面(连接 / 设置页 / 审批卡)随宿主下一版独立成区、不占内核版本号(ADR-033)。逐条拍板与变异验证收据见仓库台账(npm 包不含):`D1-MCP` 在 `tasks/待完成任务.md` 内核 5.1.0 区;`CMD-1-BYPASS` 的实现收据见同文件 `㉔` 条、最后一面见 `tasks/archive/5.1.0-kernel.md` 的 `CMD-1-CONTENT` 条目;`CMD-1-CONTENT` / `GUARD-WRITE-PROGRESS-1` / `IDEM-TASK-TABLE-1` 均在 `tasks/archive/5.1.0-kernel.md`。
55
+ > **本区归属**:仅**内核**变更;SemVer = **minor**(零删除 / 零既有签名变更;**行为变化共三处、均为修复方向、不构成破坏性**:① 脚本族执行面按正文裁决,命中黑名单/恒弹清单的执行行为收紧;② 写侧护栏判据改为「无进展」(`write_loop` 只计整文件覆盖与连续失败写,增量写不再计数);③ `task_table_update` 不再被跨轮幂等跳过(防回喂旧任务表)。三者均见 Fixed 区)。公开面**分两层**:① **包入口符号面**增量 = **仅** `ToolDefinition` 加可选字段 `confirmPolicy`(类型面)——`SecurityGuard` 类与 `SCRIPT_READ_MAX_LEN` 均**未**从包入口 `src/index.ts` 导出;② **公开成员面**零新增(`publicMemberSurfaceGuard` 成员表未增元素),但 `agent.security` 本就是公开成员,其新增方法 `requestToolCallConfirmation(toolName, summary, needConfirm)` 对消费者**可达**(文档见 `docs/memora-api-reference.md` §2.6)。宿主侧 MCP 消费面(连接 / 设置页 / 审批卡)随宿主下一版独立成区、不占内核版本号(ADR-033)。逐条拍板与变异验证收据见仓库台账(npm 包不含),**按条目 ID 检索**(`tasks/待完成任务.md` 与 `tasks/archive/5.1.0-kernel.md`,不按区名——已发行版本区已于 2026-10-26 归元折叠):`D1-MCP`(顶层条目仍留主台账 `tasks/待完成任务.md`);`CMD-1-BYPASS` 的实现收据见主台账 `㉔` 条、最后一面见 `tasks/archive/5.1.0-kernel.md` 的 `CMD-1-CONTENT` 条目;`CMD-1-CONTENT` / `GUARD-WRITE-PROGRESS-1` / `IDEM-TASK-TABLE-1` 均在 `tasks/archive/5.1.0-kernel.md`。
14
56
  > **发版纪律**:本区标题日期即**实际发布日**——`scripts/verify-changelog-version.mjs`(挂 `release.yml`,不进 pre-push)校验「合法日历日期 + 与发布日相差 ≤1 天」;已发布版本的 npm tarball 不可变、改不回来(`RELEASE-CHLOG-DATE-1` 血训),故日期须在打 tag 前定稿。
57
+ > **日期口径(2026-10-27 澄清)**:本区标题日期 = **打 tag 的那个日历日(本地时区)**;台账「版本索引」的发布日期列 = **npm 上架日(北京时间)**。二者可能差一天(5.1.0 = 本区 10-25 / 上架 10-26,跨午夜)⇒ **两者都正确,非笔误**。
15
58
 
16
59
  ### Added(内核)
17
60
 
@@ -128,19 +171,79 @@
128
171
 
129
172
  - **后台任务槽位按 Agent 实例隔离**(`MULTI-AGENT-1`,2026-10-18):模块级槽位 → `class BackgroundTaskScheduler` 实例级,同进程多 Agent 不再交叉等待/挤占(形态定案后多实例是必然)。非公开 API 变更。
130
173
 
131
- ## [0.3.0] · 未发布(Unreleased · 宿主轴 · 2026-10-25 开区)
174
+ ## [0.4.0] · 2026-10-29 · 宿主
175
+
176
+ > **本区归属**:仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版,不进内核 npm 包(ADR-033)。**开区原因**:`vscode@0.3.0` tag 早于图片输入全链(`IMG-1`~`IMG-13` 宿主面 + `IMG-3` 视觉能力位宿主面),已发布版无图片输入能力。**主体条目随 `git log vscode@0.3.0..HEAD -- hosts/` 补齐**;切片叙事不复述,逐笔变更以该 tag 区间为准。**对外文档不引用内部台账坐标**(区名会随台账重组失效,tag 区间不会)。
177
+ > **随包内核代次 = `5.2.0`**(esbuild 内联 dist,内核自身变更见内核区)。
178
+
179
+ ### Added(宿主)
180
+
181
+ - **图片输入全链(多模态用户输入)**:对话里现在能直接发图片——四种入口汇流到**同一执行面**(落盘 / 校验 / 真 chip 建连),无第二份循环 / 第二份扩展名表 / 第二份能力判据:**① 粘贴**图片到输入框;**② 上传按钮**选本地图片(模型未声明支持视觉时按钮置灰并跳设置——这是可发现性,不是裁决);**③ 资源管理器 / 编辑器右键「Memora: 添加到对话」**命中真图时直入摄取面(不再是「拒挂 + 指路」);**④ 从文件系统拖入**(外部 OS 文件须按住 `Shift`,VS Code 1.140+ 资源管理器内拖入受上游回归阻塞、等 1.142)。**为什么**:此前模型看不到图,图文混聊要绕文件引用。**对消费者**:发图即建可发送的图片 chip;模型未声明 `supportsVision` 时一级门禁 fail-closed 明确拒绝并给理由(不静默丢);字节只走 base64(不过 `postMessage` 传 `File`/`Blob`),host→webview 单向高效传输;未命中推可见占位而非静默丢。回执复用既有 `image_picked` 消息(协议零新 op);历史图片随对话轮次恢复(窗口衰减)。视觉能力位在设置面板 Provider 配置新增「支持图片输入(多模态视觉理解)」复选框(五跳透传,内核面见 `IMG-3`),由 `IMG-2` / `IMG-5` 承载宿主侧落地与热刷新。
132
182
 
133
- > **本区归属**:仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版,不进内核 npm 包(ADR-033)。**开区原因**:`vscode@0.2.0` tag 早于宿主 MCP 接入 ⇒ 已发布版没有任何 MCP 能力。**主体条目(本地 stdio MCP 接入)发布前按 `git log vscode@0.2.0..HEAD -- hosts/` 补齐**——本区先记今日订正,切片叙事不复述(真源 = 台账「宿主 0.3.0」区)。
134
- > **出包前必做**:与内核区同规——标题的「未发布」须改为**实际发布日期**(`scripts/verify-changelog-version.mjs` 校验)。
183
+ ### Fixed(宿主)
184
+
185
+ - **对话记录选区复制兜底(修复 WebviewView 原生复制失效)**(`COPY-1`):选中消息正文后 Ctrl+C / 右键「复制」都不落盘。根因:VS Code WebviewView 里非输入区原生剪贴板不可靠,且原 `copyText` 只服务 hover 动作按钮(整条 / 原始文本 / 代码块),**自由选区(选一句 / 一段)无入口**——「选中对话记录复制不出」与「右键菜单能弹但复制无效」是同一根因(都走原生复制)。现 webview 侧复制逻辑抽单点 `webview/helpers/selectionClipboard.ts`——`installSelectionCopyGuard` 在 document `copy` 事件**同步**写 `clipboardData`(`if (!sel) return` 仅接管文档选区、放行输入框原生复制,不与图片粘贴 / 原生剪贴板打架);`copyText` 从 `chatView` 外置到此(4 处调用方不变)。**为什么**:13 处 `user-select:none` 全挂标签 / 日期分隔、document 唯一 keydown 只处理 Esc、全仓无清选择逻辑、CSP 无 `clipboard` 限制——均逐符号排除假凶手。行数闸:`chatView.ts` 5097→5091(抽 `copyText` 定义 −11 + 导入 / 调用 +2,守 5098 闸门);新文件 `selectionClipboard.ts` 58 行不计入四闸门文件。**对消费者**:选中消息正文 Ctrl+C / 右键复制 → 字节落盘;输入框内选中仍走原生(不被吞);无选区时平台菜单复制行为不变。测试 `selectionClipboard.test.ts` 5 条(有选区写盘 + preventDefault / 无选区放行 / textarea 选区放行 / 幂等 / copyText 优先 `navigator.clipboard`)。
186
+
187
+ - **占用圆环「空态」滞留修复**(`OCC-STALE-1`):配置热刷新(改窗口 / 切 Provider)重推 `chat_providers` 触发空态渲染后,圆环显示「0 条对话 · 100% 可用」且与真实占用矛盾,切会话才恢复。根因(两缺口叠加,均既有代码):① `renderOccupancyLimit` 空态语义假设「首轮对话前」、配置变更也走同一分支 = 假事实(`contextLimitShown` 防误清零只比对数值,「变过去再变回来」即放行空态);② 真实快照到达时机族漏了「配置热刷新」面,拦截类不发消息则空态无限滞留(非 IMG-8 引入,occupancy 链路零触碰)。现 `chatPanel.applyActiveProviderRefresh`(IMG-5 热刷新唯一入口,覆盖配置监听 / 切 Provider / 发送前 stale 补做 3 调用方)在 `refreshActiveProvider` 返回后补推 `postHistoryOccupancy()`;`handleSetProvider` 回滚分支 `pushProviders` 后同样补推。**对消费者**:改窗口配置保存后、无需发生 round,圆环即恢复真实占用;切 Provider 失败回滚后回到 prev 口径真实占用;切会话 / 流尾既有路径不回归(守内核 / 宿主边界,webview 侧零改动)。协议零新增(复用 `context_occupancy`,计数不变)。守卫 `chatPanelHistory.test.ts` 新增「配置热刷新(retryAgentAssembly)→ 补推 context_occupancy 纠正空态」——修复前红(`expected 0 ≥ 1`,红在判据上)、修复后绿。
188
+
189
+ - **中断兜底行直出裸英文 `interrupted`**(`TERM-REASON-1`):`decideTerminus` 兜底分支构造对象写 `reason: 'interrupted'`(语义键)却当展示文案用,`stopReasonLabel` 无 `stopReason` 时回落原文 ⇒ 中断行出现裸英文。`decideTerminus` 兜底改传 `stopReason: 'interrupted'`(`reason` 仍填同键保可追溯),下游 `appendInterruptedRow` 对 `verdict.reason` 仅 `textContent` 纯展示、无字符串匹配(grep 实证零破坏面)。**为什么**:文案回落判据与调用点意图不同源(语义键 ≠ 展示文案);取「构造点改字段」单点修正,不破坏 `stopReasonLabel` 的自由文本原文回落契约(调试可追溯)。**对消费者**:中断行显示「对话已中断」(中文),不再出裸英文。测试判据随事实更新(`'interrupted'` → `'对话已中断'`),prettier / tsc / eslint / processFlowModel 23 例 / 宿主全量 vitest 绿。
190
+
191
+ - **能力徽章链路补断言覆盖**(`CAPB-1`):`#currentCapabilityBadge` 在生产骨架与测试夹具都存在、骨架 id 三方一致性守卫也覆盖其存在性,但全仓**无任何用例** dispatch `capability_badge`、也没断言过 `textContent` / `title` / `hidden` ⇒ 三分支(block 纯 LLM / allow + 无能力「全部工具」/ allow + 能力列表)全无守护。属静默失测形态(节点在、链路可跑、断言缺失),非代码缺陷。现补 4 例(block / allow + 空 / allow + 能力列表含重复 label 验去重 / 骨架初始 hidden)断言文案与 title;顺带修正 `roleBadgeView` 注释撒谎(实为骨架初始 hidden、无隐藏分支)。**为什么**:CHATVIEW-SLIM-3 第三刀搬迁前扫覆盖发现,行为等价不受影响,但缺口不补下次改动该链路无网可守。**对消费者**:无行为变化;能力徽章(模型支持的工具 / 视觉等能力)的展示逻辑此后有测试钉住。
192
+
193
+ ## [0.3.0] · 2026-10-26 · 宿主
194
+
195
+ > **本区归属**:仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版,不进内核 npm 包(ADR-033)。**开区原因**:`vscode@0.2.0` tag 早于宿主 MCP 接入 ⇒ 已发布版没有任何 MCP 能力。**主体条目(MCP 接入)已于 2026-10-26 按 `git log vscode@0.2.0..vscode@0.3.0 -- hosts/` 补齐**(该区间实测 63 笔宿主提交,其中 33 笔属 MCP 接入);切片叙事不复述,逐笔变更以该 tag 区间为准。**对外文档不引用内部台账坐标**(区名会随台账重组失效,tag 区间不会)。
196
+ > **随包内核代次 = `5.1.0`**(esbuild 内联 dist,内核自身变更见内核区)。
197
+
198
+ ### Added(宿主)
199
+
200
+ - **MCP 工具接入(本地 stdio):对话里可以直接调用外部工具服务器**(2026-10-23 ~ 10-25 落地,2026-10-26 补记):Memora 现在是一个 **MCP 客户端**——你告诉它有哪些工具服务器,它把这些服务器暴露的工具注册进 Agent,模型在对话里能像调内置工具一样调用,工具名形如 `mcp__<服务器名>__<工具名>`。配置在**设置面板 → MCP** 页(每台服务器一张卡片 + 表单增删改),写用户级 `memora.mcpServers`;工作区级配置**不读**(可被他人提交进仓库 = 让任意仓库拉起任意命令,2026-10-25 定案不开放)。启动前做一次**静态预检**(命令是否存在 / 是否把脚本当命令 / 工作目录是否存在),不通过就不拉起并把原因写在卡片上。卡片给的是**真实状态**而非「我以为连上了」:已连接 / 启动失败(附原因)/ **待接入**(配置在、运行态还没追平——不是故障)/ 已停用 / 配置不完整。配置**改完即时生效**:新增立即拉起、改参数先停后起、停用与删除立即注销工具、改白名单只重算档位不重连;配置没变但连接已坏(子进程被外部杀掉)时热更不触发,用卡片「重启」按名字重建。也支持**粘贴 JSON 片段批量导入**(Claude Desktop / Cursor / VS Code `mcp.json` 均可),同名与字段不合法的条目逐条跳过、不覆盖已有配置。**为什么**:`vscode@0.2.0` tag 早于本接入,已发布版**没有任何 MCP 能力**,这 33 笔提交(占 0.2.0 之后宿主提交的六成)此前在本区一条未记。**对消费者**:这是 0.3.0 唯一的功能级新增;调用面如实登记四条边界——单次转发 60s 超时(超时不断连接,其余工具照常可调)、单条结果超 20,000 字符截断、图片/音频等非文本内容丢弃并注明类型、合计工具数 > 64 时在输出面板告警(工具过多会降低模型选对工具的概率,可停用部分服务器收敛)。**排障入口**:输出面板 → Memora(server 的 stderr 与宿主接入告警都在此处);完整用法见 `hosts/memora-vscode/docs/mcp-setup.md`。
201
+
202
+ - **MCP 免确认白名单(工具级 / 整台级)**(2026-10-23 ~ 10-25 落地,2026-10-26 补记):默认**每次调用都弹确认**(MCP 工具来源不可信,宁多弹窗不静默放行);写进 `memora.mcpToolAllowlist` 后免弹窗但**仍写审计**(`write-auto`,可在审计记录里回查)。两种键都按**原始名**寻址:`mcp__<服务器名>__<工具名>` 只放行一个工具,`mcp__<服务器名>__*` 放行整台。最省事的做法是在 MCP 页的工具行勾「免确认」,写的就是这个键。**为什么**:只给「全问」或「全不问」两端,用户会在第三次弹窗时去关掉整个功能;放行必须逐台/逐工具显式表达才既能用又不失控。**对消费者**:① 没有「一次放行所有服务器」的写法(`mcp__*` 不是合法键,防「自动化默认」);② 键若写成**显示名**(如 `my-tool` 被清洗成 `mcp__fs__my_tool`)**不命中**、回落为每次确认——写错的表现是「还在问」,不是「悄悄放行」(fail-closed);③ 删除服务器**不联动**清白名单(那是逐条授予的信任记录),重新添加同名服务器时档位自动恢复;④ **整台级键是服务器级授权,不是工具名快照**——该台之后新增的工具(server 升级后多出工具、或同名换了另一台)**自动**落进免确认范围,不会重新问你,批准时也不存在「我当初批了哪几个工具」的记录可回查;工具名无法预知 ⇒ 想让新工具仍需确认的只能用工具级键逐个放行。
203
+
204
+ - **MCP 远程服务器接入(Streamable HTTP,无 OAuth)**(2026-10-25 落地,2026-10-26 补记):配置项新增 `transport: 'http'` + `url`;**stdio 仍是缺省**,既有配置零迁移(写盘只在 http 时落 `transport`)。从外部格式导入时 `type: "http"` 映射到本仓 `transport`(别名只在写入点映射一次,读面零第二字段名)。**为什么**:远程 MCP 是社区主流形态,只支持本地子进程等于把一半生态排除在外。**对消费者**:① 远程服务器**没有表单编辑**(本期未做)——用页脚「粘贴 JSON」导入或手写 settings.json,面板只读标注 `http · <url>`,卡片上的「编辑」按钮对远程**置灰**(表单里没有 `url` / `headers` 字段,打开也只能填 command,而 command 与 http 互斥 ⇒ 那会是个点了必然失败的假动作);② **SSE 已定案不支持**(只接 Streamable HTTP);③ 本期**不含 OAuth**,需要鉴权的远程服务器会在 401 时落到「启动失败」(归因见下方 Fixed 条);④ **`headers` 一律明文落盘**——作用域 `machine` 只表示不随 Settings Sync 同步到别的设备,**不是**加密存储,本机任何能读 `settings.json` 的程序都能看到里面的令牌;当前版本**没有** SecretStorage 托管入口,别把长期有效的高权限令牌放进去。
205
+
206
+ - **设置面板入口:侧栏「对话」视图标题栏齿轮**(2026-10-26):`menus.view/title` 挂 `memora.openSettings`(`when: view == memora.chat`,icon `$(settings-gear)`),点开即 editor tab 形态的设置面板(默认落「记忆」页,单例复用已开面板)。**为什么**:设置整体迁 editor tab 后侧栏不再有设置入口,只剩命令面板——真机反馈「输入框没有直接打开设置页的按钮」,可发现性不足。**取舍**:走 VS Code 原生 view 标题栏而非 webview 内自建按钮 ⇒ **零协议改动、零 webview 改动**;刻意不给「当前角色徽章」挂齿轮(图标承诺全局设置、行为却落角色页 = 视觉谎报),也未给徽章加常驻描边(齿轮方案落地后即取代该思路,两处都做 = 同一问题双补丁)。角色徽章维持原职(点开落角色页),与齿轮职责不同、不构成双入口。
135
207
 
136
208
  ### Changed(宿主)
137
209
 
210
+ - **设置六页从侧栏 view 迁到 editor tab(L3 设置分家)**(2026-10-26):`MemoraSettingsViewProvider`(`registerWebviewViewProvider`)→ `MemoraSettingsPanel`(`createWebviewPanel`);package.json 侧栏 `memora.settings` 视图贡献项删除,对话 view 独占侧栏。导航仍走既有 `switchTab` + `_pendingTab` + ready 握手单点(`memora.configureModel` / `memora.openRoles` 落点不变);panel 单例 reveal-or-create,**设 `retainContextWhenHidden: true` 保上下文**(切走 tab 是 editor tab 的常态用法,不设则每次失焦销毁上下文 ⇒ 六页表单草稿全丢;隐藏态投递语义官方注释两说,故导航在隐藏期只记 pending、转可见时补发,数据面同一时机补刷兜底,见下方条目),关 tab 仍走 dispose 后重开 + ready 握手重建;协议**零新增消息**、内核 `src/` 零改动、设置样式 / HTML 零逻辑改动(九条判据全过,收据见台账「L3 设置分家方案」条)。**为什么**:真机 UI 评审实测设置六页挤占对话空间、对话→设置→返回三层级导航、危险按钮贴脸、回执离视线远。**对消费者**:活动栏不再有设置入口,改用 `memora.openSettings` 命令或侧栏标题栏齿轮(见 Added)。
211
+
212
+ - **设置面板:上下文保留 + 打开入口收 tab 参数 + 挂载链数据驱动**(2026-10-26,L3 落地后审查修复):
213
+ **① 假前提订正(先认错再改)**:L3 落地时记「panel 无 `retainContextWhenHidden` 选项(API 本就不存在)」,据此判定「与侧栏隐藏销毁语义等价」——**该前提是假的**。`createWebviewPanel` 的 options 类型是 `WebviewPanelOptions & WebviewOptions`,后者明载 `retainContextWhenHidden?: boolean`,且默认行为是「面板不可见即销毁 html context」。后果真实存在:editor tab 切走是常态用法(改一半配置去看代码),而 webview 侧零 `setState` 兜底 ⇒ 六页表单草稿每次切换全丢。现设 `retainContextWhenHidden: true`。**代价不是「消息全丢」,而是官方文档在此自相矛盾**:`retainContextWhenHidden` 的注释写「You cannot send messages to a hidden webview, even with retainContextWhenHidden enabled」,同一份 `index.d.ts` 里 `Webview.postMessage` 的注释却把「hidden webviews that set retainContextWhenHidden」算作 live(可投递)——两句不可能同时为真。处理方式是不赌任何一侧:隐藏期导航只记 pending、转可见时补发(见下方条目),重新可见时另全量补刷一次作为**收敛网**(覆盖那些没有推送路径的宿主侧变更)。**对消费者**:切走再切回的设置页保状态,回来看到的是当前态。
214
+ **② 打开入口收 `tab` 参数**:`memora.openSettings` 接受可选 `SettingsTab`,`memora.configureModel` / `memora.openRoles` 变为它的薄包装(命令名保留,既有 keybinding 不断)。`chatPanel` 的「tab → 命令名」映射表删除,`open_settings_tab` 的 tab 由 `Extract<…,'config'|'roles'>` 放宽回全集——收窄的前提(其余页无导航入口)已不成立。**对消费者**:无行为变化;**对后续加页**:不必新增命令或映射表,`executeCommand('memora.openSettings', '<tab>')` 直达。
215
+ **③ 挂载链数据驱动**:`settingsView.ts` 六段手抄 try/catch → 一张 `mounts` 表,异常隔离语义不变(每项独立 try/catch,不截断末尾 ready 握手)。**为什么**:手抄版漏一段不会让任何测试红(该页有按钮无内容,只有真机能发现);`settingsTabs.ts` 旧注释承诺「加 tab = 一行数组 + 两张 Record」与实际改动面差 5 处,已按实测订正为完整清单。
216
+ **守卫**:`settingsPanelRoles.test.ts` 新增两例(创建参数含 `retainContextWhenHidden` / 仅由隐藏转可见才补刷),`settingsTabs.test.ts` 新增一例类型级(tab 收窄即 TS2322)。变异实测三条全红:`expected false to be true` / `expected "refreshAll" to not be called at all` / `TS2322: Type '"skills"' is not assignable to type '"config" | "roles"'`。
217
+
218
+ - **设置面板:导航落点可靠性 + 遗留四项收口**(2026-10-26,`L3-AUDIT-FIX-2`):
219
+ **① 导航判据从「panel 存在」改为「可投递」**:`_panel` 有值只说明 tab 存在,不说明脚本已注册监听器——`postMessage` 契约原文「A response of `true` does not mean that the message was actually received … no message listeners may have been hooked up」,而隐藏态又两说(见上条)。旧实现「投出即清 `_pendingTab`」在这两类时机(open→ready 之间 / 面板在后台)会把导航指令丢掉且宿主侧无痕,用户落在默认「记忆」页。现单点:`isDeliverable()`(`_panel` ∧ `_webviewReady` ∧ `visible`)+ `flushPendingTab()`(唯一投递点与唯一清空点,`switchTab` / `ready` / 由隐藏转可见三个时机共用);不可投递时只记 pending。**对消费者**:设置已开但还在加载、或设置 tab 在后台时点角色徽章,仍会落在「角色」页。
220
+ **② `settingsPanelHostDiag` 补接线自证**:`expect(posted).toHaveLength(0)` 是负向断言,`post → postMessage` 通道断线时照样绿(只证明「没发」,证明不了「发得出」)。现每例先投一条已知消息断言被捕获,再清空验零下行。
221
+ **③ `memora.settings.focus` 消失记入 Removed**(见下)。
222
+ **④ 闸门数字与注释对齐**:eslint 的 `settingsPanel.ts` 注「一 class 扛 5 个 tab」改为六页;三条 `max-lines` 按「闸门自报」口径下调(chatView 6716→6715 / chatPanel 4516→4515 / settingsPanel 2041→2037,只降不升)。
223
+ **守卫**:`settingsPanelRoles.test.ts` 新增两例(未 ready 不投递且 pending 保留 / 已 ready 但后台不投递、转可见补发),`settingsPanelHostDiag.test.ts` 加接线自证。变异实测三条全红:判据退回 `_panel !== undefined` ⇒ 两例 `expected [ { …(2) } ] to deeply equal []`;去掉 `visible` ⇒ 后台例同上;`post()` 断线 ⇒ `接线自证失败:post → webview.postMessage 捕获链断了: expected [] to have a length of 1 but got +0`。
224
+
225
+ - **设置面板:切走再切回不再丢列表态(重推非破坏化)**(2026-10-26,`L3-CTX-KEEP-1` + `L3-CTX-KEEP-2`):
226
+ **现象**:`retainContextWhenHidden` 只保住了「输入框里还没提交的草稿」,保不住「列表正在看哪一页」——面板由隐藏转可见时宿主会重推一次数据(`refreshAll` 收敛网,覆盖那些没有推送路径的宿主侧变更),而 webview 侧把每次重推都当「新数据」处理:技能页 `pager.show(1, …)` + `contentMap.clear()` ⇒ 翻到第 N 页被打回第 1 页、已展开的技能正文收起并需要重新向宿主取;记忆页回第 1 页,且**搜索框里的词没清、列表却回全量**(界面自相矛盾)。**即:草稿保住了,列表态被反向洗掉 = 只保一半。**
227
+ **修法(留触发、消代价)**:不删重推触发——「隐藏期消息是否可达」VS Code 自己的两份注释互相矛盾(`retainContextWhenHidden` 注说不可投递,`Webview.postMessage` 注把设了该选项的隐藏 webview 算作 live),两边各赌一半是最坏组合。改为让重推**非破坏**:① 技能页把展开态收进 `expanded` 集合(唯一真源,DOM 只做投影),`skills_loaded` 改为「留在原页(页数变少时向前夹取)+ 按名字逐出已消失技能」,不再整体清缓存;「整体清空」只保留给用户显式点刷新(显式意图与被动重推判据不同源,刻意不合并)。② 记忆页三条分支:搜索框有词 ⇒ 按原词重放 `memory_search`(检索只走一条路,不在 webview 本地过滤数组);当前页 > 1 ⇒ 走既有 `memory_page` 增量通道取该页(首屏载荷只含第 1 页,直接铺会把第 1 页数据贴上第 N 页页码);其余直接填充。③ 角色页同样漏扫(`roles_loaded` 无条件回第 1 页),本批一并收口,并把「保持当前页 + 越界夹取」的判据下沉到 `PagerController.showKeepingPage` 单点——调用方不得再各写一份 `Math.min(getPage(), pageCount)`。
228
+ **对消费者**:切去别的 tab 再切回设置页,页面停在你离开时的那一页,展开的技能正文仍展开,搜索词与结果仍在同一上下文。**代价**:重推数据变了(例如角色包被删除)时按新页数向前夹取,落到最后一个有内容的页而不是空页。
229
+ **守卫**:`settingsView.test.ts` 3 例(留在当前页 / 已展开正文保持展开 / 页数变少向前夹取)、`memoryView.test.ts` 2 例(第 2 页不被第 1 页数据顶替 / 搜索词重放且输入框与列表同上下文)、`pager.test.ts` 3 例(保持当前页 / 变少夹取 / 空数据集收敛)、`rolesView.test.ts` 2 例(重推保页 / 重推变少夹取),全部变异验证。
230
+
231
+ - **设置面板:子视图挂载表可被测试钉住**(2026-10-26,`L3-CTX-KEEP-2`):`settingsView.ts` 的六页挂载表原在 `createSettingsView` 函数作用域内 ⇒ `settingsTabs.ts` 承诺的「加一页 = 挂载表一行」**没有任何测试能守住**,而漏一行的表现是「该页有按钮、无内容」:tsc 不报错、其余测试全绿,只有真机能发现。现提到模块级导出 `SETTINGS_VIEW_MOUNTS`,由 `settingsView.test.ts` 断言「表内 name 集合 == `SETTINGS_TABS`」+ 无重复 + 每项工厂为函数(断言集合相等而非顺序相等:UI 顺序与初始化时序刻意不同源)。**对消费者**:无行为变化;**对后续加页**:漏挂载从「真机才发现」变成「测试红」。
232
+
138
233
  - **MCP 两键作用域 `application` → `machine`**(`H0-2`,2026-10-25):`memora.mcpServers` / `memora.mcpToolAllowlist` 不再随 VS Code Settings Sync 同步。**为什么**:`application` 会把 `headers` 里的明文令牌与免确认批准带到同账号的其他设备——批准的语义是「本机用户同意本机进程」,跨机继承等于替另一台机器点同意。**对消费者**:① 只写用户设置、工作区 / 文件夹写入仍被忽略(`.mcp.json` 不读的红线不变);② **升级后每台机器需各配一次**,原先靠设置同步带过来的 MCP 配置不会再自动出现;③ 本机已有配置不受影响。断言钉在 `mcpConfig.test.ts`(结构机制不在代码里,改 scope 只有这条测试能拦住)。
139
234
 
235
+ ### Removed(宿主)
236
+
237
+ - **`memora.settings.focus` 命令**(2026-10-26,L3 设置分家的连带影响):该命令**不是本扩展显式贡献的**——VS Code 为每个 `contributes.views` 视图自动提供 `<viewId>.focus`(本仓全历史 grep 无一处置,键位设置里却能搜到),`memora.settings` 视图贡献项删除后它随之消失。**对消费者**:若曾绑过该命令的快捷键,绑定会**静默失效**(按 id 调用不抛错,只是不再发生);聚焦设置请改用 `memora.openSettings`。
238
+
140
239
  ### Fixed(宿主)
141
240
 
241
+ - **安装包夹带本地文件(出包前复核发现,2026-10-26)**:0.3.0 首版 `memora-vscode.vsix`(183 条目)里实际混进了 `mcp-acceptance-server.mjs`(手工验收脚本)、`.workbuddy/*.log` ×3(本地调试日志)、`.tmp-vsce.log`(vsce 自身临时日志)、`dist/.bundle-smoke/vscode-stub.mjs`(打包前门禁探针)。**成因**:`.gitignore` 与 `.vscodeignore` 是**两套判据**——前三个前缀都已在 `.gitignore` 里,`git status` 干净,但 `vsce` **不读 `.gitignore`** ⇒ 「仓库干净」被当成了「包内干净」。**修法**:`.vscodeignore` 补 `.workbuddy/**` / `*.log` / `.tmp-vsce.log` / `mcp-acceptance-server.mjs` / `dist/.bundle-smoke/**`,本地日志与临时产物同批删除。**对消费者**:安装包不再包含验收脚本与本地日志(183 → 177 条目,1,852,326 → 1,809,088 字节),运行时行为零变化。**守卫缺口如实登记**:无自动闸门——`vsce ls` 断言只查「该有的在」(`dist/extension/host/mcp/*.js`),不查「不该有的不在」,本次靠人工按条目清单逐条核对,登记于台账 F 段。
242
+
142
243
  - **MCP 连接失败归因订正**(`H0-1`,2026-10-25):没有 `tools` 能力的 server 此前被判成「server 未声明 tools 能力」并置 `failed`——但纯 `resources` / `prompts` 的 server 是**合法形态**,这是本宿主只接 tools 的**覆盖面边界**,不是对方故障。现文案改为「本宿主当前只接 tools 能力;该 server 只提供 X / Y,暂不支持(不是 server 故障)」,并对连上后被忽略的非 tools 能力打一次 info 日志(不静默)。**为什么**:谎报成因与谎报能力同族——原文案会让用户去查一台没坏的 server。**对消费者**:仅失败原因文案变化;无 tools 的 server 仍不注册空工具清单(不静默成功)。**登记**:方案-MCP工具接入 §10 新增「`resources` / `prompts` 零接入(能力边界 · 非功能缺口)」行。
143
244
 
245
+ - **角色页:角色包被清空后不再留着幽灵分页条**(2026-10-26,`L3-ROLES-SLIM-1`):`roles_loaded` 收到空列表时,列表正确地换成了「暂无角色包」空态,但**分页条没被收掉**——它保留着上一轮的页码与条数(实测:17 个角色翻到第 2 页后角色包被清空 ⇒ 条上仍写「第 2 / 2 页(共 16 条)」且上下页都能点)。于是页面上同时存在「一个声称有 16 条内容、可双向翻页的条」和「一个永远空着的列表」,点翻页也翻不出任何东西。**成因**:空态分支渲染完空态引导就 `return`,跳过了分页态的收敛(`othersAll` 因早退没被清、`pager` 也没被重置 ⇒ 翻页切的是上一轮的旧数组)。现空态分支同批收敛两件事:`othersAll` 随 `lastData` 一并清空(派生数据必须随源更新),`pager.showKeepingPage([])` 让分页条隐藏、页码回到 1/1、上下页均禁用。**对消费者**:角色包全删光 / 切到没有角色包的工作区时,看到的是干净的空态,不会再有翻不出内容的条。**守卫**:`rolesView.test.ts` 新增一例(先翻到第 2 页,再投空载荷,断言分页条 `hidden`、双向 `disabled`、卡片数 0),变异实测:删掉收敛 ⇒ `expected false to be true`。
246
+
144
247
  ## [0.2.0] · 2026-10-23 · 宿主
145
248
 
146
249
  > 仅**宿主**(`hosts/memora-vscode`)变更,随 `vsce package` 定版。**随包内核代次 = `5.0.0`**(esbuild 内联 dist,内核自身变更见内核区)。逐条拍板与变异验证收据见台账对应 ID。
package/README.en.md CHANGED
@@ -54,6 +54,8 @@ await agent.close();
54
54
  ```
55
55
 
56
56
  > **Boundary**: Memora is a **non-standalone pure logic kernel** — persistence, sandbox, observability, CLI/UI are all injected by the host. The kernel guarantees **interface contracts + unit-tested logic correctness**; agent-level behavior evaluation is the host's responsibility.
57
+ >
58
+ > **Minimal integration surface**: constructing an `Agent` requires only `projectPath`, `provider`, `dataDir`. Without an injected store, the built-in in-memory implementation is used (chat and memory loop work as usual, just not persisted); for persistence, use the built-in `createNodeSqliteStorage` factory directly — **no need to implement a storage interface yourself**. `sessionStore` / `roundStore` / `tracer` and the external tool providers (`web_search` / `web_fetch` / `run_code` / `search_project` / environment reporting) are all optional: omitting them only disables the corresponding capability, it never blocks startup.
57
59
 
58
60
  ---
59
61
 
@@ -106,6 +108,8 @@ Memora is a **brain kernel that cannot run standalone** — it has interfaces bu
106
108
  npm install @zooique/memora
107
109
  ```
108
110
 
111
+ > **Runtime requirement**: Node.js ≥ 22.0.0 (same wording as `package.json#engines`). The SQLite persistence factory `createNodeSqliteStorage` (`node:sqlite`) additionally requires **Node ≥ 22.13** — that's when `node:sqlite` stopped needing the `--experimental-sqlite` flag. Below 22.13 the package still loads and the in-memory store works; only calling that factory throws an explicit "Node ≥22.13 required" error (`ToolErrorCode.NOT_AVAILABLE`), never a silent failure.
112
+
109
113
  ### Create an Agent
110
114
 
111
115
  ```typescript
@@ -198,7 +202,7 @@ The kernel interacts with the outside world through interfaces. Hosts inject imp
198
202
 
199
203
  | Interface | Responsibility | Built-in Implementation |
200
204
  |-----------|---------------|------------------------|
201
- | `IMemoryStorage` | Memory CRUD + search + query by source | Built-in in-memory default (placeholder, non-persistent; internal class, not on the public surface — PUB-API-PRUNE-2) + optional persistent impl `createNodeSqliteStorage(dbPath)` (built-in `node:sqlite`, zero third-party deps) | Host picks the backend: create SQLite via the kernel factory, or implement its own (JSON / own SQLite) |
205
+ | `IMemoryStorage` | Memory CRUD + search + query by source | Built-in in-memory default (placeholder, non-persistent; internal class, not on the public surface — PUB-API-PRUNE-2) + optional persistent impl `createNodeSqliteStorage(dbPath)` (built-in `node:sqlite`, zero third-party deps; requires Node ≥22.13) | Host picks the backend: create SQLite via the kernel factory, or implement its own (JSON / own SQLite) |
202
206
  | `ISessionStore` | Session history persistence | None (host implements) |
203
207
  | `ILogger` | Logging output | console fallback |
204
208
  | `ITracer` | Observability spans | Internal noop (not on the public surface; omit `tracer` for zero overhead) |
@@ -247,7 +251,7 @@ src/
247
251
 
248
252
  | Category | Choice | Rationale |
249
253
  |----------|--------|-----------|
250
- | Runtime | Node.js ≥ 22 LTS + TypeScript 5 strict + ESM | ADR-001 |
254
+ | Runtime | Node.js ≥ 22.0.0 (SQLite persistence factory needs ≥ 22.13, see Quick Start) + TypeScript 5 strict + ESM | ADR-001 |
251
255
  | Data Layer | IMemoryStorage interface (host injects persistence) | ADR-002 |
252
256
  | LLM Protocol | OpenAI Chat Completions compatible (streaming SSE + Tool Calling) | ADR-003 |
253
257
  | Memory Model | Memory-as-summary: round-summary single track, traceable to source; source open-string primitive | ADR-004 · memory-as-summary.md |
package/README.md CHANGED
@@ -54,6 +54,8 @@ await agent.close();
54
54
  ```
55
55
 
56
56
  > **边界声明**:memora 是**不可独立运行的纯逻辑内核**——持久化 / 沙箱 / 可观测 / CLI·UI 均由宿主注入。内核保证**接口契约 + 单测验证的逻辑正确性**,agent 级行为评估由宿主自行承担。
57
+ >
58
+ > **最小接入面**:构造 `Agent` 只需 `projectPath`、`provider`、`dataDir`。存储未注入时用内置内存实现(对话与记忆闭环照常,仅不持久化);要落盘可直接用内置 `createNodeSqliteStorage` 工厂,**无需自实现存储接口**。`sessionStore` / `roundStore` / `tracer` 与外部工具 provider(`web_search` / `web_fetch` / `run_code` / `search_project` / 环境上报)均为可选——不配只是不启用对应能力,不阻塞启动。
57
59
 
58
60
  > **零依赖如何成立(2026-09-21 审计)**:「零依赖」特指**零第三方运行时依赖**。内核仅使用 Node 内置模块(`node:fs` / `node:path` / `node:crypto` / `node:os` / `node:child_process`),6 类共见于 18 个生产文件,全部必要、无冗余。文件落盘(记忆 / 角色包 / 原子写 / 技能脚本执行)走**接口 + 内存默认实现**(如 `ISessionStore` → `InMemorySessionStore`),持久化 sink 交由宿主注入 `WorkspaceSessionStore` 等实现替换——这既支撑「本地、私有、零依赖」卖点,也遵守「持久化由宿主注入」边界。
59
61
 
@@ -112,6 +114,8 @@ Memora 是一个**无法独立运行**的智能大脑内核——它只有接口
112
114
  npm install @zooique/memora
113
115
  ```
114
116
 
117
+ > **运行时要求**:Node.js ≥ 22.0.0(与 `package.json#engines` 同口径)。其中 SQLite 落盘工厂 `createNodeSqliteStorage`(`node:sqlite`)需 **Node ≥ 22.13**——22.13 起 `node:sqlite` 才免 `--experimental-sqlite` 标志。低于 22.13 时包可正常加载、内存存储照常可用,仅调用该工厂会抛出明确的「需 Node ≥22.13」专属错误(`ToolErrorCode.NOT_AVAILABLE`),不会静默失败。
118
+
115
119
  ### 创建 Agent
116
120
 
117
121
  ```typescript
@@ -200,7 +204,7 @@ await agent.close();
200
204
 
201
205
  | 接口 | 职责 | 内置实现 | 宿主注意 |
202
206
  |------|------|----------|----------|
203
- | `IMemoryStorage` | 记忆 CRUD + 搜索 + 按 source 查询 | 内置内存默认实现(**仅内存占位,不持久化**;内部类,不挂公共面——PUB-API-PRUNE-2 收面)+ **可选落盘实现** `createNodeSqliteStorage(dbPath)`(基于 `node:*` 内建模块,零第三方依赖) | 持久化后端由宿主选:经内核工厂建 SQLite,或自实现(JSON / 自有 SQLite);重启后数据依赖所选实现 |
207
+ | `IMemoryStorage` | 记忆 CRUD + 搜索 + 按 source 查询 | 内置内存默认实现(**仅内存占位,不持久化**;内部类,不挂公共面——PUB-API-PRUNE-2 收面)+ **可选落盘实现** `createNodeSqliteStorage(dbPath)`(基于 `node:*` 内建模块,零第三方依赖;需 Node ≥22.13) | 持久化后端由宿主选:经内核工厂建 SQLite,或自实现(JSON / 自有 SQLite);重启后数据依赖所选实现 |
204
208
  | `ISessionStore` | 会话历史 + 标题元数据持久化 | 无(宿主实现) | **不含检查点持久化**(2026-09-10 减法:跨重启恢复链整体退役)——中止/断电一律把未完成 turn 补全为完整 turn 身份、下次会话按历史加载;运行时暂停是同 turn 内续跑(内存态),无需跨进程载体 |
205
209
  | `ILogger` | 日志输出 | console fallback | 无 |
206
210
  | `ITracer` | 可观测性 span | 内核内部 Noop 实现(不挂公共面;不传 `tracer` 即零开销) | 无 |
@@ -249,7 +253,7 @@ src/
249
253
 
250
254
  | 类别 | 选型 | 决策依据 |
251
255
  |------|------|----------|
252
- | 运行时 | Node.js ≥ 22 LTS + TypeScript 5 strict + ESM | ADR-001 |
256
+ | 运行时 | Node.js ≥ 22.0.0(SQLite 落盘工厂需 ≥ 22.13,见「快速开始」)+ TypeScript 5 strict + ESM | ADR-001 |
253
257
  | 数据层 | IMemoryStorage 接口(宿主注入持久化实现) | ADR-002 |
254
258
  | LLM 协议 | OpenAI Chat Completions 兼容(流式 SSE + Tool Calling) | ADR-003 |
255
259
  | 记忆模型 | 摘要即记忆(round-summary 单轨,可溯源回原始对话);source 开放字符串基元 | ADR-004 · memory-as-summary.md |
@@ -17,7 +17,7 @@ import { type GCResult } from '../memory/gcService.js';
17
17
  import type { SessionManager, AgentForkResult } from '../agent/managers/sessionManager.js';
18
18
  import { type ArchiveTriggerOptions } from '../agent/managers/archiveCoordinator.js';
19
19
  import { TypedEventEmitter, type AgentEventMap } from '../utils/eventEmitter.js';
20
- import type { LlmProvider, Message } from '../llm/provider.js';
20
+ import type { LlmProvider, Message, ImageRef } from '../llm/provider.js';
21
21
  import type { AgentMetrics } from '../agent/tracer.js';
22
22
  /**
23
23
  * Memora Agent 门面类
@@ -132,8 +132,11 @@ export declare class Agent extends TypedEventEmitter<AgentEventMap> {
132
132
  private createSeedOrchestrator;
133
133
  /**
134
134
  * 流式对话(核心 API)
135
+ *
136
+ * @param attachments 图片附件(可选,多模态输入);透传到种子编排器 → 装配两跳 → 持久化(方案 §7 P0)。
137
+ * 不传 = 纯文本输入,行为与历史完全一致(零兼容回归)。
135
138
  */
136
- chat(input: string, signal?: AbortSignal): AsyncGenerator<AgentChunk, void, unknown>;
139
+ chat(input: string, signal?: AbortSignal, attachments?: readonly ImageRef[]): AsyncGenerator<AgentChunk, void, unknown>;
137
140
  /**
138
141
  * 校验 chat 输入
139
142
  */
@@ -285,6 +288,43 @@ export declare class Agent extends TypedEventEmitter<AgentEventMap> {
285
288
  * 随后 resumeExecution() 续跑。与 answerQuestion 二选一消费在途提问。
286
289
  */
287
290
  cancelAsk(): void;
291
+ /**
292
+ * 当前在途轮次 id(`''` = 无在途轮)
293
+ *
294
+ * 为什么必须由内核给:宿主投影 `TurnState` 的 **waiting 相位不携带 roundId**
295
+ * (ask 挂起时轮身份从快照里消失),而 ask 期停止恰恰需要轮身份来做收场归属
296
+ * (折叠区归属 / 容器底栏时间与复制按钮 / 分叉锚点)。宿主侧任何「上次见过的
297
+ * roundId」缓存都是投影记忆,会与内核真源脱钩。
298
+ *
299
+ * 与 `loop.getCurrentRoundId` 同源同值,不缓存副本(单点直接读)。
300
+ * 保留裁决(对照 PUB-API-PRUNE-2「纯转发门面不留」):该方法**有真实宿主消费**
301
+ * (`AskCoordinator.abandonOnStop` 取轮身份随中断收场下发),非零调用门面;
302
+ * 真身在 loop、而 loop 不对外暴露,故此处转发即最短可达路径。
303
+ */
304
+ currentRoundId(): string;
305
+ /**
306
+ * 放弃当前轮(宿主 stop 语义的**收场**出口 · ADR-044 决策 3)
307
+ *
308
+ * 与 `discardCurrentCheckpoint` 的分野:后者只丢暂停上下文(检查点 + 排队插话),
309
+ * 调用后轮仍是 pending。**提问挂起轮尤其如此**——ask 轮通常无正文,而
310
+ * `appendAssistant` 有空正文守卫(`if (!content.trim()) return`)⇒ 该轮压根没有收场调用点。
311
+ * 停止若只丢检查点,盘上就留下「pending + 残留 pendingAsk」的僵尸轮:视图里永挂,
312
+ * 超时保底又因无可续跑检查点而无从接续。
313
+ *
314
+ * 故 stop = **明确地以中断收场**(不是「不处理」),三步同源:
315
+ * ① `cancelAsk` 补 `[ASK_ABORTED]` 占位 tool 结果——`assistant.tool_calls` 恒有配对,
316
+ * 否则 OpenAI 兼容端 400;无在途提问时天然 no-op;
317
+ * ② `appendInterrupted` 收场当前轮——把盘上残留 `pendingAsk` **整组**转成
318
+ * `kind:'unanswered'` 交互输入(题面与候选不丢),状态标 interrupted;已收场轮
319
+ * 由该方法自身幂等跳过(complete / interrupted 均终态);
320
+ * ③ `discardCurrentCheckpoint` 丢暂停上下文(用户不再续跑)。
321
+ *
322
+ * ① 与 ② 的先后不影响题面:`cancelAsk` 只动进程内 `pendingAsk`(保 tool 配对),
323
+ * 盘上快照不受影响,而 ② 读的正是盘上那份;先做 ① 只为缩短「调用无配对」窗口。
324
+ *
325
+ * @returns 是否清掉了暂停检查点(宿主据此给「检查点已清理」类提示;无则 false)
326
+ */
327
+ abandonTurn(): Promise<boolean>;
288
328
  /**
289
329
  * 回答在途主动提问(ask_user 工具):
290
330
  * 答案以 ask_user 的 tool result 回填(与 assistant.tool_calls 配对,结构合法)。
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"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"}
@@ -368,8 +368,11 @@ export class Agent extends TypedEventEmitter {
368
368
  }
369
369
  /**
370
370
  * 流式对话(核心 API)
371
+ *
372
+ * @param attachments 图片附件(可选,多模态输入);透传到种子编排器 → 装配两跳 → 持久化(方案 §7 P0)。
373
+ * 不传 = 纯文本输入,行为与历史完全一致(零兼容回归)。
371
374
  */
372
- async *chat(input, signal) {
375
+ async *chat(input, signal, attachments) {
373
376
  this.assertInitialized('chat');
374
377
  this.validateChatInput(input);
375
378
  const lockCtx = this.acquireChatLock(signal);
@@ -389,7 +392,7 @@ export class Agent extends TypedEventEmitter {
389
392
  }
390
393
  this._lastInteractionAt = new Date();
391
394
  // 委托种子编排器:对话路径完整闭环(prepare → act → reflect)
392
- yield* this.internals.seedOrchestrator.runChat(input, combinedSignal);
395
+ yield* this.internals.seedOrchestrator.runChat(input, combinedSignal, attachments);
393
396
  }
394
397
  finally {
395
398
  // 流已退出:清除活跃标志(与置位对称;无论正常/异常退出都复位)
@@ -499,7 +502,9 @@ export class Agent extends TypedEventEmitter {
499
502
  async *resumeExecution(input, signal, kind = 'supplement') {
500
503
  const resumeStatus = this._sessionManager?.status;
501
504
  // 错误态续跑须明确失败而非静默吞没:error 态由检查点恢复回填进入,运行时异常走
502
- // yield { type: 'error' } 不翻状态机,生产链路不会自然离开,必须显式提示重新开始
505
+ // yield { type: 'error' } 不翻状态机,生产链路不会自然离开,必须显式提示重新开始。
506
+ // 2026-10-27 拍板:维持不接线、宿主不建恢复入口(宿主策略 = error 视作终态;
507
+ // 内核 recover() 仍为库级公开 API)——详见状态机头注释与台账 HOST-ERR-1
503
508
  if (resumeStatus === 'error') {
504
509
  this.emit(AGENT_EVENTS.sessionResumeFailed, {
505
510
  sessionId: this._sessionManager?.getCheckpoint()?.sessionId,
@@ -868,6 +873,59 @@ export class Agent extends TypedEventEmitter {
868
873
  this.assertInitialized('cancelAsk');
869
874
  this.requireLoop.cancelAsk();
870
875
  }
876
+ /**
877
+ * 当前在途轮次 id(`''` = 无在途轮)
878
+ *
879
+ * 为什么必须由内核给:宿主投影 `TurnState` 的 **waiting 相位不携带 roundId**
880
+ * (ask 挂起时轮身份从快照里消失),而 ask 期停止恰恰需要轮身份来做收场归属
881
+ * (折叠区归属 / 容器底栏时间与复制按钮 / 分叉锚点)。宿主侧任何「上次见过的
882
+ * roundId」缓存都是投影记忆,会与内核真源脱钩。
883
+ *
884
+ * 与 `loop.getCurrentRoundId` 同源同值,不缓存副本(单点直接读)。
885
+ * 保留裁决(对照 PUB-API-PRUNE-2「纯转发门面不留」):该方法**有真实宿主消费**
886
+ * (`AskCoordinator.abandonOnStop` 取轮身份随中断收场下发),非零调用门面;
887
+ * 真身在 loop、而 loop 不对外暴露,故此处转发即最短可达路径。
888
+ */
889
+ currentRoundId() {
890
+ this.assertInitialized('currentRoundId');
891
+ return this.requireLoop.getCurrentRoundId();
892
+ }
893
+ /**
894
+ * 放弃当前轮(宿主 stop 语义的**收场**出口 · ADR-044 决策 3)
895
+ *
896
+ * 与 `discardCurrentCheckpoint` 的分野:后者只丢暂停上下文(检查点 + 排队插话),
897
+ * 调用后轮仍是 pending。**提问挂起轮尤其如此**——ask 轮通常无正文,而
898
+ * `appendAssistant` 有空正文守卫(`if (!content.trim()) return`)⇒ 该轮压根没有收场调用点。
899
+ * 停止若只丢检查点,盘上就留下「pending + 残留 pendingAsk」的僵尸轮:视图里永挂,
900
+ * 超时保底又因无可续跑检查点而无从接续。
901
+ *
902
+ * 故 stop = **明确地以中断收场**(不是「不处理」),三步同源:
903
+ * ① `cancelAsk` 补 `[ASK_ABORTED]` 占位 tool 结果——`assistant.tool_calls` 恒有配对,
904
+ * 否则 OpenAI 兼容端 400;无在途提问时天然 no-op;
905
+ * ② `appendInterrupted` 收场当前轮——把盘上残留 `pendingAsk` **整组**转成
906
+ * `kind:'unanswered'` 交互输入(题面与候选不丢),状态标 interrupted;已收场轮
907
+ * 由该方法自身幂等跳过(complete / interrupted 均终态);
908
+ * ③ `discardCurrentCheckpoint` 丢暂停上下文(用户不再续跑)。
909
+ *
910
+ * ① 与 ② 的先后不影响题面:`cancelAsk` 只动进程内 `pendingAsk`(保 tool 配对),
911
+ * 盘上快照不受影响,而 ② 读的正是盘上那份;先做 ① 只为缩短「调用无配对」窗口。
912
+ *
913
+ * @returns 是否清掉了暂停检查点(宿主据此给「检查点已清理」类提示;无则 false)
914
+ */
915
+ async abandonTurn() {
916
+ this.assertInitialized('abandonTurn');
917
+ this.cancelAsk();
918
+ const roundId = this.requireLoop.getCurrentRoundId();
919
+ if (roundId && this.history) {
920
+ try {
921
+ await this.history.appendInterrupted(roundId);
922
+ }
923
+ catch (err) {
924
+ logger.warn({ err, roundId }, 'abandonTurn: 中断收场写入失败');
925
+ }
926
+ }
927
+ return this.discardCurrentCheckpoint();
928
+ }
871
929
  /**
872
930
  * 回答在途主动提问(ask_user 工具):
873
931
  * 答案以 ask_user 的 tool result 回填(与 assistant.tool_calls 配对,结构合法)。