@migor/agentia 0.10.2 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/CHANGELOG.md +552 -36
  2. package/README.md +1 -1
  3. package/dist/AGENTS.md +95 -25
  4. package/dist/core/limits.d.ts +33 -1
  5. package/dist/core/limits.js +37 -1
  6. package/dist/core/limits.js.map +1 -1
  7. package/dist/core/run.d.ts +2 -2
  8. package/dist/core/timeout.d.ts +5 -5
  9. package/dist/core/timeout.js +5 -5
  10. package/dist/core/tool.d.ts +2 -2
  11. package/dist/core/trace.d.ts +10 -1
  12. package/dist/core/trace.js +10 -1
  13. package/dist/core/trace.js.map +1 -1
  14. package/dist/engine/concurrency.d.ts +1 -1
  15. package/dist/engine/concurrency.js +1 -1
  16. package/dist/engine/errors.d.ts +2 -2
  17. package/dist/engine/errors.js +2 -2
  18. package/dist/engine/loop-result.d.ts +2 -2
  19. package/dist/engine/loop.js +91 -56
  20. package/dist/engine/loop.js.map +1 -1
  21. package/dist/engine/mcp-server-http.js +1 -1
  22. package/dist/engine/mcp-server-http.js.map +1 -1
  23. package/dist/engine/mcp-server-stdio.js +7 -3
  24. package/dist/engine/mcp-server-stdio.js.map +1 -1
  25. package/dist/engine/mcp-server.d.ts +15 -0
  26. package/dist/engine/mcp-server.js +39 -8
  27. package/dist/engine/mcp-server.js.map +1 -1
  28. package/dist/engine/resume-input.d.ts +1 -1
  29. package/dist/engine/resume-input.js +1 -1
  30. package/dist/engine/retry.d.ts +15 -0
  31. package/dist/engine/retry.js +51 -2
  32. package/dist/engine/retry.js.map +1 -1
  33. package/dist/engine/span-scope.d.ts +15 -0
  34. package/dist/engine/span-scope.js +8 -1
  35. package/dist/engine/span-scope.js.map +1 -1
  36. package/dist/engine/spec.d.ts +5 -1
  37. package/dist/engine/spec.js.map +1 -1
  38. package/dist/engine/tracer.d.ts +8 -4
  39. package/dist/engine/tracer.js +24 -17
  40. package/dist/engine/tracer.js.map +1 -1
  41. package/dist/engine/turn.d.ts +2 -2
  42. package/dist/engine/turn.js +19 -4
  43. package/dist/engine/turn.js.map +1 -1
  44. package/dist/engine/types.d.ts +8 -3
  45. package/dist/eval/export.js +2 -2
  46. package/dist/eval/export.js.map +1 -1
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.js +2 -2
  49. package/dist/index.js.map +1 -1
  50. package/dist/integrations/anthropic.d.ts +1 -1
  51. package/dist/integrations/anthropic.js +1 -1
  52. package/dist/integrations/anthropic.js.map +1 -1
  53. package/dist/integrations/file-sink.d.ts +2 -2
  54. package/dist/integrations/file-sink.js +2 -2
  55. package/dist/integrations/mcp-http.js +4 -3
  56. package/dist/integrations/mcp-http.js.map +1 -1
  57. package/dist/integrations/mcp-protocol.d.ts +35 -10
  58. package/dist/integrations/mcp-protocol.js +19 -1
  59. package/dist/integrations/mcp-protocol.js.map +1 -1
  60. package/dist/integrations/mcp-stdio.js +28 -8
  61. package/dist/integrations/mcp-stdio.js.map +1 -1
  62. package/dist/integrations/mcp.d.ts +1 -1
  63. package/dist/integrations/mcp.js +19 -3
  64. package/dist/integrations/mcp.js.map +1 -1
  65. package/dist/integrations/metrics-otlp.d.ts +1 -1
  66. package/dist/integrations/metrics-otlp.js +8 -2
  67. package/dist/integrations/metrics-otlp.js.map +1 -1
  68. package/dist/integrations/metrics-render.js +1 -1
  69. package/dist/integrations/metrics-render.js.map +1 -1
  70. package/dist/integrations/metrics-state.d.ts +2 -2
  71. package/dist/integrations/metrics-state.js +4 -4
  72. package/dist/integrations/metrics-state.js.map +1 -1
  73. package/dist/integrations/metrics.d.ts +2 -2
  74. package/dist/integrations/otlp.d.ts +29 -6
  75. package/dist/integrations/otlp.js +128 -7
  76. package/dist/integrations/otlp.js.map +1 -1
  77. package/dist/integrations/report.d.ts +14 -2
  78. package/dist/integrations/report.js +39 -6
  79. package/dist/integrations/report.js.map +1 -1
  80. package/dist/store/fsStore.js +9 -5
  81. package/dist/store/fsStore.js.map +1 -1
  82. package/dist/store/record.d.ts +2 -2
  83. package/dist/store/record.js +1 -1
  84. package/dist/store/sqliteStore.d.ts +2 -2
  85. package/dist/store/sqliteStore.js +3 -3
  86. package/dist/store/sqliteStore.js.map +1 -1
  87. package/dist/store/store.d.ts +27 -7
  88. package/dist/store/store.js +36 -5
  89. package/dist/store/store.js.map +1 -1
  90. package/dist/toolkit/collect.d.ts +11 -5
  91. package/dist/toolkit/collect.js +10 -4
  92. package/dist/toolkit/collect.js.map +1 -1
  93. package/dist/toolkit/module.js +78 -1
  94. package/dist/toolkit/module.js.map +1 -1
  95. package/dist/toolkit/prompt.d.ts +1 -1
  96. package/dist/toolkit/prompt.js +2 -2
  97. package/dist/toolkit/prompt.js.map +1 -1
  98. package/dist/toolkit/subagent.js +17 -3
  99. package/dist/toolkit/subagent.js.map +1 -1
  100. package/dist/transport/approval-policy.js +1 -1
  101. package/dist/transport/approval-policy.js.map +1 -1
  102. package/dist/transport/approval-supervisor.d.ts +8 -0
  103. package/dist/transport/approval-supervisor.js +23 -3
  104. package/dist/transport/approval-supervisor.js.map +1 -1
  105. package/dist/transport/async.d.ts +3 -0
  106. package/dist/transport/async.js +128 -25
  107. package/dist/transport/async.js.map +1 -1
  108. package/dist/transport/http-endpoints.js +1 -1
  109. package/dist/transport/http-route.js +2 -2
  110. package/dist/transport/http-route.js.map +1 -1
  111. package/dist/transport/http-shapes.d.ts +1 -1
  112. package/dist/transport/http-shapes.js +1 -1
  113. package/dist/transport/resume-scanner.d.ts +7 -0
  114. package/dist/transport/resume-scanner.js +40 -9
  115. package/dist/transport/resume-scanner.js.map +1 -1
  116. package/dist/transport/run-call-options.js +7 -3
  117. package/dist/transport/run-call-options.js.map +1 -1
  118. package/dist/transport/scheduler.js +5 -0
  119. package/dist/transport/scheduler.js.map +1 -1
  120. package/dist/transport/signal-supervisor.d.ts +10 -2
  121. package/dist/transport/signal-supervisor.js +15 -2
  122. package/dist/transport/signal-supervisor.js.map +1 -1
  123. package/dist/transport/wake-policy.d.ts +1 -1
  124. package/package.json +1 -1
package/README.md CHANGED
@@ -42,7 +42,7 @@ npm run dev # = agentia dev:本地 inspector 面板
42
42
  > 只 import app.ts、从不执行入口 —— 写错一侧会让 `npm run dev` 静默读不到 `.env` 而 `npm start` 读得到。
43
43
  > 真实环境变量优先(CI / docker / 命令行永远赢过文件),`loadEnvFile({ override: true })` 才反过来。
44
44
 
45
- > **版本**:`0.10.2`(`@migor/agentia` 与 `@migor/cli` 均已发布到 npm)。`examples/` **刻意**用
45
+ > **版本**:`0.10.3`(`@migor/agentia` 与 `@migor/cli` 均已发布到 npm)。`examples/` **刻意**用
46
46
  > `file:../..` 指向本仓库而不是 npm 版本 —— 跑的是**工作区代码**,理由见
47
47
  > [`examples/README.md`](examples/README.md) 的「依赖说明」。
48
48
 
package/dist/AGENTS.md CHANGED
@@ -248,6 +248,10 @@ agentia export .agentia/traces.jsonl # → 训练数据集 JSONL
248
248
 
249
249
  ## 3. 装饰器 spec 字段速查
250
250
 
251
+ 四个装饰器都只接**实例方法**:私有方法(`#method`)与静态方法(`static`)都在装饰期直接抛错
252
+ —— 能力收集沿实例原型链扫描(调用要绑定 `this`),私有名不可见、静态方法挂在构造函数上,
253
+ 不拦的话能力会静默从菜单里消失。唯一例外是 `@Prompt`(纯文本资产),静态方法同样收集(见下)。
254
+
251
255
  ### `@Tool(spec: ToolSpec)`
252
256
 
253
257
  | 字段 | 说明 |
@@ -321,7 +325,7 @@ agentia export .agentia/traces.jsonl # → 训练数据集 JSONL
321
325
  | `retry` | 缺省模型请求重试策略(可被单次 run 覆盖):缺省**开启**(`DEFAULT_RETRY`:maxAttempts=3、指数退避 + 抖动);`false` 关闭 |
322
326
  | `contextPolicy` | 上下文预算策略(`createBudgetPolicy(...)`);带状态的策略应实现 `forRun()` 按 run 隔离(见 §长上下文) |
323
327
  | `toolSources` | 白名单:只把这些 provider 的能力放进主菜单 |
324
- | `tools` | 直接追加到主菜单的**裸工具**(`AgentTool[]`):给「构造期才知道有哪些工具」的场合(典型:MCP 桥,见 §6)。与能力**同过中间件、同进重名查重**,不是旁路 |
328
+ | `tools` | 直接追加到主菜单的**裸工具**(`AgentTool[]`):给「构造期才知道有哪些工具」的场合(典型:MCP 桥,见 §6)。与能力**同过中间件、同进重名查重**,不是旁路。重名查重覆盖**主菜单 + 子菜单**(@SubAgent/@Skill 的 `tools` 引用展开结果也查,报错指到哪个能力的哪个引用片) |
325
329
  | `middleware` | 能力调用中间件(洋葱链,链序 = 注册顺序) |
326
330
  | `sinks` | trace 出口,run 收尾投递 |
327
331
  | `onTraceEvent` | **增量记账出口的缺省值**:run **进行中**逐笔回调(`span.begin` / `span.end` / `span.event` / `span.attribute` / `span.link`),给等不了收尾的消费者(面板 / SSE / 任务流)。与 `sinks` 是**两条缝**、可同时配;单次 run 给了自己的那个是**叠加**(应用级在前)而非覆盖。⚠️ **不保证送达**(宿主自己的流断了就断了),也不替代 `sinks` |
@@ -366,7 +370,7 @@ agentia export .agentia/traces.jsonl # → 训练数据集 JSONL
366
370
  | `maxToolConcurrency` | 同回合并行工具上限;缺省不限 |
367
371
  | `maxEventChars` | trace 事件正文截断上限(字符):数字 = 入参/出参统一用该上限,`false` = **不截断**;缺省按类型收敛(入参/成功出参 2000、失败出参 1000)。**透传给子 agent/skill 的子循环** —— 同一棵调用树上口径一致。只影响**记账**,回给模型的 tool_result 永远完整 |
368
372
  | `session` | 会话持久化 `{ store, id }`:run 前拼历史、成功收尾追加本轮(见 `SessionStore`) |
369
- | `sessionId` | 会话**引用**(可序列化):单次覆盖后**记进 run 根 `session.id`**(引擎侧读它,见 `loop.ts` 的属性写入)。⚠️ 直接 `app.run` 时它**不注入历史** —— 注入要上一行的 `session: { store, id }`;「`sessionId` + runner 的 `sessionStore`」是**异步宿主**那条路(任务里只落 id,store 实例不可序列化) |
373
+ | `sessionId` | 会话**引用**(可序列化):**只被异步宿主消费** —— 「`sessionId` + runner 的 `sessionStore`」那条路(任务里只落 id,store 实例不可序列化;runner 没配 `sessionStore` 而任务带了它 ⇒ submit 当场报错)。⚠️ 直接 `app.run` 传它**不生效**(不建 `session.id`、不接历史),入口会 `console.warn` 一次指出改用上一行的 `session: { store, id }`;只要 run 根的 `session.id` 标记而不要历史,直连 `executeRun` / `runAgent` 的引擎级 `sessionId`(见 §6.4「提示词版本化与会话标记」) |
370
374
  | `memory` | 跨 run 记忆 `{ store, keys }`:run 前水合进 blackboard(用户种子优先)、收尾写回;与 `session` 正交(见 `MemoryStore`) |
371
375
  | `beforeFlush` | `(trace, result) => void \| Promise<void>`:**sinks 冲刷之前**的最后一笔(run 正常收尾后调一次,抛错被吞)。给「**拿到结果才判得出**的结论」用的缝 —— 典型是 `defineEval` 的 score:等 `app.run` 返回再 `attachScore`,`metricsSink` 早在导出那一刻聚完账,分数就永远进不了指标。读 trace 就够的判断不必用它,写进 sinks 里即可(见 §6 判官配方) |
372
376
  | `approvals` | HITL 审批决定(`Record<tool_use_id, ApprovalDecision>`):恢复 `suspended` 的 run 时传入(异步宿主会自动带,见 §6.6「人工审批」);手工续跑「assistant 结尾带 tool_use」的消息历史时也可直接给 |
@@ -561,6 +565,12 @@ const app = await createApp({ ... });
561
565
  ⚠️ 框架**刻意不替你调**:`drain()` 不关 store(同一个 store 可能被调度器或另一个宿主共用,
562
566
  关掉它是**宿主的**生命周期决定)。压实频率建议低频(如 cron 每小时一次)。
563
567
 
568
+ **副本契约(自定义 store 必读)**:`save` 存**副本**、`get` / `byIdempotency` / `list` 交**副本** ——
569
+ 内存推进只许由 `save` 驱动。内建实现经 `cloneTaskRecord` 坐实(深拷纯数据;`AbortSignal` /
570
+ 函数等进程内对象按引用保留,不是序列化往返);sqlite / redis 走序列化天然满足。自实现若交
571
+ 活引用,「改 rec → `await save`」的纪律会让未落库的中间态对其他读者可见,save 失败时
572
+ 污染留在库里(approve 重试撞 409、任务搁死到重启那一类)。
573
+
564
574
  #### gRPC 宿主(第 4 个宿主,**框架不内置**)
565
575
 
566
576
  gRPC 不是「另一种 broker」,它与 HTTP 是同一档的东西:**触发宿主**。所以正确形状与 HTTP 宿主
@@ -579,7 +589,7 @@ MCP stdio 只用标准库(`spawn` + 全局 `fetch`)⇒ **内置不新增一
579
589
  gRPC 必须引第三方客户端(`@grpc/grpc-js`)⇒ 落在「可选能力一律 duck-typed / peer」那一侧。
580
590
  「零运行时依赖」是公开承诺(`package.json` 三个依赖字段全空),所以它只能以**配方 + 示例**存在。
581
591
  真有第二个使用方要同一份逻辑时再考虑独立包,且粒度是**一个第三方客户端一个包** ——
582
- 不是把所有集成塞进一个「服务包」(理由见 spec §10 2026-09-18 ⑪)。
592
+ 不是把所有集成塞进一个「服务包」(理由见 spec §10 2026-09-18 ref-host-integration-recipe)。
583
593
 
584
594
  **宿主必须自己接上的四处**(漏掉任何一条都**不会报错**,只会静默丢东西):
585
595
 
@@ -728,7 +738,7 @@ process.on('SIGTERM', async () => {
728
738
  | `mapWithConcurrency` | 有界并发 map(结果保序);`maxToolConcurrency` 的底座,也可自用 |
729
739
 
730
740
  - **取消**:`app.run(messages, { signal })` 传 `AbortSignal` —— 框架会 abort 在飞请求(内置 Anthropic / OpenAI 适配器都转发 `signal`),run 以 `stopReason='aborted'` 收尾(算失败)。`createHttpHandler` 已内置「客户端断开即中止」;`AsyncRunner.runTimeoutMs` 到点同样是**真中止**(构造期校验:必须 ≥ 0 的有限数、且不超过 `2^31-1`ms ≈ 24.86 天 —— NaN/Infinity 与超上限的值都会被 `setTimeout` 钳到 1ms,等于每个任务立即超时,故直接抛错;要「不限」传 0 或不设)。
731
- - **重试**:缺省自动重试可重试失败(429 / 5xx / 连接失败),指数退避 + 抖动。`retry: false` 关闭,或 `retry: { maxAttempts, baseDelayMs, maxDelayMs, jitter, onRetry }` 调参。**只在本次尝试尚未产出任何文本时重试**(已吐出的字无法撤回)。⚠️ 与底层 client 的**内置重试**叠加 —— **两条内置适配器口径一致**(`createAnthropicClient` / `createOpenAIClient` 都有 `maxRetries`,缺省 2,重试同一状态码集合 408/409/429/5xx)—— 建议二选一调(这里 `maxAttempts: 1`,或 `<适配器>({ maxRetries: 0 })`)。`maxRetries` 在**构造期**校验:只收非负安全整数(`0` = 不重试),NaN / ±Infinity / 负数 / 小数一律抛 `TypeError` —— 判定是 `attempt >= maxRetries`,NaN 恒假、Infinity 永不达到,两者都等于**无限重试**(且静默)。
741
+ - **重试**:缺省自动重试可重试失败(429 / 5xx / 连接失败),指数退避 + 抖动。`retry: false` 关闭,或 `retry: { maxAttempts, baseDelayMs, maxDelayMs, jitter, onRetry }` 调参。**只在本次尝试尚未产出任何文本时重试**(已吐出的字无法撤回)。⚠️ 与底层 client 的**内置重试**叠加 —— **两条内置适配器口径一致**(`createAnthropicClient` / `createOpenAIClient` 都有 `maxRetries`,缺省 2,重试同一状态码集合 408/409/429/5xx)—— 建议二选一调(这里 `maxAttempts: 1`,或 `<适配器>({ maxRetries: 0 })`)。`maxRetries` 在**构造期**校验:只收非负安全整数(`0` = 不重试),NaN / ±Infinity / 负数 / 小数一律抛 `TypeError` —— 判定是 `attempt >= maxRetries`,NaN 恒假、Infinity 永不达到,两者都等于**无限重试**(且静默)。引擎层 `retry` 的数值旋钮同款纪律:`maxAttempts` 只收非负安全整数(`0` = 关闭重试),`baseDelayMs` / `maxDelayMs` 只收 0 ~ 2^31-1ms 的有限数(`0` = 不退避 / 封顶为零),`jitter` 只收 0~1 —— 坏值在 run 入口抛 `TypeError`(`maxAttempts: NaN` 曾静默关闭重试、`baseDelayMs: NaN` 曾被误报成「用户取消」)。
732
742
  - **流式**:`POST /run` 带 `Accept: text/event-stream` → SSE 逐帧下发(`text.delta` / `run.end` / `error`,外加一族 **`trace.event`** —— 增量记账事件,body 即 `TraceRecordEvent`,用它做实时面板;不认识这一族的老客户端行为零变化);不带该头仍回一元 JSON。
733
743
  - **工具超时 / 并发闸门**:`toolTimeoutMs` 超时**不杀 run**(该条 tool_result 记 `is_error`,模型可换路);`maxToolConcurrency` 给同回合的并行工具设上限(默认全并行)。⚠️ 超时 = **放弃等待**:`AgentTool.run` 没有 signal 参数,**副作用可能已发生**;但引擎放弃等待时会 abort `ToolRunContext.abandoned` —— 想真停的工具监听它自行收尾(框架自带的 @SubAgent / @Skill 已这么做:超时即中止子循环,capability span 以 error 收尾)。**超时判定只有一个裁判**:`toolTimeoutMs` 是唯一判据 —— 工具自带的超时(如 MCP 桥的 `timeoutMs`)在设了本项时**不参与**判定;反过来说,工具自判的超时(抛 `code='timeout'` 的错误)与引擎判的记**同一类账**(`errorKind='timeout'`),并同样回 `is_error`。
734
744
 
@@ -820,7 +830,7 @@ trace 出去之后能干什么:指标、调用树面板、调优报告、生
820
830
  | `TraceRecorder` | 内存 recorder(一次 run 一个);`addLink(spanId, { traceId, spanId? })` 记一条跨 trace 链路(见 §6「跨进程关联」) |
821
831
  | `parseTraceparent` | 解析 W3C `traceparent` 头 → `{ traceId, spanId? }`;**非法 / 缺头一律返回 `undefined`**(不抛、不打 400)—— 结果直接交给 `traceContext` 选项,见 §6「跨进程关联」 |
822
832
  | `createOtlpExporter` | OTLP/JSON 导出,零依赖;选项见下面「`OtlpExporterOptions`」表 |
823
- | `jsonlTraceSink` | JSONL 文件 sink:`jsonlTraceSink({ path })` → `TraceSink`,一行一条裸 Trace 追加落盘(父目录自动创建、追加不覆盖)—— **`agentia report` / `diff` / `harvest` 的输入格式**,见 §6「调优报告」 |
833
+ | `jsonlTraceSink` | JSONL 文件 sink:`jsonlTraceSink({ path })` → `TraceSink`,一行一条裸 Trace 追加落盘(父目录自动创建、追加不覆盖)—— **`agentia report` / `diff` / `harvest` / `export` 的输入格式**,见 §6「调优报告」 |
824
834
  | `TraceRecordEvent` | **增量记账事件**(`onTraceEvent` 的回调参数):`span.begin` / `span.end` / `span.event` / `span.attribute` / `span.link`,每条带单调 `seq`。载荷是**增量 + 此刻的拷贝**(`span.begin` 只给初始形状,属性/事件/链路各走自己的类型);按 `seq` 升序折回必须**逐字等于**收尾时的 trace |
825
835
  | `metricsSink` | 指标累加器(Prometheus 文本 / OTLP metrics),满足 `TraceSink` 即接入 —— 见 §6「指标」 |
826
836
  | `buildRunReport` | 从一条 trace 生成**调优报告**(能力/模型的耗时、token、成本、错误率排行)—— 见 §6「调优报告」 |
@@ -836,6 +846,7 @@ trace 出去之后能干什么:指标、调用树面板、调优报告、生
836
846
  | `serviceName` | OTLP resource 的 `service.name`,缺省 `agentia` |
837
847
  | `timeoutMs` | 单次导出请求超时(毫秒,缺省 10000,非正数 = 不限)——裸 `fetch` 没有超时,collector 半开连接会让 run 收尾**永久挂起**;超时按导出失败处理 |
838
848
  | `onExportError` | 导出失败回调:给了它,**所有**失败(非 2xx / 超时 / **HTTP 200 但 collector 报部分接收**)都交给它、不再向 `TraceSink` 调用方抛;不给则维持既有行为(抛出,由 `flushSinks` 吞掉并落 `console.warn` —— 观测失败不击穿业务)。存在理由:`TraceSink` 的失败缺省只有一条泛化的 warn,「导出其实少了一半数据」这类**带分类的**消息得有人能收到 |
849
+ | `projectToolSpans` | 把 span 上按 `tool_use_id` 配对的 `tool.input` / `tool.output` 事件**投影**成 `execute_tool` child span,缺省 **false**(关闭时导出产物与既往一致):name 为 `execute_tool <工具名>`、带 `gen_ai.operation.name=execute_tool` + `gen_ai.tool.name`,start/end 取两事件的真实记账时刻;`ok:false` → status Error + `error.type=errorKind`;孤儿 input(`traceLimits.maxEvents` 截断可造出)→ **不写 `endTimeUnixNano` / status** 并带 `agentia.projection.orphan: true`(不编零时长)。原事件保留在父 span 上,engine 记账点不动 |
839
850
 
840
851
  导出器的两条线缆口径(都有守卫钉着,别按直觉改):
841
852
 
@@ -853,11 +864,14 @@ trace 出去之后能干什么:指标、调用树面板、调优报告、生
853
864
  (`gen_ai.evaluation.name` / `.score.value`,`source` / `comment` 走自有 `agentia.score.*` 键)→
854
865
  `metricsSink` 聚合成 `agentia_score` 指标族(见 §6「指标」)。eval / 在线评估怎么用见 §6「evals」与「在线评估采样」。
855
866
 
856
- **OTLP 的 `gen_ai.*` 对齐**(对齐 OTel GenAI semconv **v1.37**,**additive** —— 只追加 `gen_ai.*` 键,既有 `usage.*` 等键一律保留):
867
+ **OTLP 的 `gen_ai.*` 对齐**(对齐 `open-telemetry/semantic-conventions-genai` @ `6fd0d763`(2026-10-09)—— GenAI 约定自 v1.42(2026-06-12)起移出语义约定主线、该独立仓**无 tag、未版本化**,所以基准钉 commit,**additive** —— 只追加 `gen_ai.*` 键,既有 `usage.*` 等键一律保留):
857
868
  run 根 → `gen_ai.operation.name=invoke_agent` + `gen_ai.agent.name`(attributes 有 `session.id` 时另发 `gen_ai.conversation.id`);
858
869
  `llm.turn` → `gen_ai.operation.name=chat` + `gen_ai.request.model` + `gen_ai.usage.input_tokens` / `output_tokens`;
870
+ 缓存读数 > 0 时另发 `gen_ai.usage.cache_read.input_tokens` / `gen_ai.usage.cache_write.input_tokens`(上游口径「when applicable」:0 = 没走缓存 ⇒ 不留键,与自有 `usage.cache*` 键双发不替换);
871
+ 父 span 上有早于本回合开始的 `context.budget` 事件 ⇒ `gen_ai.conversation.compacted: true`(上游口径:只在能可靠判定时置真,**不设 false**);
859
872
  capability span 按 **attributes** 分(`subagent` / `skill`;span 的 `name` 是**裸能力名**):`subagent` → `invoke_agent` + `gen_ai.agent.name`,`skill` → `execute_tool` + `gen_ai.tool.name`;
860
- `score` 事件 → `gen_ai.evaluation.result`。映射集中在 `createOtlpExporter` 一处,下游(Langfuse / Grafana / Datadog)按 1.37+ 识别这批键做 GenAI 专项视图。
873
+ `score` 事件 → `gen_ai.evaluation.result`。映射集中在 `createOtlpExporter` 一处。
874
+ 普通 @Tool 只有 `tool.input` / `tool.output` 事件、没有 span(刻意口径);要上游六家框架同款的 `execute_tool` span,开 `projectToolSpans`(导出侧投影,见上表)。
861
875
  从 Tempo / Grafana 按 run 找回 trace 的做法(id 的 hex 投影、run 根按 `invoke_agent` 过滤)见 `docs/observability.md` §2.7。
862
876
 
863
877
  > **生产落地**(按 runId 落库检索 / 日志关联 / 采样 / 脱敏)见 `docs/observability.md` ——
@@ -871,11 +885,12 @@ capability span 按 **attributes** 分(`subagent` / `skill`;span 的 `name`
871
885
  把它接回上游 —— 触发它的那个 span(网关请求 / 队列消息 / 另一个服务)记在 run 根 span 的 `links` 上,
872
886
  OTLP 导出时就是标准的 **span links**,后端能把因果边画出来。
873
887
 
874
- **入站两种给法**:
888
+ **入站三种给法**:
875
889
 
876
890
  | 场景 | 写法 |
877
891
  |---|---|
878
892
  | HTTP 宿主(网关 / 消费者通过 HTTP 打过来) | 请求头 `traceparent: 00-<32位trace>-<16位span>-01`(W3C)—— `createHttpHandler` 自动解析,`POST /run` 与 `POST /tasks` 都认;**畸形头静默当作没有上游**,不会打 400 |
893
+ | MCP 反向桥(Claude Code / 别的 agent 框架经 `tools/call` 调你的工具) | 请求 `params._meta.traceparent`(**SEP-414** 定的载体:`_meta` 里的**裸键**,不加前缀)—— `createMcpServer` 自动解析,合法即记成该次 trace run 根的一条 `links`;**缺失 / 畸形静默当作没有上游**(不造空上下文、不影响调用成败) |
879
894
  | 程序内直接调 `app.run` / `runner.submit` | `options.traceContext: { traceId, spanId? }` —— 也可写 `parseTraceparent(头值)` 自己解析 |
880
895
 
881
896
  **队列消费者(Kafka / RabbitMQ / SQS)的形态**:拿消息键当 `idempotencyKey`,把消息里带的
@@ -926,7 +941,11 @@ class OrderTools {
926
941
 
927
942
  - **粒度**:普通工具与 `@Prompt` **不建 span**,它们的「当前 span」就是发起它们的那次 `llm.turn`;
928
943
  `@Skill` / `@SubAgent` 的方法体内则是它自己的 `capability` span。内层覆盖外层。
929
- - **不自动注入**:框架不创建出站请求,注入那一行是你自己的(同上 `fetch`;gRPC 宿主塞进 metadata)。
944
+ - **不自动注入**(一个例外):框架不替你创建出站请求,注入那一行是你自己的
945
+ (同上 `fetch`;gRPC 宿主塞进 metadata)。例外是 **MCP 正向桥**:`tools/call` 的请求由桥自己发,
946
+ 所以在 run 内经 `mcpTools` 调 MCP 工具时,桥自动把当前 span 的 `traceparent` 放进
947
+ `params._meta`(SEP-414 裸键,**不进 `arguments`**;不在 run 内则不带;对端不认 `_meta`
948
+ 静默忽略 —— 这是观测,不是协议要求)。
930
949
  - 与入站同一个格式、同一份 id 投影:`currentTraceparent()` 的输出喂回 `parseTraceparent()` 逐字还原,
931
950
  下游 OTLP 里看到的 span id 与本地 collector 里的是**同一个数**(见 §7 已知边界)。
932
951
 
@@ -976,7 +995,7 @@ class OrderTools {
976
995
  | `intervalMs` | OTLP 导出间隔(毫秒,缺省 60000);`0` = 每次 run 收尾立即导出。定时器已 `unref()`,不阻止进程退出 |
977
996
  | `resourceAttributes` / `serviceName` | OTLP resource 属性(`service.name` 缺省 `agentia`) |
978
997
  | `timeoutMs` | OTLP 单次导出请求超时(毫秒,缺省 10000,非正数 = 不限)——collector 半开连接时兜底,`intervalMs: 0` 模式不被挂死;超时按导出失败处理 |
979
- | `onExportError` | 导出失败回调(缺省吞掉 —— 观测失败不得击穿业务) |
998
+ | `onExportError` | 导出失败回调(缺省每次失败落一条 `console.warn` —— 观测失败不得击穿业务,但不零信号) |
980
999
  | `windowSize` | 时长分位保留的样本数(环形窗口,缺省 1024,**run / 能力 / 模型各自独立**);非正数抛错 |
981
1000
  | `prefix` | 指标名前缀,缺省 `agentia_` |
982
1001
  | `labelMode` | 能力标签粒度:`'capability'`(缺省,`tool:search` 这种)/ `'kind'`(只按类型,基数极小)/ `'none'`(不产出能力指标) |
@@ -1048,8 +1067,8 @@ class OrderTools {
1048
1067
 
1049
1068
  | API | 说明 |
1050
1069
  |---|---|
1051
- | `buildRunReport(trace)` | 一条 trace → `RunReport`:能力排行(按总耗时降序)、模型归因、未定价模型清单 |
1052
- | `mergeRunReports(reports)` | 跨 run 汇总(**分位只在多条 run 上才有统计意义**) |
1070
+ | `buildRunReport(trace)` | 一条 trace → `RunReport`:能力排行(按总耗时降序;嵌套能力的 usage **只计顶层行** —— 内层行的 `tokens`/`costUsd` 为 `null`,各行可加总,与 `agentia report` 同口径)、模型归因、未定价模型清单 |
1071
+ | `mergeRunReports(reports)` | 跨 run 汇总(**分位只在多条 run 上才有统计意义**);按 `traceId` 去重、同一 traceId 只留最后一份(append-only 落盘的同一棵 trace 会被写多次,与 `agentia report` 同口径) |
1053
1072
  | `renderRunReport(report)` | 人类可读的纯文本表(CLI / 日志用) |
1054
1073
 
1055
1074
  ```ts
@@ -1065,29 +1084,47 @@ console.log(renderRunReport(report));
1065
1084
  CLI 侧有薄壳:`agentia report <trace.jsonl>` —— 每行一个 JSON(裸 Trace,或含 `result.trace` /
1066
1085
  `trace` 的 TaskRecord,如 `FileTaskStore` 的导出),跨行按能力合并后打印排行。
1067
1086
  加 `--json` 得到机器可读输出:stdout 只有一个 JSON 文档(`{ file, runs, failed, skippedLines,
1068
- failures, capabilities, totals }`)、没有人类装饰,适合脚本与 CI 断言;出错仍走 stderr
1087
+ failures, capabilities, sessions, totals }`)、没有人类装饰,适合脚本与 CI 断言;出错仍走 stderr
1069
1088
  (`错误:…`)并把退出码置 1、stdout 保持为空 —— 脚本据此区分「有结果」与「没跑成」。
1070
1089
 
1090
+ **会话 / 任务维度(`sessions[]`)**:能力排行之外另打一张按**分组键**归组的表 —— 键取 run 根
1091
+ span 的 `session.id`(宿主传 `session: { store, id }` 才会写,见 §6.4「提示词版本化与会话标记」),没有就退到记录
1092
+ 里的 `taskId`(`FileTaskStore` / `SqliteTaskStore` 的导出),再没有落 `(无会话)` 桶。
1093
+ 每组给 `runs / ok / fail / total / cost / cost-ok` 六列。三条口径值得记住:
1094
+ **成功率一定带分母**(小组上只报百分比是噪声,所以 `runs` 与 `ok` 都单独出列);
1095
+ **成功数为 0 时 `cost-ok` 是 `-`(JSON 里 `null`),不是 0** —— 「除不了」不等于「不花钱」;
1096
+ **挂起计入 `ok`** —— 成败判据与引擎同一条(`trace.status !== 'error'`),而引擎的口径是
1097
+ 「挂起不是失败」(取消才是 `error`)⇒ 10 条 run 全挂在审批上会报「成功率 100%」。
1098
+ 这是刻意的取舍,读数时把「等审批」与「跑成了」分开看。
1099
+ 成本取该 run 的 `totalUsage.costEstimate`(= 各 `llm.turn` 之和,**不含** capability 聚合 ⇒
1100
+ `@SubAgent` 里套 `@Skill` 时不会把同一批 token 数两遍)。
1101
+ 能力排行的 tokens / cost 列同一条纪律:**只认顶层 capability**(没有 capability 祖先的)——
1102
+ capability span 的 usage 是其子孙 `llm.turn` 的聚合,嵌套时内层行的 tokens / cost 显示为 `-`
1103
+ (那批 token 已在外层行里 ⇒ 各行的 tokens / cost 可加总、不重复计数);内层行的
1104
+ calls / err / 耗时照记(那是它自己这次调用的真账)。
1105
+
1071
1106
  > ⚠️ **单条 run 内样本常 < 5,分位没有意义** —— 所以报告以 `total` / `max` 为主;
1072
1107
  > 要看分位请用 `mergeRunReports` 汇总多条,或用 `metricsSink` 的直方图。
1073
1108
  > CLI 报告的聚合口径与 `agentia dev` 面板的能力排行同源(同一份 `@migor/trace-view` 实现)。
1074
1109
 
1075
1110
  那个 jsonl 从哪来 —— 框架内置了文件 sink,一行接入(零依赖)。它产出的格式就是
1076
- **CLI 三件套的输入**:`agentia report` / `agentia diff` / `agentia harvest` 都吃这个文件
1077
- (一行一个 JSON,裸 Trace):
1111
+ **CLI 四件套的输入**:`agentia report` / `agentia diff` / `agentia harvest` / `agentia export`
1112
+ 都吃这个文件(一行一个 JSON,裸 Trace):
1078
1113
 
1079
1114
  ```ts
1080
1115
  import { createApp, jsonlTraceSink } from '@migor/agentia';
1081
1116
 
1082
1117
  const app = await createApp({ /* … */ sinks: [jsonlTraceSink({ path: 'trace.jsonl' })] });
1083
- // 之后:agentia report trace.jsonl / agentia diff a.jsonl b.jsonl / agentia harvest trace.jsonl
1118
+ // 之后:agentia report trace.jsonl / agentia diff a.jsonl b.jsonl / agentia harvest trace.jsonl / agentia export trace.jsonl
1084
1119
  ```
1085
1120
 
1086
1121
  父目录不存在会自动递归创建;**追加不覆盖**(多跑几次就累积多行);写失败抛给 `flushSinks`
1087
1122
  吞掉并落 `console.warn`(观测失败不击穿业务,但不再零信号)。
1088
1123
 
1089
1124
  异步宿主更省事:把 `FileTaskStore` 的落盘文件直接喂给它 —— `TaskRecord` 里带 `result.trace`,
1090
- `report` 认这种形态,不用另写 sink。
1125
+ `report` 认这种形态,不用另写 sink。⚠️ 它是 **append-only**(每次 save 追加一行):审批流里
1126
+ 同一棵挂起段 trace 会出现多行(挂起 / approve / 接管各 save 一次)。`report` 按 **`traceId`
1127
+ 去重、只留最后一行**(append-only 里后面的是新状态),runs / 成功率 / 成本不会按行数翻倍。
1091
1128
 
1092
1129
  #### 生效配置快照(「这条 run 用了哪套旋钮」)
1093
1130
 
@@ -1107,9 +1144,36 @@ const app = await createApp({ /* … */ sinks: [jsonlTraceSink({ path: 'trace.js
1107
1144
  - 单次 `app.run(..., { system })` 覆盖时,版本**跟当次那个 `SystemPrompt` 走**;`system` 传已拼好的 `SystemParam` 则无版本可记(不写空串冒充实有版本)。
1108
1145
  - 直连 `runAgent` / `executeRun` 时可用引擎级选项 `systemVersion` 显式给。
1109
1146
  - **`@Prompt` 资产版本**:`@Prompt({ version })` 声明后,装配期把菜单里全部带版本的 @Prompt 收集成 `{ 能力名: 版本 }` 表(与主菜单同一条收集路径,`toolSources` 收窄同样生效),每次 run 落 run 根 span 的 `prompts.versions` attribute(`name@ver` 逗号拼接、按名排序、空表不记)—— 质量回归能定位到具体资产版本。直连 `runAgent` 时用引擎级选项 `promptVersions` 显式给。
1110
- - **会话标识**:`app.run(..., { session })` / `executeRun` 给了 `session` 时,session id 自动落 run 根 span 的 `session.id` attribute(OTLP 导出时映射 `gen_ai.conversation.id`)—— 多轮对话的 run 由此可按会话聚合,不用手填。直连 `runAgent` 时用引擎级选项 `sessionId` 显式给。
1147
+ - **会话标识**:`app.run(..., { session })` / `executeRun` 给了 `session` 时,session id 自动落 run 根 span 的 `session.id` attribute(OTLP 导出时映射 `gen_ai.conversation.id`)—— 多轮对话的 run 由此可按会话聚合,不用手填。直连 `runAgent` / `executeRun` 时用引擎级选项 `sessionId` 显式给。⚠️ **别把 `sessionId` 传给 `app.run`**:那个字段是异步宿主的可序列化会话引用(见 §4 选项表),`app.run` 不消费它 —— 直传会 `console.warn` 一次且不生效。
1111
1148
  - **菜单签名**:每次 run 落 run 根 span 的 `tools.names`(装配后菜单的名字、按名排序、超长截断带 `…(+N)`)与 `tools.menuHash`(12 位摘要,材料 = 排序后的「名字 + **输入 schema**」规范序列化)—— 与 `prompts.versions` 同动机:质量回归能回答「这两段 run 跑在同一个菜单上吗」。口径:与菜单顺序、schema 键序无关;**`description` 不参与**(润色文案不算菜单变化,代价是「只改描述」看不见 —— 有意)。给了 `tools` 就自动记,无需开关。
1112
- - **菜单漂移(续跑时菜单变了)**:挂起段之后**续跑**时,未决 tool_use 引用的工具若已不在当前菜单(删了 / 改名了),框架记**三处信号**:`menu.drift` 事件(含 `{ missing, tool_use_ids, menu_size }`;时间线与 `GET /tasks/:id/stream` 都看得到)、父 span 的 `menu.drift` attribute(如 `missing:danger`)、一条 `console.warn`。⚠️ **run 照常收尾**(不判失败):那些 tool_use 会以 `unknown tool` 回给模型 —— 为什么不做严格模式见 spec §10 2026-09-27 ⑧。注意这与「回合内模型编了个不存在的工具名」不同:那个是幻觉,走既有 `unknown_tool` 路径、**不**报漂移。
1149
+ - **菜单漂移(续跑时菜单变了)**:挂起段之后**续跑**时,未决 tool_use 引用的工具若已不在当前菜单(删了 / 改名了),框架记**三处信号**:`menu.drift` 事件(含 `{ missing, tool_use_ids, menu_size }`;时间线与 `GET /tasks/:id/stream` 都看得到)、父 span 的 `menu.drift` attribute(如 `missing:danger`)、一条 `console.warn`。⚠️ **run 照常收尾**(不判失败):那些 tool_use 会以 `unknown tool` 回给模型 —— 为什么不做严格模式见 spec §10 2026-09-27 ref-menu-drift-signals。注意这与「回合内模型编了个不存在的工具名」不同:那个是幻觉,走既有 `unknown_tool` 路径、**不**报漂移。
1150
+
1151
+ #### 交接与护栏(`agentia.handoff.*` / `agentia.guardrail.*`)
1152
+
1153
+ **交接**(agent → agent)与**护栏**(审批)在这个框架里都不是 span:前者就是一条 `capability`
1154
+ span 本身(`attributes.subagent`),后者**只是事件**(`approval.requested` / `approval.decided`)。
1155
+ 这两样对外部 OTLP 消费者都等于「要解析才看得见」⇒ 各补一个 additive 属性当入口:
1156
+
1157
+ | 键 | 值 | 写在哪 | 何时 |
1158
+ |---|---|---|---|
1159
+ | `agentia.handoff.from` | **调用方** agent 名 | 被调 `@SubAgent` 的 capability span | 该 span 由另一个 agent 的回合发起时 |
1160
+ | `agentia.handoff.to` | **被调** agent 名 | 同上 | 同上 |
1161
+ | `agentia.guardrail.name` | 待决的**首个**工具名 | 与 `approval.requested` **同一个 span**:首段是发起回合的 `llm.turn`;**续跑段再挂起时是 run 根**(续跑入口把 run 根 id 当 turnId,本段没有对应 `llm.turn`) | 记 `approval.requested` 时 |
1162
+ | `agentia.guardrail.triggered` | `true` | 同上 | 同上 |
1163
+
1164
+ - 名字从哪来:run 根用 `runName`(默认 `agent.run`,与 OTLP 的 `gen_ai.agent.name` 同源),
1165
+ 子 agent 用它注册的 `name`。嵌套交接会**逐层换名**(内层 `from` 是外层子 agent,不是应用)。
1166
+ - ⚠️ **刻意不做**:不把审批**升级成 span**。它现在是事件、与「普通 `@Tool` 只发
1167
+ `tool.input` / `tool.output`」同形;升级会动引擎记账点,且下游已能按事件消费。
1168
+ - ⚠️ 两处**只发一半**是口径不是遗漏:`guardrail.*` **只在触发时发**,不设 `false`
1169
+ (与 `gen_ai.conversation.compacted` 同款);`handoff.*` 拿不到调用方身份时(宿主手搓
1170
+ `recorder` + `ctx` 直调 `subagentToTool`)**两个键都不发** —— 编不出来就不编。
1171
+ - **视图**:`@migor/trace-view` 的 summary(`agentia report` 与 `agentia dev` 面板同源)把
1172
+ `approval.decided` 聚成 `guardrail:<工具名>` 一行 —— `calls` = 走到决定的次数、
1173
+ `err` = **被拒**次数(护栏真挡下的)、`total` / `max` = 等审批时长(事件的 `waitedMs`;
1174
+ 宿主没回填 `requestedAt` 时记 0,**不编造**)。聚合**不限 span kind**(首段的决定记在
1175
+ `llm.turn`、恢复段的记在 run 根,两处都聚)。⚠️ 只有 `approval.requested` 而始终没恢复的
1176
+ 挂起**不产出行**:它没有结论也没有时长。
1113
1177
 
1114
1178
  ### 6.5 集成
1115
1179
 
@@ -1182,7 +1246,7 @@ class MyMemoryStore implements MemoryStore {
1182
1246
  | API | 说明 |
1183
1247
  |---|---|
1184
1248
  | `mcpTools` | 把 MCP server 的 `tools/list` 映射成框架 `AgentTool[]`(进 `createApp({ tools })`) |
1185
- | `McpClientLike` | 最小结构面:`listTools()` + `callTool(name, args)`;框架**不 import** MCP SDK |
1249
+ | `McpClientLike` | 最小结构面:`listTools()` + `callTool(name, args, opts?)`(`opts` 带 `abandoned` 与 SEP-414 的 `traceparent`,均可选);框架**不 import** MCP SDK |
1186
1250
  | `createStdioMcpConnector` | **出厂 stdio 连接器**:spawn 一个 MCP server 子进程,走换行分隔 JSON-RPC(只用 `node:child_process`) |
1187
1251
  | `createStreamableHttpMcpConnector` | **出厂 StreamableHTTP 连接器**:一个 endpoint POST JSON-RPC;`application/json` 与 `text/event-stream` 两种响应都接(只用全局 `fetch`) |
1188
1252
  | `McpConnector` | 两个连接器的公共面 = `McpClientLike` + `close()`。自己写传输时实现 `McpClientLike` 即可,不必碰它 |
@@ -1196,6 +1260,7 @@ class MyMemoryStore implements MemoryStore {
1196
1260
  - **超时**:**只有一个裁判**。引擎设了 `toolTimeoutMs` 时,桥的 `timeoutMs`(缺省 `MCP_DEFAULT_TIMEOUT_MS` = 60000)**不参与判定**;它只在「桥脱离引擎单用」或「引擎没设 `toolTimeoutMs`」时作为兜底。两条路径共用同一判定(`core/timeout.ts`:**看实测耗时,不看竞速**),超时都记 `errorKind='timeout'` + `is_error` 回模型、**不杀 run**。你自己写的工具要报超时,抛一个 `code === 'timeout'` 的错误即可(不必 import 框架的类)。
1197
1261
  - **连接器出厂自带,但仍只给缝**:两个连接器只用标准库(`node:child_process` + 全局 `fetch`)⇒ **不新增任何第三方依赖**。要接官方 SDK / 远程 server / 自研传输,实现 `McpClientLike` 两个方法即可(同 `RedisLike` 的形状)。
1198
1262
  - **连接器替你兜住三件只有它能做的事**:① spawn 失败(命令不存在 → `ENOENT`)是**异步 `'error'` 事件**,不接住会把宿主进程带崩;② stdout 的分帧 —— 一条报文可能跨多个 chunk;③ **协议层 `isError: true` 转成抛错**。
1263
+ - **trace 上下文(SEP-414)**:在 run 内调用时,桥把当前 span 的 W3C `traceparent` 放进 `tools/call` 的 `params._meta`(**裸键、不加前缀**;两个出厂连接器都做),认出它的 server 就能把这次调用链回你的 trace;不在 run 内(桥脱离引擎单用)则不带 —— 不造空上下文。自己实现 `McpClientLike` 时读 `callTool` 第三参的 `traceparent` 即可对齐(不读也兼容,只是链路断在你的传输上)。
1199
1264
  - **连接器的 `timeoutMs` 只管装配期**(握手 + `tools/list`):那两步**没有任何别的裁判**,server 卡住会让 `createApp` 永久挂起;`callTool` 的裁判仍是引擎 / 桥(一次调用只有一个)。
1200
1265
 
1201
1266
  ```ts
@@ -1262,9 +1327,11 @@ server —— Claude Code / Cursor / 任何 MCP 宿主都能直接调你的 `@To
1262
1327
 
1263
1328
  - **两个传输都只用标准库**:stdio = stdin/stdout 换行分隔 JSON-RPC(日志只去 stderr,stdout 是协议面);http = StreamableHTTP(POST 收报文、应答 `application/json`,简单应答不上 SSE;GET → 405、DELETE → 200)。
1264
1329
  - **trace 叙事不破**:每次 `tools/call` 造一棵 trace —— run 根 `mcp.tools/call` 下挂一个 capability span(name = 工具名),记 `tool.input` / `tool.output` 事件(与引擎同账目形状),收尾投递 `sinks`;`initialize` / `tools/list` 不建 trace。capability span 无 skill/subagent 属性 ⇒ metrics 里以 `capability:<工具名>` 标签进能力指标。
1330
+ - **入站 trace 上下文(SEP-414)**:`tools/call` 的 `params._meta.traceparent` 合法时记成那棵 trace run 根的一条 `links`(与 HTTP 宿主认 `traceparent` 头同款缝合);缺失 / 畸形静默当作孤立根 —— 不报错、不影响调用成败、不造空上下文。对端是 agentia 正向桥(或 MCP Python SDK 等已按 SEP-414 注入的实现)时这条链自动接上。
1265
1331
  - **结果映射与正向桥方向对称**:工具返回 string → `content: [{ type: 'text', text }]`,其他 JSON 化进 text;抛错 → 协议层成功 + `isError: true`(MCP 惯例;正向桥的连接器正好把 `isError` 转回抛错)。
1266
1332
  - **取消是协作式**:客户端断连 / `close()` 会中止该次调用的 `ToolRunContext.signal`;`toolTimeoutMs` 与引擎同款语义(非正数 / 不设 = 不限;超时 = **放弃等待** + abort `abandoned`,该次调用回 `isError`,server 不挂)。
1267
1333
  - **默认 client 是惰性构造的**:`client` 不给时第一次 `tools/call` 才走 `createAnthropicClient()`(与引擎默认同款)—— 纯工具 server 不需要 API key 在场。
1334
+ - **想看一个真用它干活的例子**:`examples/observability-mcp/` 把 `buildRunReport` / `diffTraces` 包成两个只读工具(`report_trace` / `diff_traces`)暴露给任意 MCP 宿主,让 agent 自己查「我上一轮慢在哪」;还带一条**实边界**(工具参数由模型给 ⇒ 只读 trace 根内的文件,realpath 比前缀),以及一条端到端的验收脚本(起真 server ⇐ 出厂连接器 + `mcpTools`)。
1268
1335
 
1269
1336
  ```ts
1270
1337
  import { createMcpServer, jsonlTraceSink } from '@migor/agentia';
@@ -1296,6 +1363,8 @@ console.log(mcp.url); // http://127.0.0.1:8787/mcp
1296
1363
  | `server` | 挂进**既有** `http.Server`(框架不替它 listen;`close()` 只摘本 handler 不关它)。非本 `path` 的请求本 handler 直接忽略(交给宿主自己的路由) |
1297
1364
  | `client` | 进 `ToolRunContext.client`(子 agent / skill 类工具要它拉子循环);缺省惰性 `createAnthropicClient()` |
1298
1365
  | `sinks` | trace 出口:每次 `tools/call` 收尾投递(抛错被吞 + `console.warn`,观测不击穿业务) |
1366
+ | `traceLimits` | 每次 `tools/call` 那棵 trace 的事件数闸(与引擎 `traceLimits` 同款:超限停记 + run 根留 `trace.truncated` 簿记;缺省 = 不限;坏值构造期抛 TypeError) |
1367
+ | `maxEventChars` | 事件正文截断上限(与引擎 `maxEventChars` 同款;`false` = 不截断;缺省 = 引擎缺省) |
1299
1368
  | `toolTimeoutMs` | 单次 `tools/call` 的工具执行超时(毫秒),语义与引擎 `toolTimeoutMs` 同款;非正数 / 不设 = 不限 |
1300
1369
  | `auth` | http 侧鉴权钩子:在读 body 之前调用,抛错即 401(原文只进服务端日志);stdio 侧信任父进程、本项不生效 |
1301
1370
  | `name` | `serverInfo.name`(握手回给客户端),缺省 `'agentia'` |
@@ -1404,8 +1473,8 @@ const c = await app.run(messages); // 起一条新 run,沿着分叉点前的
1404
1473
  每个 span 带 `path` / `missing` / `fields`),**退出码语义不变**(有差异仍为 1)—— 门禁照旧可用,
1405
1474
  只是「差在哪」也能被读。`agentia doctor --json` 同理(体检结果结构化,有错误仍退出 1)。
1406
1475
 
1407
- > `report` / `diff` / `doctor` 支持 `--json`;`harvest` **没有**:它的 stdout 本身就是产物
1408
- > (生成的 eval 文件源码),加 `--json` 会自相矛盾。
1476
+ > `report` / `diff` / `doctor` 支持 `--json`;`harvest` / `export` **没有**:它们的 stdout
1477
+ > 本身就是产物(生成的 eval 文件源码 / 训练数据 JSONL),加 `--json` 会自相矛盾。
1409
1478
 
1410
1479
  - **配对语义**(结构性配对,字段差异不影响配对):llm.turn 按回合序配对、**忽略 span name** ——
1411
1480
  name 是模型 id,而「换模型重跑」正是 A/B 主用例,按 name 配对会把两侧所有 turn 报成缺失;
@@ -1760,7 +1829,8 @@ const callable = {
1760
1829
  | MCP 工具不能进 DI 容器 | 它没有 provider token,也不能被别的能力的 `tools` 引用(两种引用粒度都要先有 token) |
1761
1830
  | 指标分位是窗口内精确值 | `*_last{quantile=...}` 只反映最近 `windowSize`(缺省 1024)条样本;要跨实例聚合请用直方图(`*_bucket` / `_sum` / `_count`,累积语义) |
1762
1831
  | 指标是**进程内**累加 | 不做分布式聚合与持久化:多实例各算各的(直方图可相加),重启即清零。要长期保留请把 `render()` 抓走或用 `export:'otlp'` 推给采集端 |
1763
- | OTLP metrics 只推当前累计 | 按 `intervalMs` 周期导出**累积值**(CUMULATIVE),不做增量/背压;导出失败按 `onExportError` 处理(缺省吞掉,不重试、不阻塞 run)。`reset()` 语义是**开启新窗口**:计数清零**且**数据点起点前移(同一 `startTime` 下 counter 只能单调不减,只清零会让后端算出负增量或丢样本) |
1832
+ | OTLP metrics 只推当前累计 | 按 `intervalMs` 周期导出**累积值**(CUMULATIVE),不做增量/背压;导出失败按 `onExportError` 处理(缺省每次失败落一条 `console.warn`,不重试、不阻塞 run)。`reset()` 语义是**开启新窗口**:计数清零**且**数据点起点前移(同一 `startTime` 下 counter 只能单调不减,只清零会让后端算出负增量或丢样本) |
1833
+ | OTLP trace 导出**只发 JSON**(直打 Phoenix 会 415) | `createOtlpExporter` 的 content-type 写死 `application/json`,`OtlpExporterOptions` **没有编码选项**;只收 `application/x-protobuf` 的接收端(Phoenix 的 traces 路由对别的 content-type 回 415,源码级核实 2026-10-12)**直打不进去** —— OTLP 规范对接收端只是 SHOULD 双收,Phoenix 未遵循推荐但不违规。处置:中间加一层 OTLP Collector 收 JSON、转 binary(最小配置见 `docs/observability.md` §7)。**不内建 protobuf 编码器**:零运行时依赖是硬约定,手写编码器几百行进核心不值 |
1764
1834
  | `GET /metrics` 不鉴权 | 与 `/healthz` 同档(拉取端在集群内网)。要保护请放反代之后,或不传 `metrics` 选项自行在外层挂路由 |
1765
1835
  | 工具没有 token/成本指标 | 工具是**你的代码**、本身不消耗 token,所以只产出调用数/失败数/耗时;token 与成本只对 `skill`/`subagent`(有 `capability` span)与模型维度产出 |
1766
1836
  | `@Prompt` 没有能力指标 | 资产类能力不建 span、无独立耗时,故不出现在能力排行里(这是刻意的:硬凑一个假耗时会误导调优) |
@@ -1770,7 +1840,7 @@ const callable = {
1770
1840
  | `agentia harvest` 的产物是轨迹骨架 | trace **不记 assistant 文本**(llm.turn 只记 usage/事件),故 harvest 用例脚本里的 text 块是占位、预填 `expect` 是从原 trace 抄录的实际轨迹 —— 脚手架不是成品,人工核对后再进 CI(见 §6「线上 trace 回流」) |
1771
1841
  | 分叉重放不是续跑 | `forkMessages` 与 `traceToMessages` / harvest **同源有损**:trace **缺省**不记 assistant 文本(opt-in 例外:`traceContent: 'full'`,见 §4)与 run 原始输入(重放里 assistant 是标注占位、首尾 user 是合成),也不记 blackboard(分叉种子经 `RunInvocationOptions.blackboard` 自带);它产出喂回 `app.run` 的 messages、起的是**新 run**,不是接着原 run 的循环位置跑 |
1772
1842
  | 评分来自 run 之外 | `Score` 走 run 根 `score` **事件**而非 span 字段(评分通常在 run 跑完后才产生);`attachScore` 找不到根 span 时静默忽略,多次调用即多条事件(不同维度各记各的) |
1773
- | 链路关联:入站自动、**出站只给读取器** | `traceContext` / `traceparent` 头把**上游**接进来(run 根的 `links`);出站方向给 `currentTraceparent()`(当前 span 的 W3C 串,回合 / 能力调用粒度),但框架**不替你做注入** —— 它不创建出站请求,那一行由宿主的 `fetch` / metadata 自己写。两个边界:① `run` 根 span 由 `runAgent` 打开 ⇒ 更早的 `contextInit` / 记忆水合取到 `undefined`(那时确实没有 span);② flags 恒 `00`(本框架不采样)。id 宽度经**同一份投影**压到 16 位(与 OTLP 导出共用,单一真源)—— 故下游收到的 span id 与 collector 里的是同一个数。另:link 只落在 run 根(子 span 不散),且**一进程内**不跨进程自动传播 —— 队列场景要自己把 `traceContext` 传下去(HTTP 头带走,或随 `TaskRecord.spec.options` 落库) |
1843
+ | 链路关联:入站自动、出站默认只给读取器(MCP 桥除外) | `traceContext` / `traceparent` 头把**上游**接进来(run 根的 `links`);出站方向给 `currentTraceparent()`(当前 span 的 W3C 串,回合 / 能力调用粒度),但框架**不替你做注入** —— 它不创建出站请求,那一行由宿主的 `fetch` / metadata 自己写。**唯一的例外是 MCP 正向桥**:`tools/call` 的请求由桥自己发,故 run 内经 `mcpTools` 的调用自动带 `params._meta.traceparent`(SEP-414)。两个边界:① `run` 根 span 由 `runAgent` 打开 ⇒ 更早的 `contextInit` / 记忆水合取到 `undefined`(那时确实没有 span);② flags 恒 `00`(本框架不采样)。id 宽度经**同一份投影**压到 16 位(与 OTLP 导出共用,单一真源)—— 故下游收到的 span id 与 collector 里的是同一个数。另:link 只落在 run 根(子 span 不散),且**一进程内**不跨进程自动传播 —— 队列场景要自己把 `traceContext` 传下去(HTTP 头带走,或随 `TaskRecord.spec.options` 落库) |
1774
1844
  | 配额不是框架子系统 | 只给缝(middleware + TraceSink + BudgetGuard),计数放哪(内存 / Redis / DB)与超限怎么办都是你的策略 |
1775
1845
  | 人工审批两种形态 | 进程内闸门用 `middleware`(`await` 决策再放行);跨进程耐久审批用 `@Tool({ approval: 'required' })` + `POST /tasks/:id/approve`(挂起/恢复,见 §6.6「人工审批」) |
1776
1846
  | 审批超时是**惰性**判定 | `approvalTimeoutMs` 不起定时器:`approve` / `poll` / `resumePending` 读到过期挂起任务时才自动全拒并重派 —— 没人读的任务不会自己超时(要定期扫就调 `resumePending()`) |
@@ -1797,7 +1867,7 @@ const callable = {
1797
1867
  | 症状 | 原因与修法 |
1798
1868
  |---|---|
1799
1869
  | 菜单里没有我的能力 | ① 方法没写装饰器;② 类没注册进 `providers`;③ 框架双实例(见第 2 节陷阱);④ `toolSources` 白名单把它排除了 |
1800
- | `菜单能力重名` 装配期抛错 | 四类能力**共用命名空间**,改名即可 |
1870
+ | `菜单能力重名` / `子菜单能力重名` 装配期抛错 | 四类能力**共用命名空间**,改名即可;查重覆盖主菜单与 @SubAgent/@Skill 的 `tools` 引用展开出的子菜单(两个 provider 各有同名能力被同一能力整片引用时,报错会指到哪个能力的哪个引用片,用能力级路径 `<token>/<能力名>` 收窄即可) |
1801
1871
  | 编译错 `不能把 X 赋给 Y` | 用了 `fromZod<T>`,方法签名与 `T` 不一致(这是护栏,不是 bug) |
1802
1872
  | 模型传的入参没被拦 | 只填了 `schema` 没写 `strict`;且框架的校验是**子集校验**(`format`/`minimum` 等不校验) |
1803
1873
  | `ctx.get('k')` 没有类型 | 没做 `Blackboard` 声明合并(见 5.1) |
@@ -142,6 +142,22 @@ export declare const LIMIT_SEMANTICS: readonly [{
142
142
  readonly zeroClause: '0 = 不重试';
143
143
  readonly badValue: 'throws';
144
144
  readonly note: '坏值必须响亮失败:判定是 `attempt >= maxRetries` ⇒ `NaN` 比较恒假、`Infinity` 永远达不到,两者都是**无限重试**(429 场景下每一次都是真金白银);`-1` 静默变成「不重试」;`1.5` 实际只允许 1 次。';
145
+ }, {
146
+ readonly knob: 'RetryOptions.maxAttempts';
147
+ readonly where: 'engine/retry.ts(resolveRetry)';
148
+ readonly unit: 'count';
149
+ readonly zero: 'disabled';
150
+ readonly zeroClause: '0 = 关闭重试';
151
+ readonly badValue: 'throws';
152
+ readonly note: '含首次尝试(1 = 只试一次不重试)。⚠️ 2026-10-13 深评 A1 补登 + 补校验:`maxAttempts: NaN` 曾让 `!(NaN >= 1)` 成立 ⇒ 重试被**静默关闭**,run 根快照记 `config.retry.maxAttempts: 0`,看着像用户主动关的;与 client 层 maxRetries 同纪律改为 `resolveRetry` 抛 TypeError(runAgent 入口另有一次同款校验,配置错不收成「失败的 run」)。';
153
+ }, {
154
+ readonly knob: 'RetryOptions.jitter';
155
+ readonly where: 'engine/retry.ts(resolveRetry)';
156
+ readonly unit: 'n/a';
157
+ readonly zero: 'disabled';
158
+ readonly zeroClause: '0 = 不加抖动';
159
+ readonly badValue: 'throws';
160
+ readonly note: '抖动比例 0~1。>1 会把退避拉成负数再被 `Math.max(0, …)` 静默钳回 0(抖动与退避一起失效,429 场景变热重试);NaN 让退避算成 NaN。2026-10-13 深评 A1 补登。';
145
161
  }, {
146
162
  readonly knob: 'maxEventChars';
147
163
  readonly where: 'engine/tool-events.ts';
@@ -198,6 +214,22 @@ export declare const LIMIT_SEMANTICS: readonly [{
198
214
  readonly zeroClause: '0 = 立即导出';
199
215
  readonly badValue: 'none';
200
216
  readonly note: '⚠️ **同名反义**:`Scheduler.every` 的 `intervalMs: 0` 是**配置错误**(抛错),这里却是「关掉定时器、每次累加后立即导出」。两个同名旋钮两种读法 —— 改任何一个之前先看这张表。';
217
+ }, {
218
+ readonly knob: 'RetryOptions.baseDelayMs';
219
+ readonly where: 'engine/retry.ts(resolveRetry)';
220
+ readonly unit: 'ms';
221
+ readonly zero: 'immediate';
222
+ readonly zeroClause: '0 = 不退避(立即重试)';
223
+ readonly badValue: 'throws';
224
+ readonly note: '⚠️ 2026-10-13 深评 A1 补登 + 补校验:`baseDelayMs: NaN` 让 backoffDelay 算出 NaN ⇒ `interruptibleSleep` 的 `assertTimerDelay` 抛 RangeError —— 它曾被 turn.ts 退避处的裸 `catch` 吞成「用户取消」(配置错被谎报成取消,实测 `retry:{baseDelayMs:NaN}` + 429 → stopReason:aborted)。超 2^31-1ms 同理拒(Node 钳到 1ms ⇒ 热重试;上限单源 core/timeout.ts)。';
225
+ }, {
226
+ readonly knob: 'RetryOptions.maxDelayMs';
227
+ readonly where: 'engine/retry.ts(resolveRetry)';
228
+ readonly unit: 'ms';
229
+ readonly zero: 'immediate';
230
+ readonly zeroClause: '0 = 退避封顶为零(立即重试)';
231
+ readonly badValue: 'throws';
232
+ readonly note: '同 baseDelayMs:NaN 穿透 `Math.min` 让封顶失效(`Math.min(x, NaN)` = NaN);超上限被 Node 钳到 1ms。2026-10-13 深评 A1 补登。⚠️ 正向抖动可能把最终退避推过 maxDelayMs(±jitter 是有意的),但 `backoffDelay` 会把它夹在 2^31-1ms 以内,sleep 不会因此抛。';
201
233
  }, {
202
234
  readonly knob: 'BudgetGuardOptions.maxTotalTokens';
203
235
  readonly where: 'engine/budget.ts(createBudgetGuard;由 RunAgentOptions.maxTotalTokens 传进来)';
@@ -325,7 +357,7 @@ export declare const LIMIT_SEMANTICS: readonly [{
325
357
  readonly zero: 'invalid';
326
358
  readonly zeroClause: '0 = 一个标签组合都认不下,全折进一个桶';
327
359
  readonly badValue: 'throws';
328
- readonly note: '**组合数**上限(2026-09-27 ⑧ 补的第四条基数上限)。`maxLabelValues` 只封每个键的**值域**,而进内存的是组合,数量是叉乘 `(maxLabelValues+1)^labelKeys.length` —— 缺省 100 × 3 键就是一百万条,且每键的 dropped 计数看不见它。与另外三道同款:超限折进一个全 `__other__` 的桶(量不丢),折叠数见 `droppedLabelCombos` / `dropped_keys{kind="label:combos"}`。';
360
+ readonly note: '**组合数**上限(2026-09-27 ref-menu-drift-signals 补的第四条基数上限)。`maxLabelValues` 只封每个键的**值域**,而进内存的是组合,数量是叉乘 `(maxLabelValues+1)^labelKeys.length` —— 缺省 100 × 3 键就是一百万条,且每键的 dropped 计数看不见它。与另外三道同款:超限折进一个全 `__other__` 的桶(量不丢),折叠数见 `droppedLabelCombos` / `dropped_keys{kind="label:combos"}`。';
329
361
  }];
330
362
  /** 表里全部旋钮的标识(用例按它建穷尽表:少一项 `typecheck:tests` 就红) */
331
363
  export type LimitKnob = (typeof LIMIT_SEMANTICS)[number]['knob'];
@@ -105,6 +105,24 @@ export const LIMIT_SEMANTICS = [
105
105
  badValue: 'throws',
106
106
  note: '坏值必须响亮失败:判定是 `attempt >= maxRetries` ⇒ `NaN` 比较恒假、`Infinity` 永远达不到,两者都是**无限重试**(429 场景下每一次都是真金白银);`-1` 静默变成「不重试」;`1.5` 实际只允许 1 次。',
107
107
  },
108
+ {
109
+ knob: 'RetryOptions.maxAttempts',
110
+ where: 'engine/retry.ts(resolveRetry)',
111
+ unit: 'count',
112
+ zero: 'disabled',
113
+ zeroClause: '0 = 关闭重试',
114
+ badValue: 'throws',
115
+ note: '含首次尝试(1 = 只试一次不重试)。⚠️ 2026-10-13 深评 A1 补登 + 补校验:`maxAttempts: NaN` 曾让 `!(NaN >= 1)` 成立 ⇒ 重试被**静默关闭**,run 根快照记 `config.retry.maxAttempts: 0`,看着像用户主动关的;与 client 层 maxRetries 同纪律改为 `resolveRetry` 抛 TypeError(runAgent 入口另有一次同款校验,配置错不收成「失败的 run」)。',
116
+ },
117
+ {
118
+ knob: 'RetryOptions.jitter',
119
+ where: 'engine/retry.ts(resolveRetry)',
120
+ unit: 'n/a',
121
+ zero: 'disabled',
122
+ zeroClause: '0 = 不加抖动',
123
+ badValue: 'throws',
124
+ note: '抖动比例 0~1。>1 会把退避拉成负数再被 `Math.max(0, …)` 静默钳回 0(抖动与退避一起失效,429 场景变热重试);NaN 让退避算成 NaN。2026-10-13 深评 A1 补登。',
125
+ },
108
126
  {
109
127
  knob: 'maxEventChars',
110
128
  where: 'engine/tool-events.ts',
@@ -169,6 +187,24 @@ export const LIMIT_SEMANTICS = [
169
187
  badValue: 'none',
170
188
  note: '⚠️ **同名反义**:`Scheduler.every` 的 `intervalMs: 0` 是**配置错误**(抛错),这里却是「关掉定时器、每次累加后立即导出」。两个同名旋钮两种读法 —— 改任何一个之前先看这张表。',
171
189
  },
190
+ {
191
+ knob: 'RetryOptions.baseDelayMs',
192
+ where: 'engine/retry.ts(resolveRetry)',
193
+ unit: 'ms',
194
+ zero: 'immediate',
195
+ zeroClause: '0 = 不退避(立即重试)',
196
+ badValue: 'throws',
197
+ note: '⚠️ 2026-10-13 深评 A1 补登 + 补校验:`baseDelayMs: NaN` 让 backoffDelay 算出 NaN ⇒ `interruptibleSleep` 的 `assertTimerDelay` 抛 RangeError —— 它曾被 turn.ts 退避处的裸 `catch` 吞成「用户取消」(配置错被谎报成取消,实测 `retry:{baseDelayMs:NaN}` + 429 → stopReason:aborted)。超 2^31-1ms 同理拒(Node 钳到 1ms ⇒ 热重试;上限单源 core/timeout.ts)。',
198
+ },
199
+ {
200
+ knob: 'RetryOptions.maxDelayMs',
201
+ where: 'engine/retry.ts(resolveRetry)',
202
+ unit: 'ms',
203
+ zero: 'immediate',
204
+ zeroClause: '0 = 退避封顶为零(立即重试)',
205
+ badValue: 'throws',
206
+ note: '同 baseDelayMs:NaN 穿透 `Math.min` 让封顶失效(`Math.min(x, NaN)` = NaN);超上限被 Node 钳到 1ms。2026-10-13 深评 A1 补登。⚠️ 正向抖动可能把最终退避推过 maxDelayMs(±jitter 是有意的),但 `backoffDelay` 会把它夹在 2^31-1ms 以内,sleep 不会因此抛。',
207
+ },
172
208
  {
173
209
  knob: 'BudgetGuardOptions.maxTotalTokens',
174
210
  where: 'engine/budget.ts(createBudgetGuard;由 RunAgentOptions.maxTotalTokens 传进来)',
@@ -312,7 +348,7 @@ export const LIMIT_SEMANTICS = [
312
348
  zero: 'invalid',
313
349
  zeroClause: '0 = 一个标签组合都认不下,全折进一个桶',
314
350
  badValue: 'throws',
315
- note: '**组合数**上限(2026-09-27 ⑧ 补的第四条基数上限)。`maxLabelValues` 只封每个键的**值域**,而进内存的是组合,数量是叉乘 `(maxLabelValues+1)^labelKeys.length` —— 缺省 100 × 3 键就是一百万条,且每键的 dropped 计数看不见它。与另外三道同款:超限折进一个全 `__other__` 的桶(量不丢),折叠数见 `droppedLabelCombos` / `dropped_keys{kind="label:combos"}`。',
351
+ note: '**组合数**上限(2026-09-27 ref-menu-drift-signals 补的第四条基数上限)。`maxLabelValues` 只封每个键的**值域**,而进内存的是组合,数量是叉乘 `(maxLabelValues+1)^labelKeys.length` —— 缺省 100 × 3 键就是一百万条,且每键的 dropped 计数看不见它。与另外三道同款:超限折进一个全 `__other__` 的桶(量不丢),折叠数见 `droppedLabelCombos` / `dropped_keys{kind="label:combos"}`。',
316
352
  },
317
353
  ];
318
354
  /** 按旋钮取那行(拼错旋钮名 = 编译期报错,不是运行期 undefined) */
@@ -1 +1 @@
1
- {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/core/limits.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"limits.js","sourceRoot":"","sources":["../../src/core/limits.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,7 @@ import type { SpanError } from './trace.js';
10
10
  * 收尾释放)、`resumePending` 不捡走(它不是孤儿,崩溃续跑语义不适用于「在等」);
11
11
  * 消息历史(含未决 tool_use)与待决清单随 TaskRecord 落库。
12
12
  *
13
- * 「挂起」是**一个状态 + 一个原因**(2026-09-28 ①:从前 `awaiting_approval` 一个状态兼职
13
+ * 「挂起」是**一个状态 + 一个原因**(2026-09-28 ref-suspend-state-reason:从前 `awaiting_approval` 一个状态兼职
14
14
  * 两件事):状态只说「它在等」,等什么由 `SuspendedReason` 说 —— 判据(审批超时 / 能否
15
15
  * 审批)落在**原因**上,于是「时间挂起被审批超时提前叫醒」这类误伤在类型上就写不出来。
16
16
  */
@@ -41,7 +41,7 @@ export type SuspendedReason = 'approval' | 'timer';
41
41
  /** 该状态是否已到终态(不会再变)。判定只此一处 —— 别在调用点重写。 */
42
42
  export declare function isTerminalStatus(status: RunStatus): boolean;
43
43
  /**
44
- * run 事件(2026-09-28 ⑥,run 事件投入口):外部系统投给一条**挂起** run 的一条输入
44
+ * run 事件(2026-09-28 ref-run-event-input,run 事件投入口):外部系统投给一条**挂起** run 的一条输入
45
45
  * (`AsyncRunner.signalTask` / `POST /tasks/:id/events`;审批是它的特例)。
46
46
  *
47
47
  * 白名单形状(设计稿 B1):**全是字符串** —— 外部永远不能构造消息块,投毒面只到
@@ -4,7 +4,7 @@
4
4
  * 为什么在 core:engine 的工具级超时(`engine/turn.ts`)与桥的 MCP 调用超时
5
5
  * (`integrations/mcp.ts`)**必须共用同一套判定**。此前两处各写一份,代价是
6
6
  * 2026-09-14 的「硬保证」收紧只落进了 `engine/concurrency.ts`,桥那一份继续用竞速判定 ——
7
- * 同一个承诺两套实现,于是同一个事件在 trace 里能有两种账(见 `docs/spec.md` §10 2026-09-17 ①)。
7
+ * 同一个承诺两套实现,于是同一个事件在 trace 里能有两种账(见 `docs/spec.md` §10 2026-09-17 ref-mcp-timeout-single-source)。
8
8
  * `integrations` 只能依赖 core(`tests/architecture/layering.test.ts` 强制),
9
9
  * 所以单源的落点是 core。core 是叶子:本文件只 import `limits.js`(**纯数据表,零 import**)
10
10
  * —— 2026-09-28 起它要 `zeroClauseOf`:两处 `assertTimerDelay` 的文案必须与 limits 表同源
@@ -26,7 +26,7 @@ export declare const TIMED_OUT: unique symbol;
26
26
  * `withTimeout`(引擎 `toolTimeoutMs`)、`interruptibleSleep`(退避)、
27
27
  * `DrainGate.waitForIdle`(drain 预算)、`#raceTimeout`(`runTimeoutMs`)、
28
28
  * `composeSignal`(client `timeout`)五处都直喂 `setTimeout` 且只查「非负有限」。
29
- * 单源收在这里(见 `docs/spec.md` §10 2026-09-28 ⑪)。
29
+ * 单源收在这里(见 `docs/spec.md` §10 2026-09-28 ref-timer-cap-single-source)。
30
30
  */
31
31
  export declare const MAX_TIMER_DELAY_MS = 2147483647;
32
32
  /**
@@ -58,7 +58,7 @@ export declare function clampTimerDelay(ms: number): number;
58
58
  * 为什么需要它:超时此前只能靠**错误文案**辨认 —— 桥抛的是普通 `Error`,而
59
59
  * `classifyError` 里没有 timeout 这一类,于是 trace 里记成 `error(unknown)` +
60
60
  * `errorKind=threw`,与引擎自己判的超时(`error(timeout)` + `errorKind=timeout`)
61
- * 成为同一事件的**两种账**(见 `docs/spec.md` §10 2026-09-17 ①)。
61
+ * 成为同一事件的**两种账**(见 `docs/spec.md` §10 2026-09-17 ref-mcp-timeout-single-source)。
62
62
  *
63
63
  * 判定契约(对使用者可见):**任何** `code === 'timeout'` 的错误都会被引擎归为
64
64
  * `errorKind='timeout'`,不需要 import 这个类(`isTimeoutError` 也认鸭子类型)。
@@ -87,7 +87,7 @@ export declare function abortError(message?: string): Error;
87
87
  *
88
88
  * 为什么第 3 条也算:`engine/errors.ts` 的分类**此前只有它**认这一条(当时把超时归进 `connection`),
89
89
  * 于是「超时」在 trace 里混在「连不上」里,看板与 `trace-diff` 分不出两者。现在超时有自己的
90
- * `type: 'timeout'`,这条判据由分类与工具级记账**共用**,口径一致(spec §10 2026-09-17 ②)。
90
+ * `type: 'timeout'`,这条判据由分类与工具级记账**共用**,口径一致(spec §10 2026-09-17 ref-timeout-error-type)。
91
91
  */
92
92
  export declare function isTimeoutError(e: unknown): boolean;
93
93
  /**
@@ -128,7 +128,7 @@ export declare function withTimeout<T>(p: Promise<T>, timeoutMs: number): Promis
128
128
  * 不必再等)与 `integrations/anthropic.ts` 的 `interruptibleSleep`(client 层退避)。
129
129
  * 那边此前自带一段「与 engine/retry.ts 的 sleep 同语义但不复用它 —— 分层约束:
130
130
  * integrations 只能依赖 core」的注解:**正是那条约束把两份代码逼成了重复**,
131
- * 所以下沉到 core 是让它们合一的唯一合法落点(见 spec §10 2026-09-17 ① 的单源化口径)。
131
+ * 所以下沉到 core 是让它们合一的唯一合法落点(见 spec §10 2026-09-17 ref-mcp-timeout-single-source 的单源化口径)。
132
132
  *
133
133
  * ⚠️ 「不合并退避计算器」的例外只针对**引擎层**:`engine/retry.ts` 的 `backoffDelay`
134
134
  * 是 ±20% 均匀抖动、底数/上限来自 `RetryOptions`,与 client 层策略不同(见下方