minimal-agent 0.13.0 → 0.15.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 (474) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  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 +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  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 +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  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 +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  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 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  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 +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  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/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +536 -0
  103. package/src/advisor/advisorCoordinator.ts +693 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/quickModelSetup.js +12 -1
  108. package/src/cli/quickModelSetup.tsx +15 -3
  109. package/src/cli/streamJson.js +5 -6
  110. package/src/cli/streamJson.ts +8 -4
  111. package/src/cli/wizards/advisorWizard.js +4 -2
  112. package/src/cli/wizards/advisorWizard.tsx +8 -2
  113. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  114. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  115. package/src/cli/wizards/providerPresets.js +18 -8
  116. package/src/cli/wizards/providerPresets.ts +18 -8
  117. package/src/collaboration/taskFlow.js +115 -0
  118. package/src/collaboration/taskFlow.ts +169 -0
  119. package/src/config/configDefaults.js +41 -1
  120. package/src/config/configDefaults.ts +43 -1
  121. package/src/config/configDiagnostics.ts +2 -2
  122. package/src/config/configFile.js +40 -9
  123. package/src/config/configFile.ts +60 -11
  124. package/src/config/configService.js +419 -74
  125. package/src/config/configService.ts +703 -145
  126. package/src/config/numericLimits.js +22 -0
  127. package/src/config/numericLimits.ts +24 -0
  128. package/src/config.js +1 -0
  129. package/src/config.ts +3 -2
  130. package/src/context/budgetPlan.js +1 -1
  131. package/src/context/budgetPlan.ts +1 -1
  132. package/src/context/compact.js +7 -2
  133. package/src/context/compact.ts +9 -2
  134. package/src/context/microCompactLite.js +212 -13
  135. package/src/context/microCompactLite.ts +261 -12
  136. package/src/context/sessionRegistry.js +8 -1
  137. package/src/context/sessionRegistry.ts +18 -5
  138. package/src/context/toolResultArchive.js +72 -0
  139. package/src/context/toolResultArchive.ts +95 -0
  140. package/src/goal/errors.js +8 -0
  141. package/src/goal/errors.ts +18 -0
  142. package/src/goal/goalRuntime.js +344 -0
  143. package/src/goal/goalRuntime.ts +466 -0
  144. package/src/goal/goalStore.js +200 -0
  145. package/src/goal/goalStore.ts +219 -0
  146. package/src/goal/index.js +4 -0
  147. package/src/goal/index.ts +4 -0
  148. package/src/goal/statusMapping.js +71 -0
  149. package/src/goal/statusMapping.ts +95 -0
  150. package/src/goal/types.js +7 -0
  151. package/src/goal/types.ts +179 -0
  152. package/src/goal/workflowController.js +306 -0
  153. package/src/goal/workflowController.ts +360 -0
  154. package/src/harness/evidenceLedger.js +2 -0
  155. package/src/harness/evidenceLedger.ts +1 -0
  156. package/src/harness/stallGuard.js +9 -3
  157. package/src/harness/stallGuard.ts +7 -3
  158. package/src/images/imageResolver.js +161 -0
  159. package/src/images/imageResolver.ts +189 -0
  160. package/src/infra/verification.js +34 -5
  161. package/src/infra/verification.ts +39 -4
  162. package/src/llm/client.js +79 -21
  163. package/src/llm/client.ts +182 -35
  164. package/src/llm/gatewayClient.js +201 -0
  165. package/src/llm/gatewayClient.ts +299 -0
  166. package/src/llm/messageProvenance.js +46 -0
  167. package/src/llm/messageProvenance.ts +58 -0
  168. package/src/llm/modelProvider.js +1 -0
  169. package/src/llm/modelProvider.ts +22 -0
  170. package/src/llm/providers/anthropicFormat.js +108 -1
  171. package/src/llm/providers/anthropicFormat.ts +115 -4
  172. package/src/llm/providers/openaiFormat.js +9 -0
  173. package/src/llm/providers/openaiFormat.ts +12 -3
  174. package/src/loop.js +328 -55
  175. package/src/loop.ts +382 -58
  176. package/src/main.js +4 -1
  177. package/src/main.tsx +4 -1
  178. package/src/managedExecution/index.js +2 -0
  179. package/src/managedExecution/index.ts +2 -0
  180. package/src/managedExecution/registry.js +15 -0
  181. package/src/managedExecution/registry.ts +20 -0
  182. package/src/managedExecution/types.js +1 -0
  183. package/src/managedExecution/types.ts +86 -0
  184. package/src/modelRef.js +9 -0
  185. package/src/modelRef.ts +31 -0
  186. package/src/multimodal.js +14 -28
  187. package/src/multimodal.ts +17 -33
  188. package/src/net/lanDiscovery.js +65 -0
  189. package/src/net/lanDiscovery.ts +82 -0
  190. package/src/plugin-sdk.js +28 -3
  191. package/src/plugin-sdk.ts +39 -6
  192. package/src/plugins/pluginApi.ts +16 -1
  193. package/src/plugins/pluginLoader.js +4 -0
  194. package/src/plugins/pluginLoader.ts +6 -0
  195. package/src/plugins/pluginRunner.js +139 -7
  196. package/src/plugins/pluginRunner.ts +173 -9
  197. package/src/plugins/slashFallback.js +113 -0
  198. package/src/plugins/slashFallback.ts +137 -0
  199. package/src/prompts/policyRegistry.js +12 -32
  200. package/src/prompts/policyRegistry.ts +15 -32
  201. package/src/prompts/promptAssembly.js +103 -12
  202. package/src/prompts/promptAssembly.ts +114 -12
  203. package/src/prompts/skillList.js +21 -3
  204. package/src/prompts/skillList.ts +27 -2
  205. package/src/prompts/stableSystemPrompt.js +18 -0
  206. package/src/prompts/stableSystemPrompt.ts +33 -0
  207. package/src/runtime/agentRuntimeContext.js +8 -2
  208. package/src/runtime/agentRuntimeContext.ts +17 -4
  209. package/src/session/runAgentTurn.js +78 -12
  210. package/src/session/runAgentTurn.ts +105 -23
  211. package/src/session/runTurn.js +10 -9
  212. package/src/session/runTurn.ts +17 -8
  213. package/src/session/sessionState.ts +2 -0
  214. package/src/team/auth.js +186 -0
  215. package/src/team/auth.ts +298 -0
  216. package/src/team/cli.js +105 -0
  217. package/src/team/cli.ts +122 -0
  218. package/src/team/onlineToolContract.js +64 -0
  219. package/src/team/onlineToolContract.ts +109 -0
  220. package/src/team/toolPolicy.js +36 -0
  221. package/src/team/toolPolicy.ts +75 -0
  222. package/src/tools/advisor/advisor.js +115 -50
  223. package/src/tools/advisor/advisor.ts +124 -51
  224. package/src/tools/advisor/advisorDecision.js +71 -0
  225. package/src/tools/advisor/advisorDecision.ts +85 -0
  226. package/src/tools/agent/agent.js +18 -5
  227. package/src/tools/agent/agent.ts +21 -7
  228. package/src/tools/agent/agentControl.js +246 -0
  229. package/src/tools/agent/agentControl.ts +284 -0
  230. package/src/tools/agent/agentTaskService.js +40 -1
  231. package/src/tools/agent/agentTaskService.ts +44 -1
  232. package/src/tools/agent/agentTypes.js +14 -2
  233. package/src/tools/agent/agentTypes.ts +15 -2
  234. package/src/tools/applypatch/applyPatch.js +362 -0
  235. package/src/tools/applypatch/applyPatch.ts +428 -0
  236. package/src/tools/bash/bash.js +22 -15
  237. package/src/tools/bash/bash.ts +23 -17
  238. package/src/tools/capabilities.js +10 -5
  239. package/src/tools/capabilities.ts +10 -5
  240. package/src/tools/computeruse/computerIntent.js +32 -0
  241. package/src/tools/computeruse/computerIntent.ts +46 -0
  242. package/src/tools/computeruse/telemetryLog.js +12 -0
  243. package/src/tools/computeruse/telemetryLog.ts +16 -0
  244. package/src/tools/computeruse/vision/telemetry.js +1 -0
  245. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  246. package/src/tools/effectiveToolSet.js +4 -0
  247. package/src/tools/effectiveToolSet.ts +4 -0
  248. package/src/tools/index.js +21 -2
  249. package/src/tools/index.ts +33 -2
  250. package/src/tools/presentresult/presentresult.js +6 -15
  251. package/src/tools/presentresult/presentresult.ts +6 -15
  252. package/src/tools/read/read.js +62 -9
  253. package/src/tools/read/read.ts +63 -9
  254. package/src/tools/shared/fileUtils.js +1 -2
  255. package/src/tools/shared/fileUtils.ts +1 -2
  256. package/src/tools/shared/toolOutputStore.js +23 -1
  257. package/src/tools/shared/toolOutputStore.ts +22 -1
  258. package/src/tools/skill/skill.js +9 -3
  259. package/src/tools/skill/skill.ts +8 -4
  260. package/src/tools/toolPromptGuides.js +125 -0
  261. package/src/tools/toolPromptGuides.ts +146 -0
  262. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  263. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  264. package/src/tools/webbrowser/browser.js +27 -11
  265. package/src/tools/webbrowser/browser.ts +68 -24
  266. package/src/tools/webbrowser/browserAutomation.js +329 -0
  267. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  268. package/src/tools/webbrowser/browserAxState.js +97 -0
  269. package/src/tools/webbrowser/browserAxState.ts +142 -0
  270. package/src/tools/webbrowser/browserBatch.js +1578 -0
  271. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  272. package/src/tools/webbrowser/browserCdp.js +208 -0
  273. package/src/tools/webbrowser/browserCdp.ts +255 -0
  274. package/src/tools/webbrowser/browserConditions.js +24 -0
  275. package/src/tools/webbrowser/browserConditions.ts +45 -0
  276. package/src/tools/webbrowser/browserContent.js +281 -0
  277. package/src/tools/webbrowser/browserContent.ts +438 -0
  278. package/src/tools/webbrowser/browserControl.js +131 -34
  279. package/src/tools/webbrowser/browserControl.ts +210 -56
  280. package/src/tools/webbrowser/browserDaemon.js +22 -14
  281. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  282. package/src/tools/webbrowser/browserFrames.js +47 -0
  283. package/src/tools/webbrowser/browserFrames.ts +54 -0
  284. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  286. package/src/tools/webbrowser/browserLocator.js +140 -0
  287. package/src/tools/webbrowser/browserLocator.ts +194 -0
  288. package/src/tools/webbrowser/browserOutcome.js +10 -17
  289. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  290. package/src/tools/webbrowser/browserRecovery.js +58 -0
  291. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  292. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  293. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  294. package/src/tools/webbrowser/browserService.js +28 -2
  295. package/src/tools/webbrowser/browserService.ts +49 -9
  296. package/src/tools/webbrowser/browserStream.js +132 -33
  297. package/src/tools/webbrowser/browserStream.ts +224 -50
  298. package/src/tools/webbrowser/browserTabs.js +48 -15
  299. package/src/tools/webbrowser/browserTabs.ts +178 -96
  300. package/src/tools/webbrowser/webbrowser.js +679 -144
  301. package/src/tools/webbrowser/webbrowser.ts +975 -236
  302. package/src/tools/webfetch/preapproved.js +0 -2
  303. package/src/tools/webfetch/preapproved.ts +0 -2
  304. package/src/tools/websearch/websearch.js +129 -8
  305. package/src/tools/websearch/websearch.ts +138 -6
  306. package/src/types.ts +459 -40
  307. package/src/ui/App.js +377 -58
  308. package/src/ui/App.tsx +576 -111
  309. package/src/ui/LiveArea.js +14 -8
  310. package/src/ui/LiveArea.tsx +14 -10
  311. package/src/ui/MessageList.js +63 -20
  312. package/src/ui/MessageList.tsx +101 -16
  313. package/src/ui/ModelPicker.js +7 -4
  314. package/src/ui/ModelPicker.tsx +55 -8
  315. package/src/ui/hooks/useChat.js +152 -163
  316. package/src/ui/hooks/useChat.ts +396 -334
  317. package/src/ui/loginCommand.js +56 -0
  318. package/src/ui/loginCommand.ts +63 -0
  319. package/src/ui/toolProgress.js +41 -0
  320. package/src/ui/toolProgress.ts +44 -0
  321. package/src/web/browserBridge.js +20 -2
  322. package/src/web/browserBridge.ts +20 -2
  323. package/src/web/protocol.ts +1897 -194
  324. package/workflows/adaptive-research/workflow.mjs +86 -0
  325. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  326. package/workflows/e2e-llm/workflow.mjs +52 -0
  327. package/workflows/e2e-smoke/workflow.mjs +59 -0
  328. package/workflows/e2e-vision-schema/README.md +48 -0
  329. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  330. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  331. package/workflows/file-census/README.md +14 -0
  332. package/workflows/file-census/scripts/.gitkeep +2 -0
  333. package/workflows/file-census/workflow.mjs +110 -0
  334. package/workflows/goal/README.md +166 -0
  335. package/workflows/goal/prompts/audit.md +57 -0
  336. package/workflows/goal/prompts/contract.md +56 -0
  337. package/workflows/goal/prompts/iterate.md +37 -0
  338. package/workflows/goal/workflow.mjs +501 -0
  339. package/workflows/illustrate/README.md +90 -0
  340. package/workflows/illustrate/assets/engines.json +20 -0
  341. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  342. package/workflows/illustrate/assets/extract-bing.js +33 -0
  343. package/workflows/illustrate/assets/extract-google.js +31 -0
  344. package/workflows/illustrate/workflow.mjs +301 -0
  345. package/workflows/plan/workflow.mjs +389 -0
  346. package/workflows/question-crops/README.md +35 -0
  347. package/workflows/question-crops/prompts/inventory.md +23 -0
  348. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  349. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  350. package/workflows/question-crops/workflow.mjs +172 -0
  351. package/workflows/ralph-loop/workflow.mjs +162 -0
  352. package/workflows/research/README.md +74 -0
  353. package/workflows/research/prompts/s0-goal.md +43 -0
  354. package/workflows/research/prompts/s1-early-exit.md +22 -0
  355. package/workflows/research/prompts/s1-map.md +58 -0
  356. package/workflows/research/prompts/s2-options.md +53 -0
  357. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  358. package/workflows/research/prompts/s4-verify.md +74 -0
  359. package/workflows/research/prompts/s5-synthesis.md +81 -0
  360. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  361. package/workflows/research/prompts/s6-package.md +32 -0
  362. package/workflows/research/scripts/build-report.mjs +98 -0
  363. package/workflows/research/workflow.mjs +288 -0
  364. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  365. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  366. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  367. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  368. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  369. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  370. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  371. package/workflows/wrong-question-docx/README.md +55 -0
  372. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  373. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  374. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  375. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  376. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  377. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  378. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  379. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  380. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  381. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  382. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  383. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  384. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  385. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  386. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  387. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  388. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  389. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  390. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  391. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  392. package/plugins/workflow-runner/src/expressions.js +0 -639
  393. package/plugins/workflow-runner/src/expressions.ts +0 -640
  394. package/plugins/workflow-runner/src/loader.js +0 -573
  395. package/plugins/workflow-runner/src/loader.ts +0 -721
  396. package/plugins/workflow-runner/src/multimodal.js +0 -38
  397. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  398. package/plugins/workflow-runner/src/recovery.js +0 -126
  399. package/plugins/workflow-runner/src/recovery.ts +0 -156
  400. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  401. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  402. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  403. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  404. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  405. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  406. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  407. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  408. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  409. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  410. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  411. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  412. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  413. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  414. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  415. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  416. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  417. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  418. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  419. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  420. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  421. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  422. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  423. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  424. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  425. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  426. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  427. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  428. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  429. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  430. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  431. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  432. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  433. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  434. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  435. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  436. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  437. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  438. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  439. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  440. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  441. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  442. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  443. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  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 -201
  468. package/workflows/research.yaml +0 -873
  469. package/workflows/schema.json +0 -176
  470. package/workflows/webppt.yaml +0 -496
  471. package/workflows/wechat-reading-shots.yaml +0 -315
  472. package/workflows/word.yaml +0 -720
  473. package/workflows/youtube-shorts.yaml +0 -202
  474. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -1,324 +0,0 @@
1
- /**
2
- * ============================================================
3
- * test/taskLifecycle.test.ts —— 任务身份生命周期 + in-run retry 的新增覆盖
4
- * ------------------------------------------------------------
5
- * 钉死本轮修复的三条新行为(此前缺直接覆盖):
6
- * L2 completed 经 .done 检测:成功归档后,同 goal 重跑 → completed(报真实产物),
7
- * 不再因 archive 改名而误判 fresh 重跑。
8
- * L3 new-task 清声明产物:换一个不同 goal 重跑同名 workflow → new-task,
9
- * 删掉旧任务在 cwd 留下的声明产物(如旧 PLAN.md),不污染新任务。
10
- * retry in-run 重试:llm 步首次 LLM 出错(空产出)→ 抛异常 → runner 按 max_retries
11
- * 确定性重跑同一步 → 第 2 次成功 → workflow_done(验证 P0-1 + 重试闭环)。
12
- *
13
- * L2/L3 用 WorkflowState 单元测试(无需 LLM);retry 用 runWorkflow + ctx.chat DI。
14
- * ============================================================
15
- */
16
-
17
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
18
- import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
19
- import { tmpdir } from 'node:os';
20
- import { join } from 'node:path';
21
-
22
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
23
- import { WorkflowState } from '../src/workflowState.js';
24
- import { runWorkflow } from '../src/runner.js';
25
- import type { LoopEvent, Provider } from '../../../src/types.js';
26
- import type { RunContext, StepDef, WorkflowDef, WorkflowEvent } from '../src/types.js';
27
-
28
- type WfOrLoop = WorkflowEvent | LoopEvent;
29
-
30
- const fakeProvider: Provider = {
31
- name: 'test',
32
- baseURL: '',
33
- apiKey: '',
34
- model: 'm',
35
- contextWindow: 128000,
36
- };
37
-
38
- async function collect(
39
- gen: AsyncGenerator<WfOrLoop, void, void>,
40
- ): Promise<WfOrLoop[]> {
41
- const out: WfOrLoop[] = [];
42
- for await (const ev of gen) out.push(ev);
43
- return out;
44
- }
45
-
46
- const STEPS: StepDef[] = [{ id: 's1', type: 'assert', condition: 'true' }];
47
-
48
- describe('任务身份生命周期(L2 completed / L3 new-task 清产物)', () => {
49
- let tmp: string;
50
-
51
- beforeEach(() => {
52
- tmp = mkdtempSync(join(tmpdir(), 'wf-lifecycle-'));
53
- });
54
- afterEach(() => {
55
- rmSync(tmp, { recursive: true, force: true });
56
- });
57
-
58
- it('成功归档后同 goal 重跑 → completed,报真实存在的声明产物(L2)', async () => {
59
- const artifacts = ['PLAN.md'];
60
-
61
- // 第一次:fresh
62
- const s1 = new WorkflowState(tmp, 'plan');
63
- const r1 = await s1.init('plan', { goal: '目标A' }, STEPS, 1, artifacts);
64
- expect(r1.mode).toBe('fresh');
65
-
66
- // 模拟成功:产物落到 cwd 根 + 标记 done + 归档(改名 .done)
67
- writeFileSync(join(tmp, 'PLAN.md'), '# plan');
68
- await s1.markDone();
69
- await s1.archive();
70
- // 归档后活动实例被改名 .done(workflow 级父目录保留——里面可能有多个实例)
71
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'plan'))).toBe(true);
72
- expect(existsSync(s1.dir + '.done')).toBe(true);
73
- expect(existsSync(s1.dir)).toBe(false);
74
-
75
- // 第二次:同 goal 重跑 → completed(经 .done 检测),报真实产物
76
- const s2 = new WorkflowState(tmp, 'plan');
77
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, artifacts);
78
- expect(r2.mode).toBe('completed');
79
- expect(r2.artifacts).toEqual(['PLAN.md']);
80
- });
81
-
82
- it('completed 只报实际存在的产物(声明了但被删的不报)', async () => {
83
- const s1 = new WorkflowState(tmp, 'plan');
84
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md', 'EXTRA.md']);
85
- writeFileSync(join(tmp, 'PLAN.md'), '# plan'); // 只写 PLAN.md,不写 EXTRA.md
86
- await s1.markDone();
87
- await s1.archive();
88
-
89
- const s2 = new WorkflowState(tmp, 'plan');
90
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md', 'EXTRA.md']);
91
- expect(r2.mode).toBe('completed');
92
- expect(r2.artifacts).toEqual(['PLAN.md']); // EXTRA.md 不存在 → 不报
93
- });
94
-
95
- it('换不同 goal 重跑同名 workflow → new-task,清掉旧任务的声明产物(L3)', async () => {
96
- // 任务A 成功归档,留下 PLAN.md
97
- const s1 = new WorkflowState(tmp, 'plan');
98
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
99
- writeFileSync(join(tmp, 'PLAN.md'), '# plan A');
100
- await s1.markDone();
101
- await s1.archive();
102
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(true);
103
-
104
- // 换完全不同的 goal 重跑 → new-task,旧 PLAN.md 被清(不污染新任务)
105
- const s2 = new WorkflowState(tmp, 'plan');
106
- const r2 = await s2.init('plan', { goal: '完全不相关的目标B' }, STEPS, 1, ['PLAN.md']);
107
- expect(r2.mode).toBe('new-task');
108
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
109
- expect(r2.archivedTo).toBeDefined();
110
- expect(existsSync(join(tmp, r2.archivedTo as string, 'PLAN.md'))).toBe(true);
111
- });
112
-
113
- it('legacy 状态文件(无 artifacts 字段)+ 同名 workflow 换 goal → new-task 用本次声明清单兜底清理', async () => {
114
- // 手写旧版 current.json(没有 artifacts 字段)+ 磁盘残留 PLAN.md(E6 后按名隔离路径)
115
- const { mkdirSync } = await import('node:fs');
116
- mkdirSync(join(tmp, '.minimal-agent-workflow', 'plan'), { recursive: true });
117
- writeFileSync(
118
- join(tmp, '.minimal-agent-workflow', 'plan', 'current.json'),
119
- JSON.stringify({
120
- name: 'plan',
121
- taskId: 'deadbeefdeadbeef',
122
- status: 'running',
123
- startedAt: '2026-01-01T00:00:00.000Z',
124
- // 注意:无 artifacts 字段(legacy)
125
- }),
126
- );
127
- writeFileSync(join(tmp, 'PLAN.md'), '# 旧任务残留');
128
-
129
- const s = new WorkflowState(tmp, 'plan');
130
- const r = await s.init('plan', { goal: '全新目标' }, STEPS, 1, ['PLAN.md']);
131
- expect(r.mode).toBe('new-task');
132
- // 兜底清理生效:同名 workflow 的声明产物语义稳定,按本次声明清单清掉残留
133
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
134
- expect(r.archivedTo).toBeDefined();
135
- expect(existsSync(join(tmp, r.archivedTo as string, 'PLAN.md'))).toBe(true);
136
- });
137
-
138
- it('/new 后孤儿产物:无任何状态但声明产物已存在 → fresh 启动时清理(全新任务从干净状态开始)', async () => {
139
- // /new 删掉了 .minimal-agent-workflow*/(artifacts 清单随之丢失),PLAN.md 成孤儿。
140
- // 用户约定:全新 plan 一律清理残留与中间文件;删除范围仅限本工作流声明的产物。
141
- writeFileSync(join(tmp, 'PLAN.md'), '# 孤儿产物');
142
-
143
- const s = new WorkflowState(tmp, 'plan');
144
- const r = await s.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
145
- expect(r.mode).toBe('fresh');
146
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
147
- expect(r.archivedTo).toBeDefined();
148
- expect(existsSync(join(tmp, r.archivedTo as string, 'PLAN.md'))).toBe(true);
149
- });
150
-
151
- it('A4:归档保留相对路径结构,只归档声明产物、不碰未声明文件', async () => {
152
- const { mkdirSync } = await import('node:fs');
153
- mkdirSync(join(tmp, 'out'), { recursive: true });
154
- const s1 = new WorkflowState(tmp, 'plan');
155
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['out/PLAN.md']);
156
- writeFileSync(join(tmp, 'out', 'PLAN.md'), '# A');
157
- writeFileSync(join(tmp, 'out', 'USER-OWN.md'), '# 用户自己的文件');
158
-
159
- const s2 = new WorkflowState(tmp, 'plan');
160
- const r2 = await s2.init('plan', { goal: '目标B' }, STEPS, 1, ['out/PLAN.md']);
161
- expect(r2.mode).toBe('new-task');
162
- expect(existsSync(join(tmp, 'out', 'PLAN.md'))).toBe(false);
163
- expect(existsSync(join(tmp, 'out', 'USER-OWN.md'))).toBe(true);
164
- expect(existsSync(join(tmp, r2.archivedTo as string, 'out', 'PLAN.md'))).toBe(true);
165
- });
166
-
167
- it('B8:声明产物支持 glob(out/*.md),new-task 清理时展开为实际文件归档', async () => {
168
- const { mkdirSync } = await import('node:fs');
169
- mkdirSync(join(tmp, 'out'), { recursive: true });
170
- const s1 = new WorkflowState(tmp, 'research');
171
- await s1.init('research', { goal: '目标A' }, STEPS, 1, ['out/deep-dive-*.md']);
172
- writeFileSync(join(tmp, 'out', 'deep-dive-a.md'), '# A');
173
- writeFileSync(join(tmp, 'out', 'deep-dive-b.md'), '# B');
174
- writeFileSync(join(tmp, 'out', 'notes.txt'), '# 不匹配 md');
175
-
176
- const s2 = new WorkflowState(tmp, 'research');
177
- const r2 = await s2.init('research', { goal: '目标B' }, STEPS, 1, ['out/deep-dive-*.md']);
178
- expect(r2.mode).toBe('new-task');
179
- expect(existsSync(join(tmp, 'out', 'deep-dive-a.md'))).toBe(false);
180
- expect(existsSync(join(tmp, 'out', 'deep-dive-b.md'))).toBe(false);
181
- expect(existsSync(join(tmp, 'out', 'notes.txt'))).toBe(true);
182
- const trash = join(tmp, r2.archivedTo as string);
183
- expect(existsSync(join(trash, 'out', 'deep-dive-a.md'))).toBe(true);
184
- expect(existsSync(join(trash, 'out', 'deep-dive-b.md'))).toBe(true);
185
- });
186
-
187
- it('B8:越界 glob(../x*)不展开不清理(fail-closed)', async () => {
188
- writeFileSync(join(tmp, 'PLAN.md'), '# inside');
189
- const outside = mkdtempSync(join(tmpdir(), 'wf-outside-'));
190
- try {
191
- writeFileSync(join(outside, 'secret.md'), '# outside');
192
- const s = new WorkflowState(tmp, 'plan');
193
- const r = await s.init('plan', { goal: '目标A' }, STEPS, 1, ['../x*.md', 'PLAN.md']);
194
- expect(r.mode).toBe('fresh');
195
- expect(existsSync(join(outside, 'secret.md'))).toBe(true);
196
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
197
- } finally {
198
- rmSync(outside, { recursive: true, force: true });
199
- }
200
- });
201
-
202
- it('resume 恢复点用最后完成步的【索引】而非 checkpoint 计数(when 跳过步不再被重复执行)', async () => {
203
- // steps: s1 ✓ / s2(when=false 跳过,无 checkpoint) / s3 ✓ / s4 失败。
204
- // 计数法:2 个 checkpoint - backoff(1) = 1 → 从 s2 重跑(重复执行已決策跳过的步);
205
- // 索引法:s3 的索引 2 + 1 - 1 = 2 → 从 s3 重跑(正确的覆盖重合区)。
206
- const stepsWithSkip: StepDef[] = [
207
- { id: 's1', type: 'assert', condition: 'true' },
208
- { id: 's2', type: 'assert', condition: 'true', when: 'false' },
209
- { id: 's3', type: 'assert', condition: 'true' },
210
- { id: 's4', type: 'assert', condition: 'true' },
211
- ];
212
- const s1 = new WorkflowState(tmp, 'plan');
213
- await s1.init('plan', { goal: '目标A' }, stepsWithSkip, 1, []);
214
- await s1.recordCheckpoint('s1', 'ok', {}, {});
215
- await s1.recordCheckpoint('s3', 'ok', {}, {});
216
- // 不 markDone(s4 失败现场)
217
-
218
- const s2 = new WorkflowState(tmp, 'plan');
219
- const r = await s2.init('plan', { goal: '目标A' }, stepsWithSkip, 1, []);
220
- expect(r.mode).toBe('resume');
221
- expect(r.startFrom).toBe(2); // s3 的索引,而不是计数法的 1
222
- });
223
-
224
- it('同任务 resume 不清理声明产物(清理只发生在 fresh/new-task)', async () => {
225
- const s1 = new WorkflowState(tmp, 'plan');
226
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
227
- writeFileSync(join(tmp, 'PLAN.md'), '# 半成品'); // 任务自己写出的中间产物
228
- // 不 markDone(模拟中断)→ 同 goal 重跑 resume
229
- const s2 = new WorkflowState(tmp, 'plan');
230
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
231
- expect(r2.mode).toBe('resume');
232
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(true); // 现场保留
233
- });
234
-
235
- it('未完成(中断)任务同 goal 重跑 → resume(非 completed)', async () => {
236
- const s1 = new WorkflowState(tmp, 'plan');
237
- const r1 = await s1.init('plan', { goal: '目标A' }, STEPS, 1, []);
238
- expect(r1.mode).toBe('fresh');
239
- // 不 markDone、不 archive(模拟中断)
240
- const s2 = new WorkflowState(tmp, 'plan');
241
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, []);
242
- expect(r2.mode).toBe('resume');
243
- });
244
- });
245
-
246
- describe('in-run retry(self_heal / max_retries)', () => {
247
- let tmp: string;
248
- let ctx: RunContext;
249
-
250
- beforeEach(() => {
251
- tmp = mkdtempSync(join(tmpdir(), 'wf-retry-'));
252
- process.env.MINIMAL_AGENT_CWD = tmp;
253
- _resetWorkingDir();
254
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
255
- getWorkingDir: () => tmp,
256
- initWorkingDir: () => tmp,
257
- _resetWorkingDir: () => {},
258
- }));
259
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: [] };
260
- });
261
- afterEach(() => {
262
- delete process.env.MINIMAL_AGENT_CWD;
263
- _resetWorkingDir();
264
- rmSync(tmp, { recursive: true, force: true });
265
- });
266
-
267
- it('llm 步首次 LLM 出错(空产出)→ max_retries 重跑 → 第 2 次成功 → done', async () => {
268
- let calls = 0;
269
- // 第 1 次 chat 抛错 → 真实 runQuery 捕获为 llm_error → llm.ts 空产出抛异常 → runner 重试;
270
- // 第 2 次 chat 正常产出 → 成功。
271
- ctx.chat = async function* () {
272
- calls++;
273
- if (calls === 1) throw new Error('transient LLM error');
274
- yield { type: 'text_delta', delta: 'recovered-output' };
275
- yield { type: 'done', stopReason: 'stop' };
276
- };
277
-
278
- const def: WorkflowDef = {
279
- name: 'retry-wf',
280
- description: 'd',
281
- steps: [
282
- { id: 'g', llm: 'do it', capture: { text: 'out' }, max_retries: 1 },
283
- { id: 'check', type: 'assert', condition: 'out == "recovered-output"' },
284
- ],
285
- };
286
-
287
- const events = await collect(runWorkflow(def, {}, ctx));
288
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
289
- // 确实重试了:chat 被调 2 次 + 有一条重试 warning
290
- expect(calls).toBe(2);
291
- expect(
292
- events.some((e) => e.type === 'warning' && e.message.includes('重试')),
293
- ).toBe(true);
294
- });
295
-
296
- it('max_retries 用尽仍失败 → halt(无 done)', async () => {
297
- // chat 每次都抛 → llm 步每次空产出抛异常 → 重试用尽 → 默认 onError=halt。
298
- ctx.chat = async function* () {
299
- throw new Error('always fails');
300
- // biome-ignore lint/correctness/noUnreachable: stub
301
- yield { type: 'done', stopReason: 'stop' };
302
- };
303
-
304
- const def: WorkflowDef = {
305
- name: 'retry-exhaust',
306
- description: 'd',
307
- steps: [
308
- { id: 'g', llm: 'do it', max_retries: 1 },
309
- { id: 'after', type: 'assert', condition: 'true' }, // 不应执行
310
- ],
311
- };
312
-
313
- const events = await collect(runWorkflow(def, {}, ctx));
314
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
315
- expect(events.some((e) => e.type === 'error')).toBe(true);
316
- const startedIds = events
317
- .filter(
318
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
319
- e.type === 'workflow_step_start',
320
- )
321
- .map((e) => e.id);
322
- expect(startedIds).not.toContain('after');
323
- });
324
- });
@@ -1,221 +0,0 @@
1
- /**
2
- * ============================================================
3
- * plugins/workflow-runner/test/toolArtifactOverwrite.test.ts
4
- * ------------------------------------------------------------
5
- * tool 步「声明产物覆盖」契约(P0-B 回归锚):
6
- *
7
- * 内核 Write/Edit 有「文件已存在必须先 Read」守卫(fileState 进程级 Map,
8
- * 跨进程 / resume / 残留旧产物时必空)。确定性 tool 步(如 plan.yaml 的
9
- * write_plan: tool:Write → ./PLAN.md)的 args 是 yaml 写死的,模型没机会先
10
- * Read —— 曾导致旧 PLAN.md 存在时整条工作流 halt(且重试同败)。
11
- *
12
- * 契约:目标文件命中**声明产物**(def 级 / step 级 artifacts:)→ 自动
13
- * pre-Read 解守卫、覆盖成功;非声明产物 → 盲写保护原样生效。
14
- * 每个用例 clearFileState() 模拟新进程(守卫状态为空的最坏情形)。
15
- * ============================================================
16
- */
17
-
18
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
19
- import {
20
- mkdirSync,
21
- mkdtempSync,
22
- readFileSync,
23
- rmSync,
24
- writeFileSync,
25
- } from 'node:fs';
26
- import { tmpdir } from 'node:os';
27
- import { join } from 'node:path';
28
-
29
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
30
- import { clearFileState } from '../../../src/tools/shared/fileState.js';
31
- import { ALL_TOOLS } from '../../../src/tools/index.js';
32
- import type { LoopEvent, Provider } from '../../../src/types.js';
33
- import { computeTaskId } from '../src/taskIdentity.js';
34
- import { runWorkflow } from '../src/runner.js';
35
- import type { RunContext, WorkflowDef, WorkflowEvent } from '../src/types.js';
36
-
37
- type WfOrLoop = WorkflowEvent | LoopEvent;
38
-
39
- const fakeProvider: Provider = {
40
- name: 'test',
41
- baseURL: '',
42
- apiKey: '',
43
- model: 'm',
44
- contextWindow: 128000,
45
- };
46
-
47
- async function collect(
48
- gen: AsyncGenerator<WfOrLoop, void, void>,
49
- ): Promise<WfOrLoop[]> {
50
- const out: WfOrLoop[] = [];
51
- for await (const ev of gen) out.push(ev);
52
- return out;
53
- }
54
-
55
- describe('workflows/tool 步声明产物覆盖(P0-B)', () => {
56
- let tmp: string;
57
- let ctx: RunContext;
58
-
59
- beforeEach(() => {
60
- tmp = mkdtempSync(join(tmpdir(), 'wf-artifact-'));
61
- process.env.MINIMAL_AGENT_CWD = tmp;
62
- _resetWorkingDir();
63
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
64
- getWorkingDir: () => tmp,
65
- initWorkingDir: () => tmp,
66
- _resetWorkingDir: () => {},
67
- }));
68
- clearFileState(); // 模拟新进程:守卫的"已 Read"记录为空
69
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: ALL_TOOLS };
70
- });
71
-
72
- afterEach(() => {
73
- delete process.env.MINIMAL_AGENT_CWD;
74
- _resetWorkingDir();
75
- clearFileState();
76
- rmSync(tmp, { recursive: true, force: true });
77
- });
78
-
79
- function writeDef(artifacts: {
80
- defLevel?: string[];
81
- stepLevel?: string[];
82
- filePath?: string;
83
- }): WorkflowDef {
84
- return {
85
- name: 'write-out',
86
- description: '确定性落盘',
87
- artifacts: artifacts.defLevel,
88
- steps: [
89
- {
90
- id: 'w1',
91
- tool: 'Write',
92
- args: {
93
- file_path: artifacts.filePath ?? 'OUT.md',
94
- content: 'fresh-content',
95
- },
96
- artifacts: artifacts.stepLevel,
97
- },
98
- ],
99
- };
100
- }
101
-
102
- /** 预置「同任务未完成」状态:让下一次 runWorkflow 判 resume(不清产物、不重建),
103
- * 从而专测 tool 步的声明产物 pre-Read 解守卫路径(fresh/new-task 会先把残留清掉,
104
- * 到不了守卫;resume + 新进程才是守卫挡死的真实场景)。 */
105
- function seedSameTaskState(name: string): void {
106
- const { hash } = computeTaskId(name, {});
107
- // E6 后状态目录按 workflow 名隔离
108
- const dir = join(tmp, '.minimal-agent-workflow', name);
109
- mkdirSync(join(dir, 'checkpoints'), { recursive: true });
110
- writeFileSync(
111
- join(dir, 'current.json'),
112
- JSON.stringify({
113
- name,
114
- taskId: hash,
115
- status: 'running',
116
- startedAt: '2026-01-01T00:00:00.000Z',
117
- }),
118
- );
119
- }
120
-
121
- it('残留旧产物 + def 级 artifacts 声明 → fresh 启动时清理 + warning + 正常写出', async () => {
122
- // 复现现场:上次任务残留的 0 字节产物(如 /new 后的孤儿 PLAN.md)。
123
- // 全新任务约定:启动即清理声明产物残留,从干净状态开始。
124
- writeFileSync(join(tmp, 'OUT.md'), '');
125
-
126
- const events = await collect(
127
- runWorkflow(writeDef({ defLevel: ['OUT.md'] }), {}, ctx),
128
- );
129
-
130
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
131
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
132
- // 清理可见化:fresh 启动时报「已清理旧产物」warning
133
- expect(
134
- events.some((e) => e.type === 'warning' && e.message.includes('旧产物')),
135
- ).toBe(true);
136
- });
137
-
138
- it('同任务 resume(新进程)+ def 级声明 → pre-Read 解守卫、覆盖自家产物成功', async () => {
139
- // resume 不清产物(现场保留),新进程守卫表为空 → 必须靠 pre-Read 解守卫
140
- seedSameTaskState('write-out');
141
- writeFileSync(join(tmp, 'OUT.md'), '# 上次任务自己写出的半成品');
142
-
143
- const events = await collect(
144
- runWorkflow(writeDef({ defLevel: ['OUT.md'] }), {}, ctx),
145
- );
146
-
147
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
148
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
149
- });
150
-
151
- it('残留同名文件但【未】声明 artifact → 盲写保护原样生效(halt 带"请先 Read")', async () => {
152
- writeFileSync(join(tmp, 'OUT.md'), '用户自己的文件,不该被盲写');
153
-
154
- const events = await collect(runWorkflow(writeDef({}), {}, ctx));
155
-
156
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
157
- const halt = events.find(
158
- (e): e is { type: 'error'; error: string } =>
159
- e.type === 'error' && e.error.includes('Workflow halted'),
160
- );
161
- expect(halt).toBeDefined();
162
- expect(halt!.error).toContain('Read');
163
- // 内容未被覆盖
164
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toContain('用户自己的文件');
165
- });
166
-
167
- it('resume + 仅 step 级 artifacts 声明也走 pre-Read', async () => {
168
- seedSameTaskState('write-out');
169
- writeFileSync(join(tmp, 'OUT.md'), 'old');
170
-
171
- const events = await collect(
172
- runWorkflow(writeDef({ stepLevel: ['OUT.md'] }), {}, ctx),
173
- );
174
-
175
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
176
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
177
- });
178
-
179
- it('resume + 声明产物超字符上限(真 Read 会截断)→ 解截断守卫、覆盖成功', async () => {
180
- // 复现 plan.yaml 回写「变长 PLAN.md」的 halt(真实事故):声明产物已存在且
181
- // 内容 > DEFAULT_MAX_RESULT_SIZE_CHARS(30000) —— 旧实现 pre-Read 用真 Read 解守卫,
182
- // 会触发字符上限截断 → 记 truncated:true → Write 的「截断禁写」硬守卫拒绝 → 整条 halt。
183
- // 修复后 pre-Read 直接登记 truncated:false,never-read + truncated 两道守卫一并解除,
184
- // 声明产物整体覆盖放行。
185
- seedSameTaskState('write-out');
186
- writeFileSync(join(tmp, 'OUT.md'), 'A'.repeat(40_000));
187
-
188
- const events = await collect(
189
- runWorkflow(writeDef({ defLevel: ['OUT.md'] }), {}, ctx),
190
- );
191
-
192
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
193
- expect(events.some((e) => e.type === 'error')).toBe(false);
194
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
195
- });
196
-
197
- it('resume + args 用 ./相对路径、声明用裸文件名 → 归一化后等价命中', async () => {
198
- seedSameTaskState('write-out');
199
- writeFileSync(join(tmp, 'OUT.md'), 'old');
200
-
201
- const events = await collect(
202
- runWorkflow(
203
- writeDef({ defLevel: ['OUT.md'], filePath: './OUT.md' }),
204
- {},
205
- ctx,
206
- ),
207
- );
208
-
209
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
210
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
211
- });
212
-
213
- it('目标文件不存在(新建场景)→ 不需要解守卫,正常写出', async () => {
214
- const events = await collect(
215
- runWorkflow(writeDef({ defLevel: ['OUT.md'] }), {}, ctx),
216
- );
217
-
218
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
219
- expect(readFileSync(join(tmp, 'OUT.md'), 'utf8')).toBe('fresh-content');
220
- });
221
- });
@@ -1,29 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
-
3
- import { ALL_TOOLS } from '../../../src/tools/index.js';
4
- import type { Provider } from '../../../src/types.js';
5
- import { execToolStep } from '../src/stepExecutors/tool.js';
6
- import { VarStack, type RunContext } from '../src/types.js';
7
-
8
- const provider: Provider = {
9
- name: 'test', baseURL: '', apiKey: '', model: 'fixture', contextWindow: 128_000,
10
- };
11
-
12
- describe('workflow deterministic tool capability boundary', () => {
13
- test('a YAML tool step cannot restore WebBrowser removed by the host runtime', async () => {
14
- const ctx: RunContext = {
15
- provider,
16
- history: [],
17
- cwd: process.cwd(),
18
- tools: ALL_TOOLS.filter((tool) => ['WebSearch', 'WebFetch'].includes(tool.name)),
19
- };
20
- const generator = execToolStep(
21
- { id: 'hidden-browser', tool: 'WebBrowser', args: { action: 'navigate', url: 'https://example.com' } },
22
- new VarStack(),
23
- ctx,
24
- );
25
- await expect(generator.next()).rejects.toThrow(
26
- '不在当前宿主授权的 Workflow 工具集中',
27
- );
28
- });
29
- });