@lqc123qwe/car-runtime 1.14.1 → 1.15.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
@@ -286,8 +286,18 @@ node --experimental-transform-types --test test/*.spec.ts
286
286
 
287
287
  ## 状态
288
288
 
289
- - **版本主线**:S1-S4 48/48 | M2 89/89(v0.2.0)| M3 127/127(v0.3.0)| M4 139/139(**1.0.0-rc.1 已发布**)| M5 156/156(DEC-4 预埋项转正)| M6 179/179(2026-09-15 收口)| M7 全量 195(192 PASS + 3 能力门控 skip,2026-09-19 收口)| **M5-S28 装载签名门 全量 204(201 PASS + 3 skip,2026-09-26)** | **M8 运行时底座 全量 231(228 PASS + 3 skip,2026-09-26 收口,§3.2 八模块全部收口)** | **1.1 签名收尾最小集 全量 249(246 PASS + 3 skip,2026-09-27 收口,1.1.0 已发布,enforce 翻转准备就绪)** | **1.2 会话/遥测小项 全量 263(260 PASS + 3 skip,2026-09-27 收口,1.2.0 已发布)** | **1.3 发布资产自动化 全量 270(267 PASS + 3 skip,2026-09-27 收口,1.3.0 已发布,全链零人工拖拽兑现)** | **1.4 真实模型接入 全量 282(279 PASS + 3 skip,2026-09-27 收口,1.4.0 已发布)** | **1.5 provider 扩展+远程 MCP+配置完整形态 全量 300(297 PASS + 3 skip,2026-09-28 收口,1.5.0 已发布)** | **1.6 宿主工具面+投影收敛+jiti 载体 全量 318(315 PASS + 3 skip,2026-09-28 收口,1.6.0 已发布)** | **1.7 OTLP span 语义收口+metrics 时序修正+mcp-serve span 面 全量 328(325 PASS + 3 skip,2026-09-28 收口,1.7.0 已发布)** | **1.8 W3C traceparent 跨进程传播+LLM 出站通道修复 全量 335(332 PASS + 3 skip,2026-09-29 收口,1.8.0 已发布)** | **1.9 远程 MCP traceparent 传播(HTTP 头通道) 全量 339(336 PASS + 3 skip,2026-09-29 收口,1.9.0 已发布)** | **1.10 KernelSeam 公开导出面+库构建产物 全量 341(338 PASS + 3 skip,2026-09-29 收口,1.10.0 已发布)** | **1.11 seam authz 导出+usage 事件计量采集 全量 355(352 PASS + 3 skip,2026-10-07 收口,1.11.0 已发布)** | **1.12 seam MCP/PTC 真桥导出面+jiti epoch 面确认 全量 363(360 PASS + 3 skip,2026-10-07 收口,1.12.0 已发布)** | **1.13 桌面 S3 治理面(K-FS-1/2/3+K-SC-1 authorizeAll/decideByRule/fs-read·fs-delete 能力 + seam 出面 redact/loadSessionLog/exportForensicsBundle;恢复面 K-S3-2 零登记确认——fromEvents 自 M5 在产) 全量 374(371 PASS + 3 skip,2026-10-11 收口,1.13.0 已发布)** | **1.14 模型参数/压缩/分段/模型池/PluginManager 五候选(K-MP-1 reasoning 透传 + K-MP-2 压缩面 append-only context/compact + K-MP-2b 分段计量 + K-POOL-1 模型池 routing/decide 落链 + K-S4-1 seam 出面装载报告面;D-43 裁决登记 strict 期限不引入 sigstore——engines 硬不兼容见评估报告) 全量 419(416 PASS + 3 skip,2026-10-18 收口,1.14.0 已发布)**
289
+ - **版本主线**:S1-S4 48/48 | M2 89/89(v0.2.0)| M3 127/127(v0.3.0)| M4 139/139(**1.0.0-rc.1 已发布**)| M5 156/156(DEC-4 预埋项转正)| M6 179/179(2026-09-15 收口)| M7 全量 195(192 PASS + 3 能力门控 skip,2026-09-19 收口)| **M5-S28 装载签名门 全量 204(201 PASS + 3 skip,2026-09-26)** | **M8 运行时底座 全量 231(228 PASS + 3 skip,2026-09-26 收口,§3.2 八模块全部收口)** | **1.1 签名收尾最小集 全量 249(246 PASS + 3 skip,2026-09-27 收口,1.1.0 已发布,enforce 翻转准备就绪)** | **1.2 会话/遥测小项 全量 263(260 PASS + 3 skip,2026-09-27 收口,1.2.0 已发布)** | **1.3 发布资产自动化 全量 270(267 PASS + 3 skip,2026-09-27 收口,1.3.0 已发布,全链零人工拖拽兑现)** | **1.4 真实模型接入 全量 282(279 PASS + 3 skip,2026-09-27 收口,1.4.0 已发布)** | **1.5 provider 扩展+远程 MCP+配置完整形态 全量 300(297 PASS + 3 skip,2026-09-28 收口,1.5.0 已发布)** | **1.6 宿主工具面+投影收敛+jiti 载体 全量 318(315 PASS + 3 skip,2026-09-28 收口,1.6.0 已发布)** | **1.7 OTLP span 语义收口+metrics 时序修正+mcp-serve span 面 全量 328(325 PASS + 3 skip,2026-09-28 收口,1.7.0 已发布)** | **1.8 W3C traceparent 跨进程传播+LLM 出站通道修复 全量 335(332 PASS + 3 skip,2026-09-29 收口,1.8.0 已发布)** | **1.9 远程 MCP traceparent 传播(HTTP 头通道) 全量 339(336 PASS + 3 skip,2026-09-29 收口,1.9.0 已发布)** | **1.10 KernelSeam 公开导出面+库构建产物 全量 341(338 PASS + 3 skip,2026-09-29 收口,1.10.0 已发布)** | **1.11 seam authz 导出+usage 事件计量采集 全量 355(352 PASS + 3 skip,2026-10-07 收口,1.11.0 已发布)** | **1.12 seam MCP/PTC 真桥导出面+jiti epoch 面确认 全量 363(360 PASS + 3 skip,2026-10-07 收口,1.12.0 已发布)** | **1.13 桌面 S3 治理面(K-FS-1/2/3+K-SC-1 authorizeAll/decideByRule/fs-read·fs-delete 能力 + seam 出面 redact/loadSessionLog/exportForensicsBundle;恢复面 K-S3-2 零登记确认——fromEvents 自 M5 在产) 全量 374(371 PASS + 3 skip,2026-10-11 收口,1.13.0 已发布)** | **1.14 模型参数/压缩/分段/模型池/PluginManager 五候选(K-MP-1 reasoning 透传 + K-MP-2 压缩面 append-only context/compact + K-MP-2b 分段计量 + K-POOL-1 模型池 routing/decide 落链 + K-S4-1 seam 出面装载报告面;D-43 裁决登记 strict 期限不引入 sigstore——engines 硬不兼容见评估报告) 全量 419(416 PASS + 3 skip,2026-10-18 收口,1.14.0 已发布)** | **1.14.1 B2 前置消费面(ChatStepOptions.reasoning 透传 + shouldCompact/applyCompaction + assembleModelPool/probePoolMember 出面,seam 35→39 符号) 全量 423(420 PASS + 3 skip,2026-10-18,1.14.1 已发布)** | **1.15 白盒记忆+引导消息双候选(K-MEM-1 记忆 CRUD 落链 + 链即版本库 rollback + 注入装载预算门控 + K-STEER-1 投影隔离 + pendingSteerTurns 排队扫描;seam 39→42 符号) 全量 439(438 PASS + 1 skip,2026-10-19 收口,1.15.0 发布中)**
290
+ - **1.15 状态(白盒记忆 + 引导消息双候选,桌面 v0.2-B3 批)**:S1 K-MEM-1(`be08c3e`)+ S2 K-STEER-1(`2f1a466`)+ S3 seam 出面(39→42 运行时符号:+MemoryStore/+loadMemoryForInjection/+pendingSteerTurns + 5 类型;负面清单:存储引擎内部件/注入落链执行器/消费调度器不出面);dist 重建 s44 检查绿;规划与执行注记:`car-docs/10-内核v1/1.15-迭代规划.md`(D-46/D-47/D-48)。
290
291
  - **1.14.0 正式发布(2026-10-18,桌面 v0.2-B1 批)**:npm `@lqc123qwe/car-runtime@1.14.0` 在架——**dist-tags latest → 1.14.0 + SLSA provenance 在案**(npm transparency log 3308759260)。Release `1.14.0`(id 416323415,target_commitish=完整 SHA `92a35904c5179a99cdb69d82542953f82fb920ba`;main 推送**首次直连通道**——90c653c→92a3590 共 13 commits,WorkBuddy 沙箱代理 502 根因落档后直连常态化,Git Data API 复刻通道退役为应急预案)→ **j16 run 全 13 步 success**(cosign keyless OIDC+Rekor:tgz bundle logIndex 3308757191)→ **post-publish REMOTE_CHECK 13 PASS / 0 DRY-RUN / 0 FAIL**(G-09 npm 在架 latest + SLSA provenance ✓ / G-10 Release 五件套齐备 / G-04 audit 0);外部等价检查:Release 实下载件 SHA256 MATCH(cb43ec0b9b1f7ad4…)+ cosign verify-blob **Verified OK**(Fulcio + Rekor tlog)+ registry tarball ↔ tag 树 src 面逐字节一致(51 文件)+ dist 面语义等价(去引号逐字节一致——CI `npx -y -p typescript` 未钉版引号发射差异,登记非偏差)+ dist/seam.js 35 符号在库 ✓。seam 32→35 运行时符号(+8 类型)。
292
+ - **1.14.1 已发布(2026-10-18,B2 前置消费面,`cdb28d0`)**:npm latest → 1.14.1——ChatStepOptions.reasoning 透传(K-MP-1 消费面:reasoning 仅经直接 adapter.chat 在 1.14.0 不可达,off/缺席 = 字节面零痕迹)+ seam 出面 shouldCompact/applyCompaction + CompactionConfig(K-MP-2 行为 API:自动挂载点在宿主装配层,立即压缩 API 独立可用,append-only 红线随本面)+ assembleModelPool/probePoolMember + PoolMember/RoutingDecision 类型(K-POOL-1 池设置 UI + doctor 端点健康消费面);s54 4/4;seam 35→39 符号;桌面 B2 消费实证(v0.2-S5 终验 12/12 PASS)。
293
+
294
+ ## 1.15 状态(白盒记忆 + 引导消息双候选:K-MEM-1 + K-STEER-1)
295
+
296
+ | `src/memory/store.ts` | 1.15-S1(K-MEM-1 / D-46,`be08c3e`):**白盒记忆面**——MemoryStore(`<workspace>/.car/memory/` 逐条 JSON:id 即文件名 + ID_RE 路径穿越拒绝 + tmp+rename 原子写 + dir 分片天然隔离)+ CRUD 落链(EventKind `'memory'` 加法:actor='user'、turnId='memory' 同 'compaction' 先例、payload.type write/edit/delete/rollback;**text=操作后/before=操作前统一口径**;log 参数必填 CAR-E-MEM-NOCHAIN——无会话上下文显式拒绝不留旁路写入通道)+ **链即版本库 rollback**(undo 栈单步时间回退:edit→恢复 before / delete→undelete / 删除后重建→回退到删除态返回 null;重放 = push…push/pop 与调用期回退同构)+ loadMemoryForInjection(updatedAt 降序全量确定性拼装禁静默选择性 + CAR-E-MEM-BUDGET 字符近似门控 fail-visible + 空记忆正常态)+ fail-visible 九码(NOCHAIN/EXISTS/NOENT/EMPTY/ID/FORMAT/IO/NOREV/BUDGET)+ 零凭据路径(spec 行为锁定)。**执行注记(s55 首轮三红根因)**:rollback 重放首版把 rollback 事件也 push 进栈致回退振荡——修正为版本栈模型 **rollback 重放 = pop**(连续回退单方向逐版本回走);payload 初稿 text/after 双字段并存统一为 text/before 双字段 | 审计链同源 = 记忆篡改在链上可见(D-V02-2 差异化核心);注入落链 = 宿主 system ctx 行(D-C3 预留位),内核零投影 |
297
+ | `src/session/steer.ts` + `src/session/log.ts` + `src/runtime-core/chatStep.ts` + `src/loop/stop.ts` | 1.15-S2(K-STEER-1 / D-47,`2f1a466`):**引导消息语义**——投影隔离(deriveMessages 增 opts.activeTurnId:跳过 kind='user' 且 seq > 活跃 turn 起点 seq 且 turnId ≠ 活跃 turnId = 引导排队事件链上特征精确匹配;**非 turn 开始快照**——快照会误杀 turn 内 toolResult 增量〔agent loop 依赖实时投影〕;无引导链过滤零命中 = 与 1.14.1 逐字节一致)+ 快照口径同构(ModelSnapshot.activeTurnId **随快照落盘**,assertModelVisibleLogged 同口径重算逐字节比对)+ chatStep 单点接线(宿主经既有 model() 闭包自动获益)+ pendingSteerTurns 排队扫描(未闭合 user 事件按 seq 序 {seq,ts,turnId,text};excludeTurnId 排除执行中 turn;FIFO 消费调度留宿主装配层;steer append 零内核加法——SessionLog.append 本就任意时刻可调)。**执行注记(N1 假红根因)**:快照首版存了过滤投影但漏存 activeTurnId 口径字段——assert 重算口径丢失 → CAR-E-N1 atSeq=4 假红(spy 对拍定位);修复 = 口径必须随快照落盘。R-8 锁定:消费前崩溃 → 执行中+引导 turn 均补记 interrupted(recovered=true)+ pending 清零 + 引导事件留链不静默吞 | 引导 ≠ 注入当前 turn 上下文(D-V02-9 红线:请求体逐字节对拍在册);消费 turn 以引导事件自身 turnId 续跑,链上 turnEnd 全齐 |
298
+ | `src/seam.ts` + `test/s44` | 1.15-S3:**seam 出面统一**——39→**42 运行时符号**(+MemoryStore/+loadMemoryForInjection/+pendingSteerTurns + 5 类型 MemoryEntry/MemoryOp/MemoryEventPayload/MemoryInjectionResult/PendingSteerTurn);负面清单(不出面):存储引擎内部件(文件读写器/预算计算器/版本栈重放器 #私有)、注入落链执行器(宿主 system ctx 行职责)、消费调度器(宿主 FIFO 续跑职责)、cli 引导接线(非验收必需);dist 重建 s44 dist 检查绿 | 桌面 B4(T-11 记忆面板 / T-18 引导交互)消费面;最窄面纪律(T-6 口径) |
299
+
300
+ - **1.15 工程收口(2026-10-19,S1~S3)**:全量 **439(438 PASS + 1 skip / 0 fail)** = 1.14.1 基线 423 + s55 10 + s56 6;tsc strict 双配置 0 + secrets-scan 0(commit 后复跑)+ contract-check 4/4(golden 不动)+ package-check 3/3;存量 spec 零改动通过 = 兼容验收线(无记忆调用无引导事件时 1.14.1 行为零变化)。1.15.0 发布(S4)后解锁桌面 B4。
291
301
  - **1.13.0 正式发布(2026-10-11,桌面 S3-S1)**:npm `@lqc123qwe/car-runtime@1.13.0` 在架——**dist-tags latest → 1.13.0 + provenance 在案**。Release `1.13.0`(id 409512865,target_commitish=完整 SHA;main 推送经 Git Data API 逐字节复刻——blob 9/9 + tree `eea7249` + commit `ab59468` 全 SHA 对拍零分叉;**发布工程事件两项**:①GitHub commit API 保留 author/committer 时区偏移(+08:00 原样入对象)但**消息不自动补尾 `\n`**——payload 须带原文尾换行,否则 SHA 分叉(39477b4 教训,本地 `$()` 吞尾换行加剧排查成本);②registry 元数据 CDN 滞后使本地 `npm install` notarget——cache-buster 复查口径 + `--prefer-online` 安装)→ **run 38122530955 全步 success** → registry tarball dist/seam.js 32 符号文本核验 ✓ + **桌面侧消费验证:car-desktop 装 1.13.0 后 29/29 测试全绿 + SMOKE PASS(seamVersion 1.13.0 · symbolCount 32)**。
292
302
  - **1.0.0 正式发布(2026-09-26,S29/S30)**:npm `@lqc123qwe/car-runtime@1.0.0` 在架——**dist-tag latest → 1.0.0,rc 保留指向 1.0.0-rc.1**(§1.1 口径);SLSA provenance(Actions OIDC,透明日志在案);GitHub Release v1.0.0 六资产(tgz/bundle/SHA256SUMS/SBOM/审计/公钥);**post-publish 全链 13 PASS / 0 DRY-RUN / 0 FAIL** + 外部验证者等价检查(Release 实下载件 SHA256 MATCH + cosign Verified OK)。**宽限期时钟:2026-09-26 起算,2026-12-25 到期 verifier 默认值 warn→enforce 翻转(计划内变更)**。终验报告:`car-docs/10-内核v1/M5-S30-1.0收口终验报告.md`。发布工程事件:j16 首跑 E403(npm 2FA 策略 vs granular token 无 bypass——清单预设回退路径兑现)→ bypass token re-run 绿;G-09 期望 tag 动态化(`4c84b17`)在真实发布兑现价值。
293
303
  - **1.0.0-rc.1 已发布(2026-09-09)**:npm `@lqc123qwe/car-runtime@1.0.0-rc.1`(rc + latest 双 tag,SLSA provenance 在案)+ GitHub Release 6 制品;发布预演 **13 PASS / 0 DRY-RUN / 0 FAIL**(c762b72)。S22 GO 清单已全绿收口。
package/dist/SHA256SUMS CHANGED
@@ -1 +1 @@
1
- 88b55ba110b87ca79e9ea635b0b58d875d7d5c0018493f6154e210e1e1613aed car-runtime-1.14.1.tgz
1
+ 9ba612b6464b7bc4798446987dc683af7f38964846e761b52d0f4f12caa7922e car-runtime-1.15.0.tgz
Binary file
@@ -0,0 +1 @@
1
+ {"base64Signature":"MEQCIFcn/dz1pH2TuIhMJ7gmmIeBNWNWzbAZyPkMFDLWWEe5AiBMPsruOYpxxCHS1EcnPe7baqT7OmtF1rUyblO0ucrPLg==","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1ekNDQm0yZ0F3SUJBZ0lVUEI5WUptSStySlBtTWtoL1dPaWZWOG5vREFrd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1ERTVNRFl6TkRNM1doY05Nall4TURFNU1EWTBORE0zV2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVvdnBUdnpCRHRSemQ4VU9leFM4ck1lanNLVVBhVVVSMzlSR3AKeGNiWFdTV1FSR1Y0NEtpN2JMcUNwWHFxcUwwaWZiSVdPcW1Wa2dQTTJ1NXp3d0pBOHFPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUxTGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRGswWVdSbVlXTTBaR1poTXpZNU16SmtNamczT0RkaQpOekV6Tm1FMk5ERXdNMk5pTXpBNFlXVXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNVFV1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUxTGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnNQpOR0ZrWm1Gak5HUm1ZVE0yT1RNeVpESTROemczWWpjeE16WmhOalF4TUROallqTXdPR0ZsTUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnNQpOR0ZrWm1Gak5HUm1ZVE0yT1RNeVpESTROemczWWpjeE16WmhOalF4TUROallqTXdPR0ZsTUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNVFV1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpFMUxqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2c1TkdGa1ptRmpOR1JtWVRNMk9UTXlaREk0TnpnM1lqY3hNelpoTmpReE1ETmpZak13T0dGbE1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6TTVNakV3TmprMgpNemcyTDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eE5TNHdNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2hVdDZGYUFBQUJBTUFSekJGCkFpRUExZ05kSDdqUXVHTENRcDFZSjhIK0F2TW81Z2xBYWFRM1dNM2JpSFBwT3ZNQ0lHUEM0S29EOTg1aldZQW4KeE81eG9GMDhua3JpSms1bWVvaWhWK0I1VVhXbk1Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01BNlYwR1hEOFF2SQpKVVNGT3RaTEVQb2ZTVU90cTlhdmZKaFdsK1lzc1VFUldwQnRkbDFZRXB4blpNYm5sc05kQndJeEFMYjQzREFyCjM5cUhZbUdqNmc4cFRxb0VIZkMvelRFMXBpVGdkVTFxWjZaeDRnNHhYcHpXWFZpU2pXaHd5VEc5VEE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEQCICyxor/1QbW6qzgO6LFkHPbfLog9AKl0T4iGuJg6wkpWAiA2e8brMg+PWLrEADbTTmmoP2Vm2TGqgJDJNIY7tGMm0g==","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiI5YmE2MTJiNjQ2NGI3YmM0Nzk4NDQ2OTg3ZGM2ODNhZjdmMzg5NjQ4NDZlNzYxYjUyZDBmNGYxMmNhYTc5MjJlIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJRmNuL2R6MXBIMlR1SWhNSjdnbW1JZUJOV05XemJBWnlQa01GRExXV0VlNUFpQk1Qc3J1T1lweHhDSFMxRWNuUGU3YmFxVDdPbXRGMXJVeWJsTzB1Y3JQTGc9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFla05EUW0weVowRjNTVUpCWjBsVlVFSTVXVXB0U1N0eVNsQnRUV3RvTDFkUGFXWldPRzV2UkVGcmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFUlRWTlJGbDZUa1JOTTFkb1kwNU5hbGw0VFVSRk5VMUVXVEJPUkUwelYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZ2ZG5CVWRucENSSFJTZW1RNFZVOWxlRk00Y2sxbGFuTkxWVkJoVlZWU016bFNSM0FLZUdOaVdGZFRWMUZTUjFZME5FdHBOMkpNY1VOd1dIRnhjVXd3YVdaaVNWZFBjVzFXYTJkUVRUSjFOWHAzZDBwQk9IRlBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha1V4VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkdzd1dWZFNiVmxYVFRCYVIxcG9UWHBaTlUxNlNtdE5hbWN6VDBSa2FRcE9la1Y2VG0xRk1rNUVSWGROTWs1cFRYcEJORmxYVlhkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOVkZWMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrVXhUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5OUXBPUjBacldtMUdhazVIVW0xWlZFMHlUMVJOZVZwRVNUUk9lbWN6V1dwamVFMTZXbWhPYWxGNFRVUk9hbGxxVFhkUFIwWnNUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk5RcE9SMFpyV20xR2FrNUhVbTFaVkUweVQxUk5lVnBFU1RST2VtY3pXV3BqZUUxNldtaE9hbEY0VFVST2FsbHFUWGRQUjBac1RVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOVkZWMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BGTVV4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjMVRrZEdhMXB0Um1wT1IxSnRXVlJOTWs5VVRYbGFSRWswVG5wbk0xbHFZM2hOZWxwb1RtcFJlRTFFVG1wWmFrMTNUMGRHYkUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlRUVk5ha1YzVG1wck1ncE5lbWN5VERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZUU1VE5IZE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyaFZkRFpHWVVGQlFVSkJUVUZTZWtKR0NrRnBSVUV4WjA1a1NEZHFVWFZIVEVOUmNERlpTamhJSzBGMlRXODFaMnhCWVdGUk0xZE5NMkpwU0ZCd1QzWk5RMGxIVUVNMFMyOUVPVGcxYWxkWlFXNEtlRTgxZUc5R01EaHVhM0pwU21zMWJXVnZhV2hXSzBJMVZWaFhiazFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMUJObFl3UjFoRU9GRjJTUXBLVlZOR1QzUmFURVZRYjJaVFZVOTBjVGxoZG1aS2FGZHNLMWx6YzFWRlVsZHdRblJrYkRGWlJYQjRibHBOWW01c2MwNWtRbmRKZUVGTVlqUXpSRUZ5Q2pNNWNVaFpiVWRxTm1jNGNGUnhiMFZJWmtNdmVsUkZNWEJwVkdka1ZURnhXalphZURSbk5IaFljSHBYV0ZacFUycFhhSGQ1VkVjNVZFRTlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1792391678,"logIndex":3319511581,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
package/dist/loop/stop.js CHANGED
@@ -114,7 +114,9 @@ export async function runTurn(opts) {
114
114
  return { reason: 'aborted', steps, endReasonTrail: trail };
115
115
  }
116
116
  steps++;
117
- log.snapshotModelRequest(); // agent-loop 集成点:请求时快照(N1)
117
+ // 1.15-S2(K-STEER-1 / D-47):快照带活跃 turn 口径——与请求投影(chatStep 内
118
+ // activeTurnId 过滤)同构,N1 逐快照自洽;无引导事件时与 1.14.1 逐字节一致
119
+ log.snapshotModelRequest({ activeTurnId: turnId }); // agent-loop 集成点:请求时快照(N1)
118
120
  const step = await model();
119
121
  if (step.stopReason === 'error') {
120
122
  const seq = closeTurn({ reason: 'error' }).seq;
@@ -0,0 +1,67 @@
1
+ import type { SessionLog } from '../session/log.ts';
2
+ export type MemoryOp = 'write' | 'edit' | 'delete' | 'rollback';
3
+ export interface MemoryEntry {
4
+ id: string;
5
+ text: string;
6
+ tags?: string[];
7
+ createdAt: number;
8
+ updatedAt: number;
9
+ /** 创建来源会话(write 时调用方提供;可溯性辅助,非鉴权字段) */
10
+ sourceSession?: string;
11
+ }
12
+ /** 链上 memory 事件 payload 统一形态(kind='memory',payload.type 区分操作) */
13
+ export interface MemoryEventPayload {
14
+ type: MemoryOp;
15
+ id: string;
16
+ /** 操作后状态正文:write 的初始正文 / edit 的新正文 / rollback 的恢复正文;delete 与回退到删除态时缺席 */
17
+ text?: string;
18
+ /** 操作前状态正文:edit 的被替换正文 / delete 的被删正文 / rollback 的被回退正文(链即版本库的恢复数据源) */
19
+ before?: string;
20
+ tags?: string[];
21
+ /** rollback 溯源:被回退到的状态所对应的事件 seq */
22
+ fromSeq?: number;
23
+ }
24
+ export declare class MemoryStore {
25
+ #private;
26
+ readonly dir: string;
27
+ constructor(dir: string);
28
+ /** 列出全部记忆(updatedAt 降序——最近维护优先);坏文件显式拒绝(带病不静默,loadSessionLog 同纪律) */
29
+ list(): MemoryEntry[];
30
+ get(id: string): MemoryEntry | undefined;
31
+ /**
32
+ * 创建记忆:落 memory/write 事件(payload 携带完整正文)→ 原子写文件。
33
+ * id 缺省派生 `mem-<ts36>-<rand>`;对已存在 id 冲突显式拒绝(改用 edit)。
34
+ */
35
+ write(log: SessionLog, input: {
36
+ id?: string;
37
+ text: string;
38
+ tags?: string[];
39
+ sourceSession?: string;
40
+ }): MemoryEntry;
41
+ /** 修改记忆:落 memory/edit 事件(payload before/after 全文——rollback 的恢复数据源)→ 原子重写 */
42
+ edit(log: SessionLog, id: string, text: string, tags?: string[]): MemoryEntry;
43
+ /** 删除记忆:落 memory/delete 事件(payload 携带被删正文——rollback 可恢复)→ 删文件 */
44
+ remove(log: SessionLog, id: string): void;
45
+ /**
46
+ * 回滚记忆:沿事件链单步时间回退(undo 栈语义——连续回退逐版本回走:v3→v2→v1)。
47
+ * 恢复数据源 = 链上版本栈重放(链即版本库,不依赖文件系统历史)。落 memory/rollback
48
+ * 事件(before/after 全文 + fromSeq 溯源)→ 文件动作。返回 null = 回退到删除态。
49
+ * 语义:edit 后回退 → 恢复 before;delete 后回退 → undelete(恢复被删正文);
50
+ * 仅剩 write 初始版 / 链上无历史 → CAR-E-MEM-NOREV。
51
+ */
52
+ rollback(log: SessionLog, id: string): MemoryEntry | null;
53
+ }
54
+ export interface MemoryInjectionResult {
55
+ count: number;
56
+ totalChars: number;
57
+ /** 确定性拼装文本(updatedAt 降序全量)——宿主落 system ctx 行的原文(D-C3 预留位) */
58
+ rendered: string;
59
+ }
60
+ /**
61
+ * 注入装载:全量装入(updatedAt 降序,禁静默选择性注入——选择性 = 不可解释),
62
+ * 字符近似预算门控(行为门控非计量出数;超预算 fail-visible 不静默截断——
63
+ * 提示宿主调大预算或删减记忆)。空记忆 = 空串 + count 0(正常态非错误,宿主跳过注入行)。
64
+ */
65
+ export declare function loadMemoryForInjection(store: MemoryStore, opts: {
66
+ budgetChars: number;
67
+ }): MemoryInjectionResult;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * 1.15-S1 · 白盒记忆面(K-MEM-1 / D-46)——存储 + CRUD 落链 + 注入装载
3
+ *
4
+ * 口径(红线先立后码):
5
+ * - **审计链同源(差异化核心,D-V02-2)**:记忆 write/edit/delete/rollback 全部落会话
6
+ * JSONL 审计事件(EventKind='memory',actor='user',turnId='memory'——会话级能力面,
7
+ * 同 'compaction' 先例),哈希链保护——记忆篡改在链上可见;**链即版本库**:rollback
8
+ * 的恢复数据源 = 链上历史事件的 payload(before/after 全文),不依赖文件系统历史;
9
+ * - **append-only 红线**:CRUD 只走 SessionLog.append(SessionLog 无 update/delete API);
10
+ * delete 与 rollback 均为补偿事件追加,已落链事件零改写;node:test 断言操作前后
11
+ * verifyChain() 均 null 且旧事件逐字节不变;
12
+ * - **存储形态(D-46 ①)**:`<workspace>/.car/memory/` 逐条 JSON 文件(记忆 id 为文件名,
13
+ * 内含正文 + 元数据),与 `.car/sessions/` 每会话一文件同构——白盒可见性最强、CRUD
14
+ * 单条原子性天然;写入 = 临时文件 + rename 原子替换(半文件不落地);工作区分片 =
15
+ * 不同 dir 的 store 实例天然隔离;id 即文件名——形态校验拒绝路径穿越(fail-visible);
16
+ * - **落链作用域(D-46 ②)**:CRUD 事件落调用方传入的会话链(宿主指定当前活跃会话
17
+ * 承载);log 参数必填——无会话上下文调用显式拒绝(CAR-E-MEM-NOCHAIN,fail-visible,
18
+ * 不留旁路写入通道);
19
+ * - **落链与文件动作顺序(§3.2.M7.5 同源)**:先落链(sink 成功后才入内存)后写文件——
20
+ * 审计链为权威;文件动作失败 CAR-E-MEM-IO 显式抛出(调用方知情,fail-visible);
21
+ * - **注入装载(D-46 ③④)**:loadMemoryForInjection 出确定性拼装文本(updatedAt 降序,
22
+ * 全量装入——禁静默选择性注入),字符近似预算门控(行为门控非计量出数,D-41 不适用);
23
+ * 超预算 CAR-E-MEM-BUDGET fail-visible 不静默截断;注入落链由宿主装配层执行(turn
24
+ * 开始前 append system ctx 行 = D-C3 预留位,Model-visible means logged 由构造保证);
25
+ * - **零凭据路径**:本模块不读 env、不触 CredentialService(spec 行为断言锁定);
26
+ * - **零新依赖**:node:fs / node:crypto 内置件;v0.2 收窄 = 手动白盒(D-V02-4)——
27
+ * 自动抽取/Dream/向量检索/全文匹配过滤均不做(登记可溯)。
28
+ */
29
+ import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from 'node:fs';
30
+ import { join } from 'node:path';
31
+ import { randomBytes } from 'node:crypto';
32
+ /** id 即文件名——禁路径穿越:字母数字开头,仅 [A-Za-z0-9._-],且不接纳以 '.' 开头的隐藏态(write 派生 id 恒字母开头) */
33
+ const ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
34
+ function assertValidId(id) {
35
+ if (typeof id !== 'string' || !ID_RE.test(id) || id.includes('..')) {
36
+ throw new Error(`CAR-E-MEM-ID: 非法记忆 id "${String(id).slice(0, 64)}"(允许:字母/数字开头,[A-Za-z0-9._-],≤128——id 即文件名,路径穿越 fail-visible 拒绝)`);
37
+ }
38
+ }
39
+ export class MemoryStore {
40
+ dir;
41
+ constructor(dir) {
42
+ this.dir = dir;
43
+ mkdirSync(dir, { recursive: true });
44
+ }
45
+ #file(id) {
46
+ assertValidId(id);
47
+ return join(this.dir, `${id}.json`);
48
+ }
49
+ /** 列出全部记忆(updatedAt 降序——最近维护优先);坏文件显式拒绝(带病不静默,loadSessionLog 同纪律) */
50
+ list() {
51
+ const out = [];
52
+ for (const name of readdirSync(this.dir)) {
53
+ if (!name.endsWith('.json'))
54
+ continue;
55
+ const file = join(this.dir, name);
56
+ let entry;
57
+ try {
58
+ entry = JSON.parse(readFileSync(file, 'utf8'));
59
+ }
60
+ catch (e) {
61
+ throw new Error(`CAR-E-MEM-FORMAT: 记忆文件 ${name} 非法 JSON——拒绝带病装载(${e.message})`);
62
+ }
63
+ if (typeof entry?.id !== 'string' || typeof entry?.text !== 'string') {
64
+ throw new Error(`CAR-E-MEM-FORMAT: 记忆文件 ${name} 缺 id/text 字段——拒绝带病装载`);
65
+ }
66
+ out.push(entry);
67
+ }
68
+ return out.sort((a, b) => b.updatedAt - a.updatedAt);
69
+ }
70
+ get(id) {
71
+ const file = this.#file(id);
72
+ if (!existsSync(file))
73
+ return undefined;
74
+ const entry = JSON.parse(readFileSync(file, 'utf8'));
75
+ if (typeof entry?.id !== 'string' || typeof entry?.text !== 'string') {
76
+ throw new Error(`CAR-E-MEM-FORMAT: 记忆文件 ${id}.json 缺 id/text 字段——拒绝带病装载`);
77
+ }
78
+ return entry;
79
+ }
80
+ /** 原子写(临时文件 + rename——半文件不落地) */
81
+ #writeFile(entry) {
82
+ const file = this.#file(entry.id);
83
+ const tmp = `${file}.tmp`;
84
+ writeFileSync(tmp, JSON.stringify(entry, null, 2) + '\n', 'utf8');
85
+ renameSync(tmp, file);
86
+ }
87
+ /**
88
+ * 创建记忆:落 memory/write 事件(payload 携带完整正文)→ 原子写文件。
89
+ * id 缺省派生 `mem-<ts36>-<rand>`;对已存在 id 冲突显式拒绝(改用 edit)。
90
+ */
91
+ write(log, input) {
92
+ if (!log || typeof log.append !== 'function') {
93
+ throw new Error('CAR-E-MEM-NOCHAIN: 记忆 CRUD 必须传入会话链(D-46 ②:落链作用域 = 宿主指定活跃会话;无会话上下文显式拒绝,不留旁路写入通道)');
94
+ }
95
+ if (typeof input?.text !== 'string' || !input.text.trim().length) {
96
+ throw new Error('CAR-E-MEM-EMPTY: 记忆正文为空(fail-visible——空正文条目无白盒价值,禁静默落盘)');
97
+ }
98
+ const id = input.id ?? `mem-${Date.now().toString(36)}-${randomBytes(3).toString('hex')}`;
99
+ assertValidId(id);
100
+ if (this.get(id)) {
101
+ throw new Error(`CAR-E-MEM-EXISTS: 记忆 "${id}" 已存在(write 冲突 fail-visible——修改请走 edit)`);
102
+ }
103
+ const now = Date.now();
104
+ const entry = { id, text: input.text, createdAt: now, updatedAt: now };
105
+ if (input.tags?.length)
106
+ entry.tags = [...input.tags];
107
+ if (input.sourceSession)
108
+ entry.sourceSession = input.sourceSession;
109
+ log.append('user', 'memory', 'memory', { type: 'write', id, text: entry.text, ...(entry.tags ? { tags: entry.tags } : {}) });
110
+ try {
111
+ this.#writeFile(entry);
112
+ }
113
+ catch (e) {
114
+ throw new Error(`CAR-E-MEM-IO: 记忆文件写入失败 "${id}"(事件已落链——盘面动作失败显式抛出,§3.2.M7.5 落链先行动作顺序;${e.message})`);
115
+ }
116
+ return entry;
117
+ }
118
+ /** 修改记忆:落 memory/edit 事件(payload before/after 全文——rollback 的恢复数据源)→ 原子重写 */
119
+ edit(log, id, text, tags) {
120
+ if (!log || typeof log.append !== 'function') {
121
+ throw new Error('CAR-E-MEM-NOCHAIN: 记忆 CRUD 必须传入会话链(D-46 ②;无会话上下文显式拒绝)');
122
+ }
123
+ const prev = this.#mustGet(id);
124
+ if (typeof text !== 'string' || !text.trim().length) {
125
+ throw new Error(`CAR-E-MEM-EMPTY: 记忆 "${id}" 新正文为空(fail-visible——清空请走 delete)`);
126
+ }
127
+ // tags 语义:undefined = 不变(payload 不带键,重放取前态);数组 = 整体替换(含空数组 =
128
+ // 清空,payload 恒带键——重放 [] 与清空同构,禁「带键/缺键」二义)
129
+ const next = { ...prev, text, updatedAt: Date.now() };
130
+ if (tags !== undefined) {
131
+ const { tags: _drop, ...rest } = next;
132
+ void _drop;
133
+ const cleaned = tags.length ? { ...rest, tags: [...tags] } : rest;
134
+ log.append('user', 'memory', 'memory', { type: 'edit', id, before: prev.text, text, tags });
135
+ try {
136
+ this.#writeFile(cleaned);
137
+ }
138
+ catch (e) {
139
+ throw new Error(`CAR-E-MEM-IO: 记忆文件写入失败 "${id}"(事件已落链;${e.message})`);
140
+ }
141
+ return cleaned;
142
+ }
143
+ log.append('user', 'memory', 'memory', { type: 'edit', id, before: prev.text, text });
144
+ try {
145
+ this.#writeFile(next);
146
+ }
147
+ catch (e) {
148
+ throw new Error(`CAR-E-MEM-IO: 记忆文件写入失败 "${id}"(事件已落链;${e.message})`);
149
+ }
150
+ return next;
151
+ }
152
+ /** 删除记忆:落 memory/delete 事件(payload 携带被删正文——rollback 可恢复)→ 删文件 */
153
+ remove(log, id) {
154
+ if (!log || typeof log.append !== 'function') {
155
+ throw new Error('CAR-E-MEM-NOCHAIN: 记忆 CRUD 必须传入会话链(D-46 ②;无会话上下文显式拒绝)');
156
+ }
157
+ const prev = this.#mustGet(id);
158
+ log.append('user', 'memory', 'memory', { type: 'delete', id, before: prev.text });
159
+ try {
160
+ rmSync(this.#file(id));
161
+ }
162
+ catch (e) {
163
+ throw new Error(`CAR-E-MEM-IO: 记忆文件删除失败 "${id}"(事件已落链;${e.message})`);
164
+ }
165
+ }
166
+ /**
167
+ * 回滚记忆:沿事件链单步时间回退(undo 栈语义——连续回退逐版本回走:v3→v2→v1)。
168
+ * 恢复数据源 = 链上版本栈重放(链即版本库,不依赖文件系统历史)。落 memory/rollback
169
+ * 事件(before/after 全文 + fromSeq 溯源)→ 文件动作。返回 null = 回退到删除态。
170
+ * 语义:edit 后回退 → 恢复 before;delete 后回退 → undelete(恢复被删正文);
171
+ * 仅剩 write 初始版 / 链上无历史 → CAR-E-MEM-NOREV。
172
+ */
173
+ rollback(log, id) {
174
+ if (!log || typeof log.append !== 'function') {
175
+ throw new Error('CAR-E-MEM-NOCHAIN: 记忆 CRUD 必须传入会话链(D-46 ②;无会话上下文显式拒绝)');
176
+ }
177
+ const states = this.#rebuildStates(log, id);
178
+ if (states.length < 2) {
179
+ throw new Error(states.length
180
+ ? `CAR-E-MEM-NOREV: 记忆 "${id}" 已处初始版本(write seq=${states[0].seq},无更早状态可回退——fail-visible)`
181
+ : `CAR-E-MEM-NOREV: 记忆 "${id}" 无链上历史(rollback 数据源 = 审计链——链外写入的条目无版本可回退,fail-visible)`);
182
+ }
183
+ const cur = states[states.length - 1];
184
+ const target = states[states.length - 2]; // 单步回退目标(present 或 absent)
185
+ log.append('user', 'memory', 'memory', {
186
+ type: 'rollback',
187
+ id,
188
+ ...(cur.present ? { before: cur.text } : {}),
189
+ ...(target.present ? { text: target.text, ...(target.tags ? { tags: target.tags } : {}) } : {}),
190
+ fromSeq: cur.seq,
191
+ });
192
+ try {
193
+ if (target.present) {
194
+ const entry = { id, text: target.text, createdAt: target.createdAt, updatedAt: Date.now() };
195
+ if (target.tags?.length)
196
+ entry.tags = [...target.tags];
197
+ if (target.sourceSession)
198
+ entry.sourceSession = target.sourceSession;
199
+ this.#writeFile(entry);
200
+ return entry;
201
+ }
202
+ rmSync(this.#file(id));
203
+ return null; // 回退到删除态:条目移除(调用方以 get 校验)
204
+ }
205
+ catch (e) {
206
+ throw new Error(`CAR-E-MEM-IO: 记忆文件动作失败 "${id}"(事件已落链;${e.message})`);
207
+ }
208
+ }
209
+ #mustGet(id) {
210
+ const prev = this.get(id);
211
+ if (!prev) {
212
+ throw new Error(`CAR-E-MEM-NOENT: 记忆 "${id}" 不存在(fail-visible——先 write 再操作)`);
213
+ }
214
+ return prev;
215
+ }
216
+ /**
217
+ * 链上版本栈重放:按 seq 序重放该 id 的全部 memory 事件。write/edit → push present;
218
+ * delete → push absent;**rollback → pop(单步时间回退的重放同构——调用时回退一步,
219
+ * 重放时同样回退一步,pop 后栈顶即当前有效状态;连续 rollback 逐版本回走)**。
220
+ * 栈底恒为 write 初始版;每个状态记录来源事件 seq(fromSeq 溯源)+ 进入时的正文/元数据。
221
+ */
222
+ #rebuildStates(log, id) {
223
+ assertValidId(id);
224
+ const stack = [];
225
+ for (const e of log.events) {
226
+ if (e.kind !== 'memory')
227
+ continue;
228
+ const p = (e.payload ?? {});
229
+ if (p.id !== id)
230
+ continue;
231
+ const prevTop = stack[stack.length - 1];
232
+ if (p.type === 'write')
233
+ stack.push({ seq: e.seq, present: true, text: p.text, tags: p.tags, createdAt: e.ts, sourceSession: prevTop?.sourceSession });
234
+ else if (p.type === 'edit')
235
+ stack.push({ seq: e.seq, present: true, text: p.text, tags: p.tags, createdAt: prevTop?.createdAt ?? e.ts, sourceSession: prevTop?.sourceSession });
236
+ else if (p.type === 'delete')
237
+ stack.push({ seq: e.seq, present: false });
238
+ else if (p.type === 'rollback')
239
+ stack.pop(); // 单步回退重放同构(栈空 pop 为坏链防御——正常链形不发生)
240
+ }
241
+ return stack;
242
+ }
243
+ }
244
+ /**
245
+ * 注入装载:全量装入(updatedAt 降序,禁静默选择性注入——选择性 = 不可解释),
246
+ * 字符近似预算门控(行为门控非计量出数;超预算 fail-visible 不静默截断——
247
+ * 提示宿主调大预算或删减记忆)。空记忆 = 空串 + count 0(正常态非错误,宿主跳过注入行)。
248
+ */
249
+ export function loadMemoryForInjection(store, opts) {
250
+ const budget = opts?.budgetChars;
251
+ if (typeof budget !== 'number' || !Number.isFinite(budget) || budget <= 0) {
252
+ throw new Error(`CAR-E-MEM-BUDGET: 注入预算非法(${String(budget)})——须为正数(字符近似门控口径)`);
253
+ }
254
+ const entries = store.list();
255
+ if (!entries.length)
256
+ return { count: 0, totalChars: 0, rendered: '' };
257
+ const lines = entries.map(e => `- [${e.id}] ${e.text.replace(/\r?\n/g, ' ')}`);
258
+ const rendered = `[CAR 记忆注入] 共 ${entries.length} 条:\n${lines.join('\n')}`;
259
+ if (rendered.length > budget) {
260
+ throw new Error(`CAR-E-MEM-BUDGET: 记忆注入超预算(${rendered.length} > ${budget} 字符)——fail-visible 禁静默截断(调大预算或删减记忆)`);
261
+ }
262
+ return { count: entries.length, totalChars: rendered.length, rendered };
263
+ }
@@ -1,4 +1,4 @@
1
- {"stage":"archive","detail":"git archive HEAD → car-runtime-1.14.1.tgz(373973 bytes,树哈希锚定)","ts":1792313224480}
2
- {"stage":"sha256sums","detail":"SHA256SUMS 88b55ba110b87ca7…(裸字节复核通过)","ts":1792313224481}
3
- {"stage":"sbom","detail":"53 个组件(运行时依赖 0 项)","ts":1792313224489}
4
- {"stage":"cosign-keyless","detail":"signed car-runtime-1.14.1.tgz (keyless OIDC + Rekor)","ts":1792313226954}
1
+ {"stage":"archive","detail":"git archive HEAD → car-runtime-1.15.0.tgz(392889 bytes,树哈希锚定)","ts":1792391675984}
2
+ {"stage":"sha256sums","detail":"SHA256SUMS 9ba612b6464b7bc4…(裸字节复核通过)","ts":1792391675985}
3
+ {"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1792391675989}
4
+ {"stage":"cosign-keyless","detail":"signed car-runtime-1.15.0.tgz (keyless OIDC + Rekor)","ts":1792391678478}
@@ -15,7 +15,10 @@ export async function chatStep(opts) {
15
15
  // 1.5-BUG-1:此前仅透传 m.content,toolCall 属性被丢弃——工具调用历史在后续请求
16
16
  // 静默消失(真实 provider 对无 tool_calls 前驱的 tool 消息直接 400);anthropic E2E
17
17
  // 生产调用点核查(1.5-GO-5)暴露,openai-compat 同样受益。
18
- const messages = log.deriveMessages().map(m => ({
18
+ // 1.15-S2(K-STEER-1 / D-47):投影带活跃 turn 口径——turn 进行中落链的他 turn user
19
+ // 事件(引导排队)不进当前 turn 请求(引导 ≠ 注入当前 turn 上下文红线);无引导事件
20
+ // 时与 1.14.1 投影逐字节一致(兼容线)。
21
+ const messages = log.deriveMessages(undefined, { activeTurnId: turnId }).map(m => ({
19
22
  role: m.role,
20
23
  content: m.toolCall !== undefined
21
24
  ? { toolCall: m.toolCall }
package/dist/sbom.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bomFormat": "CAR-SBOM",
3
3
  "specVersion": "0.1",
4
- "version": "1.14.1",
4
+ "version": "1.15.0",
5
5
  "components": [
6
6
  {
7
7
  "type": "file",
@@ -106,7 +106,7 @@
106
106
  {
107
107
  "type": "file",
108
108
  "path": "src/loop/stop.ts",
109
- "sha256": "e24206282b2821e4bde36352a988ec871de3d7d1c57bb3a4b30801c56b152734"
109
+ "sha256": "2c85b1378ab69b3ab52c5cf631c8e75c33b20f532028b1bd7464d782ab6bb49a"
110
110
  },
111
111
  {
112
112
  "type": "file",
@@ -123,6 +123,11 @@
123
123
  "path": "src/mcp/stdioClient.ts",
124
124
  "sha256": "5c5c576e906eeef1c68397fde90e468183e3f4eabd93a72e23b5bbf0154fb6c6"
125
125
  },
126
+ {
127
+ "type": "file",
128
+ "path": "src/memory/store.ts",
129
+ "sha256": "656abef78cae852baa6ac21849f206aaf6a0a0e17492a860aeff34ad803f4ca1"
130
+ },
126
131
  {
127
132
  "type": "file",
128
133
  "path": "src/ptc/budget.ts",
@@ -156,7 +161,7 @@
156
161
  {
157
162
  "type": "file",
158
163
  "path": "src/runtime-core/chatStep.ts",
159
- "sha256": "b4a4715b957a43513e7e645b8e64b1d1d2e99b52f64c619e9bc45f91364531d3"
164
+ "sha256": "e249519eb50503b0ed22b46cb22964c0a94a58247b8b6bea06de6bf985a06e63"
160
165
  },
161
166
  {
162
167
  "type": "file",
@@ -206,7 +211,7 @@
206
211
  {
207
212
  "type": "file",
208
213
  "path": "src/seam.ts",
209
- "sha256": "0a4a231c9ab3ad5898a9a22fd9e53e17a8261d3d4057940b7d2148325573006c"
214
+ "sha256": "b7f817da5184140f1d1b70eb5084ad3f85f7c52607587b51db82063ff7ada9df"
210
215
  },
211
216
  {
212
217
  "type": "file",
@@ -246,7 +251,12 @@
246
251
  {
247
252
  "type": "file",
248
253
  "path": "src/session/log.ts",
249
- "sha256": "9295cf0c8a7452324a0661e1d6fd2872f6289c614c8f50596e82713f35988fdb"
254
+ "sha256": "435fc7336e5de1b96688d3c973aa1129ae39e7347a324d5f15aaabe77a6e1a71"
255
+ },
256
+ {
257
+ "type": "file",
258
+ "path": "src/session/steer.ts",
259
+ "sha256": "cf8d3d0769d8dd347bdb25499b7c79fa4836c0559a2774a97933a88d43659659"
250
260
  },
251
261
  {
252
262
  "type": "file",
@@ -261,12 +271,12 @@
261
271
  {
262
272
  "type": "file",
263
273
  "path": "package.json",
264
- "sha256": "b637e74c6e9d878a3b53ba2481a15b1c3f735bf9341e9e29724c53708b35a6f1"
274
+ "sha256": "d803162bdb3aff9d6a2d71e08fde5ccd17102af97901c7db03e2f4563e30fc0f"
265
275
  },
266
276
  {
267
277
  "type": "file",
268
278
  "path": "README.md",
269
- "sha256": "d2e3490a5a0ef970884c038e4a385853fa8b293b85d7a65c1da5ef8edaa2a631"
279
+ "sha256": "41bf297bd788a2f13477d0b6e8f3ce74ba9e01dd252177d18ccc8f933f11ec69"
270
280
  }
271
281
  ],
272
282
  "runtimeDependencies": []
package/dist/seam.d.ts CHANGED
@@ -26,6 +26,15 @@
26
26
  * + CompactionConfig——自动挂载点在宿主装配层〔runTurn 之间〕,立即压缩 API 独立可用,append-only 红线随本面)
27
27
  * + K-POOL-1 池装配行为 API(assembleModelPool/probePoolMember + PoolMember/RoutingDecision 类型——
28
28
  * 桌面模型池设置 UI 与 doctor 池健康行消费面;routing/decide 落链由宿主接线 onDecide)。
29
+ * 加法登记:1.15.0 —— K-MEM-1 白盒记忆面(T-10 / D-46):MemoryStore 出面(`.car/memory/` 逐条 JSON 存储 +
30
+ * CRUD 落链行为 API——memory/write·edit·delete·rollback 审计事件随会话链哈希链保护,rollback = 链上版本栈
31
+ * 单步回退〔链即版本库〕;log 参数必填 = 无会话上下文显式拒绝)+ loadMemoryForInjection(确定性拼装 + 字符
32
+ * 近似预算门控 fail-visible;注入落链 = 宿主装配层 system ctx 行〔D-C3 预留位〕)+ 5 类型(MemoryEntry/
33
+ * MemoryOp/MemoryEventPayload/MemoryInjectionResult + MemoryStore 随类)+ K-STEER-1 排队扫描(T-17 / D-47):
34
+ * pendingSteerTurns + PendingSteerTurn(未消费引导队列按 seq 序枚举,excludeTurnId 排除执行中 turn;FIFO 消费
35
+ * 调度留宿主装配层;投影隔离〔引导不进当前 turn 投影〕在 deriveMessages/chatStep 内建,随既有符号语义可达
36
+ * 零新符号)。负面清单(不出面):存储引擎内部件(文件读写器/预算计算器/版本栈重放器——#私有方法)、
37
+ * 记忆注入落链执行器(宿主 system ctx 行职责)、消费调度器(宿主 FIFO 续跑职责)、cli 引导接线(非验收必需)。
29
38
  */
30
39
  export { SessionLog, loadSessionLog, deriveSessionId, type SessionEvent, type EventKind, type Actor } from './session/log.ts';
31
40
  export { SessionFileStore } from './session/store.ts';
@@ -53,3 +62,5 @@ export { loadPlugins, ReloadManager, type LoadReportVO, type LoadPluginsResult,
53
62
  export { verifyPluginFile, type SignatureGateOptions, type SigGateResult } from './load/sigGate.ts';
54
63
  export { shouldCompact, applyCompaction, type CompactionConfig } from './session/compact.ts';
55
64
  export { assembleModelPool, probePoolMember, type PoolMember, type PoolMemberHealth, type RoutingDecision, type RoutingAttempt } from './load/pool.ts';
65
+ export { MemoryStore, loadMemoryForInjection, type MemoryEntry, type MemoryOp, type MemoryEventPayload, type MemoryInjectionResult } from './memory/store.ts';
66
+ export { pendingSteerTurns, type PendingSteerTurn } from './session/steer.ts';
package/dist/seam.js CHANGED
@@ -26,6 +26,15 @@
26
26
  * + CompactionConfig——自动挂载点在宿主装配层〔runTurn 之间〕,立即压缩 API 独立可用,append-only 红线随本面)
27
27
  * + K-POOL-1 池装配行为 API(assembleModelPool/probePoolMember + PoolMember/RoutingDecision 类型——
28
28
  * 桌面模型池设置 UI 与 doctor 池健康行消费面;routing/decide 落链由宿主接线 onDecide)。
29
+ * 加法登记:1.15.0 —— K-MEM-1 白盒记忆面(T-10 / D-46):MemoryStore 出面(`.car/memory/` 逐条 JSON 存储 +
30
+ * CRUD 落链行为 API——memory/write·edit·delete·rollback 审计事件随会话链哈希链保护,rollback = 链上版本栈
31
+ * 单步回退〔链即版本库〕;log 参数必填 = 无会话上下文显式拒绝)+ loadMemoryForInjection(确定性拼装 + 字符
32
+ * 近似预算门控 fail-visible;注入落链 = 宿主装配层 system ctx 行〔D-C3 预留位〕)+ 5 类型(MemoryEntry/
33
+ * MemoryOp/MemoryEventPayload/MemoryInjectionResult + MemoryStore 随类)+ K-STEER-1 排队扫描(T-17 / D-47):
34
+ * pendingSteerTurns + PendingSteerTurn(未消费引导队列按 seq 序枚举,excludeTurnId 排除执行中 turn;FIFO 消费
35
+ * 调度留宿主装配层;投影隔离〔引导不进当前 turn 投影〕在 deriveMessages/chatStep 内建,随既有符号语义可达
36
+ * 零新符号)。负面清单(不出面):存储引擎内部件(文件读写器/预算计算器/版本栈重放器——#私有方法)、
37
+ * 记忆注入落链执行器(宿主 system ctx 行职责)、消费调度器(宿主 FIFO 续跑职责)、cli 引导接线(非验收必需)。
29
38
  */
30
39
  export { SessionLog, loadSessionLog, deriveSessionId } from './session/log.js';
31
40
  export { SessionFileStore } from './session/store.js';
@@ -55,3 +64,6 @@ export { verifyPluginFile } from './load/sigGate.js';
55
64
  // —— 1.14.1(B2 前置补出面):K-MP-2 压缩行为 API + K-POOL-1 池装配行为 API(1.14 消费面完成)——
56
65
  export { shouldCompact, applyCompaction } from './session/compact.js';
57
66
  export { assembleModelPool, probePoolMember } from './load/pool.js';
67
+ // —— 1.15.0(K-MEM-1 / D-46):白盒记忆面 +(K-STEER-1 / D-47):引导消息排队扫描 ——
68
+ export { MemoryStore, loadMemoryForInjection } from './memory/store.js';
69
+ export { pendingSteerTurns } from './session/steer.js';
@@ -1,4 +1,4 @@
1
- export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing';
1
+ export type EventKind = 'user' | 'assistant' | 'toolCall' | 'toolResult' | 'turnEnd' | 'goalUpdate' | 'hostRaw' | 'fork' | 'system' | 'usage' | 'compact' | 'routing' | 'memory';
2
2
  export type Actor = 'user' | 'model' | 'plugin' | 'runtime';
3
3
  export interface SessionEvent {
4
4
  seq: number;
@@ -15,6 +15,12 @@ declare const sha: (s: string) => string;
15
15
  export interface ModelSnapshot {
16
16
  /** 快照对应日志前缀边界(事件数),断言时逐字节比对前缀投影 */
17
17
  atSeq: number;
18
+ /**
19
+ * 1.15-S2(K-STEER-1 / D-47):快照时宿主声明的活跃 turn——提供时快照投影 = 边界内
20
+ * 「活跃 turn 起点之后落链的他 turn user 事件被过滤」口径(与请求投影同构,N1 逐字节
21
+ * 自洽);缺席 = 全量前缀投影(1.14.1 形态,行为零变化)。
22
+ */
23
+ activeTurnId?: string;
18
24
  request: unknown[];
19
25
  }
20
26
  export declare class SessionLog {
@@ -30,8 +36,10 @@ export declare class SessionLog {
30
36
  attachSink(sink: (line: string) => void): void;
31
37
  /** 唯一写入路径(append-only;无 update/delete API) */
32
38
  append(actor: Actor, kind: EventKind, turnId: string, payload: unknown, meta?: Record<string, unknown>): SessionEvent;
33
- /** 模型请求发起时调用(agent-loop 集成点):登记「请求时快照」 */
34
- snapshotModelRequest(): ModelSnapshot;
39
+ /** 模型请求发起时调用(agent-loop 集成点):登记「请求时快照」;opts.activeTurnId 见 ModelSnapshot 注记 */
40
+ snapshotModelRequest(opts?: {
41
+ activeTurnId?: string;
42
+ }): ModelSnapshot;
35
43
  /** 逐链校验;返回 null=完整,否则断链事件序号(审计导出前置,断链即中止) */
36
44
  verifyChain(): number | null;
37
45
  /**
@@ -45,12 +53,20 @@ export declare class SessionLog {
45
53
  * 其 compactedUpTo 前缀折叠为单条 system 摘要(事件原文不改写,仅投影层折叠);compact 之前的
46
54
  * 请求快照(atSeq ≤ compact.seq)不含 compact 事件 → 投影仍为全量形态(N1 不变量自洽——
47
55
  * 「请求时发出 = 日志前缀投影」逐快照成立);无 compact 事件的日志投影与 1.13 逐字节一致。
56
+ * 1.15-S2(K-STEER-1 / D-47)投影隔离:opts.activeTurnId 提供时,跳过「turn 进行中落链的
57
+ * 他 turn user 事件」(特征 = kind='user' 且 seq > 活跃 turn 首事件 seq 且 turnId ≠ 活跃
58
+ * turnId——引导排队事件的链上形态)——**引导 ≠ 注入当前 turn 上下文**;不采用 turn 开始
59
+ * 快照(快照会误杀 turn 内落的 toolResult——agent loop 依赖实时投影),过滤口径精确匹配
60
+ * 「turn 外增量不进、turn 内增量照进」;无引导事件时过滤零命中,投影与 1.14.1 逐字节一致
61
+ * (兼容线)。缺省(无 opts)= 1.14.1 行为零变化。
48
62
  */
49
- deriveMessages(upTo?: number): Array<{
63
+ deriveMessages(upTo?: number, opts?: {
64
+ activeTurnId?: string;
65
+ }): Array<{
50
66
  role: string;
51
67
  [k: string]: unknown;
52
68
  }>;
53
- /** N1 不变量断言(CI 门禁雏形):全部快照必须与当前日志前缀投影逐字节一致 */
69
+ /** N1 不变量断言(CI 门禁雏形):全部快照必须与当前日志前缀投影逐字节一致(快照口径含 1.15-S2 activeTurnId 过滤) */
54
70
  assertModelVisibleLogged(): {
55
71
  ok: boolean;
56
72
  failedAt?: number;