@lqc123qwe/car-runtime 1.15.2 → 1.17.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 +2 -1
- package/dist/SHA256SUMS +1 -1
- package/dist/car-runtime-1.17.0.tgz +0 -0
- package/dist/car-runtime-1.17.0.tgz.sig.bundle +1 -0
- package/dist/cli.js +10 -3
- package/dist/load/config.d.ts +11 -0
- package/dist/load/config.js +24 -2
- package/dist/loop/stop.d.ts +12 -1
- package/dist/loop/stop.js +68 -3
- package/dist/release-audit.jsonl +4 -4
- package/dist/runtime-core/llm.js +16 -1
- package/dist/sbom.json +8 -8
- package/dist/seam.d.ts +1 -1
- package/package.json +1 -1
- package/src/cli.ts +9 -3
- package/src/load/config.ts +33 -2
- package/src/loop/stop.ts +74 -5
- package/src/runtime-core/llm.ts +17 -1
- package/src/seam.ts +1 -1
- package/dist/car-runtime-1.15.2.tgz +0 -0
- package/dist/car-runtime-1.15.2.tgz.sig.bundle +0 -1
package/README.md
CHANGED
|
@@ -286,7 +286,8 @@ 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 已发布)** | **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 已发布)**
|
|
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 已发布)** | **1.16 子 Agent config schema(D-K2-2:llm.subagent 三键 model/maxConcurrent/maxCumulative 嵌套 strict zod——compaction 先例;空对象拒禁静默 no-op + 未登记键 CAR-E-CONFIG 带路径;SubagentConfig 类型面、运行时符号 43 零加法;D-1 KEY_SPACES 误写 llm.modelPool.* 勘误闭环) 全量 446(443 PASS + 3 skip,2026-10-24 收口,1.16.0 已发布)**
|
|
290
|
+
- **1.16.0 已发布(2026-10-24,K3 批——子 Agent config schema,D-K2-2 触发)**:npm latest → 1.16.0 + SLSA provenance 在案。Release `1.16.0`(id 422584868,target_commitish = `c8f6476` 完整 SHA)→ j16 run 40074395764 全 13 步 success(五件套上传齐:tgz + sig.bundle + SHA256SUMS + sbom + release-audit)→ ci success。post-publish 对拍:registry 包 src 面 53 文件与 tag 树逐字节一致(common 55 文件全同,含 package.json/README);registry dist/seam.js 43 运行时符号零 subagent 面 + `llm.subagent.model` 实解析生效(本地 dist 探针);本地 release-pipeline 预演 11 PASS / 2 DRY-RUN / 0 FAIL(干净 env——会话凭据 env 残留会使内嵌全量假红,既知纪律)。s58 5/5 + 全量 446(443 pass / 0 fail / 3 skip zstd 能力门控)。桌面消费批 K3-C 已随批落地(car-desktop `ec5d356`:SubagentManager 三键消费 + 池/端点压过口径 + k2 spec 13/13 + SMOKE seam 1.16.0)。
|
|
290
291
|
- **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)。
|
|
291
292
|
- **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
293
|
- **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)。
|
package/dist/SHA256SUMS
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
c41096564679afc091d41182a3ddddd4970e79b6c4022fa46d5363aad4d2becd car-runtime-1.17.0.tgz
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"base64Signature":"MEUCIGgexNsJf84aA4UdxElf74Okk3NjA/df7MjypGaQeOnwAiEAu6ME/UhRd96P7cGfvMoZRra9khCag//m4FRvCbfb3SY=","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1ekNDQm0yZ0F3SUJBZ0lVTFh4SHA4dllIOU9jMFg1RjdrUkZCMlBIdlEwd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1ESTBNRGd6TURNNFdoY05Nall4TURJME1EZzBNRE00V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVNSmUxZFBlaXJsS2ErdU1KMlZjcmhCbHdkS0dPVW1xNXJHSW8KQkJTRG1DNG1zQ2lEdlMxWDluQmM4RmQ5dGdsVnRTYkpYVS9BdHNyMjNHL2psb0xheHFPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUzTGpBd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLRFExT1RRNE5UY3lPRFJtTmpNMU1qTTNZemc0TjJFMQpPR0poWXpKaU56azFNV0prTVdJMVlXWXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNVGN1TURBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUzTGpBd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENnMApOVGswT0RVM01qZzBaall6TlRJek4yTTRPRGRoTlRoaVlXTXlZamM1TlRGaVpERmlOV0ZtTUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENnMApOVGswT0RVM01qZzBaall6TlRJek4yTTRPRGRoTlRoaVlXTXlZamM1TlRGaVpERmlOV0ZtTUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNVGN1TURBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpFM0xqQXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2cwTlRrME9EVTNNamcwWmpZek5USXpOMk00T0RkaE5UaGlZV015WWpjNU5URmlaREZpTldGbU1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6UXdNRGM0TXpBMApPVGt3TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eE55NHdNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2hiUWlKVmdBQUJBTUFSekJGCkFpQTVsWHl6aXdtMDV0MHIvamV4ajdMbGRQVUdDMHJ6bmxCa0dlYUVzMTNoUkFJaEFQbXJIeTlZN1c5WnNGT2QKTUtBdjk2QVhPQW8xZjcrTFltcGE2cUVpRGlvbE1Bb0dDQ3FHU000OUJBTURBMmdBTUdVQ01Dd2VzYkoyMDU5QQp2VDhXL1A5a2hYbFdEK1dLdi9FMG1xcjA0Y0syZzkveCsyL3Y2ZGdzNXd0dyt3T2lCaC9oMGdJeEFKTStoOWt3CjRuY0hwNk1reFRWS1d2bVFKQk1VbzlXaGQ3MzBUczBDVWNsMGFiV3I5V0N6YjhMb09ZWDIxQStQcXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==","rekorBundle":{"SignedEntryTimestamp":"MEUCIBRv/i7GyGNRzCBGRdS2TE1uopY0+xqxl6topqmnyYZEAiEA++PwUNO1URlr7gcj6bdwPwrcOxbXLNKdnn1t6qleiPg=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNDEwOTY1NjQ2NzlhZmMwOTFkNDExODJhM2RkZGRkNDk3MGU3OWI2YzQwMjJmYTQ2ZDUzNjNhYWQ0ZDJiZWNkIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJR2dleE5zSmY4NGFBNFVkeEVsZjc0T2trM05qQS9kZjdNanlwR2FRZU9ud0FpRUF1Nk1FL1VoUmQ5NlA3Y0dmdk1vWlJyYTlraENhZy8vbTRGUnZDYmZiM1NZPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFla05EUW0weVowRjNTVUpCWjBsVlRGaDRTSEE0ZGxsSU9VOWpNRmcxUmpkclVrWkNNbEJJZGxFd2QwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFU1RCTlJHZDZUVVJOTkZkb1kwNU5hbGw0VFVSSk1FMUVaekJOUkUwMFYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZOU21VeFpGQmxhWEpzUzJFcmRVMUtNbFpqY21oQ2JIZGtTMGRQVlcxeE5YSkhTVzhLUWtKVFJHMURORzF6UTJsRWRsTXhXRGx1UW1NNFJtUTVkR2RzVm5SVFlrcFlWUzlCZEhOeU1qTkhMMnBzYjB4aGVIRlBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha1V6VEdwQmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUkZFeFQxUlJORTVVWTNsUFJGSnRUbXBOTVUxcVRUTlplbWMwVGpKRk1RcFBSMHBvV1hwS2FVNTZhekZOVjBwclRWZEpNVmxYV1hkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOVkdOMVRVUkJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrVXpUR3BCZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm5NQXBPVkdzd1QwUlZNMDFxWnpCYWFsbDZUbFJKZWs0eVRUUlBSR1JvVGxSb2FWbFhUWGxaYW1NMVRsUkdhVnBFUm1sT1YwWnRUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVObk1BcE9WR3N3VDBSVk0wMXFaekJhYWxsNlRsUkplazR5VFRSUFJHUm9UbFJvYVZsWFRYbFphbU0xVGxSR2FWcEVSbWxPVjBadFRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOVkdOMVRVUkJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BGTTB4cVFYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJjd1RsUnJNRTlFVlROTmFtY3dXbXBaZWs1VVNYcE9NazAwVDBSa2FFNVVhR2xaVjAxNVdXcGpOVTVVUm1sYVJFWnBUbGRHYlUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlVYZE5SR00wVFhwQk1BcFBWR3QzVERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZUU1NU5IZE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyaGlVV2xLVm1kQlFVSkJUVUZTZWtKR0NrRnBRVFZzV0hsNmFYZHRNRFYwTUhJdmFtVjRhamRNYkdSUVZVZERNSEo2Ym14Q2EwZGxZVVZ6TVROb1VrRkphRUZRYlhKSWVUbFpOMWM1V25OR1QyUUtUVXRCZGprMlFWaFBRVzh4WmpjclRGbHRjR0UyY1VWcFJHbHZiRTFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbWRCVFVkVlEwMURkMlZ6WWtveU1EVTVRUXAyVkRoWEwxQTVhMmhZYkZkRUsxZExkaTlGTUcxeGNqQTBZMHN5WnprdmVDc3lMM1kyWkdkek5YZDBkeXQzVDJsQ2FDOW9NR2RKZUVGS1RTdG9PV3QzQ2pSdVkwaHdOazFyZUZSV1MxZDJiVkZLUWsxVmJ6bFhhR1EzTXpCVWN6QkRWV05zTUdGaVYzSTVWME42WWpoTWIwOVpXREl4UVN0UWNYYzlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1792830639,"logIndex":3438526446,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|
package/dist/cli.js
CHANGED
|
@@ -39,6 +39,8 @@ const HELP = `用法: car <command> [args]
|
|
|
39
39
|
装配并运行插件(快速上手流;装载前签名门 warn 缺省)
|
|
40
40
|
真路径:--prompt <text> + --base-url/--model(或 llm.* 配置);
|
|
41
41
|
--adapter-id anthropic = Messages API(凭据 ANTHROPIC_API_KEY);
|
|
42
|
+
--no-prompt-cache = 关断 anthropic 稳定前缀缓存断点(D-48;
|
|
43
|
+
等价 env CAR_LLM_PROMPT_CACHE=off,A/B 与回退通道);
|
|
42
44
|
--demo = stub 演示流
|
|
43
45
|
reload <file|dir> [--sig-enforce] [--config <path>]
|
|
44
46
|
热重载插件并打印六阶段加载报告(含 verify 签名门)
|
|
@@ -63,8 +65,9 @@ const HELP = `用法: car <command> [args]
|
|
|
63
65
|
CAR_UNSIGNED_ALLOW=1 显式声明豁免(warn 缺签路径计数 confirmed=yes,横幅保留)
|
|
64
66
|
配置文件通道(1.5 起双载体):cwd car.config.ts(export default {…};发现序 ts > json)或
|
|
65
67
|
car.config.json 或 --config <path>;键位 sandbox.unsigned.allow / sandbox.sig.enforce /
|
|
66
|
-
sandbox.sig.trustRoot / llm.* /
|
|
67
|
-
adapterId/keyEnv/priority/weight/maxTokens + probe + maxAttempts;路由决策落链)/
|
|
68
|
+
sandbox.sig.trustRoot / llm.* / modelPool.*(多端点 fallback:endpoints id/baseUrl/model/
|
|
69
|
+
adapterId/keyEnv/priority/weight/maxTokens + probe + maxAttempts;路由决策落链)/ llm.subagent.*
|
|
70
|
+
(子 Agent:model 独立锚点 / maxConcurrent / maxCumulative 护栏上限)/ mcp.servers.*
|
|
68
71
|
(stdio: command/args/env;远程: url/headers,\${ENV_VAR} 引用注入凭据);优先级 flag > env > 配置 > 缺省;未知键 fail-visible`;
|
|
69
72
|
// 进程内热重载会话(ReloadManager 持有 epoch 与实例注册表;同进程连续 reload 语义完整)
|
|
70
73
|
let reloadMgrPromise;
|
|
@@ -216,6 +219,10 @@ async function main() {
|
|
|
216
219
|
const cfgBaseUrl = llm.baseUrl;
|
|
217
220
|
const cfgModel = llm.model;
|
|
218
221
|
let modelName = cfgModel ?? '';
|
|
222
|
+
// 1.17-K4(D-48 P1 / V1-A):提示缓存断点关断 flag——flag > env(置 env 后适配器内部决策;
|
|
223
|
+
// 池/单端点两分支通用,须先于适配器创建)
|
|
224
|
+
if (rest.includes('--no-prompt-cache'))
|
|
225
|
+
process.env.CAR_LLM_PROMPT_CACHE = 'off';
|
|
219
226
|
const credService = new CredentialService();
|
|
220
227
|
const core = new RuntimeCore(credService);
|
|
221
228
|
core.bindContext(ctx);
|
|
@@ -244,7 +251,7 @@ async function main() {
|
|
|
244
251
|
console.error('CAR-E-LLM-CONFIG: 真实模型路径需要 baseUrl + model——');
|
|
245
252
|
console.error(' 配置:car.config.ts(export default)或 car.config.json {"llm":{"baseUrl":"https://…","model":"…"}} / env CAR_LLM_BASE_URL+CAR_LLM_MODEL / flag --base-url --model');
|
|
246
253
|
console.error(' anthropic:llm.adapterId "anthropic"(或 --adapter-id anthropic)+ baseUrl https://api.anthropic.com;凭据 ANTHROPIC_API_KEY');
|
|
247
|
-
console.error(' 模型池:
|
|
254
|
+
console.error(' 模型池:modelPool.endpoints(多端点 fallback + health 预检;凭据 keyEnv 引用;路由决策落链)');
|
|
248
255
|
console.error(' 凭据:OPENAI_API_KEY / ANTHROPIC_API_KEY(env fallback 需 CAR_ALLOW_ENV_CREDENTIALS=1 或 llm.allowEnvFallback)或 keychain;诊断:car doctor');
|
|
249
256
|
return 2;
|
|
250
257
|
}
|
package/dist/load/config.d.ts
CHANGED
|
@@ -21,6 +21,17 @@ export interface LlmConfig {
|
|
|
21
21
|
allowEnvFallback?: boolean;
|
|
22
22
|
/** 1.14-S2(K-MP-2 / D-40):历史压缩策略(阈值自动触发判定入参;立即压缩 API 独立可用) */
|
|
23
23
|
compaction?: CompactionConfig;
|
|
24
|
+
/** 1.16-K3(D-K2-2):子 Agent 配置(缺省 = 继承父会话模型锚点 Q-A2 + 宿主护栏常量 Q-A3) */
|
|
25
|
+
subagent?: SubagentConfig;
|
|
26
|
+
}
|
|
27
|
+
/** 1.16-K3(D-K2-2):子 Agent 配置面——宿主编排消费(内核自身不装配编排;schema 只登记键位) */
|
|
28
|
+
export interface SubagentConfig {
|
|
29
|
+
/** 独立子模型锚点(缺省 = 继承父会话现值;modelPool 激活时被池压过——与 llm.model 同口径) */
|
|
30
|
+
model?: string;
|
|
31
|
+
/** 并发子 Agent 上限(正整数;缺省 = 宿主常量 3,Q-A3) */
|
|
32
|
+
maxConcurrent?: number;
|
|
33
|
+
/** 单父会话累计派生上限(正整数;缺省 = 宿主常量 10,Q-A3) */
|
|
34
|
+
maxCumulative?: number;
|
|
24
35
|
}
|
|
25
36
|
/** 1.14-S4(K-POOL-1 / D-42):模型池端点登记(多端点 fallback 候选;凭据仅收 keyEnv 引用) */
|
|
26
37
|
export interface ModelPoolEndpointSpec {
|
package/dist/load/config.js
CHANGED
|
@@ -133,6 +133,18 @@ const rawSchema = z.object({
|
|
|
133
133
|
protectLastTurns: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
134
134
|
.refine(v => Number.isInteger(v) && v > 0, { message: '必须为正整数' }).optional(),
|
|
135
135
|
}).strict().optional(),
|
|
136
|
+
// 1.16-K3(D-K2-2):子 Agent 配置(model 独立锚点 + 护栏上限;空对象无意义显式拒——禁静默 no-op)
|
|
137
|
+
subagent: z.object({
|
|
138
|
+
model: nonEmptyTrimmed().optional(),
|
|
139
|
+
maxConcurrent: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
140
|
+
.refine(v => Number.isFinite(v) && Number.isInteger(v) && v > 0, { message: '必须为正整数' })
|
|
141
|
+
.optional(),
|
|
142
|
+
maxCumulative: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
143
|
+
.refine(v => Number.isFinite(v) && Number.isInteger(v) && v > 0, { message: '必须为正整数' })
|
|
144
|
+
.optional(),
|
|
145
|
+
}).strict()
|
|
146
|
+
.refine(v => Object.keys(v).length > 0, { message: '至少登记一个键(model/maxConcurrent/maxCumulative;无子 Agent 配置需求请移除 llm.subagent 键,行为与 1.15.2 一致)' })
|
|
147
|
+
.optional(),
|
|
136
148
|
}).strict().optional(),
|
|
137
149
|
// 1.14-S4(K-POOL-1 / D-42):模型池登记(多端点 fallback + health + routing/decide 落链)
|
|
138
150
|
modelPool: modelPoolSchema.optional(),
|
|
@@ -140,8 +152,8 @@ const rawSchema = z.object({
|
|
|
140
152
|
servers: z.record(z.string(), mcpServerSchema, { invalid_type_error: '必须为对象(serverId → 启动规格)' }),
|
|
141
153
|
}).strict().optional(),
|
|
142
154
|
}, { invalid_type_error: '配置顶层必须为 JSON 对象' }).strict();
|
|
143
|
-
/** 未登记键提示(渲染层拼 path
|
|
144
|
-
const KEY_SPACES = '登记键位:sandbox.* / llm.* / llm.
|
|
155
|
+
/** 未登记键提示(渲染层拼 path)——与系统设计键位空间同步;D-1 勘误:modelPool 为顶层键(非 llm.modelPool) */
|
|
156
|
+
const KEY_SPACES = '登记键位:sandbox.* / llm.* / modelPool.* / llm.subagent.* / mcp.servers.*';
|
|
145
157
|
/** zod issue → CAR-E-CONFIG 渲染(首个 issue;unrecognized_keys 按键路径展开) */
|
|
146
158
|
function renderIssue(error) {
|
|
147
159
|
const iss = error.issues[0];
|
|
@@ -194,6 +206,16 @@ function parseCarConfig(raw) {
|
|
|
194
206
|
cp.protectLastTurns = d.llm.compaction.protectLastTurns;
|
|
195
207
|
llm.compaction = cp;
|
|
196
208
|
}
|
|
209
|
+
if (d.llm.subagent) {
|
|
210
|
+
const sg = {};
|
|
211
|
+
if (d.llm.subagent.model !== undefined)
|
|
212
|
+
sg.model = d.llm.subagent.model;
|
|
213
|
+
if (d.llm.subagent.maxConcurrent !== undefined)
|
|
214
|
+
sg.maxConcurrent = d.llm.subagent.maxConcurrent;
|
|
215
|
+
if (d.llm.subagent.maxCumulative !== undefined)
|
|
216
|
+
sg.maxCumulative = d.llm.subagent.maxCumulative;
|
|
217
|
+
llm.subagent = sg;
|
|
218
|
+
}
|
|
197
219
|
out.llm = llm;
|
|
198
220
|
}
|
|
199
221
|
if (d.mcp) {
|
package/dist/loop/stop.d.ts
CHANGED
|
@@ -62,8 +62,19 @@ export interface TurnPreset {
|
|
|
62
62
|
concludesTurn?: 'any' | 'all';
|
|
63
63
|
terminate?: 'any' | 'all';
|
|
64
64
|
};
|
|
65
|
-
/** F13:授权拒绝即收口 blocked(默认 false =
|
|
65
|
+
/** F13:授权拒绝即收口 blocked(默认 false = 模型继续调整);1.17-K4(V2-a)缺省随档位收敛——readonly 恒 true(显式传参可覆盖) */
|
|
66
66
|
blockOnDeny?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* 1.17-K4(D-50 / G8):拒绝累计熔断——同 turn denies 累计 ≥ N 即收口 blocked(gate:'denyBreaker')。
|
|
69
|
+
* 缺省 3(预防性闸门:真实样本从未超过 1 次/turn——设计 §10.4-3 诚实定位);0 = 关。
|
|
70
|
+
*/
|
|
71
|
+
denyBreaker?: number;
|
|
72
|
+
/**
|
|
73
|
+
* 1.17-K4(D-50 / G9):重复失败熔断——失败签名(tool + 归一化错误串)同 turn 连续 ≥ N 后,
|
|
74
|
+
* 下一次同签名不再派发(成对补记 no-dispatch 事件)并收口 blocked(gate:'repeatFailureBreaker')。
|
|
75
|
+
* 异签名放行(允许探索,禁撞墙);成功派发重置连击。缺省 2;0 = 关。
|
|
76
|
+
*/
|
|
77
|
+
repeatFailureBreaker?: number;
|
|
67
78
|
}
|
|
68
79
|
export interface TurnResult {
|
|
69
80
|
reason: TurnEndReason;
|
package/dist/loop/stop.js
CHANGED
|
@@ -49,12 +49,37 @@ export async function runTurn(opts) {
|
|
|
49
49
|
const usage = turnUsageFrom(log, turnId);
|
|
50
50
|
return log.append('runtime', 'turnEnd', turnId, null, { ...meta, ...(usage ? { usage } : {}) });
|
|
51
51
|
};
|
|
52
|
+
// 1.17-K4(D-50 / V2-a):blockOnDeny 缺省随档位收敛——readonly 恒 true(拒绝即收口,禁在
|
|
53
|
+
// 错误理解模式的路上烧 token;「看一眼再决定」应切 confirm——三档设计本义);confirm/full
|
|
54
|
+
// 缺省 false 不变;显式传参可覆盖任何档位
|
|
55
|
+
const blockOnDeny = preset.blockOnDeny ?? preset.mode === 'readonly';
|
|
56
|
+
// 1.17-K4(D-50):G8/G9 熔断阈值(缺省 3/2;0 = 关——A/B 与回退通道)
|
|
57
|
+
const denyBreaker = preset.denyBreaker ?? 3;
|
|
58
|
+
const repeatFailureBreaker = preset.repeatFailureBreaker ?? 2;
|
|
59
|
+
let totalDenies = 0;
|
|
60
|
+
// G9 失败签名连击(turn 级):成功派发重置;授权拒绝不重置(拒绝 ≠ 探索进展)
|
|
61
|
+
let lastSignature = null;
|
|
62
|
+
let lastFailureTool = null;
|
|
63
|
+
let signatureStreak = 0;
|
|
64
|
+
/** 失败签名 = tool + 归一化错误串(去空白/时间戳/长 hex id、截断 200——确定性好比对) */
|
|
65
|
+
const failureSignature = (tool, err) => (tool + ':' + err.replace(/\s+/g, ' ').replace(/\d{4}-\d{2}-\d{2}T[\d:.]+Z?/g, '<ts>').replace(/\b[0-9a-f]{8,}\b/g, '<id>')).slice(0, 200);
|
|
66
|
+
const advanceStreak = (tool, err) => {
|
|
67
|
+
const sig = failureSignature(tool, err);
|
|
68
|
+
if (sig === lastSignature)
|
|
69
|
+
signatureStreak++;
|
|
70
|
+
else {
|
|
71
|
+
lastSignature = sig;
|
|
72
|
+
signatureStreak = 1;
|
|
73
|
+
}
|
|
74
|
+
lastFailureTool = tool;
|
|
75
|
+
};
|
|
52
76
|
const executeBatch = async (calls) => {
|
|
53
77
|
let concludesTurn = false;
|
|
54
78
|
let concludesVotes = 0;
|
|
55
79
|
let terminateVotes = 0;
|
|
56
80
|
let finalized = 0;
|
|
57
81
|
let denies = 0;
|
|
82
|
+
let breakerTripped = null;
|
|
58
83
|
for (const call of calls) {
|
|
59
84
|
if (signal?.aborted) {
|
|
60
85
|
// 取消:未派发调用补记成对事件(日志无缺口)
|
|
@@ -64,8 +89,23 @@ export async function runTurn(opts) {
|
|
|
64
89
|
}
|
|
65
90
|
const def = tools.get(call.tool);
|
|
66
91
|
log.append('model', 'toolCall', turnId, call);
|
|
92
|
+
// G9(D-50)熔断预检:同签名连击已达阈值且本次同工具 → 不再派发(错误串须派发方知,
|
|
93
|
+
// 预检口径 = 同工具紧邻重试——换工具探索不受影响;换参数异错误的甄别发生在 streak < 阈值期)。
|
|
94
|
+
// 未派发也成对落链(与取消补记同纪律——日志无缺口),breakerTripped 交主循环收口。
|
|
95
|
+
// 位置在 def 查找前:unknown tool 连击(def 缺失分支 continue)同样要被拦
|
|
96
|
+
if (repeatFailureBreaker > 0 && signatureStreak >= repeatFailureBreaker && lastFailureTool === call.tool) {
|
|
97
|
+
log.append('runtime', 'toolResult', turnId, {
|
|
98
|
+
id: call.id,
|
|
99
|
+
error: 'repeated-identical-failure: breaker tripped (no dispatch)',
|
|
100
|
+
signature: lastSignature,
|
|
101
|
+
});
|
|
102
|
+
breakerTripped = lastSignature;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
67
105
|
if (!def) {
|
|
68
106
|
log.append('plugin', 'toolResult', turnId, { id: call.id, error: `unknown tool "${call.tool}"` });
|
|
107
|
+
// G9:unknown tool 同为失败面(模型反复叫错工具名 = 撞墙形态之一)
|
|
108
|
+
advanceStreak(call.tool, `unknown tool "${call.tool}"`);
|
|
69
109
|
continue;
|
|
70
110
|
}
|
|
71
111
|
// 权限门(F4 集成点):write 类在 readonly/confirm 模式需放行;1.13.0(K-FS-1):
|
|
@@ -92,6 +132,15 @@ export async function runTurn(opts) {
|
|
|
92
132
|
toolError = String(e);
|
|
93
133
|
}
|
|
94
134
|
log.append('plugin', 'toolResult', turnId, { id: call.id, result, ...(toolError ? { error: toolError } : {}) });
|
|
135
|
+
// G9 连击推进:同签名 streak++,异签名重开(允许探索——换参数后不同错误 = 不同签名);
|
|
136
|
+
// 成功派发重置(拒绝不重置——拒绝 ≠ 探索进展)
|
|
137
|
+
if (toolError)
|
|
138
|
+
advanceStreak(call.tool, toolError);
|
|
139
|
+
else {
|
|
140
|
+
lastSignature = null;
|
|
141
|
+
lastFailureTool = null;
|
|
142
|
+
signatureStreak = 0;
|
|
143
|
+
}
|
|
95
144
|
finalized++;
|
|
96
145
|
if (def.concludesTurn) {
|
|
97
146
|
concludesTurn = true;
|
|
@@ -103,7 +152,7 @@ export async function runTurn(opts) {
|
|
|
103
152
|
return {
|
|
104
153
|
concludesTurn, concludesAll: finalized > 0 && concludesVotes === finalized,
|
|
105
154
|
terminateVotes, terminateAll: finalized > 0 && terminateVotes === finalized,
|
|
106
|
-
finalized, denies,
|
|
155
|
+
finalized, denies, breakerTripped,
|
|
107
156
|
};
|
|
108
157
|
};
|
|
109
158
|
try {
|
|
@@ -144,12 +193,28 @@ export async function runTurn(opts) {
|
|
|
144
193
|
}
|
|
145
194
|
if (step.stopReason === 'toolUse' && step.toolCalls?.length) {
|
|
146
195
|
const batch = await executeBatch(step.toolCalls);
|
|
147
|
-
|
|
148
|
-
|
|
196
|
+
totalDenies += batch.denies;
|
|
197
|
+
// F13:授权拒绝即收口(blockOnDeny 产出点——blocked 仅新增产出点,枚举不增);
|
|
198
|
+
// 1.17-K4(V2-a):blockOnDeny 缺省随档位(readonly 恒 true)——G6 单次拒绝即收口,
|
|
199
|
+
// 开则 G8 无机会触发(设计 §5.4 共存口径)
|
|
200
|
+
if (blockOnDeny && batch.denies > 0) {
|
|
149
201
|
const seq = closeTurn({ reason: 'blocked', denies: batch.denies }).seq;
|
|
150
202
|
trail.push({ seq, reason: 'blocked' });
|
|
151
203
|
return { reason: 'blocked', steps, endReasonTrail: trail };
|
|
152
204
|
}
|
|
205
|
+
// G8(D-50):拒绝累计熔断——同 turn denies 累计 ≥ 阈值收口 blocked(止损优先于
|
|
206
|
+
// conclude/terminate 判定;denies 为 turn 级累计跨 batch)
|
|
207
|
+
if (denyBreaker > 0 && totalDenies >= denyBreaker) {
|
|
208
|
+
const seq = closeTurn({ reason: 'blocked', denies: totalDenies, gate: 'denyBreaker' }).seq;
|
|
209
|
+
trail.push({ seq, reason: 'blocked' });
|
|
210
|
+
return { reason: 'blocked', steps, endReasonTrail: trail };
|
|
211
|
+
}
|
|
212
|
+
// G9(D-50):重复失败熔断——executeBatch 已补记 no-dispatch 成对事件,此处收口
|
|
213
|
+
if (batch.breakerTripped) {
|
|
214
|
+
const seq = closeTurn({ reason: 'blocked', gate: 'repeatFailureBreaker', signature: batch.breakerTripped }).seq;
|
|
215
|
+
trail.push({ seq, reason: 'blocked' });
|
|
216
|
+
return { reason: 'blocked', steps, endReasonTrail: trail };
|
|
217
|
+
}
|
|
153
218
|
const agg = preset.aggregate ?? {};
|
|
154
219
|
const abortedNow = (agg.terminate ?? 'all') === 'any' ? batch.terminateVotes > 0 : batch.terminateAll;
|
|
155
220
|
if (abortedNow) { // terminate 收口:默认 AND(整批),可配置 any
|
package/dist/release-audit.jsonl
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{"stage":"archive","detail":"git archive HEAD → car-runtime-1.
|
|
2
|
-
{"stage":"sha256sums","detail":"SHA256SUMS
|
|
3
|
-
{"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":
|
|
4
|
-
{"stage":"cosign-keyless","detail":"signed car-runtime-1.
|
|
1
|
+
{"stage":"archive","detail":"git archive HEAD → car-runtime-1.17.0.tgz(407177 bytes,树哈希锚定)","ts":1792830637240}
|
|
2
|
+
{"stage":"sha256sums","detail":"SHA256SUMS c41096564679afc0…(裸字节复核通过)","ts":1792830637241}
|
|
3
|
+
{"stage":"sbom","detail":"55 个组件(运行时依赖 0 项)","ts":1792830637247}
|
|
4
|
+
{"stage":"cosign-keyless","detail":"signed car-runtime-1.17.0.tgz (keyless OIDC + Rekor)","ts":1792830639351}
|
package/dist/runtime-core/llm.js
CHANGED
|
@@ -519,7 +519,15 @@ function mergeAnthropicUsage(start, delta, model, adapterId) {
|
|
|
519
519
|
* toolResult 收敛进 user 消息 content(连续多条合并为单 user 多 tool_result 块——Anthropic
|
|
520
520
|
* 消息序列约束);assistant 工具调用 = content:[{type:'tool_use',id,name,input}];
|
|
521
521
|
* declaredSideEffect 不出站(与 openai-compat 同红线)。
|
|
522
|
+
* 1.17-K4(D-48 P1):system 以单块数组出站并挂 `cache_control: ephemeral` 断点(稳定前缀
|
|
523
|
+
* 缓存——首个 system 恒不进折叠区间,锚点天然稳定)。断点 = 传输层注解:不进 SessionLog/
|
|
524
|
+
* 投影/快照比对,N1 零影响;生效有 provider 侧最小长度门槛(~1024 tokens)——短 system
|
|
525
|
+
* 静默不生效应以 usage.cacheCreationTokens 观测,禁以「配了就该生效」推断。关断 =
|
|
526
|
+
* CAR_LLM_PROMPT_CACHE=off(cli flag --no-prompt-cache 置本 env;A/B 与故障回退通道)。
|
|
522
527
|
*/
|
|
528
|
+
function promptCacheOff() {
|
|
529
|
+
return process.env.CAR_LLM_PROMPT_CACHE === 'off';
|
|
530
|
+
}
|
|
523
531
|
function toAnthropic(req, apiKey) {
|
|
524
532
|
const system = [];
|
|
525
533
|
const turns = [];
|
|
@@ -576,7 +584,14 @@ function toAnthropic(req, apiKey) {
|
|
|
576
584
|
stream: true,
|
|
577
585
|
max_tokens: maxTokens,
|
|
578
586
|
...(thinkingBudget !== undefined ? { thinking: { type: 'enabled', budget_tokens: thinkingBudget } } : {}),
|
|
579
|
-
|
|
587
|
+
// D-48 P1:缺省单块 + ephemeral 断点;关断 = 顶层字符串(1.16.x 前形态,A/B 与回退)
|
|
588
|
+
...(system.length
|
|
589
|
+
? {
|
|
590
|
+
system: promptCacheOff()
|
|
591
|
+
? system.join('\n\n')
|
|
592
|
+
: [{ type: 'text', text: system.join('\n\n'), cache_control: { type: 'ephemeral' } }],
|
|
593
|
+
}
|
|
594
|
+
: {}),
|
|
580
595
|
messages: turns,
|
|
581
596
|
...(req.tools.length
|
|
582
597
|
? { tools: req.tools.map(t => ({ name: t.name, description: t.description, input_schema: t.parameters })) }
|
package/dist/sbom.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CAR-SBOM",
|
|
3
3
|
"specVersion": "0.1",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.17.0",
|
|
5
5
|
"components": [
|
|
6
6
|
{
|
|
7
7
|
"type": "file",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
{
|
|
12
12
|
"type": "file",
|
|
13
13
|
"path": "src/cli.ts",
|
|
14
|
-
"sha256": "
|
|
14
|
+
"sha256": "833d9d33e281115d1ae50858028ce82b930a530b9ef513232f02bf3b94269fcb"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"type": "file",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
{
|
|
57
57
|
"type": "file",
|
|
58
58
|
"path": "src/load/config.ts",
|
|
59
|
-
"sha256": "
|
|
59
|
+
"sha256": "86584c58bfb5d458475e474b896de6ffa2f89e7e76364f4bfe9f2f3fd3d2ad75"
|
|
60
60
|
},
|
|
61
61
|
{
|
|
62
62
|
"type": "file",
|
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
{
|
|
107
107
|
"type": "file",
|
|
108
108
|
"path": "src/loop/stop.ts",
|
|
109
|
-
"sha256": "
|
|
109
|
+
"sha256": "d5bca2911a6cd75606fedaea041e62bcd4d3d78dc987030318f91ec53c20e223"
|
|
110
110
|
},
|
|
111
111
|
{
|
|
112
112
|
"type": "file",
|
|
@@ -176,7 +176,7 @@
|
|
|
176
176
|
{
|
|
177
177
|
"type": "file",
|
|
178
178
|
"path": "src/runtime-core/llm.ts",
|
|
179
|
-
"sha256": "
|
|
179
|
+
"sha256": "3df0703df21657121464e8495d5ffcc58b5b6362ac339d58bfc978686aa8dca0"
|
|
180
180
|
},
|
|
181
181
|
{
|
|
182
182
|
"type": "file",
|
|
@@ -211,7 +211,7 @@
|
|
|
211
211
|
{
|
|
212
212
|
"type": "file",
|
|
213
213
|
"path": "src/seam.ts",
|
|
214
|
-
"sha256": "
|
|
214
|
+
"sha256": "bd0bad44f5dc0da542556146eff1318a30cb5b56eaf682d0350947716db2628a"
|
|
215
215
|
},
|
|
216
216
|
{
|
|
217
217
|
"type": "file",
|
|
@@ -271,12 +271,12 @@
|
|
|
271
271
|
{
|
|
272
272
|
"type": "file",
|
|
273
273
|
"path": "package.json",
|
|
274
|
-
"sha256": "
|
|
274
|
+
"sha256": "2e6ab9f35a9401baa661232f059c9447d551802031bdf8809a57dfdddfd67d09"
|
|
275
275
|
},
|
|
276
276
|
{
|
|
277
277
|
"type": "file",
|
|
278
278
|
"path": "README.md",
|
|
279
|
-
"sha256": "
|
|
279
|
+
"sha256": "d44a62a9565267831bbf5a5fc0469b8528b455efafcd5aea0029435ebe1e2327"
|
|
280
280
|
}
|
|
281
281
|
],
|
|
282
282
|
"runtimeDependencies": []
|
package/dist/seam.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export { CredentialService } from './runtime-core/credentials.ts';
|
|
|
49
49
|
export type { LlmAdapter, LlmRequest, LlmChunk } from './runtime-core/types.ts';
|
|
50
50
|
export { mountPlugin } from './load/loader.ts';
|
|
51
51
|
export { Context } from './kernel/context.ts';
|
|
52
|
-
export { loadCarConfig, mergeLlmConfig, mergeSignatureGate, warmCarConfig, type CarConfig, type LlmConfig } from './load/config.ts';
|
|
52
|
+
export { loadCarConfig, mergeLlmConfig, mergeSignatureGate, warmCarConfig, type CarConfig, type LlmConfig, type SubagentConfig } from './load/config.ts';
|
|
53
53
|
export { probeCapabilities, SandboxExecutor } from './sandbox/sandbox.ts';
|
|
54
54
|
export { AuthzService, checkCapability, type Decision, type AuthzRequest, type AuthzDecision, type DeclaredCapabilities } from './authz/authz.ts';
|
|
55
55
|
export { createTelemetryFacade, telemetryConfigFromEnv } from './runtime-core/telemetry.ts';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lqc123qwe/car-runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0",
|
|
4
4
|
"description": "Composable Agent Runtime (CAR) - microkernel plugin system with sandboxed PTC, append-only hashed session log, and MCP host bridge",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/cli.ts
CHANGED
|
@@ -41,6 +41,8 @@ const HELP = `用法: car <command> [args]
|
|
|
41
41
|
装配并运行插件(快速上手流;装载前签名门 warn 缺省)
|
|
42
42
|
真路径:--prompt <text> + --base-url/--model(或 llm.* 配置);
|
|
43
43
|
--adapter-id anthropic = Messages API(凭据 ANTHROPIC_API_KEY);
|
|
44
|
+
--no-prompt-cache = 关断 anthropic 稳定前缀缓存断点(D-48;
|
|
45
|
+
等价 env CAR_LLM_PROMPT_CACHE=off,A/B 与回退通道);
|
|
44
46
|
--demo = stub 演示流
|
|
45
47
|
reload <file|dir> [--sig-enforce] [--config <path>]
|
|
46
48
|
热重载插件并打印六阶段加载报告(含 verify 签名门)
|
|
@@ -65,8 +67,9 @@ const HELP = `用法: car <command> [args]
|
|
|
65
67
|
CAR_UNSIGNED_ALLOW=1 显式声明豁免(warn 缺签路径计数 confirmed=yes,横幅保留)
|
|
66
68
|
配置文件通道(1.5 起双载体):cwd car.config.ts(export default {…};发现序 ts > json)或
|
|
67
69
|
car.config.json 或 --config <path>;键位 sandbox.unsigned.allow / sandbox.sig.enforce /
|
|
68
|
-
sandbox.sig.trustRoot / llm.* /
|
|
69
|
-
adapterId/keyEnv/priority/weight/maxTokens + probe + maxAttempts;路由决策落链)/
|
|
70
|
+
sandbox.sig.trustRoot / llm.* / modelPool.*(多端点 fallback:endpoints id/baseUrl/model/
|
|
71
|
+
adapterId/keyEnv/priority/weight/maxTokens + probe + maxAttempts;路由决策落链)/ llm.subagent.*
|
|
72
|
+
(子 Agent:model 独立锚点 / maxConcurrent / maxCumulative 护栏上限)/ mcp.servers.*
|
|
70
73
|
(stdio: command/args/env;远程: url/headers,\${ENV_VAR} 引用注入凭据);优先级 flag > env > 配置 > 缺省;未知键 fail-visible`
|
|
71
74
|
|
|
72
75
|
// 进程内热重载会话(ReloadManager 持有 epoch 与实例注册表;同进程连续 reload 语义完整)
|
|
@@ -205,6 +208,9 @@ async function main(): Promise<number> {
|
|
|
205
208
|
const cfgBaseUrl = llm.baseUrl
|
|
206
209
|
const cfgModel = llm.model
|
|
207
210
|
let modelName = cfgModel ?? ''
|
|
211
|
+
// 1.17-K4(D-48 P1 / V1-A):提示缓存断点关断 flag——flag > env(置 env 后适配器内部决策;
|
|
212
|
+
// 池/单端点两分支通用,须先于适配器创建)
|
|
213
|
+
if (rest.includes('--no-prompt-cache')) process.env.CAR_LLM_PROMPT_CACHE = 'off'
|
|
208
214
|
const credService = new CredentialService()
|
|
209
215
|
const core = new RuntimeCore(credService)
|
|
210
216
|
core.bindContext(ctx)
|
|
@@ -232,7 +238,7 @@ async function main(): Promise<number> {
|
|
|
232
238
|
console.error('CAR-E-LLM-CONFIG: 真实模型路径需要 baseUrl + model——')
|
|
233
239
|
console.error(' 配置:car.config.ts(export default)或 car.config.json {"llm":{"baseUrl":"https://…","model":"…"}} / env CAR_LLM_BASE_URL+CAR_LLM_MODEL / flag --base-url --model')
|
|
234
240
|
console.error(' anthropic:llm.adapterId "anthropic"(或 --adapter-id anthropic)+ baseUrl https://api.anthropic.com;凭据 ANTHROPIC_API_KEY')
|
|
235
|
-
console.error(' 模型池:
|
|
241
|
+
console.error(' 模型池:modelPool.endpoints(多端点 fallback + health 预检;凭据 keyEnv 引用;路由决策落链)')
|
|
236
242
|
console.error(' 凭据:OPENAI_API_KEY / ANTHROPIC_API_KEY(env fallback 需 CAR_ALLOW_ENV_CREDENTIALS=1 或 llm.allowEnvFallback)或 keychain;诊断:car doctor')
|
|
237
243
|
return 2
|
|
238
244
|
}
|
package/src/load/config.ts
CHANGED
|
@@ -52,6 +52,18 @@ export interface LlmConfig {
|
|
|
52
52
|
allowEnvFallback?: boolean
|
|
53
53
|
/** 1.14-S2(K-MP-2 / D-40):历史压缩策略(阈值自动触发判定入参;立即压缩 API 独立可用) */
|
|
54
54
|
compaction?: CompactionConfig
|
|
55
|
+
/** 1.16-K3(D-K2-2):子 Agent 配置(缺省 = 继承父会话模型锚点 Q-A2 + 宿主护栏常量 Q-A3) */
|
|
56
|
+
subagent?: SubagentConfig
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 1.16-K3(D-K2-2):子 Agent 配置面——宿主编排消费(内核自身不装配编排;schema 只登记键位) */
|
|
60
|
+
export interface SubagentConfig {
|
|
61
|
+
/** 独立子模型锚点(缺省 = 继承父会话现值;modelPool 激活时被池压过——与 llm.model 同口径) */
|
|
62
|
+
model?: string
|
|
63
|
+
/** 并发子 Agent 上限(正整数;缺省 = 宿主常量 3,Q-A3) */
|
|
64
|
+
maxConcurrent?: number
|
|
65
|
+
/** 单父会话累计派生上限(正整数;缺省 = 宿主常量 10,Q-A3) */
|
|
66
|
+
maxCumulative?: number
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
/** 1.14-S4(K-POOL-1 / D-42):模型池端点登记(多端点 fallback 候选;凭据仅收 keyEnv 引用) */
|
|
@@ -235,6 +247,18 @@ const rawSchema = z.object({
|
|
|
235
247
|
protectLastTurns: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
236
248
|
.refine(v => Number.isInteger(v) && v > 0, { message: '必须为正整数' }).optional(),
|
|
237
249
|
}).strict().optional(),
|
|
250
|
+
// 1.16-K3(D-K2-2):子 Agent 配置(model 独立锚点 + 护栏上限;空对象无意义显式拒——禁静默 no-op)
|
|
251
|
+
subagent: z.object({
|
|
252
|
+
model: nonEmptyTrimmed().optional(),
|
|
253
|
+
maxConcurrent: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
254
|
+
.refine(v => Number.isFinite(v) && Number.isInteger(v) && v > 0, { message: '必须为正整数' })
|
|
255
|
+
.optional(),
|
|
256
|
+
maxCumulative: z.number({ invalid_type_error: '必须为正整数', required_error: '必须为正整数' })
|
|
257
|
+
.refine(v => Number.isFinite(v) && Number.isInteger(v) && v > 0, { message: '必须为正整数' })
|
|
258
|
+
.optional(),
|
|
259
|
+
}).strict()
|
|
260
|
+
.refine(v => Object.keys(v).length > 0, { message: '至少登记一个键(model/maxConcurrent/maxCumulative;无子 Agent 配置需求请移除 llm.subagent 键,行为与 1.15.2 一致)' })
|
|
261
|
+
.optional(),
|
|
238
262
|
}).strict().optional(),
|
|
239
263
|
// 1.14-S4(K-POOL-1 / D-42):模型池登记(多端点 fallback + health + routing/decide 落链)
|
|
240
264
|
modelPool: modelPoolSchema.optional(),
|
|
@@ -243,8 +267,8 @@ const rawSchema = z.object({
|
|
|
243
267
|
}).strict().optional(),
|
|
244
268
|
}, { invalid_type_error: '配置顶层必须为 JSON 对象' }).strict()
|
|
245
269
|
|
|
246
|
-
/** 未登记键提示(渲染层拼 path
|
|
247
|
-
const KEY_SPACES = '登记键位:sandbox.* / llm.* / llm.
|
|
270
|
+
/** 未登记键提示(渲染层拼 path)——与系统设计键位空间同步;D-1 勘误:modelPool 为顶层键(非 llm.modelPool) */
|
|
271
|
+
const KEY_SPACES = '登记键位:sandbox.* / llm.* / modelPool.* / llm.subagent.* / mcp.servers.*'
|
|
248
272
|
|
|
249
273
|
/** zod issue → CAR-E-CONFIG 渲染(首个 issue;unrecognized_keys 按键路径展开) */
|
|
250
274
|
function renderIssue(error: z.ZodError): string {
|
|
@@ -287,6 +311,13 @@ function parseCarConfig(raw: unknown): { config: CarConfig; error?: string } {
|
|
|
287
311
|
if (d.llm.compaction.protectLastTurns !== undefined) cp.protectLastTurns = d.llm.compaction.protectLastTurns
|
|
288
312
|
llm.compaction = cp
|
|
289
313
|
}
|
|
314
|
+
if (d.llm.subagent) {
|
|
315
|
+
const sg: SubagentConfig = {}
|
|
316
|
+
if (d.llm.subagent.model !== undefined) sg.model = d.llm.subagent.model
|
|
317
|
+
if (d.llm.subagent.maxConcurrent !== undefined) sg.maxConcurrent = d.llm.subagent.maxConcurrent
|
|
318
|
+
if (d.llm.subagent.maxCumulative !== undefined) sg.maxCumulative = d.llm.subagent.maxCumulative
|
|
319
|
+
llm.subagent = sg
|
|
320
|
+
}
|
|
290
321
|
out.llm = llm
|
|
291
322
|
}
|
|
292
323
|
if (d.mcp) {
|
package/src/loop/stop.ts
CHANGED
|
@@ -57,8 +57,19 @@ export interface TurnPreset {
|
|
|
57
57
|
maxSteps?: number
|
|
58
58
|
/** F13:OR/AND 收口可配置(默认 any/all = M1 行为等价) */
|
|
59
59
|
aggregate?: { concludesTurn?: 'any' | 'all'; terminate?: 'any' | 'all' }
|
|
60
|
-
/** F13:授权拒绝即收口 blocked(默认 false =
|
|
60
|
+
/** F13:授权拒绝即收口 blocked(默认 false = 模型继续调整);1.17-K4(V2-a)缺省随档位收敛——readonly 恒 true(显式传参可覆盖) */
|
|
61
61
|
blockOnDeny?: boolean
|
|
62
|
+
/**
|
|
63
|
+
* 1.17-K4(D-50 / G8):拒绝累计熔断——同 turn denies 累计 ≥ N 即收口 blocked(gate:'denyBreaker')。
|
|
64
|
+
* 缺省 3(预防性闸门:真实样本从未超过 1 次/turn——设计 §10.4-3 诚实定位);0 = 关。
|
|
65
|
+
*/
|
|
66
|
+
denyBreaker?: number
|
|
67
|
+
/**
|
|
68
|
+
* 1.17-K4(D-50 / G9):重复失败熔断——失败签名(tool + 归一化错误串)同 turn 连续 ≥ N 后,
|
|
69
|
+
* 下一次同签名不再派发(成对补记 no-dispatch 事件)并收口 blocked(gate:'repeatFailureBreaker')。
|
|
70
|
+
* 异签名放行(允许探索,禁撞墙);成功派发重置连击。缺省 2;0 = 关。
|
|
71
|
+
*/
|
|
72
|
+
repeatFailureBreaker?: number
|
|
62
73
|
}
|
|
63
74
|
|
|
64
75
|
export interface TurnResult { reason: TurnEndReason; steps: number; endReasonTrail: Array<{ seq: number; reason: TurnEndReason }> }
|
|
@@ -117,12 +128,35 @@ export async function runTurn(opts: {
|
|
|
117
128
|
return log.append('runtime', 'turnEnd', turnId, null, { ...meta, ...(usage ? { usage } : {}) })
|
|
118
129
|
}
|
|
119
130
|
|
|
120
|
-
|
|
131
|
+
// 1.17-K4(D-50 / V2-a):blockOnDeny 缺省随档位收敛——readonly 恒 true(拒绝即收口,禁在
|
|
132
|
+
// 错误理解模式的路上烧 token;「看一眼再决定」应切 confirm——三档设计本义);confirm/full
|
|
133
|
+
// 缺省 false 不变;显式传参可覆盖任何档位
|
|
134
|
+
const blockOnDeny = preset.blockOnDeny ?? preset.mode === 'readonly'
|
|
135
|
+
// 1.17-K4(D-50):G8/G9 熔断阈值(缺省 3/2;0 = 关——A/B 与回退通道)
|
|
136
|
+
const denyBreaker = preset.denyBreaker ?? 3
|
|
137
|
+
const repeatFailureBreaker = preset.repeatFailureBreaker ?? 2
|
|
138
|
+
let totalDenies = 0
|
|
139
|
+
// G9 失败签名连击(turn 级):成功派发重置;授权拒绝不重置(拒绝 ≠ 探索进展)
|
|
140
|
+
let lastSignature: string | null = null
|
|
141
|
+
let lastFailureTool: string | null = null
|
|
142
|
+
let signatureStreak = 0
|
|
143
|
+
/** 失败签名 = tool + 归一化错误串(去空白/时间戳/长 hex id、截断 200——确定性好比对) */
|
|
144
|
+
const failureSignature = (tool: string, err: string) =>
|
|
145
|
+
(tool + ':' + err.replace(/\s+/g, ' ').replace(/\d{4}-\d{2}-\d{2}T[\d:.]+Z?/g, '<ts>').replace(/\b[0-9a-f]{8,}\b/g, '<id>')).slice(0, 200)
|
|
146
|
+
const advanceStreak = (tool: string, err: string) => {
|
|
147
|
+
const sig = failureSignature(tool, err)
|
|
148
|
+
if (sig === lastSignature) signatureStreak++
|
|
149
|
+
else { lastSignature = sig; signatureStreak = 1 }
|
|
150
|
+
lastFailureTool = tool
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const executeBatch = async (calls: ToolCall[]): Promise<{ concludesTurn: boolean; concludesAll: boolean; terminateVotes: number; terminateAll: boolean; finalized: number; denies: number; breakerTripped: string | null }> => {
|
|
121
154
|
let concludesTurn = false
|
|
122
155
|
let concludesVotes = 0
|
|
123
156
|
let terminateVotes = 0
|
|
124
157
|
let finalized = 0
|
|
125
158
|
let denies = 0
|
|
159
|
+
let breakerTripped: string | null = null
|
|
126
160
|
for (const call of calls) {
|
|
127
161
|
if (signal?.aborted) {
|
|
128
162
|
// 取消:未派发调用补记成对事件(日志无缺口)
|
|
@@ -132,8 +166,23 @@ export async function runTurn(opts: {
|
|
|
132
166
|
}
|
|
133
167
|
const def = tools.get(call.tool)
|
|
134
168
|
log.append('model', 'toolCall', turnId, call)
|
|
169
|
+
// G9(D-50)熔断预检:同签名连击已达阈值且本次同工具 → 不再派发(错误串须派发方知,
|
|
170
|
+
// 预检口径 = 同工具紧邻重试——换工具探索不受影响;换参数异错误的甄别发生在 streak < 阈值期)。
|
|
171
|
+
// 未派发也成对落链(与取消补记同纪律——日志无缺口),breakerTripped 交主循环收口。
|
|
172
|
+
// 位置在 def 查找前:unknown tool 连击(def 缺失分支 continue)同样要被拦
|
|
173
|
+
if (repeatFailureBreaker > 0 && signatureStreak >= repeatFailureBreaker && lastFailureTool === call.tool) {
|
|
174
|
+
log.append('runtime', 'toolResult', turnId, {
|
|
175
|
+
id: call.id,
|
|
176
|
+
error: 'repeated-identical-failure: breaker tripped (no dispatch)',
|
|
177
|
+
signature: lastSignature,
|
|
178
|
+
})
|
|
179
|
+
breakerTripped = lastSignature
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
135
182
|
if (!def) {
|
|
136
183
|
log.append('plugin', 'toolResult', turnId, { id: call.id, error: `unknown tool "${call.tool}"` })
|
|
184
|
+
// G9:unknown tool 同为失败面(模型反复叫错工具名 = 撞墙形态之一)
|
|
185
|
+
advanceStreak(call.tool, `unknown tool "${call.tool}"`)
|
|
137
186
|
continue
|
|
138
187
|
}
|
|
139
188
|
// 权限门(F4 集成点):write 类在 readonly/confirm 模式需放行;1.13.0(K-FS-1):
|
|
@@ -156,6 +205,10 @@ export async function runTurn(opts: {
|
|
|
156
205
|
toolError = String(e)
|
|
157
206
|
}
|
|
158
207
|
log.append('plugin', 'toolResult', turnId, { id: call.id, result, ...(toolError ? { error: toolError } : {}) })
|
|
208
|
+
// G9 连击推进:同签名 streak++,异签名重开(允许探索——换参数后不同错误 = 不同签名);
|
|
209
|
+
// 成功派发重置(拒绝不重置——拒绝 ≠ 探索进展)
|
|
210
|
+
if (toolError) advanceStreak(call.tool, toolError)
|
|
211
|
+
else { lastSignature = null; lastFailureTool = null; signatureStreak = 0 }
|
|
159
212
|
finalized++
|
|
160
213
|
if (def.concludesTurn) { concludesTurn = true; concludesVotes++ }
|
|
161
214
|
if (def.terminate) terminateVotes++
|
|
@@ -163,7 +216,7 @@ export async function runTurn(opts: {
|
|
|
163
216
|
return {
|
|
164
217
|
concludesTurn, concludesAll: finalized > 0 && concludesVotes === finalized,
|
|
165
218
|
terminateVotes, terminateAll: finalized > 0 && terminateVotes === finalized,
|
|
166
|
-
finalized, denies,
|
|
219
|
+
finalized, denies, breakerTripped,
|
|
167
220
|
}
|
|
168
221
|
}
|
|
169
222
|
|
|
@@ -208,12 +261,28 @@ export async function runTurn(opts: {
|
|
|
208
261
|
|
|
209
262
|
if (step.stopReason === 'toolUse' && step.toolCalls?.length) {
|
|
210
263
|
const batch = await executeBatch(step.toolCalls)
|
|
211
|
-
|
|
212
|
-
|
|
264
|
+
totalDenies += batch.denies
|
|
265
|
+
// F13:授权拒绝即收口(blockOnDeny 产出点——blocked 仅新增产出点,枚举不增);
|
|
266
|
+
// 1.17-K4(V2-a):blockOnDeny 缺省随档位(readonly 恒 true)——G6 单次拒绝即收口,
|
|
267
|
+
// 开则 G8 无机会触发(设计 §5.4 共存口径)
|
|
268
|
+
if (blockOnDeny && batch.denies > 0) {
|
|
213
269
|
const seq = closeTurn({ reason: 'blocked', denies: batch.denies }).seq
|
|
214
270
|
trail.push({ seq, reason: 'blocked' })
|
|
215
271
|
return { reason: 'blocked', steps, endReasonTrail: trail }
|
|
216
272
|
}
|
|
273
|
+
// G8(D-50):拒绝累计熔断——同 turn denies 累计 ≥ 阈值收口 blocked(止损优先于
|
|
274
|
+
// conclude/terminate 判定;denies 为 turn 级累计跨 batch)
|
|
275
|
+
if (denyBreaker > 0 && totalDenies >= denyBreaker) {
|
|
276
|
+
const seq = closeTurn({ reason: 'blocked', denies: totalDenies, gate: 'denyBreaker' }).seq
|
|
277
|
+
trail.push({ seq, reason: 'blocked' })
|
|
278
|
+
return { reason: 'blocked', steps, endReasonTrail: trail }
|
|
279
|
+
}
|
|
280
|
+
// G9(D-50):重复失败熔断——executeBatch 已补记 no-dispatch 成对事件,此处收口
|
|
281
|
+
if (batch.breakerTripped) {
|
|
282
|
+
const seq = closeTurn({ reason: 'blocked', gate: 'repeatFailureBreaker', signature: batch.breakerTripped }).seq
|
|
283
|
+
trail.push({ seq, reason: 'blocked' })
|
|
284
|
+
return { reason: 'blocked', steps, endReasonTrail: trail }
|
|
285
|
+
}
|
|
217
286
|
const agg = preset.aggregate ?? {}
|
|
218
287
|
const abortedNow = (agg.terminate ?? 'all') === 'any' ? batch.terminateVotes > 0 : batch.terminateAll
|
|
219
288
|
if (abortedNow) { // terminate 收口:默认 AND(整批),可配置 any
|
package/src/runtime-core/llm.ts
CHANGED
|
@@ -563,7 +563,16 @@ function mergeAnthropicUsage(
|
|
|
563
563
|
* toolResult 收敛进 user 消息 content(连续多条合并为单 user 多 tool_result 块——Anthropic
|
|
564
564
|
* 消息序列约束);assistant 工具调用 = content:[{type:'tool_use',id,name,input}];
|
|
565
565
|
* declaredSideEffect 不出站(与 openai-compat 同红线)。
|
|
566
|
+
* 1.17-K4(D-48 P1):system 以单块数组出站并挂 `cache_control: ephemeral` 断点(稳定前缀
|
|
567
|
+
* 缓存——首个 system 恒不进折叠区间,锚点天然稳定)。断点 = 传输层注解:不进 SessionLog/
|
|
568
|
+
* 投影/快照比对,N1 零影响;生效有 provider 侧最小长度门槛(~1024 tokens)——短 system
|
|
569
|
+
* 静默不生效应以 usage.cacheCreationTokens 观测,禁以「配了就该生效」推断。关断 =
|
|
570
|
+
* CAR_LLM_PROMPT_CACHE=off(cli flag --no-prompt-cache 置本 env;A/B 与故障回退通道)。
|
|
566
571
|
*/
|
|
572
|
+
function promptCacheOff(): boolean {
|
|
573
|
+
return process.env.CAR_LLM_PROMPT_CACHE === 'off'
|
|
574
|
+
}
|
|
575
|
+
|
|
567
576
|
function toAnthropic(req: LlmRequest, apiKey: string) {
|
|
568
577
|
const system: string[] = []
|
|
569
578
|
const turns: Array<{ role: 'user' | 'assistant'; content: unknown }> = []
|
|
@@ -618,7 +627,14 @@ function toAnthropic(req: LlmRequest, apiKey: string) {
|
|
|
618
627
|
stream: true,
|
|
619
628
|
max_tokens: maxTokens,
|
|
620
629
|
...(thinkingBudget !== undefined ? { thinking: { type: 'enabled', budget_tokens: thinkingBudget } } : {}),
|
|
621
|
-
|
|
630
|
+
// D-48 P1:缺省单块 + ephemeral 断点;关断 = 顶层字符串(1.16.x 前形态,A/B 与回退)
|
|
631
|
+
...(system.length
|
|
632
|
+
? {
|
|
633
|
+
system: promptCacheOff()
|
|
634
|
+
? system.join('\n\n')
|
|
635
|
+
: [{ type: 'text', text: system.join('\n\n'), cache_control: { type: 'ephemeral' } }],
|
|
636
|
+
}
|
|
637
|
+
: {}),
|
|
622
638
|
messages: turns,
|
|
623
639
|
...(req.tools.length
|
|
624
640
|
? { tools: req.tools.map(t => ({ name: t.name, description: t.description, input_schema: t.parameters })) }
|
package/src/seam.ts
CHANGED
|
@@ -49,7 +49,7 @@ export { CredentialService } from './runtime-core/credentials.ts'
|
|
|
49
49
|
export type { LlmAdapter, LlmRequest, LlmChunk } from './runtime-core/types.ts'
|
|
50
50
|
export { mountPlugin } from './load/loader.ts'
|
|
51
51
|
export { Context } from './kernel/context.ts'
|
|
52
|
-
export { loadCarConfig, mergeLlmConfig, mergeSignatureGate, warmCarConfig, type CarConfig, type LlmConfig } from './load/config.ts'
|
|
52
|
+
export { loadCarConfig, mergeLlmConfig, mergeSignatureGate, warmCarConfig, type CarConfig, type LlmConfig, type SubagentConfig } from './load/config.ts'
|
|
53
53
|
export { probeCapabilities, SandboxExecutor } from './sandbox/sandbox.ts'
|
|
54
54
|
export { AuthzService, checkCapability, type Decision, type AuthzRequest, type AuthzDecision, type DeclaredCapabilities } from './authz/authz.ts'
|
|
55
55
|
export { createTelemetryFacade, telemetryConfigFromEnv } from './runtime-core/telemetry.ts'
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"base64Signature":"MEUCICbvk8lw/0J5k1bnaKNZCM/xgESEFF1qskK5z/7inngoAiEA5582ex8TI6YiJkKaYNPzuIKkUF7S99dxANZb7kpLwLU=","cert":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUc1akNDQm0yZ0F3SUJBZ0lVSzFtZE02eUltaklTQkxGZ29TY2h3VTlJZXUwd0NnWUlLb1pJemowRUF3TXcKTnpFVk1CTUdBMVVFQ2hNTWMybG5jM1J2Y21VdVpHVjJNUjR3SEFZRFZRUURFeFZ6YVdkemRHOXlaUzFwYm5SbApjbTFsWkdsaGRHVXdIaGNOTWpZeE1ESXdNREkwTURJNFdoY05Nall4TURJd01ESTFNREk0V2pBQU1Ga3dFd1lICktvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUUwcVF3SVNGV2VndFhBYzI4dzR4dGs3U0lyOFU1TFBKWlBmOHYKbGJvdEFveGszbnI0bWs5YjlLVWRDWmNSRVYzOGdZV0N3YnVkQzZzMXpHMUc4UEJjbGFPQ0JZd3dnZ1dJTUE0RwpBMVVkRHdFQi93UUVBd0lIZ0RBVEJnTlZIU1VFRERBS0JnZ3JCZ0VGQlFjREF6QWZCZ05WSFNNRUdEQVdnQlRmCjArblBWaVFSbHZtbzJPa29WYUxHTGhoa1B6QmlCZ05WSFJFQkFmOEVXREJXaGxSb2RIUndjem92TDJkcGRHaDEKWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHpMM0psYkdWaApjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUxTGpJd09RWUtLd1lCQkFHRHZ6QUJBUVFyYUhSMGNITTZMeTkwCmIydGxiaTVoWTNScGIyNXpMbWRwZEdoMVluVnpaWEpqYjI1MFpXNTBMbU52YlRBVkJnb3JCZ0VFQVlPL01BRUMKQkFkeVpXeGxZWE5sTURZR0Npc0dBUVFCZzc4d0FRTUVLR1F4TWpaa05EUXlNVGt6TUdVMk5HVTNOV00zTmpZMQpNamcwWmpSbVpHWTNZVEpqWkRnNU5qSXdGUVlLS3dZQkJBR0R2ekFCQkFRSGNtVnNaV0Z6WlRBZ0Jnb3JCZ0VFCkFZTy9NQUVGQkJKc2NXTTJNalF2WTJGeUxYSjFiblJwYldVd0hnWUtLd1lCQkFHRHZ6QUJCZ1FRY21WbWN5OTAKWVdkekx6RXVNVFV1TWpBN0Jnb3JCZ0VFQVlPL01BRUlCQzBNSzJoMGRIQnpPaTh2ZEc5clpXNHVZV04wYVc5dQpjeTVuYVhSb2RXSjFjMlZ5WTI5dWRHVnVkQzVqYjIwd1pBWUtLd1lCQkFHRHZ6QUJDUVJXREZSb2RIUndjem92CkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMEwyTmhjaTF5ZFc1MGFXMWxMeTVuYVhSb2RXSXZkMjl5YTJac2IzZHoKTDNKbGJHVmhjMlV1ZVcxc1FISmxabk12ZEdGbmN5OHhMakUxTGpJd09BWUtLd1lCQkFHRHZ6QUJDZ1FxRENoawpNVEkyWkRRME1qRTVNekJsTmpSbE56VmpOelkyTlRJNE5HWTBabVJtTjJFeVkyUTRPVFl5TUIwR0Npc0dBUVFCCmc3OHdBUXNFRHd3TloybDBhSFZpTFdodmMzUmxaREExQmdvckJnRUVBWU8vTUFFTUJDY01KV2gwZEhCek9pOHYKWjJsMGFIVmlMbU52YlM5c2NXTTJNalF2WTJGeUxYSjFiblJwYldVd09BWUtLd1lCQkFHRHZ6QUJEUVFxRENoawpNVEkyWkRRME1qRTVNekJsTmpSbE56VmpOelkyTlRJNE5HWTBabVJtTjJFeVkyUTRPVFl5TUNBR0Npc0dBUVFCCmc3OHdBUTRFRWd3UWNtVm1jeTkwWVdkekx6RXVNVFV1TWpBYUJnb3JCZ0VFQVlPL01BRVBCQXdNQ2pFek5qRXgKT1RJM01UUXdLUVlLS3dZQkJBR0R2ekFCRUFRYkRCbG9kSFJ3Y3pvdkwyZHBkR2gxWWk1amIyMHZiSEZqTmpJMApNQmdHQ2lzR0FRUUJnNzh3QVJFRUNnd0lOamt5TXpRMU5qUXdaQVlLS3dZQkJBR0R2ekFCRWdSV0RGUm9kSFJ3CmN6b3ZMMmRwZEdoMVlpNWpiMjB2YkhGak5qSTBMMk5oY2kxeWRXNTBhVzFsTHk1bmFYUm9kV0l2ZDI5eWEyWnMKYjNkekwzSmxiR1ZoYzJVdWVXMXNRSEpsWm5NdmRHRm5jeTh4TGpFMUxqSXdPQVlLS3dZQkJBR0R2ekFCRXdRcQpEQ2hrTVRJMlpEUTBNakU1TXpCbE5qUmxOelZqTnpZMk5USTROR1kwWm1SbU4yRXlZMlE0T1RZeU1CY0dDaXNHCkFRUUJnNzh3QVJRRUNRd0hjbVZzWldGelpUQlpCZ29yQmdFRUFZTy9NQUVWQkVzTVNXaDBkSEJ6T2k4dloybDAKYUhWaUxtTnZiUzlzY1dNMk1qUXZZMkZ5TFhKMWJuUnBiV1V2WVdOMGFXOXVjeTl5ZFc1ekx6TTVNell3TVRZeApPRFE0TDJGMGRHVnRjSFJ6THpFd0ZnWUtLd1lCQkFHRHZ6QUJGZ1FJREFad2RXSnNhV013VUFZS0t3WUJCQUdECnZ6QUJHQVJDREVCeVpYQnZPbXh4WXpZeU5FQTJPVEl6TkRVMk5DOWpZWEl0Y25WdWRHbHRaVUF4TXpZeE1Ua3kKTnpFME9uSmxaanB5WldaekwzUmhaM012TVM0eE5TNHlNSUdLQmdvckJnRUVBZFo1QWdRQ0JId0VlZ0I0QUhZQQozVDB3YXNiSEVUSmpHUjRjbVdjM0FxSktYcmplUEszL2g0cHlnQzhwN280QUFBR2hWeTZETkFBQUJBTUFSekJGCkFpRUFrcWFVMUZQZVhGSzh1bHlCWmdZTFZvWHZRVnpUdThURnIwb0MwVDFXYWlJQ0lFakRpdDZsVXUyUkZRQkUKS04wMFA3TTZrUGlBK25uN1FwM1l4L09NVjYwbk1Bb0dDQ3FHU000OUJBTURBMmNBTUdRQ01BaDJEOXJPSTQ4bApjMUFrM3lnVG1ybWF3VXRsOW9rd2pVcVJkTjVrSmNMcjNKWjdpd0h3VmtCV1N3Vm5Ja09BVUFJd1NiK2dFK2loCm1FZUo3Q0VBNktmSXJad0dzN2c3UFhPS2tyVFBYQWYzYmFUSHJRRFRDbWFSeExibjd5WWFEelJICi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K","rekorBundle":{"SignedEntryTimestamp":"MEUCIGu7TqDI7QG1De0ED4bg7V58GvGtV+wwmfbPqrwhlx3vAiEAj917MyoFKHsgkZvu/rLtaR4kd1UzZ7MWzVjP+eUHf00=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlMDgwMGVjMTVkOTRjOGI0ZTY0MTBhOTg2NDJmNGRjNzAzYzIzMzVmYTg1Y2Y3NTQzNjAwM2NjYzI2YTJkMzI3In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJQ2J2azhsdy8wSjVrMWJuYUtOWkNNL3hnRVNFRkYxcXNrSzV6Lzdpbm5nb0FpRUE1NTgyZXg4VEk2WWlKa0thWU5QenVJS2tVRjdTOTlkeEFOWmI3a3BMd0xVPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVYzFha05EUW0weVowRjNTVUpCWjBsVlN6RnRaRTAyZVVsdGFrbFRRa3hHWjI5VFkyaDNWVGxKWlhVd2QwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFU1hkTlJFa3dUVVJKTkZkb1kwNU5hbGw0VFVSSmQwMUVTVEZOUkVrMFYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVV3Y1ZGM1NWTkdWMlZuZEZoQll6STRkelI0ZEdzM1UwbHlPRlUxVEZCS1dsQm1PSFlLYkdKdmRFRnZlR3N6Ym5JMGJXczVZamxMVldSRFdtTlNSVll6T0dkWlYwTjNZblZrUXpaek1YcEhNVWM0VUVKamJHRlBRMEpaZDNkbloxZEpUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFtbENaMDVXU0ZKRlFrRm1PRVZYUkVKWGFHeFNiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmlTRVpxVG1wSk1Fd3lUbWhqYVRGNVpGYzFNR0ZYTVd4TWVUVnVZVmhTYjJSWFNYWmtNamw1WVRKYWMySXpaSHBNTTBwc1lrZFdhQXBqTWxWMVpWY3hjMUZJU214YWJrMTJaRWRHYm1ONU9IaE1ha1V4VEdwSmQwOVJXVXRMZDFsQ1FrRkhSSFo2UVVKQlVWRnlZVWhTTUdOSVRUWk1lVGt3Q21JeWRHeGlhVFZvV1ROU2NHSXlOWHBNYldSd1pFZG9NVmx1Vm5wYVdFcHFZakkxTUZwWE5UQk1iVTUyWWxSQlZrSm5iM0pDWjBWRlFWbFBMMDFCUlVNS1FrRmtlVnBYZUd4WldFNXNUVVJaUjBOcGMwZEJVVkZDWnpjNGQwRlJUVVZMUjFGNFRXcGFhMDVFVVhsTlZHdDZUVWRWTWs1SFZUTk9WMDB6VG1wWk1RcE5hbWN3V21wU2JWcEhXVE5aVkVwcVdrUm5OVTVxU1hkR1VWbExTM2RaUWtKQlIwUjJla0ZDUWtGUlNHTnRWbk5hVjBaNldsUkJaMEpuYjNKQ1owVkZDa0ZaVHk5TlFVVkdRa0pLYzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMGhuV1V0TGQxbENRa0ZIUkhaNlFVSkNaMUZSWTIxV2JXTjVPVEFLV1Zka2VreDZSWFZOVkZWMVRXcEJOMEpuYjNKQ1owVkZRVmxQTDAxQlJVbENRekJOU3pKb01HUklRbnBQYVRoMlpFYzVjbHBYTkhWWlYwNHdZVmM1ZFFwamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcVlqSXdkMXBCV1V0TGQxbENRa0ZIUkhaNlFVSkRVVkpYUkVaU2IyUklVbmRqZW05MkNrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUV3eVRtaGphVEY1WkZjMU1HRlhNV3hNZVRWdVlWaFNiMlJYU1haa01qbDVZVEphYzJJelpIb0tURE5LYkdKSFZtaGpNbFYxWlZjeGMxRklTbXhhYmsxMlpFZEdibU41T0hoTWFrVXhUR3BKZDA5QldVdExkMWxDUWtGSFJIWjZRVUpEWjFGeFJFTm9hd3BOVkVreVdrUlJNRTFxUlRWTmVrSnNUbXBTYkU1NlZtcE9lbGt5VGxSSk5FNUhXVEJhYlZKdFRqSkZlVmt5VVRSUFZGbDVUVUl3UjBOcGMwZEJVVkZDQ21jM09IZEJVWE5GUkhkM1Rsb3liREJoU0ZacFRGZG9kbU16VW14YVJFRXhRbWR2Y2tKblJVVkJXVTh2VFVGRlRVSkRZMDFLVjJnd1pFaENlazlwT0hZS1dqSnNNR0ZJVm1sTWJVNTJZbE01YzJOWFRUSk5hbEYyV1RKR2VVeFlTakZpYmxKd1lsZFZkMDlCV1V0TGQxbENRa0ZIUkhaNlFVSkVVVkZ4UkVOb2F3cE5WRWt5V2tSUk1FMXFSVFZOZWtKc1RtcFNiRTU2Vm1wT2Vsa3lUbFJKTkU1SFdUQmFiVkp0VGpKRmVWa3lVVFJQVkZsNVRVTkJSME5wYzBkQlVWRkNDbWMzT0hkQlVUUkZSV2QzVVdOdFZtMWplVGt3V1Zka2VreDZSWFZOVkZWMVRXcEJZVUpuYjNKQ1owVkZRVmxQTDAxQlJWQkNRWGROUTJwRmVrNXFSWGdLVDFSSk0wMVVVWGRMVVZsTFMzZFpRa0pCUjBSMmVrRkNSVUZSWWtSQ2JHOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaVNFWnFUbXBKTUFwTlFtZEhRMmx6UjBGUlVVSm5OemgzUVZKRlJVTm5kMGxPYW10NVRYcFJNVTVxVVhkYVFWbExTM2RaUWtKQlIwUjJla0ZDUldkU1YwUkdVbTlrU0ZKM0NtTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZa2hHYWs1cVNUQk1NazVvWTJreGVXUlhOVEJoVnpGc1RIazFibUZZVW05a1YwbDJaREk1ZVdFeVduTUtZak5rZWt3elNteGlSMVpvWXpKVmRXVlhNWE5SU0Vwc1dtNU5kbVJIUm01amVUaDRUR3BGTVV4cVNYZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JYZFJjUXBFUTJoclRWUkpNbHBFVVRCTmFrVTFUWHBDYkU1cVVteE9lbFpxVG5wWk1rNVVTVFJPUjFrd1dtMVNiVTR5UlhsWk1sRTBUMVJaZVUxQ1kwZERhWE5IQ2tGUlVVSm5OemgzUVZKUlJVTlJkMGhqYlZaeldsZEdlbHBVUWxwQ1oyOXlRbWRGUlVGWlR5OU5RVVZXUWtWelRWTlhhREJrU0VKNlQyazRkbG95YkRBS1lVaFdhVXh0VG5aaVV6bHpZMWROTWsxcVVYWlpNa1o1VEZoS01XSnVVbkJpVjFWMldWZE9NR0ZYT1hWamVUbDVaRmMxZWt4NlRUVk5lbGwzVFZSWmVBcFBSRkUwVERKR01HUkhWblJqU0ZKNlRIcEZkMFpuV1V0TGQxbENRa0ZIUkhaNlFVSkdaMUZKUkVGYWQyUlhTbk5oVjAxM1ZVRlpTMHQzV1VKQ1FVZEVDblo2UVVKSFFWSkRSRVZDZVZwWVFuWlBiWGg0V1hwWmVVNUZRVEpQVkVsNlRrUlZNazVET1dwWldFbDBZMjVXZFdSSGJIUmFWVUY0VFhwWmVFMVVhM2tLVG5wRk1FOXVTbXhhYW5CNVdsZGFla3d6VW1oYU0wMTJUVk0wZUU1VE5IbE5TVWRMUW1kdmNrSm5SVVZCWkZvMVFXZFJRMEpJZDBWbFowSTBRVWhaUVFvelZEQjNZWE5pU0VWVVNtcEhValJqYlZkak0wRnhTa3RZY21wbFVFc3pMMmcwY0hsblF6aHdOMjgwUVVGQlIyaFdlVFpFVGtGQlFVSkJUVUZTZWtKR0NrRnBSVUZyY1dGVk1VWlFaVmhHU3poMWJIbENXbWRaVEZadldIWlJWbnBVZFRoVVJuSXdiME13VkRGWFlXbEpRMGxGYWtScGREWnNWWFV5VWtaUlFrVUtTMDR3TUZBM1RUWnJVR2xCSzI1dU4xRndNMWw0TDA5TlZqWXdiazFCYjBkRFEzRkhVMDAwT1VKQlRVUkJNbU5CVFVkUlEwMUJhREpFT1hKUFNUUTRiQXBqTVVGck0zbG5WRzF5YldGM1ZYUnNPVzlyZDJwVmNWSmtUalZyU21OTWNqTktXamRwZDBoM1ZtdENWMU4zVm01SmEwOUJWVUZKZDFOaUsyZEZLMmxvQ20xRlpVbzNRMFZCTmt0bVNYSmFkMGR6TjJjM1VGaFBTMnR5VkZCWVFXWXpZbUZVU0hKUlJGUkRiV0ZTZUV4aWJqZDVXV0ZFZWxKSUNpMHRMUzB0UlU1RUlFTkZVbFJKUmtsRFFWUkZMUzB0TFMwSyJ9fX19","integratedTime":1792464029,"logIndex":3329865420,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}
|