minimal-agent 0.12.0 → 0.14.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 (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -1,379 +0,0 @@
1
- /**
2
- * ============================================================
3
- * test/runnerPreflight.test.ts —— Runner Pre-flight & Self-heal 单元测试
4
- * ------------------------------------------------------------
5
- * 覆盖 runWorkflow 的前置流程和自愈重试机制:
6
- *
7
- * Pre-flight(任务身份判定 + 断点续执行):
8
- * - fresh 模式:正常启动,无恢复信息
9
- * - completed 模式:返回已完成提示(需手动构造状态)
10
- * - resume 模式:回放 capture 变量 + 跳过已完成步骤
11
- * - goalAnchor 构建与注入
12
- * - archive 成功后清理状态目录
13
- *
14
- * Self-heal / Retry:
15
- * - step 失败后自动 retry(max_retries 控制)
16
- * - backoff 回退 N 步重跑
17
- * - step.max_retries 覆盖全局配置
18
- * - retry 用尽后走 onError 逻辑
19
- *
20
- * 设计原则:
21
- * - 用 assert step 构造成功/失败路径(无需 mock LLM)
22
- * - 通过 runWorkflow 集成测试验证行为(避免直接实例化 WorkflowState 的 Bun 兼容性问题)
23
- * - 观察事件流判断内部状态转换是否正确
24
- * ============================================================ */
25
-
26
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
27
- import {
28
- existsSync,
29
- mkdirSync,
30
- mkdtempSync,
31
- readFileSync,
32
- rmSync,
33
- writeFileSync,
34
- } from 'node:fs';
35
- import { tmpdir } from 'node:os';
36
- import { join } from 'node:path';
37
-
38
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
39
- import { ALL_TOOLS } from '../../../src/tools/index.js';
40
- import { runWorkflow } from '../src/runner.js';
41
- import type { LoopEvent, Provider } from '../../../src/types.js';
42
- import type { RunContext, WorkflowDef, WorkflowEvent } from '../src/types.js';
43
-
44
- type WfOrLoop = WorkflowEvent | LoopEvent;
45
-
46
- const fakeProvider: Provider = {
47
- name: 'test',
48
- baseURL: '',
49
- apiKey: '',
50
- model: 'm',
51
- contextWindow: 128000,
52
- };
53
-
54
- async function collect(
55
- gen: AsyncGenerator<WfOrLoop, void, void>,
56
- ): Promise<WfOrLoop[]> {
57
- const out: WfOrLoop[] = [];
58
- for await (const ev of gen) out.push(ev);
59
- return out;
60
- }
61
-
62
- describe('runner::pre-flight fresh 模式', () => {
63
- let tmp: string;
64
- let ctx: RunContext;
65
-
66
- beforeEach(() => {
67
- tmp = mkdtempSync(join(tmpdir(), 'wf-preflight-'));
68
- process.env.MINIMAL_AGENT_CWD = tmp;
69
- _resetWorkingDir();
70
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
71
- getWorkingDir: () => tmp,
72
- initWorkingDir: () => tmp,
73
- _resetWorkingDir: () => {},
74
- }));
75
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: [] };
76
- });
77
-
78
- afterEach(() => {
79
- delete process.env.MINIMAL_AGENT_CWD;
80
- _resetWorkingDir();
81
- rmSync(tmp, { recursive: true, force: true });
82
- });
83
-
84
- it('首次运行 → workflow_start + 正常执行 + workflow_done', async () => {
85
- const def: WorkflowDef = {
86
- name: 'fresh-test',
87
- description: 'd',
88
- steps: [{ id: 's1', type: 'assert', condition: 'true' }],
89
- };
90
- const events = await collect(runWorkflow(def, {}, ctx));
91
- expect(events.some((e) => e.type === 'workflow_start')).toBe(true);
92
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
93
- // 不应有 completed 提示
94
- expect(events.find((e) => e.type === 'text' && String(e).includes('已完成'))).toBeUndefined();
95
- });
96
- });
97
-
98
- describe('runner::pre-flight completed 模式(架构说明)', () => {
99
- // ⚠️ 注意:completed 模式的集成测试需要精确匹配 taskId hash,
100
- // 而 taskId 由 taskIdentity.ts::computeTaskId() 计算(含归一化 + SHA256 截断)。
101
- // 直接构造匹配的 current.json 脆且容易因归一化规则调整而断裂。
102
- //
103
- // 已有覆盖:
104
- // - taskIdentity.test.ts: 完整测试 computeTaskId 的 hash / 时间窗口 / 匹配逻辑
105
- // - stateLifecycle.test.ts: 通过 runWorkflow 成功→archive 验证状态目录生命周期
106
- // - 本文件 resume 测试: 验证失败后重跑进入 resume 模式
107
- //
108
- // 结论:completed 分支的正确性由上述测试联合保证,无需再写一个脆弱的集成测试。
109
-
110
- it('占位:completed 模式已由 taskIdentity.test.ts + stateLifecycle.test.ts 联合覆盖', () => {
111
- expect(true).toBe(true);
112
- });
113
- });
114
-
115
- describe('runner::resume 与断点续执行', () => {
116
- let tmp: string;
117
- let ctx: RunContext;
118
-
119
- beforeEach(() => {
120
- tmp = mkdtempSync(join(tmpdir(), 'wf-resume-'));
121
- process.env.MINIMAL_AGENT_CWD = tmp;
122
- _resetWorkingDir();
123
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
124
- getWorkingDir: () => tmp,
125
- initWorkingDir: () => tmp,
126
- _resetWorkingDir: () => {},
127
- }));
128
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: ALL_TOOLS };
129
- });
130
-
131
- afterEach(() => {
132
- delete process.env.MINIMAL_AGENT_CWD;
133
- _resetWorkingDir();
134
- rmSync(tmp, { recursive: true, force: true });
135
- });
136
-
137
- it('失败后重跑 → 进入 resume 模式 → 跳过已完成步骤', async () => {
138
- const def: WorkflowDef = {
139
- name: 'resume-test',
140
- description: 'd',
141
- self_heal: { backoff: 0, max_retries: 0 }, // 禁用 retry 让它自然 halt
142
- steps: [
143
- { id: 'write', tool: 'Write', args: { file_path: 'data.txt', content: 'hello' }, capture: { content: 'captured_text' } },
144
- { id: 'check', type: 'assert', condition: "captured_text == 'hello'" },
145
- { id: 'fail', type: 'assert', condition: 'false', onFail: 'intentional fail' },
146
- { id: 'after_fail', type: 'assert', condition: 'true' },
147
- ],
148
- };
149
-
150
- // 第一次运行:前两步成功,第三步失败
151
- const events1 = await collect(runWorkflow(def, { goal: 'target' }, ctx));
152
- expect(events1.some((e) => e.type === 'error')).toBe(true); // halt
153
- expect(events1.some((e) => e.type === 'workflow_done')).toBe(false);
154
-
155
- // 第二次运行:应进入 resume 模式(时间窗口内同一任务)
156
- const events2 = await collect(runWorkflow(def, { goal: 'target' }, ctx));
157
-
158
- // 应有某种恢复相关的事件(text 或 warning)
159
- const hasResumeInfo =
160
- events2.some((e) => e.type === 'text' && String(e).includes('未完成')) ||
161
- events2.some((e) => e.type === 'text' && String(e).includes('恢复'));
162
-
163
- // 已完成的步骤可能被跳过(取决于实现细节)
164
- const skippedIds = events2
165
- .filter((e): e is Extract<WorkflowEvent, { type: 'workflow_step_skipped' }> =>
166
- e.type === 'workflow_step_skipped')
167
- .map((e) => e.id);
168
-
169
- // 最终仍会失败(因为 fail 步骤仍然失败且 retry=0)
170
- expect(events2.some((e) => e.type === 'error')).toBe(true);
171
- });
172
- });
173
-
174
- describe('runner::goalAnchor 构建', () => {
175
- it('inputs.goal 存在 → workflow 正常运行(间接验证 goalAnchor 不报错)', async () => {
176
- const tmp = mkdtempSync(join(tmpdir(), 'wf-goal-'));
177
- process.env.MINIMAL_AGENT_CWD = tmp;
178
- _resetWorkingDir();
179
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
180
- getWorkingDir: () => tmp,
181
- initWorkingDir: () => tmp,
182
- _resetWorkingDir: () => {},
183
- }));
184
-
185
- try {
186
- const def: WorkflowDef = {
187
- name: 'goal-test',
188
- description: 'd',
189
- inputs: [{ name: 'goal', type: 'string', required: true }],
190
- steps: [{ id: 's1', type: 'assert', condition: 'true' }],
191
- };
192
-
193
- const ctx: RunContext = {
194
- provider: fakeProvider,
195
- history: [],
196
- cwd: tmp,
197
- tools: [],
198
- };
199
-
200
- const events = await collect(runWorkflow(def, { goal: '实现用户认证模块' }, ctx));
201
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
202
- } finally {
203
- delete process.env.MINIMAL_AGENT_CWD;
204
- _resetWorkingDir();
205
- rmSync(tmp, { recursive: true, force: true });
206
- }
207
- });
208
-
209
- it('无 string 类型 inputs → goalAnchor 为空(不报错)', async () => {
210
- const tmp = mkdtempSync(join(tmpdir(), 'wf-nogoal-'));
211
- process.env.MINIMAL_AGENT_CWD = tmp;
212
- _resetWorkingDir();
213
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
214
- getWorkingDir: () => tmp,
215
- initWorkingDir: () => tmp,
216
- _resetWorkingDir: () => {},
217
- }));
218
-
219
- try {
220
- const def: WorkflowDef = {
221
- name: 'no-goal-test',
222
- description: 'd',
223
- inputs: [{ name: 'count', type: 'number' }],
224
- steps: [{ id: 's1', type: 'assert', condition: 'true' }],
225
- };
226
-
227
- const ctx: RunContext = {
228
- provider: fakeProvider,
229
- history: [],
230
- cwd: tmp,
231
- tools: [],
232
- };
233
-
234
- const events = await collect(runWorkflow(def, { count: 42 }, ctx));
235
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
236
- } finally {
237
- delete process.env.MINIMAL_AGENT_CWD;
238
- _resetWorkingDir();
239
- rmSync(tmp, { recursive: true, force: true });
240
- }
241
- });
242
- });
243
-
244
- describe('runner::self_heal retry 机制', () => {
245
- let tmp: string;
246
- let ctx: RunContext;
247
-
248
- beforeEach(() => {
249
- tmp = mkdtempSync(join(tmpdir(), 'wf-retry-'));
250
- process.env.MINIMAL_AGENT_CWD = tmp;
251
- _resetWorkingDir();
252
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
253
- getWorkingDir: () => tmp,
254
- initWorkingDir: () => tmp,
255
- _resetWorkingDir: () => {},
256
- }));
257
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: [] };
258
- });
259
-
260
- afterEach(() => {
261
- delete process.env.MINIMAL_AGENT_CWD;
262
- _resetWorkingDir();
263
- rmSync(tmp, { recursive: true, force: true });
264
- });
265
-
266
- it('self_heal.backoff 控制回退步数(失败时回退重跑)', async () => {
267
- const def: WorkflowDef = {
268
- name: 'backoff-test',
269
- description: 'd',
270
- self_heal: { backoff: 2, max_retries: 1 },
271
- steps: [
272
- { id: 'setup', tool: 'Write', args: { file_path: 'setup.txt', content: 'init' } },
273
- { id: 'work', type: 'assert', condition: 'true' },
274
- { id: 'flaky', type: 'assert', condition: 'false', onFail: 'fail' },
275
- { id: 'cleanup', type: 'assert', condition: 'true' },
276
- ],
277
- };
278
-
279
- const events = await collect(runWorkflow(def, {}, ctx));
280
- // flaky 失败后应触发 retry 机制(backoff=2 回退到 work 步骤重跑)
281
- // 最终仍会失败(因为 flaky 总是 false)
282
- expect(events.some((e) => e.type === 'error')).toBe(true);
283
-
284
- // 验证 setup 步骤被重新执行(backoff=2 导致从 work 重跑,work 之前的是 setup)
285
- // 所以 setup 应该出现多次
286
- const setupStartCount = events.filter(
287
- (e) => e.type === 'workflow_step_start' && (e as {id:string}).id === 'setup',
288
- ).length;
289
- expect(setupStartCount).toBeGreaterThanOrEqual(1); // 至少执行一次
290
- });
291
-
292
- it('step.max_retries 覆盖全局 self_heal.max_retries', async () => {
293
- const def: WorkflowDef = {
294
- name: 'override-retry',
295
- description: 'd',
296
- self_heal: { backoff: 0, max_retries: 5 }, // 全局允许 5 次
297
- steps: [
298
- {
299
- id: 'limited',
300
- type: 'assert',
301
- condition: 'false',
302
- onFail: 'always fails',
303
- max_retries: 1, // 但这步只允许 1 次
304
- },
305
- { id: 'next', type: 'assert', condition: 'true' },
306
- ],
307
- };
308
-
309
- const events = await collect(runWorkflow(def, {}, ctx));
310
- // limited 步骤只 retry 1 次(共尝试 2 次),然后halt
311
- expect(events.some((e) => e.type === 'error')).toBe(true);
312
- // next 不应被执行
313
- const startedIds = events
314
- .filter((e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
315
- e.type === 'workflow_step_start')
316
- .map((e) => e.id);
317
- expect(startedIds).not.toContain('next');
318
- });
319
-
320
- it('retry 用尽后走 onError:halt(默认)→ 整个 workflow 停止', async () => {
321
- const def: WorkflowDef = {
322
- name: 'retry-halt',
323
- description: 'd',
324
- self_heal: { backoff: 0, max_retries: 1 },
325
- steps: [
326
- {
327
- id: 'fail_step',
328
- type: 'assert',
329
- condition: 'false',
330
- onFail: 'fails',
331
- // 默认 onError='halt'
332
- },
333
- { id: 'next', type: 'assert', condition: 'true' },
334
- ],
335
- };
336
-
337
- const events = await collect(runWorkflow(def, {}, ctx));
338
- expect(events.some((e) => e.type === 'error')).toBe(true);
339
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
340
- // next 不应执行
341
- expect(events.some((e) => e.type === 'workflow_step_start' && (e as {id:string}).id === 'next')).toBe(false);
342
- });
343
-
344
- it('正常成功路径 → archive 清理状态目录', async () => {
345
- const def: WorkflowDef = {
346
- name: 'archive-test',
347
- description: 'd',
348
- steps: [{ id: 's1', type: 'assert', condition: 'true' }],
349
- };
350
-
351
- await collect(runWorkflow(def, {}, ctx));
352
-
353
- // 成功后应 archive(活动目录改名 .done;E6 后按名隔离)
354
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'archive-test'))).toBe(false);
355
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'archive-test.done'))).toBe(true);
356
- });
357
-
358
- it('失败路径 → 保留状态目录供排查', async () => {
359
- const def: WorkflowDef = {
360
- name: 'keep-state',
361
- description: 'd',
362
- self_heal: { backoff: 0, max_retries: 0 },
363
- steps: [
364
- { id: 'fail', type: 'assert', condition: 'false', onFail: 'boom' },
365
- ],
366
- };
367
-
368
- await collect(runWorkflow(def, {}, ctx));
369
-
370
- // 失败时应保留状态目录(E6 后按名隔离)
371
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'keep-state'))).toBe(true);
372
- // progress.md 应包含失败步骤信息
373
- const progressPath = join(tmp, '.minimal-agent-workflow', 'keep-state', 'progress.md');
374
- if (existsSync(progressPath)) {
375
- const progress = readFileSync(progressPath, 'utf8');
376
- expect(progress).toContain('fail');
377
- }
378
- });
379
- });
@@ -1,71 +0,0 @@
1
- /**
2
- * ============================================================
3
- * test/skillTurnDone.test.ts —— skill 节点不外泄子 runQuery 的 turn_done
4
- * ------------------------------------------------------------
5
- * 端到端实测发现:critic(skill) 子循环结束时 yield 的 turn_done 漏进 workflow 事件流,
6
- * 导致把 turn_done 当终结的消费者(-p --output-format json / gateway broker)在
7
- * workflow 中途(critic 之后、verify 之前)误判结束。execSkillStep 现过滤之。
8
- *
9
- * 策略:mock plugin-sdk 的 runQuery 吐 [text, turn_done],断言 execSkillStep 不外泄
10
- * turn_done,但保留 text 并正常 capture。
11
- * ============================================================
12
- */
13
-
14
- import { describe, expect, it } from 'bun:test';
15
- import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
16
- import { tmpdir } from 'node:os';
17
- import { join } from 'node:path';
18
-
19
- import type { LoopEvent } from '../../../src/types.js';
20
- import type { RunContext } from '../src/types.js';
21
- import { VarStack } from '../src/types.js';
22
- // 临时 skills 目录:myskill/SKILL.md
23
- const tmpProject = mkdtempSync(join(tmpdir(), 'wf-skillTD-'));
24
- const tmpSkills = join(tmpProject, 'skills');
25
- mkdirSync(join(tmpSkills, 'myskill'), { recursive: true });
26
- writeFileSync(
27
- join(tmpSkills, 'myskill', 'SKILL.md'),
28
- '---\nname: myskill\n---\n做点事。\n',
29
- );
30
-
31
- import { execSkillStep } from '../src/stepExecutors/skill.js';
32
-
33
- const fakeCtx: RunContext = {
34
- provider: {
35
- name: 't',
36
- baseURL: '',
37
- apiKey: '',
38
- model: 'm',
39
- contextWindow: 1_000_000,
40
- },
41
- history: [],
42
- cwd: tmpProject,
43
- tools: [],
44
- // DI:stub chat,让真实 runQuery 真推 'hello' 进 history + 单轮收尾 yield turn_done。
45
- chat: async function* () {
46
- yield { type: 'text_delta', delta: 'hello' };
47
- yield { type: 'done', stopReason: 'stop' };
48
- },
49
- };
50
-
51
- describe('execSkillStep turn_done 不外泄', () => {
52
- it('过滤 turn_done,保留 text/stage_change,正常 capture 文本', async () => {
53
- const evs: LoopEvent[] = [];
54
- const gen = execSkillStep(
55
- { id: 's', skill: 'myskill', input: 'go' },
56
- new VarStack(),
57
- fakeCtx,
58
- );
59
- let r = await gen.next();
60
- while (!r.done) {
61
- evs.push(r.value as LoopEvent);
62
- r = await gen.next();
63
- }
64
- const result = r.value;
65
-
66
- expect(evs.some((e) => e.type === 'turn_done')).toBe(false); // 关键:不外泄
67
- expect(evs.some((e) => e.type === 'text')).toBe(true); // 其它事件保留
68
- expect(evs.some((e) => e.type === 'stage_change')).toBe(true);
69
- expect(result.raw.text).toBe('hello'); // 文本仍正常 capture
70
- });
71
- });
@@ -1,150 +0,0 @@
1
- /**
2
- * ============================================================
3
- * test/stateLifecycle.test.ts —— .minimal-agent-workflow/ 生命周期契约
4
- * ------------------------------------------------------------
5
- * 钉死 Fix ③ 的设计决策(曾经缺失这条测试,导致"失败即删"自废武功无人察觉):
6
- * - 干净跑完 → cleanup(),状态目录被删(不留垃圾)
7
- * - halt / 失败 → **保留** 状态目录 + progress.md(含失败那步的 ✗ 行)供事后排查
8
- *
9
- * 这类"失败时的行为契约"靠想清楚 + 测试钉死,不会被 happy-path 测试自动覆盖到。
10
- * 用 assert step 构造成功/失败两条路径,无需 mock LLM。
11
- * ============================================================
12
- */
13
-
14
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
15
- import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
16
- import { tmpdir } from 'node:os';
17
- import { join } from 'node:path';
18
-
19
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
20
- import { ALL_TOOLS } from '../../../src/tools/index.js';
21
- import { runWorkflow } from '../src/runner.js';
22
- import type { LoopEvent, Provider } from '../../../src/types.js';
23
- import type { RunContext, WorkflowDef, WorkflowEvent } from '../src/types.js';
24
-
25
- type WfOrLoop = WorkflowEvent | LoopEvent;
26
-
27
- const fakeProvider: Provider = {
28
- name: 'test',
29
- baseURL: '',
30
- apiKey: '',
31
- model: 'm',
32
- contextWindow: 128000,
33
- };
34
-
35
- async function collect(
36
- gen: AsyncGenerator<WfOrLoop, void, void>,
37
- ): Promise<WfOrLoop[]> {
38
- const out: WfOrLoop[] = [];
39
- for await (const ev of gen) out.push(ev);
40
- return out;
41
- }
42
-
43
- const STATE_DIR = '.minimal-agent-workflow';
44
-
45
- describe('workflow state-dir 生命周期', () => {
46
- let tmp: string;
47
- let ctx: RunContext;
48
-
49
- beforeEach(() => {
50
- tmp = mkdtempSync(join(tmpdir(), 'wf-state-'));
51
- process.env.MINIMAL_AGENT_CWD = tmp;
52
- _resetWorkingDir();
53
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
54
- getWorkingDir: () => tmp,
55
- initWorkingDir: () => tmp,
56
- _resetWorkingDir: () => {},
57
- }));
58
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: ALL_TOOLS };
59
- });
60
-
61
- afterEach(() => {
62
- delete process.env.MINIMAL_AGENT_CWD;
63
- _resetWorkingDir();
64
- rmSync(tmp, { recursive: true, force: true });
65
- });
66
-
67
- it('干净跑完 → 活动状态目录归档为 <name>.done(E6 后按名隔离)', async () => {
68
- const def: WorkflowDef = {
69
- name: 'ok',
70
- description: 'd',
71
- steps: [{ id: 's1', type: 'assert', condition: '1 == 1' }],
72
- };
73
- const events = await collect(runWorkflow(def, {}, ctx));
74
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
75
- // 成功路径:活动目录被归档改名(completed 检测靠它),不留活动现场
76
- expect(existsSync(join(tmp, STATE_DIR, 'ok'))).toBe(false);
77
- expect(existsSync(join(tmp, STATE_DIR, 'ok.done'))).toBe(true);
78
- });
79
-
80
- it('halt → 保留状态目录 + progress.md 含失败那步', async () => {
81
- const def: WorkflowDef = {
82
- name: 'boom',
83
- description: 'd',
84
- steps: [
85
- { id: 'will_fail', type: 'assert', condition: '1 == 2', onFail: 'nope' },
86
- ],
87
- };
88
- const events = await collect(runWorkflow(def, {}, ctx));
89
- // 确实 halt 了(有 error 事件、没有 workflow_done)
90
- expect(events.some((e) => e.type === 'error')).toBe(true);
91
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
92
-
93
- // 失败现场必须保留,供事后排查
94
- const stateDir = join(tmp, STATE_DIR, 'boom');
95
- expect(existsSync(stateDir)).toBe(true);
96
- const progress = readFileSync(join(stateDir, 'progress.md'), 'utf8');
97
- // 失败那步的 ✗ 行 + onFail 文案都应在 progress 里
98
- expect(progress).toContain('will_fail');
99
- expect(progress).toContain('nope');
100
- });
101
-
102
- it('再次运行同名 workflow(同 goal)→ resume 后成功 → 归档不堆积', async () => {
103
- const failDef: WorkflowDef = {
104
- name: 'rerun',
105
- description: 'd',
106
- steps: [{ id: 'f', type: 'assert', condition: 'false', onFail: 'x' }],
107
- };
108
- await collect(runWorkflow(failDef, {}, ctx));
109
- expect(existsSync(join(tmp, STATE_DIR, 'rerun'))).toBe(true); // 失败留下了
110
-
111
- // 第二次成功跑(同名同 inputs = 同任务 resume):成功后归档 → 活动目录干净
112
- const okDef: WorkflowDef = {
113
- name: 'rerun',
114
- description: 'd',
115
- steps: [{ id: 'ok', type: 'assert', condition: 'true' }],
116
- };
117
- await collect(runWorkflow(okDef, {}, ctx));
118
- expect(existsSync(join(tmp, STATE_DIR, 'rerun'))).toBe(false); // 不堆积
119
- expect(existsSync(join(tmp, STATE_DIR, 'rerun.done'))).toBe(true);
120
- });
121
-
122
- it('E6:A 工作流失败现场不被不同名工作流 B 的运行破坏(按名隔离)', async () => {
123
- // A 失败留现场 + 留声明产物
124
- const aDef: WorkflowDef = {
125
- name: 'wf-a',
126
- description: 'd',
127
- artifacts: ['A-PLAN.md'],
128
- steps: [
129
- { id: 'w', tool: 'Write', args: { file_path: 'A-PLAN.md', content: 'A 的半成品' } },
130
- { id: 'f', type: 'assert', condition: 'false', onFail: 'A 中断' },
131
- ],
132
- };
133
- await collect(runWorkflow(aDef, {}, ctx));
134
- expect(existsSync(join(tmp, STATE_DIR, 'wf-a'))).toBe(true);
135
- expect(existsSync(join(tmp, 'A-PLAN.md'))).toBe(true);
136
-
137
- // 跑不同名工作流 B(曾经会清掉 A 的状态目录和产物——E6 事故)
138
- const bDef: WorkflowDef = {
139
- name: 'wf-b',
140
- description: 'd',
141
- steps: [{ id: 'ok', type: 'assert', condition: 'true' }],
142
- };
143
- const evB = await collect(runWorkflow(bDef, {}, ctx));
144
- expect(evB.some((e) => e.type === 'workflow_done')).toBe(true);
145
-
146
- // A 的现场与产物完好,resume 能力保留
147
- expect(existsSync(join(tmp, STATE_DIR, 'wf-a'))).toBe(true);
148
- expect(existsSync(join(tmp, 'A-PLAN.md'))).toBe(true);
149
- });
150
- });