@zhushanwen/subagent-core 0.4.0 → 0.5.1

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 (272) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +16418 -14070
  11. package/dist/index.d.cts +5136 -4016
  12. package/dist/index.d.ts +5136 -4016
  13. package/dist/index.js +16343 -14048
  14. package/dist/{types-DpUO16pj.d.cts → types-Dv4QhSJ_.d.cts} +215 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-Dv4QhSJ_.d.ts} +215 -112
  16. package/package.json +3 -3
  17. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  18. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  19. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  20. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  21. package/src/__tests__/manifest-store.test.ts +10 -9
  22. package/src/__tests__/record-store-cache.test.ts +0 -2
  23. package/src/__tests__/record-store-index.test.ts +1 -2
  24. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  25. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  26. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  27. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  28. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  29. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  30. package/src/__tests__/session-runner.test.ts +1 -1
  31. package/src/core/__tests__/host-services.test.ts +2 -2
  32. package/src/core/__tests__/logger.test.ts +1 -1
  33. package/src/core/error-message.ts +9 -0
  34. package/src/core/host-services.ts +21 -5
  35. package/src/core/notify-ports.ts +18 -5
  36. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  37. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  38. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  39. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  40. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  41. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  42. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  43. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  44. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  45. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  46. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  47. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  48. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  49. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  50. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  51. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  52. package/src/execution/__tests__/execution-record.test.ts +217 -60
  53. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  54. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  55. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  56. package/src/execution/__tests__/gc-timer.test.ts +55 -2
  57. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  58. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  59. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  60. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  61. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  62. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  63. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  64. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  65. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  66. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  67. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  68. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  69. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  70. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  71. package/src/execution/__tests__/notify-ledger.test.ts +973 -18
  72. package/src/execution/__tests__/output-collector.test.ts +117 -6
  73. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  74. package/src/execution/__tests__/record-store.test.ts +10 -9
  75. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  76. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  77. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  78. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  79. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  80. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  81. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  82. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  83. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  84. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  85. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  86. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  87. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  88. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  89. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  90. package/src/execution/__tests__/session-pending.test.ts +257 -14
  91. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  92. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  93. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  94. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  95. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  96. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  97. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  98. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  99. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  100. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  101. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  102. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  103. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  104. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  105. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  106. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  107. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  108. package/src/execution/__tests__/subagent-actions-core.test.ts +42 -22
  109. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  110. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +8 -8
  111. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  112. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  113. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  114. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  115. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  116. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  117. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  118. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  119. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  120. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  121. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  122. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  123. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  124. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  125. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  126. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  127. package/src/execution/agent-registry.ts +74 -30
  128. package/src/execution/agent-result-mapper.ts +3 -0
  129. package/src/execution/cold-resurrect.ts +199 -0
  130. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  131. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  132. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  133. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  134. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  135. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  136. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  137. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  138. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  139. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  140. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  141. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  142. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  143. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  144. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  145. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  146. package/src/execution/engine/__tests__/registry.test.ts +4 -2
  147. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  148. package/src/execution/engine/common/capability-gate.ts +92 -0
  149. package/src/execution/engine/common/journal-wiring.ts +97 -0
  150. package/src/execution/engine/common/kill-chain.ts +42 -10
  151. package/src/execution/engine/common/nesting-guard.ts +66 -0
  152. package/src/execution/engine/common/persona-router.ts +18 -8
  153. package/src/execution/engine/common/pool-manager.ts +332 -78
  154. package/src/execution/engine/common/session-view-service.ts +506 -0
  155. package/src/execution/engine/common/session-view-types.ts +125 -0
  156. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  157. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  158. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  159. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  160. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  161. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  162. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  163. package/src/execution/engine/engines/pi/reader.ts +11 -0
  164. package/src/execution/engine/engines/pi/registration.ts +4 -2
  165. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  166. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  167. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  168. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  169. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  170. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  171. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  172. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  173. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  174. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  175. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  176. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  177. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  178. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  179. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +25 -319
  180. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  181. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  182. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  183. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  184. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  185. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  186. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  187. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  188. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  189. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  190. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  191. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  192. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  193. package/src/execution/engine/host-task-spec.ts +32 -36
  194. package/src/execution/engine/model-validation.ts +177 -0
  195. package/src/execution/engine/port.ts +24 -6
  196. package/src/execution/engine/routing.ts +75 -1
  197. package/src/execution/engine/types.ts +30 -103
  198. package/src/execution/execution-record.ts +222 -144
  199. package/src/execution/finalize-record.ts +131 -93
  200. package/src/execution/idle-gc.ts +28 -0
  201. package/src/execution/lifecycle-predicates.ts +1 -1
  202. package/src/execution/notify-host.ts +212 -0
  203. package/src/execution/record-store.ts +119 -73
  204. package/src/execution/round-settlement.ts +93 -0
  205. package/src/execution/session-file-gc.ts +96 -62
  206. package/src/execution/session-reconstructor.ts +256 -143
  207. package/src/execution/sessions-index.ts +117 -47
  208. package/src/execution/settled-watchdog.ts +264 -52
  209. package/src/execution/subagent-actions-core.ts +22 -22
  210. package/src/execution/subagent-service.ts +815 -963
  211. package/src/execution/subprocess-agent-runner.ts +144 -97
  212. package/src/execution/types.ts +9 -0
  213. package/src/execution/ui-request-handler-factory.ts +102 -74
  214. package/src/execution/ui-request-queue.ts +50 -19
  215. package/src/index.ts +442 -316
  216. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  217. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  218. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  219. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  220. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  221. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  222. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  223. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  224. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  225. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  226. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  227. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  228. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  229. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  230. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  231. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  232. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  233. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  234. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  235. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  236. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  237. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  238. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  239. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  240. package/src/orchestration/agent-opts-resolver.ts +1 -1
  241. package/src/orchestration/args-validator.ts +53 -31
  242. package/src/orchestration/execute-agent-call.ts +19 -73
  243. package/src/orchestration/launcher.ts +128 -81
  244. package/src/orchestration/lifecycle.ts +43 -45
  245. package/src/orchestration/models/ports.ts +4 -4
  246. package/src/orchestration/models/run-runtime.ts +2 -2
  247. package/src/orchestration/models/trace.ts +1 -1
  248. package/src/orchestration/models/types.ts +111 -22
  249. package/src/orchestration/models/workflow-run.ts +1 -1
  250. package/src/orchestration/script-lint.ts +91 -58
  251. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  252. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  253. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  254. package/src/shared/atomic-write.ts +12 -9
  255. package/src/shared/meta-parser.ts +158 -84
  256. package/src/shared/model-ref.ts +15 -2
  257. package/src/shared/resource-discovery.ts +9 -183
  258. package/src/shared/schema-jsonify.ts +1 -1
  259. package/workflows/review-fix-loop-utils.cjs +151 -89
  260. package/workflows/review-fix-loop-utils.d.cts +287 -0
  261. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  262. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  263. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  264. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  265. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  266. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  267. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  268. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  269. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  270. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  271. package/src/execution/execute-options-mapper.ts +0 -115
  272. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -8,16 +8,23 @@
8
8
  * 职责:
9
9
  * - 重试:3 次 + 指数退避(BACKOFF_MS = [1000, 2000, 4000])
10
10
  * - 预算:超限不重试(直接 markDone failed)
11
- * - stale-context:不重试(直接 markDone failed)
12
- * - [MF-1] 确定性 schema 失败:不重试(直接 markDone failed)
11
+ * - stale-context(result.failureKind="stale_context"):不重试(直接 markDone failed)
12
+ * - [MF-1] 确定性 schema 失败(result.failureKind="schema_deterministic"):不重试
13
+ * (直接 markDone failed)
13
14
  * - 成功:consume usage + incrementCallCount + markDone + trace.update(completed)
14
15
  *
16
+ * [D5-③ 结构化分诊] 失败分诊读 AgentResult.failureKind 字段(产出侧唯一识别点 =
17
+ * execution/engine/engines/pi/output-collector.ts 的 classifyFailureKind,词表归属
18
+ * 见其文件头)。本模块不再扫 error 文案子串——**语义守恒(r1 MF4)**:unknown
19
+ * (含字段缺省)= 可重试,保持收敛前的默认重试语义;仅 stale_context(不重试、
20
+ * 换参重发场景由调用方编排)与 schema_deterministic 维持特判。
21
+ *
15
22
  * 关键设计:
16
23
  * - **usage 透传**:result.usage 直接交给 budget.consume,加权由 Budget 内部的权重常量
17
- * 处理(见 budget.ts)。此函数不再做 usage 形状的改写。
24
+ * 处理(见 budget.ts)。此函数不再做 usage 形状的改写。
18
25
  * - **参数显式化**:runner 直接传入(而非 ctx.getRun(runId).pool),无 runId 查找 / pool 守卫。
19
26
  * - **stale-state 检查**:signal.aborted 时早返回。WorkflowRun 状态由调用方 lifecycle
20
- * 持有,executeAgentCall 只关心单次 call 生命周期。
27
+ * 持有,executeAgentCall 只关心单次 call 生命周期。
21
28
  *
22
29
  * 层归属:Engine。零 infra 依赖(runner 是 AgentRunner port,budget/trace/call 是 Engine 模型)。
23
30
  *
@@ -41,69 +48,6 @@ const BACKOFF_EXPONENT_BASE = 2;
41
48
  /** 最大尝试次数(含首次):initial + 2 retries = 3。 */
42
49
  const MAX_ATTEMPTS = 3;
43
50
 
44
- /**
45
- * Stale context 检测模式(P1-5;W4b 对齐 pi 0.84.x 真实文案)。
46
- *
47
- * pi session context 被 compact/cancel 时报告的模式。这种情况下重试无意义——
48
- * 同样的 call 会再次失败。直接 markDone failed 终止单次调用。
49
- *
50
- * W4b:原 "stale context"/"stalecontext" 与 pi 真实文案零匹配(真实文案为
51
- * "This extension ctx is stale after session replacement or reload. ..."——
52
- * runner.ts:544(dist runner.js:352),词序是 "ctx is stale" 而非 "stale context"),stale 分诊对
53
- * 真实文案失效。现对齐:
54
- * - "ctx is stale":真实文案核心子串(词序修正)
55
- * - "stale after session replacement":scheduler 已验证 marker(runtime.ts
56
- * STALE_CTX_MARKER,同文案锚定)
57
- * - "context canceled"/"aborted":保留——abort 族错误同样不重试(signal.aborted
58
- * 分支的先行分诊,防边界竞态漏网),删除会放宽重试语义。
59
- */
60
- export const STALE_CONTEXT_PATTERNS = [
61
- "ctx is stale",
62
- "stale after session replacement",
63
- "context canceled",
64
- "aborted",
65
- ] as const;
66
-
67
- /**
68
- * 判断错误信息是否表示 stale/canceled pi session context。
69
- * 命中时不重试——重试只会再次失败(P1-5)。
70
- */
71
- export function isStaleContextErrorMsg(msg: string | undefined): boolean {
72
- if (!msg) return false;
73
- const lower = msg.toLowerCase();
74
- return STALE_CONTEXT_PATTERNS.some((p) => lower.includes(p));
75
- }
76
-
77
- /**
78
- * [MF-1] 确定性 schema 失败标记(error 文本前缀,产出方 = output-collector 的
79
- * describeMissingParsedOutput)。
80
- *
81
- * 标记 SSOT 放本模块(与 STALE_CONTEXT_PATTERNS 同布局:orchestration 持表、
82
- * execution 值引用;反向引用会形成 execute-agent-call → output-collector →
83
- * execute-agent-call 运行时循环)。
84
- *
85
- * 标记词逐字核对不命中 STALE_CONTEXT_PATTERNS 任一 pattern 与
86
- * isStaleContextErrorMsg 的子串匹配(否则归因 error 被误诊 stale-context,
87
- * 虽然同样不重试但归因语义被污染;output-collector.test 有交叉锁定)。
88
- *
89
- * 三态可重试性矩阵(F-1 归因):
90
- * | 归因态 | 带本标记 | 可重试性 | 理由 |
91
- * |----------------------------|---------|---------|------|
92
- * | ① 从未调用 SO tool | 是 | 不可重试 | 缺 extension 是环境确定性(C1 安装盲区),同环境重试必同结果 |
93
- * | ② SO 调用 isError(gate 终止/不可满足 schema) | 是 | 不可重试 | 同 schema 重试必同结果(第五轮实测:3 attempts/4 子进程/235s 纯烧钱) |
94
- * | ③ 调用过但无 details | 否 | 可重试 | 可能瞬态(details 提取/序列化异常),保留既有重试语义 |
95
- */
96
- export const DETERMINISTIC_SCHEMA_FAILURE_PREFIX = "Structured output failed deterministically:";
97
-
98
- /**
99
- * [MF-1] 判断错误信息是否为确定性 schema 失败(命中标记前缀)。
100
- * 命中时不重试——同 schema 重试必同结果(矩阵见 DETERMINISTIC_SCHEMA_FAILURE_PREFIX)。
101
- */
102
- export function isDeterministicSchemaFailureMsg(msg: string | undefined): boolean {
103
- if (!msg) return false;
104
- return msg.includes(DETERMINISTIC_SCHEMA_FAILURE_PREFIX);
105
- }
106
-
107
51
  // ── 内部 helper ──────────────────────────────────────────────
108
52
 
109
53
  /**
@@ -124,7 +68,7 @@ function backoffDelay(retryIndex: number): number {
124
68
  * rebuild 竞态窗口中,重跑 dispatch 已 append 同 stepIndex 新节点,旧代际
125
69
  * finalize 的 update 会命中新节点,TUI/中间快照短暂可见错误终态。正确性论证:
126
70
  * 运行期 calls Map 写点仅 discardInFlightCalls 的 delete 与 dispatchAgentCall 的
127
- * set 两族(error-recovery.ts isOrphanedCall 文档注释既定),故实例不等 ⟺ 本
71
+ * set 两族(worker-message-pump.ts isOrphanedCall 文档注释既定),故实例不等 ⟺ 本
128
72
  * finalize 属于被丢弃/被替换的旧代际——与 dispatch 层 .then/.catch 守卫
129
73
  * (S7-second 修复,8353f6b60)同一判定语义,本守卫只是把它前移到 trace.update
130
74
  * 之前。markDone 与 sessionId/sessionFile 同步保留(markDone 在孤儿实例上无害,
@@ -208,16 +152,18 @@ export async function executeAgentCall(
208
152
  budget.consume(result.usage);
209
153
  }
210
154
 
211
- // stale-context:不重试(P1-5)
212
- if (result.error !== undefined && isStaleContextErrorMsg(result.error)) {
155
+ // stale-context(D5-③ 结构化分诊:读 failureKind 字段,词表识别在产出侧
156
+ // output-collector):不重试(P1-5)
157
+ if (result.error !== undefined && result.failureKind === "stale_context") {
213
158
  finalizeCall(call, result, trace, isOrphaned);
214
159
  budget.incrementCallCount();
215
160
  return;
216
161
  }
217
162
 
218
- // [MF-1] 确定性 schema 失败:不重试(gate 终止/不可满足 schema 同 schema 重试必同
219
- // 结果——重试纯烧钱;三态可重试性矩阵见 DETERMINISTIC_SCHEMA_FAILURE_PREFIX)
220
- if (result.error !== undefined && isDeterministicSchemaFailureMsg(result.error)) {
163
+ // [MF-1] 确定性 schema 失败(failureKind="schema_deterministic"):不重试
164
+ // (gate 终止/不可满足 schema 同 schema 重试必同结果——重试纯烧钱;三态矩阵
165
+ // 见产出侧 output-collector 的确定性失败标记注释)
166
+ if (result.error !== undefined && result.failureKind === "schema_deterministic") {
221
167
  finalizeCall(call, result, trace, isOrphaned);
222
168
  budget.incrementCallCount();
223
169
  return;
@@ -31,7 +31,9 @@ import type { LifecycleDeps } from "./models/ports.ts";
31
31
  import type { RunSpec } from "./models/run-spec.ts";
32
32
  import type { DoneReason } from "./models/types.ts";
33
33
  import type { WorkflowRun } from "./models/workflow-run.ts";
34
+ import type { WorkflowScript } from "./models/workflow-script.ts";
34
35
  import type { WorkflowScriptRegistry } from "./models/workflow-script-registry.ts";
36
+ import type { LintResult } from "./script-lint.ts";
35
37
  import { assertSafeTimerDelay } from "../shared/timer-delay.ts";
36
38
 
37
39
  // ── 常量 ─────────────────────────────────────────────────────
@@ -106,6 +108,14 @@ function pollInterval(): Promise<void> {
106
108
  });
107
109
  }
108
110
 
111
+ /** lint findings 摘要串(runAndWait / executeNestedWorkflow 共用同一错误文案格式)。 */
112
+ function formatLintErrorSummary(lintResult: LintResult): string {
113
+ return lintResult.findings
114
+ .filter((f) => f.severity === "error")
115
+ .map((f) => `L${f.line}: ${f.message}`)
116
+ .join("; ");
117
+ }
118
+
109
119
  /**
110
120
  * 从 WorkflowRun 构建 WorkflowRunResult(D-8)。
111
121
  *
@@ -243,11 +253,9 @@ export async function runAndWait(
243
253
  // 2. lint 校验(失败抛错——脚本本身有问题,不应静默吞)
244
254
  const lintResult = script.validate();
245
255
  if (!lintResult.valid) {
246
- const errors = lintResult.findings
247
- .filter((f) => f.severity === "error")
248
- .map((f) => `L${f.line}: ${f.message}`)
249
- .join("; ");
250
- throw new Error(`Workflow script '${name}' has lint errors: ${errors}`);
256
+ throw new Error(
257
+ `Workflow script '${name}' has lint errors: ${formatLintErrorSummary(lintResult)}`,
258
+ );
251
259
  }
252
260
 
253
261
  // 3. 构建 RunSpec
@@ -312,19 +320,118 @@ async function safeAbort(
312
320
 
313
321
  // ── executeNestedWorkflow(workflow() 嵌套调用实现) ────────
314
322
 
323
+ /** 父 run 的循环检测链:[...parentChain, parentScriptName](顶层 run 无 chain 时前段为空)。 */
324
+ function buildParentChain(parentRun: WorkflowRun): string[] {
325
+ return [...(parentRun.spec.parentWorkflowChain ?? []), parentRun.spec.scriptName];
326
+ }
327
+
328
+ /** Step 2 的 signal 继承产物(childController + 父 signal/回调——finally 移除 listener 用)。 */
329
+ interface InheritedSignal {
330
+ childController: AbortController;
331
+ parentSignal: AbortSignal | undefined;
332
+ onParentAbort: () => void;
333
+ }
334
+
335
+ /**
336
+ * Step 2: signal 继承——子 run 响应父 run abort(parentController → childController)。
337
+ *
338
+ * [L-2] onParentAbort 提取为命名函数以便 finally removeEventListener,防子 run 完成后
339
+ * parentSignal 上残留 listener(多次嵌套调用会累积)。
340
+ */
341
+ function inheritParentSignal(parentRun: WorkflowRun): InheritedSignal {
342
+ const childController = new AbortController();
343
+ const parentSignal = parentRun.runtime?.controller.signal;
344
+ const onParentAbort = (): void => childController.abort();
345
+ if (parentSignal) {
346
+ if (parentSignal.aborted) {
347
+ childController.abort();
348
+ } else {
349
+ parentSignal.addEventListener("abort", onParentAbort, { once: true });
350
+ }
351
+ }
352
+ return { childController, parentSignal, onParentAbort };
353
+ }
354
+
355
+ /**
356
+ * Step 4: 构建 RunSpec(共享父 Budget + 循环链)。
357
+ *
358
+ * budget 共享(F-7 方案 B):子 run 直接复用父 Budget 引用(budgetRef),consume 实时
359
+ * 累加到父 Budget,消除并行嵌套下的超支窗口,无需 sync-back。
360
+ */
361
+ function buildNestedSpec(
362
+ args: Record<string, unknown>,
363
+ parentRun: WorkflowRun,
364
+ script: WorkflowScript,
365
+ chain: string[],
366
+ ): RunSpec {
367
+ return {
368
+ scriptSource: script.toExecutable(),
369
+ args,
370
+ budgetRef: parentRun.state.budget,
371
+ // Run-level override 传播(与父 run 对齐):子 run 继承父 run 的 model/thinkingLevel,
372
+ // 否则嵌套 workflow 丢失父 run 的模型指定,回落主 agent 模型。
373
+ model: parentRun.spec.model,
374
+ thinkingLevel: parentRun.spec.thinkingLevel,
375
+ scriptName: script.name,
376
+ scriptPath: script.path,
377
+ description: script.meta.description,
378
+ parameters: script.meta.parameters,
379
+ parentWorkflowChain: chain,
380
+ };
381
+ }
382
+
383
+ /**
384
+ * 嵌套 workflow timeout 从父 run 完整传导:父 spec.budgetTimeMs 显式设定时原样作为子 run
385
+ * 轮询 deadline(不 min(DEFAULT) 封顶——旧实现把父 time:2h 截断到 10min,违背「显式传参
386
+ * 完整生效」语义);父未设 → undefined,无 deadline(不限)。
387
+ * [U2] 预算语义统一:父 budgetTimeMs <=0(含 0/负)与 undefined 同义 = 不限——与
388
+ * lifecycle.runWorkflow 的 budgetTimeMs 判定(>0 才挂 scheduleTimeBudget)对齐。
389
+ */
390
+ function resolveNestedTimeoutMs(parentRun: WorkflowRun): number | undefined {
391
+ const raw = parentRun.spec.budgetTimeMs;
392
+ return raw !== undefined && raw > 0 ? raw : undefined;
393
+ }
394
+
395
+ /**
396
+ * Step 6: 结果转换(budget 已通过共享 budgetRef 实时同步,无需 sync-back)。
397
+ * completed → content = 字符串原样 / 其余 JSON.stringify;非 completed → error result。
398
+ */
399
+ function toNestedCallResult(
400
+ name: string,
401
+ result: WorkflowRunResult,
402
+ ): { content: string; parsedOutput?: unknown; error?: string } {
403
+ if (result.reason === "completed") {
404
+ const scriptResult = result.scriptResult;
405
+ return {
406
+ content:
407
+ typeof scriptResult === "string"
408
+ ? scriptResult
409
+ : JSON.stringify(scriptResult ?? ""),
410
+ parsedOutput:
411
+ typeof scriptResult === "object" && scriptResult !== null
412
+ ? scriptResult
413
+ : undefined,
414
+ };
415
+ }
416
+ return {
417
+ content: "",
418
+ error: result.error ?? `Workflow '${name}' ended: ${result.reason}`,
419
+ };
420
+ }
421
+
315
422
  /**
316
423
  * workflow() 嵌套调用的 Engine 实现。
317
424
  *
318
- * Worker 脚本内调 workflow(name, args) 时,error-recovery.dispatchWorkflowCall 路由
425
+ * Worker 脚本内调 workflow(name, args) 时,worker-message-pump.dispatchWorkflowCall 路由
319
426
  * 到 deps.onWorkflowCall,后者(Interface 层 makeDeps 注入)委托本函数。
320
427
  *
321
- * 流程(6 步):
428
+ * 流程(6 步,Step 2-6 的机制细节见各 helper):
322
429
  * 1. 循环检测——name 已在 parentWorkflowChain 中则拒绝(防 A→B→A 死循环)
323
- * 2. signal 继承——子 run 响应父 run abort(parentController → childController
430
+ * 2. signal 继承——子 run 响应父 run abort(inheritParentSignal
324
431
  * 3. registry.get + lint——失败返回 error result(不抛错,让脚本 soft-fail)
325
432
  * 4. 构建 RunSpec(共享父 Budget 引用 + parentWorkflowChain 延长)+ runWorkflow
326
433
  * 5. pollRunToResult 轮询至 done(复用 runAndWait 的轮询逻辑)
327
- * 6. 结果转换(budget 已通过共享引用实时同步)
434
+ * 6. 结果转换(toNestedCallResult)
328
435
  *
329
436
  * 不走 runAndWait:runAndWait 内部构建 RunSpec 不支持 parentWorkflowChain 与 budget
330
437
  * 共享引用,故直接构建 spec + runWorkflow + pollRunToResult。
@@ -342,10 +449,7 @@ export async function executeNestedWorkflow(
342
449
  deps: LauncherDeps,
343
450
  ): Promise<{ content: string; parsedOutput?: unknown; error?: string }> {
344
451
  // Step 1: 循环检测——parentWorkflowChain 不存在时为 [](顶层 run)
345
- const chain = [
346
- ...(parentRun.spec.parentWorkflowChain ?? []),
347
- parentRun.spec.scriptName,
348
- ];
452
+ const chain = buildParentChain(parentRun);
349
453
  if (chain.includes(name)) {
350
454
  return {
351
455
  content: "",
@@ -354,21 +458,10 @@ export async function executeNestedWorkflow(
354
458
  }
355
459
 
356
460
  // Step 2: signal 继承——子 run 响应父 run abort
357
- // [L-2] 提取命名 onParentAbort 以便 finally removeEventListener,防子 run 完成后
358
- // parentSignal 上残留 listener(多次嵌套调用会累积)。
359
- const childController = new AbortController();
360
- const parentSignal = parentRun.runtime?.controller.signal;
361
- const onParentAbort = (): void => childController.abort();
362
- if (parentSignal) {
363
- if (parentSignal.aborted) {
364
- childController.abort();
365
- } else {
366
- parentSignal.addEventListener("abort", onParentAbort, { once: true });
367
- }
368
- }
461
+ const { childController, parentSignal, onParentAbort } = inheritParentSignal(parentRun);
369
462
 
370
463
  // Step 3+:registry 查找 + lint + RunSpec + runWorkflow + poll 全程 try(m3 E8——
371
- // try 起点提到 Step 2 的 listener 注册之后,覆盖 Step 3-6。runWorkflow throw
464
+ // try 起点在 Step 2 的 listener 注册之后,覆盖 Step 3-6。runWorkflow throw
372
465
  // (含 chokepoint ArgsValidationError)与 not found/lint 早返回均走 finally 移除
373
466
  // parentSignal listener——修复原 try 外 runWorkflow 的泄漏路径)。
374
467
  try {
@@ -379,76 +472,30 @@ export async function executeNestedWorkflow(
379
472
  }
380
473
  const lintResult = script.validate();
381
474
  if (!lintResult.valid) {
382
- const errors = lintResult.findings
383
- .filter((f) => f.severity === "error")
384
- .map((f) => `L${f.line}: ${f.message}`)
385
- .join("; ");
386
475
  return {
387
476
  content: "",
388
- error: `Workflow script '${name}' has lint errors: ${errors}`,
477
+ error: `Workflow script '${name}' has lint errors: ${formatLintErrorSummary(lintResult)}`,
389
478
  };
390
479
  }
391
480
 
392
- // Step 4: 构建 RunSpec(共享父 Budget + 循环链)+ 启动子 workflow
393
- // budget 共享(F-7 方案 B):子 run 直接复用父 Budget 引用(budgetRef),consume 实时
394
- // 累加到父 Budget,消除并行嵌套下的超支窗口,无需 Step 6 sync-back。
395
- const spec: RunSpec = {
396
- scriptSource: script.toExecutable(),
397
- args,
398
- budgetRef: parentRun.state.budget,
399
- // Run-level override 传播(与父 run 对齐):子 run 继承父 run 的 model/thinkingLevel,
400
- // 否则嵌套 workflow 丢失父 run 的模型指定,回落主 agent 模型。
401
- model: parentRun.spec.model,
402
- thinkingLevel: parentRun.spec.thinkingLevel,
403
- scriptName: script.name,
404
- scriptPath: script.path,
405
- description: script.meta.description,
406
- parameters: script.meta.parameters,
407
- parentWorkflowChain: chain,
408
- };
481
+ // Step 4: 构建 RunSpec + 启动子 workflow
482
+ // budgetRef(共享 Budget)已在 spec 透传给子 run 处理 token/cost 预算,
483
+ // resolveNestedTimeoutMs budgetTimeMs 只服务 pollRunToResult 的轮询 deadline
484
+ // (wall-clock 兜底)。
485
+ const spec = buildNestedSpec(args, parentRun, script, chain);
409
486
  const runId = await runWorkflow(spec, deps, childController.signal);
410
487
 
411
488
  // Step 5: 轮询至 done(复用 runAndWait 的轮询逻辑)
412
- // [H-1] 嵌套 workflow timeout 从父 run 完整传导:父 spec.budgetTimeMs 显式设定时
413
- // 原样作为子 run 轮询 deadline(不 min(DEFAULT) 封顶——旧实现把父 time:2h 截断到
414
- // 10min,违背「显式传参完整生效」语义);父未设 → undefined,无 deadline(不限)。
415
- // budgetRef(共享 Budget)已在 Step 4 透传给子 run 处理 token/cost 预算,
416
- // 此处的 budgetTimeMs 只服务 pollRunToResult 的轮询 deadline(wall-clock 兜底)。
417
- // [U2] 预算语义统一:父 budgetTimeMs <=0(含 0/负)与 undefined 同义 = 不限——
418
- // 与 lifecycle.runWorkflow 的 budgetTimeMs 判定(>0 才挂 scheduleTimeBudget)对齐。
419
- // 旧实现 0 传导给子 run 后 deadline=now 立即超时("timed out after 0ms"),与
420
- // lifecycle 的 0=不限 语义分裂。pollRunToResult 内亦对非正值兜底归一(双写防漂移),
421
- // 此处显式归一是传导语义的文档化表达。
422
- const rawNestedTimeoutMs = parentRun.spec.budgetTimeMs;
423
- const nestedTimeoutMs =
424
- rawNestedTimeoutMs !== undefined && rawNestedTimeoutMs > 0 ? rawNestedTimeoutMs : undefined;
425
-
426
489
  const result = await pollRunToResult(
427
490
  runId,
428
491
  deps,
429
492
  childController.signal,
430
- nestedTimeoutMs,
493
+ resolveNestedTimeoutMs(parentRun),
431
494
  "Aborted by parent signal",
432
495
  );
433
496
 
434
- // Step 6: 结果转换(budget 已通过共享 budgetRef 实时同步,无需 sync-back)
435
- if (result.reason === "completed") {
436
- const scriptResult = result.scriptResult;
437
- return {
438
- content:
439
- typeof scriptResult === "string"
440
- ? scriptResult
441
- : JSON.stringify(scriptResult ?? ""),
442
- parsedOutput:
443
- typeof scriptResult === "object" && scriptResult !== null
444
- ? scriptResult
445
- : undefined,
446
- };
447
- }
448
- return {
449
- content: "",
450
- error: result.error ?? `Workflow '${name}' ended: ${result.reason}`,
451
- };
497
+ // Step 6: 结果转换
498
+ return toNestedCallResult(name, result);
452
499
  } catch (err) {
453
500
  // m3:chokepoint 校验失败 → {error}(§5.3 指引文案),非 ArgsValidationError 保持传播
454
501
  // (dispatchWorkflowCall 的 .catch 兜底转 postResult,worker 不崩)。
@@ -24,7 +24,7 @@
24
24
  * 「releaseRuntime → 改 status」原子顺序。
25
25
  *
26
26
  * **G3-001**(run 一次性生命周期):AbortController 一次性无法复用,runtime 释放后
27
- * 只有两类重建——rebuildRuntime(error-recovery,崩溃重试路径,run 保持 running、
27
+ * 只有两类重建——rebuildRuntime(worker-message-pump,崩溃重试路径,run 保持 running、
28
28
  * replaceRuntime 原子换新)与 abort/terminate 的终态释放(transition("done") 内
29
29
  * releaseRuntime,run 不再恢复)。
30
30
  * (旧并发门闩 gate 抽象已删——no-op 无生产语义,实际并发由 SubagentService
@@ -42,12 +42,11 @@ import { assertSafeTimerDelay } from "../shared/timer-delay.ts";
42
42
  import { validateRunArgs } from "./args-validator.ts";
43
43
  import {
44
44
  closeOutInFlightCalls,
45
- emitPendingUnregister,
46
- emitTerminalSideEffects,
45
+ finalizeRun,
47
46
  handleWorkerError,
48
47
  handleWorkerExit,
49
48
  handleWorkerMessage,
50
- } from "./error-recovery.ts";
49
+ } from "./worker-message-pump.ts";
51
50
  import { Budget } from "./models/budget.ts";
52
51
  import type { LifecycleDeps, RunStore, WorkerHandlers } from "./models/ports.ts";
53
52
  import { RunRuntime } from "./models/run-runtime.ts";
@@ -56,6 +55,7 @@ import { Trace } from "./models/trace.ts";
56
55
  import type { DoneReason } from "./models/types.ts";
57
56
  import { WorkflowRun } from "./models/workflow-run.ts";
58
57
  import type { WorkerHandle } from "./worker-handle.ts";
58
+ import { toErrorMessage } from "../core/error-message.ts";
59
59
 
60
60
  const logger = getLogger("subagents");
61
61
 
@@ -118,24 +118,24 @@ function broadcastAbortToWorker(run: WorkflowRun, reason: string): void {
118
118
  try {
119
119
  run.runtime?.worker.postMessage({ type: "abort", reason });
120
120
  } catch (err) {
121
- const msg = err instanceof Error ? err.message : String(err);
121
+ const msg = toErrorMessage(err);
122
122
  logger.debug(
123
123
  `[workflow] abort broadcast to worker failed (runId=${run.runId}, worker likely already exited): ${msg}`,
124
124
  );
125
125
  }
126
126
  }
127
127
 
128
- // ── makeHandlers(路由 worker 事件到 error-recovery handle* 函数) ──────
128
+ // ── makeHandlers(路由 worker 事件到 worker-message-pump handle* 函数) ──────
129
129
 
130
130
  /**
131
131
  * 构造 WorkerHandlers——将 worker 的 onMessage/onError/onExit 事件路由到
132
- * error-recovery 的 handleWorker* 函数。
132
+ * worker-message-pump 的 handleWorker* 函数。
133
133
  *
134
134
  * 闭包捕获 run + deps。runtime 重建(replaceRuntime)后 run 实例不变、deps 不变,
135
- * 故 handlers 对新 worker 仍有效(lifecycle 与 error-recovery 共用 handlers)。
135
+ * 故 handlers 对新 worker 仍有效(lifecycle 与 worker-message-pump 共用 handlers)。
136
136
  *
137
137
  * **onExit G-025**:handleWorkerExit 内部检查 handle.isCurrent(stale exit 丢弃)。
138
- * 本函数不在 onExit 里重复检查——error-recovery.handleWorkerExit 是单一守卫点。
138
+ * 本函数不在 onExit 里重复检查——worker-message-pump.handleWorkerExit 是单一守卫点。
139
139
  *
140
140
  * **workerErrorCount**:onError 触发时递增(C.5 跨 runtime 存活的重试计数载体)。
141
141
  * 注意 handleWorkerError 内部也会递增——这里 onError 递增是 worker 事件层面的
@@ -144,10 +144,10 @@ function broadcastAbortToWorker(run: WorkflowRun, reason: string): void {
144
144
  */
145
145
  function makeHandlers(run: WorkflowRun, deps: LifecycleDeps): WorkerHandlers {
146
146
  // [OR-7] per-run deps 视图:包装 onRunDone,把「run 终态」转译为「移除 signal abort
147
- // listener」。error-recovery 全部终态路径(handleReturn / handleWorkerError /
147
+ // listener」。worker-message-pump 全部终态路径(handleReturn / handleWorkerError /
148
148
  // handleScriptError / handleWorkerExit / 预算终止 / time_limited / [OR-2] rebuild
149
- // 失败收敛)都经 handlers 调用链消费本视图——消息面终态在此统一收口;
150
- // abortRun / terminateRunningRuns 两个 lifecycle 自有终态路径另行显式 dispose。
149
+ // 失败收敛——均经 finalizeRun)都经 handlers 调用链消费本视图——消息面终态在此
150
+ // 统一收口;abortRun / terminateRunningRuns 两个 lifecycle 自有终态路径另行显式 dispose。
151
151
  const depsWithTerminalCleanup: LifecycleDeps = {
152
152
  ...deps,
153
153
  onRunDone: (doneRun: WorkflowRun): void => {
@@ -155,7 +155,7 @@ function makeHandlers(run: WorkflowRun, deps: LifecycleDeps): WorkerHandlers {
155
155
  deps.onRunDone?.(doneRun);
156
156
  },
157
157
  };
158
- // 自引用——error-recovery rebuildRuntime 需要 handlers 参数(handlers 引用自身)
158
+ // 自引用——worker-message-pump rebuildRuntime 需要 handlers 参数(handlers 引用自身)
159
159
  const handlers: WorkerHandlers = {
160
160
  async onMessage(raw: unknown): Promise<void> {
161
161
  await handleWorkerMessage(run, raw, depsWithTerminalCleanup, handlers);
@@ -198,7 +198,7 @@ export function scheduleTimeBudget(
198
198
  const timer = setTimeout(() => {
199
199
  void abortRun(runId, deps, "Time budget exceeded", "time_limited").catch(
200
200
  (err: unknown) => {
201
- const msg = err instanceof Error ? err.message : String(err);
201
+ const msg = toErrorMessage(err);
202
202
  logger.error(`[workflow] time budget abort failed: ${msg}`);
203
203
  },
204
204
  );
@@ -213,7 +213,7 @@ export function scheduleTimeBudget(
213
213
  /**
214
214
  * rfl 仪表(tier-1 §7.1):向 spec.args 原地注入稳定 _runId。runAndWait 与
215
215
  * executeNestedWorkflow 两个 args 入口都经 runWorkflow 这一 choke point;
216
- * rebuildRuntime 复用 run.spec.args 同一对象(error-recovery.ts),worker rebuild
216
+ * rebuildRuntime 复用 run.spec.args 同一对象(worker-message-pump.ts),worker rebuild
217
217
  * 后脚本侧 $ARGS._runId 不漂移——修复「rebuild 回退 run-<Date.now()> 导致同一
218
218
  * 逻辑 run 碎裂到多个 state 目录」。注入在 validateRunArgs 之后,不参与脚本
219
219
  * 参数 schema 校验(引擎内部字段)。
@@ -307,7 +307,7 @@ function registerSignalAbortListener(
307
307
  const onAbort = (): void => {
308
308
  disposeSignalAbortListener(run);
309
309
  void abortRun(runId, deps, "External signal aborted").catch((err: unknown) => {
310
- const msg = err instanceof Error ? err.message : String(err);
310
+ const msg = toErrorMessage(err);
311
311
  logger.error(`[workflow] abortRun on signal failed: ${msg}`);
312
312
  });
313
313
  };
@@ -426,20 +426,16 @@ export async function abortRun(
426
426
  // [OR-3] 先广播 abort 再 transition(transition 内 releaseRuntime→terminate,
427
427
  // terminate 之后广播发不进去)——worker 侧 pending 优雅解阻
428
428
  broadcastAbortToWorker(run, reason ?? `Workflow aborted (${doneReason})`);
429
- // A4: transition 内部 releaseRuntime(cleanup before mutate)
430
- run.transition("done", doneReason);
431
429
  // [OR-7] run 终态:移除 signal abort listener(幂等;abort 由 signal 触发时
432
- // listener 已在 onAbort 内自移除,此处为其余 abort 入口的收口)
430
+ // listener 已在 onAbort 内自移除,此处为其余 abort 入口的收口;即使 finalizeRun
431
+ // 因并发终态化让位,WeakMap 条目也应清除,不依赖 transition 成败)
433
432
  disposeSignalAbortListener(run);
434
- // [OR-8] 终态收口残留 in-flight call(先收口再落盘——快照不再含 running 节点)
435
- closeOutInFlightCalls(run);
436
- await deps.store.save(run);
437
- deps.log?.("debug", "workflow:lifecycle", "abortRun transition done", { runId, reason: run.state.reason });
438
- // C-4: run 到达 done 终态 → 注销 pending-notification + 通知 Interface
439
- // [OR-4][B-4] M12 同款围栏(emit pending:unregister + onRunDone 各自独立 try)——
440
- // listener 同步抛错不再跳过 onRunDone 或把错误抛给 abort 调用方;错误 error 留痕后
441
- // 本函数仍按 abort 成功语义正常返回(内存态已终态)。
442
- emitTerminalSideEffects(run, deps, `abortRun (done,${doneReason})`);
433
+ // A4 + C-4: transition 内部 releaseRuntime(cleanup before mutate);到达 done 终态
434
+ // → 注销 pending-notification + 通知 Interface 层(D5-② 终态 coda 收敛为
435
+ // worker-message-pump 的 finalizeRun 单写点——OR-8 in-flight 收口 + save best-effort
436
+ // (SW-DATA-3)不再向上抛,内存态已终态,调用方无需因落盘失败收到 abort 异常;
437
+ // OR-4/B-4 unregister onRunDone 各自独立围栏)
438
+ await finalizeRun(run, deps, doneReason, { context: `abortRun (${doneReason})` });
443
439
  }
444
440
 
445
441
  // ── terminateRunningRuns(session 切换/关闭:终止全部 running run) ────────
@@ -451,11 +447,12 @@ export async function abortRun(
451
447
  * done,failed 持久化落盘——重启后 kill-9 恢复不误判,也不再存在「挂起待恢复」
452
448
  * 的中间态。
453
449
  *
454
- * per-run 行为:`state.error = reason` → `transition("done","failed")`(内部先
455
- * releaseRuntime,A4)→ `await store.save(run)` `eventBus.emit("pending:unregister",
456
- * {reason:"failed"})`。
450
+ * per-run 行为:`state.error = reason` → `finalizeRun(run, deps, "failed",
451
+ * {notifyDone:false})`(transition("done","failed") 内部先 releaseRuntime,A4 →
452
+ * save best-effort → `eventBus.emit("pending:unregister", {reason:"failed"})`)。
457
453
  *
458
- * **不调 deps.onRunDone**:对齐 session_start 恢复先例(index.ts kill-9 恢复只发
454
+ * **不调 deps.onRunDone**(经 finalizeRun notifyDone:false 承载,D5-②):
455
+ * 对齐 session_start 恢复先例(index.ts kill-9 恢复只发
459
456
  * unregister、不发 onRunDone)——session 切换/关闭语境下主 agent 已离开本 session,
460
457
  * 注入完成通知只会把消息发给已离开的 session。
461
458
  *
@@ -480,21 +477,22 @@ export async function terminateRunningRuns(
480
477
  run.state.error = reason;
481
478
  // [OR-3] 同 abortRun:先广播 abort 再 transition(worker 侧 pending 优雅解阻)
482
479
  broadcastAbortToWorker(run, reason);
483
- // A4: transition 内部先 releaseRuntime(cleanup before mutate)
484
- run.transition("done", "failed");
485
480
  // [OR-7] run 终态:移除 signal abort listener(terminateRunningRuns 不走
486
- // onRunDone——本路径显式收口)
481
+ // onRunDone——本路径显式收口,不依赖 finalizeRun 的 notifyDone 分支)
487
482
  disposeSignalAbortListener(run);
488
- // [OR-8] 终态收口残留 in-flight call(先收口再落盘)
489
- closeOutInFlightCalls(run);
490
- await deps.store.save(run);
491
- // C-4: run 到达 done 终态 → 注销 pending-notification(reason 固定 "failed")。
492
- // [B-4] M12 同款围栏:emit 单独 try(listener 同步抛错 error 留痕不中断本 run
493
- // 收尾日志与其余 run 的终止;本路径不调 onRunDone——session 离开语境不发完成通知)。
494
- emitPendingUnregister(run, deps, "terminateRunningRuns");
483
+ // A4 + C-4: transition 内部 releaseRuntime(cleanup before mutate);done 终态 →
484
+ // 注销 pending-notification(D5-② 终态 coda 收敛为 finalizeRun 单写点)。
485
+ // notifyDone: false——**不调 deps.onRunDone**(真差异经参数承载):对齐
486
+ // session_start 恢复先例(index.ts kill-9 恢复只发 unregister、不发
487
+ // onRunDone)——session 切换/关闭语境下主 agent 已离开本 session,注入完成
488
+ // 通知只会把消息发给已离开的 session。OR-8 in-flight 收口由 finalizeRun 承载。
489
+ await finalizeRun(run, deps, "failed", {
490
+ context: "terminateRunningRuns",
491
+ notifyDone: false,
492
+ });
495
493
  deps.log?.("debug", "workflow:lifecycle", "run terminated", { runId: run.runId, reason: run.state.reason });
496
494
  } catch (err) {
497
- const msg = err instanceof Error ? err.message : String(err);
495
+ const msg = toErrorMessage(err);
498
496
  logger.error(
499
497
  `[workflow] terminateRunningRuns failed for run ${run.runId}: ${msg} (reason: ${reason})`,
500
498
  );
@@ -644,7 +642,7 @@ export async function recoverCrashedRuns(
644
642
  try {
645
643
  hooks?.onRunRecovered?.({ id: run.runId, reason: "failed" });
646
644
  } catch (err) {
647
- const msg = err instanceof Error ? err.message : String(err);
645
+ const msg = toErrorMessage(err);
648
646
  logger.warn(
649
647
  `[workflow] recoverCrashedRuns onRunRecovered hook failed for run ${run.runId} (recovery continues): ${msg}`,
650
648
  );
@@ -653,7 +651,7 @@ export async function recoverCrashedRuns(
653
651
  try {
654
652
  await store.save(run);
655
653
  } catch (err) {
656
- const msg = err instanceof Error ? err.message : String(err);
654
+ const msg = toErrorMessage(err);
657
655
  logger.error(
658
656
  `[workflow] recoverCrashedRuns store.save failed for run ${run.runId}: ${msg} (reason: ${reason})`,
659
657
  );
@@ -5,7 +5,7 @@
5
5
  * 是真需要 mock 测试的依赖(子进程/文件系统/线程)。
6
6
  *
7
7
  * 编排层共享类型(WorkerHandlers / LifecycleDeps)——打破 lifecycle ↔
8
- * error-recovery 循环依赖:2 个 engine 函数文件各自独立,共用同一组
8
+ * worker-message-pump 循环依赖:2 个 engine 函数文件各自独立,共用同一组
9
9
  * 依赖签名(D-12)。
10
10
  *
11
11
  * 层归属:Engine。零 infra 依赖(AC-1)。
@@ -71,7 +71,7 @@ export interface WorkerHost {
71
71
 
72
72
  /**
73
73
  * Worker 线程事件回调集合——WorkerHost.start 的入参,由 lifecycle
74
- * 构造并注入。2 个 engine 文件(lifecycle / error-recovery)共用此签名,
74
+ * 构造并注入。2 个 engine 文件(lifecycle / worker-message-pump)共用此签名,
75
75
  * 避免各自定义形状不一致的 handler bag(打破循环依赖)。
76
76
  *
77
77
  * 所有回调返回 Promise——允许 engine 层在回调内做 await persistState 等异步操作。
@@ -88,7 +88,7 @@ export interface WorkerHandlers {
88
88
  // ── 编排层共享类型 2: LifecycleDeps ────────────────────────────
89
89
 
90
90
  /**
91
- * lifecycle / error-recovery 2 个 engine 函数文件的共同依赖 bag。
91
+ * lifecycle / worker-message-pump 2 个 engine 函数文件的共同依赖 bag。
92
92
  *
93
93
  * 取代旧 4 个 Context factory(errorHandlerContext / agentCallContext /
94
94
  * budgetCallbacks / 旧 terminate bag,AC-2 目标)。函数签名 `(deps: LifecycleDeps, ...)`
@@ -142,7 +142,7 @@ export interface LifecycleDeps {
142
142
  * workflow() 嵌套调用回调(可选)。Worker 脚本内调 workflow(name, args) 时触发。
143
143
  *
144
144
  * 由 Interface 层 makeDeps 注入(闭包捕获 registry + deps)。Engine 层的
145
- * error-recovery.handleWorkerMessage 收到 workflow-call 消息后调本回调,
145
+ * worker-message-pump.handleWorkerMessage 收到 workflow-call 消息后调本回调,
146
146
  * 拿到子 workflow 执行结果后 postMessage(workflow-result) 回 worker。
147
147
  *
148
148
  * 不注入时 workflow() 返回 error result(向后兼容,不影响非嵌套场景)。