@zhushanwen/pi-subagent-workflow 8.5.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/package.json +13 -16
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +142 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +157 -0
  16. package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
  17. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  18. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  19. package/src/interface/bg-notify-render.ts +34 -13
  20. package/src/interface/commands.ts +3 -3
  21. package/src/interface/format.ts +2 -2
  22. package/src/interface/helpers.ts +3 -3
  23. package/src/interface/list-component.ts +4 -4
  24. package/src/interface/list-shared.ts +2 -2
  25. package/src/interface/list-view.ts +2 -2
  26. package/src/interface/subagent-actions.ts +288 -19
  27. package/src/interface/subagent-tool-schema.ts +163 -0
  28. package/src/interface/subagent-tool.ts +65 -129
  29. package/src/interface/subagents.ts +5 -5
  30. package/src/interface/tool-render.ts +34 -2
  31. package/src/interface/tool-workflow-script.ts +4 -4
  32. package/src/interface/tool-workflow.ts +6 -6
  33. package/src/interface/views/WorkflowsView.ts +5 -5
  34. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  35. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  36. package/src/interface/views/detail-content.ts +4 -4
  37. package/src/interface/views/format.ts +4 -4
  38. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +132 -18
  39. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  40. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  41. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  42. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  43. package/src/execution/__tests__/alive-store.test.ts +0 -147
  44. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  45. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  46. package/src/execution/__tests__/bg-notify-render.test.ts +0 -256
  47. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  48. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -597
  49. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  50. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  51. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  52. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  53. package/src/execution/__tests__/config.test.ts +0 -110
  54. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  55. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  56. package/src/execution/__tests__/delivery-methods.test.ts +0 -385
  57. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  58. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  59. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  60. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  61. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -189
  62. package/src/execution/__tests__/execution-record.test.ts +0 -1284
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -138
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -238
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -593
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -337
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -109
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -413
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -574
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  87. package/src/execution/__tests__/output-collector.test.ts +0 -61
  88. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  89. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  90. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  91. package/src/execution/__tests__/record-store.test.ts +0 -1057
  92. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  93. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  94. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  95. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  96. package/src/execution/__tests__/relay-env.test.ts +0 -42
  97. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  98. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -644
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  105. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  106. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  107. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  108. package/src/execution/__tests__/session-pending.test.ts +0 -197
  109. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  110. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -311
  112. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  113. package/src/execution/__tests__/spawn-args.test.ts +0 -434
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  117. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  118. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  119. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  120. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  122. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  124. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  125. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  126. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  127. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -506
  128. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  129. package/src/execution/__tests__/timeout-integration.test.ts +0 -397
  130. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  131. package/src/execution/__tests__/tool-action.test.ts +0 -385
  132. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  133. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  134. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  135. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  136. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  137. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  138. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  139. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  140. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  141. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  142. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  143. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  144. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  145. package/src/execution/agent-registry.ts +0 -193
  146. package/src/execution/agent-result-mapper.ts +0 -90
  147. package/src/execution/alive-store.ts +0 -92
  148. package/src/execution/argv-mirror.ts +0 -109
  149. package/src/execution/best-effort.ts +0 -38
  150. package/src/execution/channel-registry-access.ts +0 -144
  151. package/src/execution/concurrency-pool.ts +0 -116
  152. package/src/execution/config.ts +0 -96
  153. package/src/execution/dialog-queue.ts +0 -330
  154. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  155. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  156. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  158. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  159. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  160. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  161. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  162. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  163. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  164. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  165. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  166. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  167. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  168. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  169. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  170. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  171. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  172. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  173. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  174. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  175. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  176. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  177. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  178. package/src/execution/engine/common/data-dir.ts +0 -62
  179. package/src/execution/engine/common/errors.ts +0 -183
  180. package/src/execution/engine/common/event-journal.ts +0 -254
  181. package/src/execution/engine/common/journal-replay.ts +0 -62
  182. package/src/execution/engine/common/kill-chain.ts +0 -221
  183. package/src/execution/engine/common/nesting-guard.ts +0 -50
  184. package/src/execution/engine/common/persona-router.ts +0 -108
  185. package/src/execution/engine/common/pool-manager.ts +0 -226
  186. package/src/execution/engine/common/schema-emulation.ts +0 -189
  187. package/src/execution/engine/common/session-view-projection.ts +0 -51
  188. package/src/execution/engine/engine-discovery.ts +0 -65
  189. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  190. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  191. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  192. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  193. package/src/execution/engine/engines/pi/reader.ts +0 -48
  194. package/src/execution/engine/engines/pi/registration.ts +0 -35
  195. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  197. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  198. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  199. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  200. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  201. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -567
  204. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  205. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  206. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  207. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  208. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  209. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  210. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  211. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -648
  212. package/src/execution/engine/host-task-spec.ts +0 -47
  213. package/src/execution/engine/model-prompt.ts +0 -59
  214. package/src/execution/engine/paths.ts +0 -42
  215. package/src/execution/engine/port.ts +0 -153
  216. package/src/execution/engine/registry.ts +0 -123
  217. package/src/execution/engine/routing.ts +0 -218
  218. package/src/execution/engine/types.ts +0 -304
  219. package/src/execution/execute-options-mapper.ts +0 -111
  220. package/src/execution/execution-record.ts +0 -906
  221. package/src/execution/finalize-record.ts +0 -251
  222. package/src/execution/finalized-marker.ts +0 -51
  223. package/src/execution/get-state-handshake.ts +0 -104
  224. package/src/execution/host-mode.ts +0 -56
  225. package/src/execution/idle-gc.ts +0 -47
  226. package/src/execution/lifecycle-manager.ts +0 -491
  227. package/src/execution/lifecycle-predicates.ts +0 -65
  228. package/src/execution/manifest-store.ts +0 -256
  229. package/src/execution/model-config-service.ts +0 -204
  230. package/src/execution/model-resolver.ts +0 -276
  231. package/src/execution/notifier.ts +0 -260
  232. package/src/execution/output-collector.ts +0 -88
  233. package/src/execution/path-encoding.ts +0 -60
  234. package/src/execution/pi-invocation.ts +0 -120
  235. package/src/execution/record-entry.ts +0 -132
  236. package/src/execution/record-store.ts +0 -1234
  237. package/src/execution/relay-env.ts +0 -37
  238. package/src/execution/session-context-resolver.ts +0 -64
  239. package/src/execution/session-file-gc.ts +0 -120
  240. package/src/execution/session-pending.ts +0 -164
  241. package/src/execution/session-reconstructor.ts +0 -678
  242. package/src/execution/session-runner.ts +0 -1548
  243. package/src/execution/sessions-index.ts +0 -304
  244. package/src/execution/spawn-event-adapter.ts +0 -363
  245. package/src/execution/stdin-writer.ts +0 -198
  246. package/src/execution/stream-sink.ts +0 -126
  247. package/src/execution/subagent-service.ts +0 -2119
  248. package/src/execution/subprocess-agent-runner.ts +0 -303
  249. package/src/execution/temp-prompt.ts +0 -62
  250. package/src/execution/tombstone-store.ts +0 -72
  251. package/src/execution/turn-limiter.ts +0 -102
  252. package/src/execution/types.ts +0 -910
  253. package/src/execution/ui-channels.ts +0 -216
  254. package/src/execution/ui-interaction-model.ts +0 -48
  255. package/src/execution/ui-request-handler-factory.ts +0 -212
  256. package/src/execution/ui-request-observability.ts +0 -81
  257. package/src/execution/ui-request-queue.ts +0 -174
  258. package/src/execution/worktree-manager.ts +0 -688
  259. package/src/execution/worktree-registry.ts +0 -222
  260. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -336
  261. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -208
  262. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -157
  263. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  264. package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
  265. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  266. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -724
  267. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  268. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  269. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  270. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -314
  271. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  272. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  273. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -277
  274. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  275. package/src/orchestration/__tests__/lifecycle.test.ts +0 -625
  276. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -1971
  277. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  278. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -157
  279. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  280. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  281. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  282. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -520
  283. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  284. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -110
  285. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  286. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  287. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  288. package/src/orchestration/agent-opts-resolver.ts +0 -93
  289. package/src/orchestration/args-validator.ts +0 -127
  290. package/src/orchestration/concurrency-gate.ts +0 -69
  291. package/src/orchestration/config-loader.ts +0 -315
  292. package/src/orchestration/error-recovery.ts +0 -862
  293. package/src/orchestration/execute-agent-call.ts +0 -217
  294. package/src/orchestration/launcher.ts +0 -410
  295. package/src/orchestration/lifecycle.ts +0 -396
  296. package/src/orchestration/models/__tests__/budget.test.ts +0 -367
  297. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  298. package/src/orchestration/models/agent-call.ts +0 -83
  299. package/src/orchestration/models/budget.ts +0 -148
  300. package/src/orchestration/models/ports.ts +0 -164
  301. package/src/orchestration/models/run-runtime.ts +0 -89
  302. package/src/orchestration/models/run-spec.ts +0 -83
  303. package/src/orchestration/models/run-state.ts +0 -44
  304. package/src/orchestration/models/trace.ts +0 -183
  305. package/src/orchestration/models/types.ts +0 -292
  306. package/src/orchestration/models/workflow-run.ts +0 -254
  307. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  308. package/src/orchestration/models/workflow-script.ts +0 -117
  309. package/src/orchestration/script-lint.ts +0 -766
  310. package/src/orchestration/skill-discovery.ts +0 -92
  311. package/src/orchestration/worker-handle.ts +0 -115
  312. package/src/orchestration/worker-host.ts +0 -98
  313. package/src/orchestration/worker-script-builder.ts +0 -408
  314. package/src/orchestration/workflow-files.ts +0 -85
  315. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  316. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  317. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  318. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  319. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  320. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  321. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  322. package/src/shared/agent-event.ts +0 -13
  323. package/src/shared/agent-ref.ts +0 -57
  324. package/src/shared/meta-parser.ts +0 -261
  325. package/src/shared/resource-discovery.ts +0 -811
  326. package/src/shared/resource-meta.ts +0 -65
  327. package/src/shared/schema-jsonify.ts +0 -56
  328. package/src/shared/xml-injection.ts +0 -35
  329. package/workflows/README.md +0 -81
  330. package/workflows/_shared/agent-refs.cjs +0 -40
  331. package/workflows/chain.js +0 -131
  332. package/workflows/map-reduce.js +0 -174
  333. package/workflows/parallel.js +0 -148
  334. package/workflows/review-fix-loop-utils.cjs +0 -1307
  335. package/workflows/review-fix-loop.js +0 -1396
  336. package/workflows/scatter-gather.js +0 -178
@@ -1,724 +0,0 @@
1
- /**
2
- * error-recovery handlers — handleWorkerExit/Error/ScriptError + postBudgetUpdate 测试。
3
- *
4
- * 参考 error-recovery-workflow-call.test.ts 的 mock 构建。通过 vi.useFakeTimers() 跳过
5
- * scheduleRebuild 的指数退避(1s/2s/4s)。
6
- *
7
- * 覆盖:
8
- * - handleWorkerExit:code=0 正常退出(no-op) / code!=0 委托 handleWorkerError / stale handle 过滤
9
- * - handleWorkerError:超限(count > MAX=3)→ transition done,failed + emit pending:unregister
10
- * / 未超限 → rebuildRuntime(workerHost.start 重建)
11
- * - handleScriptError:超限 → transition done,failed / workerLogs 捕获
12
- * - postBudgetUpdate:postMessage budget-update(usedTokens/usedCost)
13
- * - stale handle 过滤(handle.isCurrent=false)+ terminal stale 守卫(isTerminal 语义)
14
- * - rebuildRuntime:worker 崩溃后 workerHost.start + scheduleTimeBudget 重排 + replaceRuntime
15
- * + 在飞 call 清理(discardInFlightCalls 生效:在飞清除、done 保留)
16
- */
17
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
18
-
19
- import { ConcurrencyGate } from "../concurrency-gate.ts";
20
- import {
21
- handleScriptError,
22
- handleWorkerError,
23
- handleWorkerExit,
24
- handleWorkerMessage,
25
- postBudgetUpdate,
26
- rebuildRuntime,
27
- } from "../error-recovery.ts";
28
- import { Budget } from "../models/budget.ts";
29
- import { RunRuntime } from "../models/run-runtime.ts";
30
- import { Trace } from "../models/trace.ts";
31
- import type { AgentResult } from "../models/types.ts";
32
- import { WorkflowRun } from "../models/workflow-run.ts";
33
- import type { LifecycleDeps, WorkerHandlers } from "../models/ports.ts";
34
- import type { WorkerHandle } from "../worker-handle.ts";
35
-
36
- // ── helpers ──────────────────────────────────────────────────
37
-
38
- /** 构造一个 status="running" 的 mock WorkflowRun,meta 可配置。 */
39
- function makeRunningRun(opts: {
40
- workerErrorCount?: number;
41
- scriptErrorCount?: number;
42
- budgetTimeMs?: number;
43
- postMessage?: ReturnType<typeof vi.fn>;
44
- } = {}): WorkflowRun {
45
- return {
46
- state: {
47
- status: "running",
48
- budget: { usedTokens: 50, usedCost: 0.1 },
49
- // L9: errorLogs 现在用 push 追加——必须是真实数组,不能省略
50
- errorLogs: [],
51
- // rebuildRuntime 内 discardInFlightCalls 遍历 calls + 移除 trace 节点——
52
- // 必须是真实 Map(空 = 无在飞 call,discard 为 no-op)
53
- calls: new Map(),
54
- trace: { removeByStepIndex: vi.fn() },
55
- },
56
- meta: {
57
- startedAt: new Date().toISOString(),
58
- workerErrorCount: opts.workerErrorCount,
59
- scriptErrorCount: opts.scriptErrorCount,
60
- },
61
- spec: {
62
- scriptName: "test-wf",
63
- scriptSource: "execute() {}",
64
- args: {},
65
- budgetTimeMs: opts.budgetTimeMs,
66
- },
67
- runtime: {
68
- worker: { postMessage: opts.postMessage ?? vi.fn() },
69
- },
70
- // transition 副作用——run.state.status 由调用方通过 mock 控制后再次断言
71
- transition(target: string, reason?: string): void {
72
- this.state.status = target;
73
- if (target === "done") this.state.reason = reason;
74
- },
75
- replaceRuntime(rt: unknown): void {
76
- this.runtime = rt;
77
- },
78
- } as unknown as WorkflowRun;
79
- }
80
-
81
- /** LifecycleDeps mock:store/workerHost/runner/eventBus/scheduleTimeBudget 可观察。 */
82
- function makeDeps(opts: {
83
- scheduleTimeBudget?: LifecycleDeps["scheduleTimeBudget"];
84
- } = {}): LifecycleDeps & {
85
- store: { save: ReturnType<typeof vi.fn> };
86
- workerHost: { start: ReturnType<typeof vi.fn> };
87
- eventBus: { emit: ReturnType<typeof vi.fn> };
88
- onRunDone: ReturnType<typeof vi.fn>;
89
- log: ReturnType<typeof vi.fn>;
90
- } {
91
- return {
92
- store: { save: vi.fn(async () => {}) },
93
- workerHost: { start: vi.fn(() => ({ postMessage: vi.fn() })) },
94
- runner: { run: vi.fn(async () => ({})) },
95
- runs: new Map(),
96
- eventBus: { emit: vi.fn() },
97
- onRunDone: vi.fn(),
98
- log: vi.fn(),
99
- scheduleTimeBudget: opts.scheduleTimeBudget,
100
- } as unknown as ReturnType<typeof makeDeps>;
101
- }
102
-
103
- /** WorkerHandlers 占位(handler 路径递归调本对象上的回调,但测试场景不触发)。 */
104
- function makeHandlers(): WorkerHandlers {
105
- return {
106
- onMessage: vi.fn(async () => {}),
107
- onError: vi.fn(async () => {}),
108
- onExit: vi.fn(async () => {}),
109
- } as unknown as WorkerHandlers;
110
- }
111
-
112
- /** 构造 mock WorkerHandle(isCurrent 可配)。 */
113
- function makeHandle(isCurrent = true): WorkerHandle {
114
- return { isCurrent } as unknown as WorkerHandle;
115
- }
116
-
117
- beforeEach(() => {
118
- vi.useFakeTimers();
119
- });
120
-
121
- afterEach(() => {
122
- vi.useRealTimers();
123
- });
124
-
125
- // ── handleWorkerExit ─────────────────────────────────────────
126
-
127
- describe("handleWorkerExit", () => {
128
- it("code=0 正常退出:no-op(不 transition、不 save)", async () => {
129
- const run = makeRunningRun();
130
- const deps = makeDeps();
131
- const handle = makeHandle(true);
132
-
133
- await handleWorkerExit(run, 0, handle, deps, makeHandlers());
134
-
135
- expect(run.state.status).toBe("running"); // 未改
136
- expect(deps.store.save).not.toHaveBeenCalled();
137
- expect(deps.eventBus.emit).not.toHaveBeenCalled();
138
- });
139
-
140
- it("code!=0 异常退出:委托 handleWorkerError → 超 MAX 重试 → transition done,failed", async () => {
141
- // workerErrorCount 已达 MAX=3 → handleWorkerError 内 count=4 > 3 → failed
142
- const run = makeRunningRun({ workerErrorCount: 3 });
143
- const deps = makeDeps();
144
- const handle = makeHandle(true);
145
-
146
- await handleWorkerExit(run, 1, handle, deps, makeHandlers());
147
-
148
- expect(run.state.status).toBe("done");
149
- expect(run.state.reason).toBe("failed");
150
- expect(run.state.error).toContain("Worker exited with code 1");
151
- // 持久化 + 完成通知
152
- expect(deps.store.save).toHaveBeenCalledTimes(1);
153
- expect(deps.onRunDone).toHaveBeenCalledTimes(1);
154
- });
155
-
156
- it("stale handle(isCurrent=false):丢弃 exit 事件,不处理", async () => {
157
- const run = makeRunningRun();
158
- const deps = makeDeps();
159
- const staleHandle = makeHandle(false);
160
-
161
- await handleWorkerExit(run, 1, staleHandle, deps, makeHandlers());
162
-
163
- // 状态未变,store 未 save
164
- expect(run.state.status).toBe("running");
165
- expect(deps.store.save).not.toHaveBeenCalled();
166
- });
167
-
168
- it("run 已终态(done):stale 守卫前置丢弃", async () => {
169
- const run = makeRunningRun();
170
- run.state.status = "done";
171
- (run.state as { reason?: string }).reason = "completed";
172
- const deps = makeDeps();
173
- const handle = makeHandle(true);
174
-
175
- await handleWorkerExit(run, 1, handle, deps, makeHandlers());
176
-
177
- expect(deps.store.save).not.toHaveBeenCalled();
178
- });
179
- });
180
-
181
- // ── handleWorkerError ────────────────────────────────────────
182
-
183
- describe("handleWorkerError", () => {
184
- it("count > MAX(3):transition done,failed + save + emit pending:unregister", async () => {
185
- // workerErrorCount=3 → count=4 > MAX
186
- const run = makeRunningRun({ workerErrorCount: 3 });
187
- const deps = makeDeps();
188
-
189
- await handleWorkerError(run, new Error("worker boom"), deps, makeHandlers());
190
-
191
- expect(run.meta.workerErrorCount).toBe(4);
192
- expect(run.state.status).toBe("done");
193
- expect(run.state.reason).toBe("failed");
194
- expect(run.state.error).toBe("worker boom");
195
- expect(deps.store.save).toHaveBeenCalledTimes(1);
196
- expect(deps.eventBus.emit).toHaveBeenCalledWith("pending:unregister", {
197
- id: undefined, // mock run 无 runId
198
- reason: "failed",
199
- });
200
- expect(deps.onRunDone).toHaveBeenCalledTimes(1);
201
- });
202
-
203
- it("count <= MAX:退避 + rebuildRuntime(workerHost.start 重建新 runtime)", async () => {
204
- const run = makeRunningRun({ workerErrorCount: 0 }); // count=1 <= MAX
205
- const deps = makeDeps();
206
-
207
- const promise = handleWorkerError(run, new Error("transient"), deps, makeHandlers());
208
-
209
- // 推进指数退避(第 1 次重试:1s)
210
- await vi.advanceTimersByTimeAsync(1000);
211
- await promise;
212
-
213
- expect(run.meta.workerErrorCount).toBe(1);
214
- // 状态仍 running(重试不改 status)
215
- expect(run.state.status).toBe("running");
216
- // workerHost.start 被调(rebuildRuntime 内重建 worker)
217
- expect(deps.workerHost.start).toHaveBeenCalledTimes(1);
218
- });
219
-
220
- it("终态(done):stale 守卫前置丢弃(不递增 workerErrorCount)", async () => {
221
- const run = makeRunningRun();
222
- run.state.status = "done";
223
- (run.state as { reason?: string }).reason = "completed";
224
- const deps = makeDeps();
225
-
226
- await handleWorkerError(run, new Error("stale"), deps, makeHandlers());
227
-
228
- expect(run.meta.workerErrorCount).toBeUndefined(); // 未递增
229
- expect(deps.store.save).not.toHaveBeenCalled();
230
- });
231
- });
232
-
233
- // ── handleScriptError ────────────────────────────────────────
234
-
235
- describe("handleScriptError", () => {
236
- it("count > MAX(3):transition done,failed + 捕获 workerLogs", async () => {
237
- const run = makeRunningRun({ scriptErrorCount: 3 }); // count=4 > MAX
238
- const deps = makeDeps();
239
- const workerLogs = [
240
- { level: "error" as const, message: "line 5 boom" },
241
- ];
242
-
243
- await handleScriptError(run, "TypeError: x is undefined", workerLogs, deps, makeHandlers());
244
-
245
- expect(run.meta.scriptErrorCount).toBe(4);
246
- expect(run.state.status).toBe("done");
247
- expect(run.state.reason).toBe("failed");
248
- expect(run.state.error).toContain("Workflow failed after 3 retries");
249
- expect(run.state.error).toContain("TypeError: x is undefined");
250
- // workerLogs 捕获到 errorLogs
251
- expect(run.state.errorLogs).toEqual(workerLogs);
252
- expect(deps.store.save).toHaveBeenCalledTimes(1);
253
- expect(deps.onRunDone).toHaveBeenCalledTimes(1);
254
- });
255
-
256
- it("count <= MAX:退避 + rebuildRuntime", async () => {
257
- const run = makeRunningRun({ scriptErrorCount: 1 }); // count=2 <= MAX
258
- const deps = makeDeps();
259
-
260
- const promise = handleScriptError(run, "ReferenceError", [], deps, makeHandlers());
261
-
262
- // 第 2 次重试退避:2s
263
- await vi.advanceTimersByTimeAsync(2000);
264
- await promise;
265
-
266
- expect(run.meta.scriptErrorCount).toBe(2);
267
- expect(run.state.status).toBe("running");
268
- expect(deps.workerHost.start).toHaveBeenCalledTimes(1);
269
- });
270
-
271
- it("terminal 状态:stale 守卫前置丢弃", async () => {
272
- const run = makeRunningRun();
273
- run.state.status = "done";
274
- (run.state as { reason?: string }).reason = "completed";
275
- const deps = makeDeps();
276
-
277
- await handleScriptError(run, "late error", [], deps, makeHandlers());
278
-
279
- expect(run.meta.scriptErrorCount).toBeUndefined();
280
- expect(deps.store.save).not.toHaveBeenCalled();
281
- });
282
- });
283
-
284
- // ── postBudgetUpdate ─────────────────────────────────────────
285
-
286
- describe("postBudgetUpdate", () => {
287
- it("向 worker postMessage budget-update(usedTokens/usedCost)", () => {
288
- const postMessage = vi.fn();
289
- const run = makeRunningRun({ postMessage });
290
-
291
- postBudgetUpdate(run);
292
-
293
- expect(postMessage).toHaveBeenCalledWith({
294
- type: "budget-update",
295
- budget: { usedTokens: 50, usedCost: 0.1 },
296
- });
297
- });
298
-
299
- it("runtime 不存在时 no-op(不抛错)", () => {
300
- const run = makeRunningRun();
301
- // runtime.worker.postMessage 为 undefined 时应安全
302
- run.runtime = undefined;
303
-
304
- expect(() => postBudgetUpdate(run)).not.toThrow();
305
- });
306
- });
307
-
308
- // ── rebuildRuntime ───────────────────────────────────────────
309
-
310
- describe("rebuildRuntime", () => {
311
- it("worker 崩溃后重建:workerHost.start + replaceRuntime(保持 running)", () => {
312
- const run = makeRunningRun({ budgetTimeMs: 0 }); // 无时间预算
313
- const deps = makeDeps();
314
-
315
- rebuildRuntime(run, deps, makeHandlers());
316
-
317
- // workerHost.start 被调(构造新 worker)
318
- expect(deps.workerHost.start).toHaveBeenCalledTimes(1);
319
- // replaceRuntime 被调(新 runtime 绑定,mock 内仅替换 runtime 字段)
320
- expect(run.runtime).toBeDefined();
321
- // status 仍 running(replaceRuntime 不改 status)
322
- expect(run.state.status).toBe("running");
323
- });
324
-
325
- it("带 budgetTimeMs 时重排 scheduleTimeBudget 计时器", () => {
326
- const run = makeRunningRun({ budgetTimeMs: 5000 });
327
- const scheduleTimeBudget = vi.fn(() => undefined);
328
- const deps = makeDeps({ scheduleTimeBudget });
329
-
330
- rebuildRuntime(run, deps, makeHandlers());
331
-
332
- // D-12 regression fix (round-2 #2):replaceRuntime 后重排时间预算
333
- expect(scheduleTimeBudget).toHaveBeenCalledTimes(1);
334
- // 第 1 参 = runId(mock run 无 runId),第 2 参 = budgetTimeMs
335
- const args = scheduleTimeBudget.mock.calls[0]!;
336
- expect(args[1]).toBe(5000);
337
- });
338
-
339
- it("无 scheduleTimeBudget 注入时不重排(向后兼容,不抛错)", () => {
340
- const run = makeRunningRun({ budgetTimeMs: 5000 });
341
- const deps = makeDeps({ scheduleTimeBudget: undefined });
342
-
343
- expect(() => rebuildRuntime(run, deps, makeHandlers())).not.toThrow();
344
- expect(deps.workerHost.start).toHaveBeenCalledTimes(1);
345
- });
346
-
347
- it("rebuildRuntime 后同步清理在飞 call(status !== done 清除、done 保留)", () => {
348
- const run = makeRunningRun({ budgetTimeMs: 0 });
349
- // 注入在飞 call(running)与已完成 call(done)+ trace 节点移除 spy
350
- const removeByStepIndex = vi.fn();
351
- const calls = new Map<number, { id: number; status: string }>([
352
- [7, { id: 7, status: "running" }],
353
- [8, { id: 8, status: "done" }],
354
- ]);
355
- (run.state as { calls: unknown }).calls = calls;
356
- (run.state as { trace: unknown }).trace = { removeByStepIndex };
357
- const deps = makeDeps();
358
-
359
- rebuildRuntime(run, deps, makeHandlers());
360
-
361
- // 在飞 call(running)被移除(含 trace 节点);已完成 call(done)保留供重跑 replay
362
- expect(calls.has(7)).toBe(false);
363
- expect(calls.has(8)).toBe(true);
364
- expect(removeByStepIndex).toHaveBeenCalledTimes(1);
365
- expect(removeByStepIndex).toHaveBeenCalledWith(7);
366
- // 重建本身不受影响
367
- expect(deps.workerHost.start).toHaveBeenCalledTimes(1);
368
- });
369
- });
370
-
371
- // ── orphan call guard(S7-second 竞态回归) ─────────────────
372
- //
373
- // 复刻 gate-report §3 的竞态形态:dispatch agent-call → 立即 rebuildRuntime(同步
374
- // discard 在飞 call)→ 旧 dispatch 的 promise 以失败/成功 resolve → 迟到的旧代际
375
- // 结果不得经 postAgentResult 投给**新 worker** 的同 callId pending(否则重跑中的
376
- // agent() 被旧结果劫持 resolve 为空串 → 脚本假成功,PHASE_B 子进程被连带收割)。
377
- //
378
- // 用真实 WorkflowRun/RunRuntime/Trace/Budget(而非 makeRunningRun 的简化 mock):
379
- // rebuildRuntime → replaceRuntime → release 的 abort 旧 controller / terminate 旧
380
- // worker / discardInFlightCalls 全链路需要真实聚合根行为才成立。
381
-
382
- /** 手动控制的 deferred——精确编排「dispatch 挂起 → rebuild → 旧 promise settle」交错。 */
383
- interface Deferred<T> {
384
- promise: Promise<T>;
385
- resolve: (value: T) => void;
386
- reject: (err: unknown) => void;
387
- }
388
-
389
- function createDeferred<T>(): Deferred<T> {
390
- let resolve!: (value: T) => void;
391
- let reject!: (err: unknown) => void;
392
- const promise = new Promise<T>((res, rej) => {
393
- resolve = res;
394
- reject = rej;
395
- });
396
- return { promise, resolve, reject };
397
- }
398
-
399
- /** flush 微任务队列(dispatch 的 fire-and-forget promise 链推进到稳定态)。 */
400
- async function flushMicrotasks(ticks = 10): Promise<void> {
401
- for (let i = 0; i < ticks; i++) {
402
- // eslint-disable-next-line no-await-in-loop
403
- await Promise.resolve();
404
- }
405
- }
406
-
407
- /** 构造真实 WorkflowRun(真实状态机/replaceRuntime/Trace/Budget)+ 初始 RunRuntime。 */
408
- function makeRealRun(runId: string, opts: { budgetTimeMs?: number } = {}): WorkflowRun {
409
- const run = new WorkflowRun(
410
- runId,
411
- {
412
- scriptName: "test-wf",
413
- scriptSource: "agent('hi')",
414
- args: {},
415
- scriptPath: "/tmp/test-wf.js",
416
- budgetTimeMs: opts.budgetTimeMs,
417
- },
418
- {
419
- status: "running",
420
- budget: new Budget(),
421
- calls: new Map(),
422
- trace: new Trace(),
423
- errorLogs: [],
424
- },
425
- { startedAt: new Date().toISOString() },
426
- );
427
- // 初始 worker mock 必须带 terminate——真实 replaceRuntime 会 release 旧 runtime
428
- const initialWorker = {
429
- postMessage: vi.fn(),
430
- terminate: vi.fn(async () => {}),
431
- } as unknown as WorkerHandle;
432
- run.assignRuntime(new RunRuntime(initialWorker, new ConcurrencyGate(), new AbortController()));
433
- return run;
434
- }
435
-
436
- /** agent-call 消息(opts 无 skill/schema——resolveAgentOpts 直通,无 IO)。 */
437
- function makeAgentCallMsg(callId: number): unknown {
438
- return {
439
- type: "agent-call",
440
- callId,
441
- opts: { prompt: "test task", agent: "worker", description: "test-slug" },
442
- };
443
- }
444
-
445
- /** 从 postMessage spy 的调用记录中找 type:"agent-result" 且 callId 匹配的报文。 */
446
- function findAgentResultPost(
447
- postMessage: ReturnType<typeof vi.fn>,
448
- callId: number,
449
- ): { type: string; callId: number; result: AgentResult; cached: boolean } | undefined {
450
- for (const call of postMessage.mock.calls) {
451
- const msg = call[0] as { type?: string; callId?: number };
452
- if (msg?.type === "agent-result" && msg.callId === callId) {
453
- return msg as never;
454
- }
455
- }
456
- return undefined;
457
- }
458
-
459
- describe("orphan call guard(rebuild 后迟到 completion 不投递新 worker)", () => {
460
- it("失败路径:discard + 重跑替换后,旧 dispatch 的失败 completion 不投新 worker、不复活 Map 条目", async () => {
461
- const run = makeRealRun("wf-orphan-1");
462
- const deps = makeDeps();
463
- // rebuild 的新 worker——postMessage 记录用于断言「孤儿结果未投递」
464
- const newWorkerPost = vi.fn();
465
- deps.workerHost.start.mockImplementation(
466
- () =>
467
- ({ postMessage: newWorkerPost, terminate: vi.fn(async () => {}) }) as unknown as WorkerHandle,
468
- );
469
- const handlers = makeHandlers();
470
-
471
- // 旧 runtime 代际:dispatch callId=1,runner 挂起(模拟在飞子进程)
472
- const deferredA = createDeferred<AgentResult>();
473
- deps.runner.run.mockImplementation(() => deferredA.promise);
474
- await handleWorkerMessage(run, makeAgentCallMsg(1), deps, handlers);
475
- await flushMicrotasks();
476
- expect(run.state.calls.get(1)?.status).toBe("running");
477
-
478
- // worker 崩溃 → rebuildRuntime:replaceRuntime(abort 旧 controller)+ 同步 discard 在飞 call
479
- rebuildRuntime(run, deps, handlers);
480
- expect(run.state.calls.has(1)).toBe(false);
481
- expect(run.state.trace.find(1)).toBeUndefined();
482
-
483
- // 新 worker 重跑脚本:同 callId=1 再 dispatch(重跑实例 B 挂起在飞)
484
- const deferredB = createDeferred<AgentResult>();
485
- deps.runner.run.mockImplementation(() => deferredB.promise);
486
- await handleWorkerMessage(run, makeAgentCallMsg(1), deps, handlers);
487
- await flushMicrotasks();
488
- const rerunCall = run.state.calls.get(1);
489
- expect(rerunCall).toBeDefined();
490
-
491
- // 旧 dispatch 的 promise 以失败 resolve(abort 收割子进程后的迟到 finalize,
492
- // error 含 "aborted" 命中 stale-context 快速路径——真实形态)
493
- deferredA.resolve({ content: "", error: "Subprocess aborted by runtime shutdown" });
494
- await flushMicrotasks();
495
-
496
- // 孤儿失败结果不得投给新 worker(否则劫持重跑 pending 为空串假成功)
497
- expect(findAgentResultPost(newWorkerPost, 1)).toBeUndefined();
498
- // calls Map 无孤儿复活条目:callId=1 仍是重跑实例 B
499
- expect(run.state.calls.get(1)).toBe(rerunCall);
500
- });
501
-
502
- it("成功路径:discard 后旧 dispatch 的成功 completion 不投新 worker、不复活 Map/trace 条目", async () => {
503
- const run = makeRealRun("wf-orphan-2");
504
- const deps = makeDeps();
505
- const newWorkerPost = vi.fn();
506
- deps.workerHost.start.mockImplementation(
507
- () =>
508
- ({ postMessage: newWorkerPost, terminate: vi.fn(async () => {}) }) as unknown as WorkerHandle,
509
- );
510
-
511
- const deferred = createDeferred<AgentResult>();
512
- deps.runner.run.mockImplementation(() => deferred.promise);
513
- await handleWorkerMessage(run, makeAgentCallMsg(2), deps, makeHandlers());
514
- await flushMicrotasks();
515
-
516
- rebuildRuntime(run, deps, makeHandlers());
517
- expect(run.state.calls.has(2)).toBe(false);
518
-
519
- // 旧 promise 以成功 resolve(runner 已完成、结果晚于 rebuild 到达)
520
- deferred.resolve({ content: "late success", durationMs: 5, error: undefined, toolCalls: [] });
521
- await flushMicrotasks();
522
-
523
- expect(findAgentResultPost(newWorkerPost, 2)).toBeUndefined();
524
- expect(run.state.calls.has(2)).toBe(false);
525
- expect(run.state.trace.find(2)).toBeUndefined();
526
- });
527
-
528
- it("catch 路径:discard 后旧 dispatch 的异常 reject 不投新 worker、不复活 Map 条目", async () => {
529
- // catch 块的 logger.error 会打印——静默防噪音
530
- const spy = vi.spyOn(console, "error").mockImplementation(() => {});
531
- try {
532
- const run = makeRealRun("wf-orphan-3");
533
- const deps = makeDeps();
534
- const newWorkerPost = vi.fn();
535
- deps.workerHost.start.mockImplementation(
536
- () =>
537
- ({ postMessage: newWorkerPost, terminate: vi.fn(async () => {}) }) as unknown as WorkerHandle,
538
- );
539
-
540
- const deferred = createDeferred<AgentResult>();
541
- deps.runner.run.mockImplementation(() => deferred.promise);
542
- await handleWorkerMessage(run, makeAgentCallMsg(3), deps, makeHandlers());
543
- await flushMicrotasks();
544
-
545
- rebuildRuntime(run, deps, makeHandlers());
546
- expect(run.state.calls.has(3)).toBe(false);
547
-
548
- deferred.reject(new Error("runner exploded"));
549
- await flushMicrotasks();
550
-
551
- expect(findAgentResultPost(newWorkerPost, 3)).toBeUndefined();
552
- expect(run.state.calls.has(3)).toBe(false);
553
- } finally {
554
- spy.mockRestore();
555
- }
556
- });
557
-
558
- it("非孤儿正常路径:成功 completion 照常投递 agent-result(守卫不误伤)", async () => {
559
- const run = makeRealRun("wf-orphan-4");
560
- const deps = makeDeps();
561
- const postMessage = run.runtime!.worker.postMessage as ReturnType<typeof vi.fn>;
562
- deps.runner.run.mockImplementation(
563
- async () => ({ content: "real result", durationMs: 1, error: undefined, toolCalls: [] }) as AgentResult,
564
- );
565
-
566
- await handleWorkerMessage(run, makeAgentCallMsg(4), deps, makeHandlers());
567
- await flushMicrotasks(20);
568
-
569
- const posted = findAgentResultPost(postMessage, 4);
570
- expect(posted).toBeDefined();
571
- expect(posted?.result.content).toBe("real result");
572
- expect(run.state.calls.get(4)?.status).toBe("done");
573
- expect(run.state.trace.find(4)?.status).toBe("completed");
574
- });
575
-
576
- it("U6/S3 场景重放:discard + 重跑替换后,旧 finalize 不污染重跑新 trace 节点(旧 call 实例仍 markDone)", async () => {
577
- const run = makeRealRun("wf-orphan-s3");
578
- const deps = makeDeps();
579
- const newWorkerPost = vi.fn();
580
- deps.workerHost.start.mockImplementation(
581
- () => ({ postMessage: newWorkerPost, terminate: vi.fn(async () => {}) }) as unknown as WorkerHandle,
582
- );
583
- const handlers = makeHandlers();
584
-
585
- // 旧代际 dispatch callId=9:runner 挂起(模拟在飞子进程)
586
- const deferredA = createDeferred<AgentResult>();
587
- deps.runner.run.mockImplementation(() => deferredA.promise);
588
- await handleWorkerMessage(run, makeAgentCallMsg(9), deps, handlers);
589
- await flushMicrotasks();
590
- const oldCall = run.state.calls.get(9);
591
- expect(oldCall?.status).toBe("running");
592
-
593
- // rebuild:discard 移除旧 call 条目 + trace 节点(replaceRuntime 同步 abort 旧 signal)
594
- rebuildRuntime(run, deps, handlers);
595
- expect(run.state.calls.has(9)).toBe(false);
596
- expect(run.state.trace.find(9)).toBeUndefined();
597
-
598
- // 重跑 dispatch 同 callId=9:新实例 + 新 trace 节点 running,挂起在飞
599
- const deferredB = createDeferred<AgentResult>();
600
- deps.runner.run.mockImplementation(() => deferredB.promise);
601
- await handleWorkerMessage(run, makeAgentCallMsg(9), deps, handlers);
602
- await flushMicrotasks();
603
- const rerunCall = run.state.calls.get(9);
604
- expect(rerunCall).toBeDefined();
605
- expect(rerunCall).not.toBe(oldCall);
606
- expect(run.state.trace.find(9)?.status).toBe("running");
607
-
608
- // 旧 runner promise 以非 stale 失败 resolve——rebuild 已 abort 旧 signal,旧
609
- // executeAgentCall 醒来走 signal.aborted finalize 调用点(错误文案不含 stale
610
- // 模式词,确保不进 stale 分支)。红性锚点:无 OB2 守卫时此处 trace.update(9)
611
- // 命中重跑新节点 → 短暂污染为 failed。
612
- deferredA.resolve({ content: "", durationMs: 3, error: "old generation failure", toolCalls: [] });
613
- await flushMicrotasks();
614
-
615
- // 新 trace 节点未被旧 finalize 污染:仍 running、无 result、无 completedAt
616
- const newNode = run.state.trace.find(9);
617
- expect(newNode?.status).toBe("running");
618
- expect(newNode?.result).toBeUndefined();
619
- expect(newNode?.completedAt).toBeUndefined();
620
- // 旧实例 markDone 保留(dispatch 层 catch 路径依赖 call.status 语义)
621
- expect(oldCall?.status).toBe("done");
622
- expect(oldCall?.result?.error).toBe("old generation failure");
623
- // 重跑实例仍在飞,未被旧 completion 干扰;孤儿结果不投新 worker
624
- expect(rerunCall?.status).toBe("running");
625
- expect(findAgentResultPost(newWorkerPost, 9)).toBeUndefined();
626
-
627
- // 收尾:resolve 重跑 deferred,让挂起的 promise 链走完(非孤儿 → 正常完成路径)
628
- deferredB.resolve({ content: "rerun ok", durationMs: 1, error: undefined, toolCalls: [] });
629
- await flushMicrotasks();
630
- expect(run.state.trace.find(9)?.status).toBe("completed");
631
- });
632
- });
633
-
634
- // ── rebuildRuntime 可观察性(OB3 日志点 L1-L4) ─────────────
635
-
636
- /** 从 deps.log 的 mock 调用记录提取 (message, payload)——message 非字符串时置空串(断言自然失败)。 */
637
- function toLogEntries(calls: unknown[][]): Array<{ message: string; payload: unknown }> {
638
- return calls.map((c) => ({
639
- message: typeof c[2] === "string" ? c[2] : "",
640
- payload: c[3],
641
- }));
642
- }
643
-
644
- describe("rebuildRuntime 可观察性(OB3 日志点)", () => {
645
- it("U7: 无 budgetTimeMs 时按序打 L1 start → L4 complete(payload 含 runId),无 L2 重排日志", () => {
646
- const run = makeRealRun("wf-rebuild-log-1");
647
- const deps = makeDeps();
648
-
649
- rebuildRuntime(run, deps, makeHandlers());
650
-
651
- const entries = toLogEntries(deps.log.mock.calls);
652
- const messages = entries.map((e) => e.message);
653
- expect(messages).toContain("runtime rebuild start");
654
- expect(messages).toContain("runtime rebuild complete");
655
- // L4 在 L1 之后(顺序锚)
656
- expect(messages.indexOf("runtime rebuild complete")).toBeGreaterThan(
657
- messages.indexOf("runtime rebuild start"),
658
- );
659
- // 无 budgetTimeMs → 该分支本就跳过重排,L2 不打
660
- expect(messages).not.toContain("time budget rescheduled");
661
- // L1/L4 payload 含 runId
662
- const l1 = entries.find((e) => e.message === "runtime rebuild start");
663
- expect(l1?.payload).toMatchObject({ runId: "wf-rebuild-log-1" });
664
- const l4 = entries.find((e) => e.message === "runtime rebuild complete");
665
- expect(l4?.payload).toEqual({ runId: "wf-rebuild-log-1" });
666
- });
667
-
668
- it("U7: 带 budgetTimeMs + scheduleTimeBudget 注入时含 L2(在 L1 之后、L3 之前,payload 含 budgetTimeMs)", () => {
669
- const run = makeRealRun("wf-rebuild-log-2", { budgetTimeMs: 5000 });
670
- const scheduleTimeBudget = vi.fn(() => undefined);
671
- const deps = makeDeps({ scheduleTimeBudget });
672
-
673
- rebuildRuntime(run, deps, makeHandlers());
674
-
675
- const entries = toLogEntries(deps.log.mock.calls);
676
- const messages = entries.map((e) => e.message);
677
- expect(messages).toContain("time budget rescheduled");
678
- expect(messages.indexOf("time budget rescheduled")).toBeGreaterThan(
679
- messages.indexOf("runtime rebuild start"),
680
- );
681
- expect(messages.indexOf("time budget rescheduled")).toBeLessThan(
682
- messages.indexOf("in-flight calls discarded"),
683
- );
684
- const l2 = entries.find((e) => e.message === "time budget rescheduled");
685
- expect(l2?.payload).toEqual({ runId: "wf-rebuild-log-2", budgetTimeMs: 5000 });
686
- });
687
-
688
- it("U8: 含 2 个在飞 call 的 run 经 rebuild → L3 callIds 升序、count === 2,与实际被弃 callId 一致", async () => {
689
- const run = makeRealRun("wf-rebuild-log-3");
690
- const deps = makeDeps();
691
- const handlers = makeHandlers();
692
-
693
- // 两个在飞 call(dispatch 插入序 5 → 3,验证 L3 callIds 是升序而非插入序)
694
- const deferreds = [createDeferred<AgentResult>(), createDeferred<AgentResult>()];
695
- let next = 0;
696
- deps.runner.run.mockImplementation(() => {
697
- const d = deferreds[next];
698
- next += 1;
699
- return d!.promise;
700
- });
701
- await handleWorkerMessage(run, makeAgentCallMsg(5), deps, handlers);
702
- await handleWorkerMessage(run, makeAgentCallMsg(3), deps, handlers);
703
- await flushMicrotasks();
704
- expect(run.state.calls.get(5)?.status).toBe("running");
705
- expect(run.state.calls.get(3)?.status).toBe("running");
706
-
707
- rebuildRuntime(run, deps, makeHandlers());
708
-
709
- // L3 payload:callIds 升序 [3, 5]、count === 2(即 discardInFlightCalls 返回值)
710
- const entries = toLogEntries(deps.log.mock.calls);
711
- const l3 = entries.find((e) => e.message === "in-flight calls discarded");
712
- expect(l3?.payload).toEqual({ runId: "wf-rebuild-log-3", callIds: [3, 5], count: 2 });
713
- // 返回值(经 L3 暴露)与实际被弃 callId 一致:Map/trace 条目均已移除
714
- expect(run.state.calls.has(5)).toBe(false);
715
- expect(run.state.calls.has(3)).toBe(false);
716
- expect(run.state.trace.find(5)).toBeUndefined();
717
- expect(run.state.trace.find(3)).toBeUndefined();
718
-
719
- // 收尾:resolve 两个挂起的 deferred(孤儿守卫 drop,无投递无污染)
720
- deferreds[0]!.resolve({ content: "", durationMs: 1, error: undefined, toolCalls: [] });
721
- deferreds[1]!.resolve({ content: "", durationMs: 1, error: undefined, toolCalls: [] });
722
- await flushMicrotasks();
723
- });
724
- });