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,270 +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(E6 后按名隔离)
71
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'plan'))).toBe(false);
72
- expect(existsSync(join(tmp, '.minimal-agent-workflow', 'plan.done'))).toBe(true);
73
-
74
- // 第二次:同 goal 重跑 → completed(经 .done 检测),报真实产物
75
- const s2 = new WorkflowState(tmp, 'plan');
76
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, artifacts);
77
- expect(r2.mode).toBe('completed');
78
- expect(r2.artifacts).toEqual(['PLAN.md']);
79
- });
80
-
81
- it('completed 只报实际存在的产物(声明了但被删的不报)', async () => {
82
- const s1 = new WorkflowState(tmp, 'plan');
83
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md', 'EXTRA.md']);
84
- writeFileSync(join(tmp, 'PLAN.md'), '# plan'); // 只写 PLAN.md,不写 EXTRA.md
85
- await s1.markDone();
86
- await s1.archive();
87
-
88
- const s2 = new WorkflowState(tmp, 'plan');
89
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md', 'EXTRA.md']);
90
- expect(r2.mode).toBe('completed');
91
- expect(r2.artifacts).toEqual(['PLAN.md']); // EXTRA.md 不存在 → 不报
92
- });
93
-
94
- it('换不同 goal 重跑同名 workflow → new-task,清掉旧任务的声明产物(L3)', async () => {
95
- // 任务A 成功归档,留下 PLAN.md
96
- const s1 = new WorkflowState(tmp, 'plan');
97
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
98
- writeFileSync(join(tmp, 'PLAN.md'), '# plan A');
99
- await s1.markDone();
100
- await s1.archive();
101
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(true);
102
-
103
- // 换完全不同的 goal 重跑 → new-task,旧 PLAN.md 被清(不污染新任务)
104
- const s2 = new WorkflowState(tmp, 'plan');
105
- const r2 = await s2.init('plan', { goal: '完全不相关的目标B' }, STEPS, 1, ['PLAN.md']);
106
- expect(r2.mode).toBe('new-task');
107
- expect(r2.cleanedArtifacts).toContain('PLAN.md');
108
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
109
- });
110
-
111
- it('legacy 状态文件(无 artifacts 字段)+ 同名 workflow 换 goal → new-task 用本次声明清单兜底清理', async () => {
112
- // 手写旧版 current.json(没有 artifacts 字段)+ 磁盘残留 PLAN.md(E6 后按名隔离路径)
113
- const { mkdirSync } = await import('node:fs');
114
- mkdirSync(join(tmp, '.minimal-agent-workflow', 'plan'), { recursive: true });
115
- writeFileSync(
116
- join(tmp, '.minimal-agent-workflow', 'plan', 'current.json'),
117
- JSON.stringify({
118
- name: 'plan',
119
- taskId: 'deadbeefdeadbeef',
120
- status: 'running',
121
- startedAt: '2026-01-01T00:00:00.000Z',
122
- // 注意:无 artifacts 字段(legacy)
123
- }),
124
- );
125
- writeFileSync(join(tmp, 'PLAN.md'), '# 旧任务残留');
126
-
127
- const s = new WorkflowState(tmp, 'plan');
128
- const r = await s.init('plan', { goal: '全新目标' }, STEPS, 1, ['PLAN.md']);
129
- expect(r.mode).toBe('new-task');
130
- // 兜底清理生效:同名 workflow 的声明产物语义稳定,按本次声明清单清掉残留
131
- expect(r.cleanedArtifacts).toContain('PLAN.md');
132
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
133
- });
134
-
135
- it('/new 后孤儿产物:无任何状态但声明产物已存在 → fresh 启动时清理(全新任务从干净状态开始)', async () => {
136
- // /new 删掉了 .minimal-agent-workflow*/(artifacts 清单随之丢失),PLAN.md 成孤儿。
137
- // 用户约定:全新 plan 一律清理残留与中间文件;删除范围仅限本工作流声明的产物。
138
- writeFileSync(join(tmp, 'PLAN.md'), '# 孤儿产物');
139
-
140
- const s = new WorkflowState(tmp, 'plan');
141
- const r = await s.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
142
- expect(r.mode).toBe('fresh');
143
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(false);
144
- // 可见化:runner 据此报「已清理旧产物」warning
145
- expect(r.cleanedArtifacts).toEqual(['PLAN.md']);
146
- });
147
-
148
- it('resume 恢复点用最后完成步的【索引】而非 checkpoint 计数(when 跳过步不再被重复执行)', async () => {
149
- // steps: s1 ✓ / s2(when=false 跳过,无 checkpoint) / s3 ✓ / s4 失败。
150
- // 计数法:2 个 checkpoint - backoff(1) = 1 → 从 s2 重跑(重复执行已決策跳过的步);
151
- // 索引法:s3 的索引 2 + 1 - 1 = 2 → 从 s3 重跑(正确的覆盖重合区)。
152
- const stepsWithSkip: StepDef[] = [
153
- { id: 's1', type: 'assert', condition: 'true' },
154
- { id: 's2', type: 'assert', condition: 'true', when: 'false' },
155
- { id: 's3', type: 'assert', condition: 'true' },
156
- { id: 's4', type: 'assert', condition: 'true' },
157
- ];
158
- const s1 = new WorkflowState(tmp, 'plan');
159
- await s1.init('plan', { goal: '目标A' }, stepsWithSkip, 1, []);
160
- await s1.recordCheckpoint('s1', 'ok', {}, {});
161
- await s1.recordCheckpoint('s3', 'ok', {}, {});
162
- // 不 markDone(s4 失败现场)
163
-
164
- const s2 = new WorkflowState(tmp, 'plan');
165
- const r = await s2.init('plan', { goal: '目标A' }, stepsWithSkip, 1, []);
166
- expect(r.mode).toBe('resume');
167
- expect(r.startFrom).toBe(2); // s3 的索引,而不是计数法的 1
168
- });
169
-
170
- it('同任务 resume 不清理声明产物(清理只发生在 fresh/new-task)', async () => {
171
- const s1 = new WorkflowState(tmp, 'plan');
172
- await s1.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
173
- writeFileSync(join(tmp, 'PLAN.md'), '# 半成品'); // 任务自己写出的中间产物
174
- // 不 markDone(模拟中断)→ 同 goal 重跑 resume
175
- const s2 = new WorkflowState(tmp, 'plan');
176
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, ['PLAN.md']);
177
- expect(r2.mode).toBe('resume');
178
- expect(existsSync(join(tmp, 'PLAN.md'))).toBe(true); // 现场保留
179
- });
180
-
181
- it('未完成(中断)任务同 goal 重跑 → resume(非 completed)', async () => {
182
- const s1 = new WorkflowState(tmp, 'plan');
183
- const r1 = await s1.init('plan', { goal: '目标A' }, STEPS, 1, []);
184
- expect(r1.mode).toBe('fresh');
185
- // 不 markDone、不 archive(模拟中断)
186
- const s2 = new WorkflowState(tmp, 'plan');
187
- const r2 = await s2.init('plan', { goal: '目标A' }, STEPS, 1, []);
188
- expect(r2.mode).toBe('resume');
189
- });
190
- });
191
-
192
- describe('in-run retry(self_heal / max_retries)', () => {
193
- let tmp: string;
194
- let ctx: RunContext;
195
-
196
- beforeEach(() => {
197
- tmp = mkdtempSync(join(tmpdir(), 'wf-retry-'));
198
- process.env.MINIMAL_AGENT_CWD = tmp;
199
- _resetWorkingDir();
200
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
201
- getWorkingDir: () => tmp,
202
- initWorkingDir: () => tmp,
203
- _resetWorkingDir: () => {},
204
- }));
205
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: [] };
206
- });
207
- afterEach(() => {
208
- delete process.env.MINIMAL_AGENT_CWD;
209
- _resetWorkingDir();
210
- rmSync(tmp, { recursive: true, force: true });
211
- });
212
-
213
- it('llm 步首次 LLM 出错(空产出)→ max_retries 重跑 → 第 2 次成功 → done', async () => {
214
- let calls = 0;
215
- // 第 1 次 chat 抛错 → 真实 runQuery 捕获为 llm_error → llm.ts 空产出抛异常 → runner 重试;
216
- // 第 2 次 chat 正常产出 → 成功。
217
- ctx.chat = async function* () {
218
- calls++;
219
- if (calls === 1) throw new Error('transient LLM error');
220
- yield { type: 'text_delta', delta: 'recovered-output' };
221
- yield { type: 'done', stopReason: 'stop' };
222
- };
223
-
224
- const def: WorkflowDef = {
225
- name: 'retry-wf',
226
- description: 'd',
227
- steps: [
228
- { id: 'g', llm: 'do it', capture: { text: 'out' }, max_retries: 1 },
229
- { id: 'check', type: 'assert', condition: 'out == "recovered-output"' },
230
- ],
231
- };
232
-
233
- const events = await collect(runWorkflow(def, {}, ctx));
234
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
235
- // 确实重试了:chat 被调 2 次 + 有一条重试 warning
236
- expect(calls).toBe(2);
237
- expect(
238
- events.some((e) => e.type === 'warning' && e.message.includes('重试')),
239
- ).toBe(true);
240
- });
241
-
242
- it('max_retries 用尽仍失败 → halt(无 done)', async () => {
243
- // chat 每次都抛 → llm 步每次空产出抛异常 → 重试用尽 → 默认 onError=halt。
244
- ctx.chat = async function* () {
245
- throw new Error('always fails');
246
- // biome-ignore lint/correctness/noUnreachable: stub
247
- yield { type: 'done', stopReason: 'stop' };
248
- };
249
-
250
- const def: WorkflowDef = {
251
- name: 'retry-exhaust',
252
- description: 'd',
253
- steps: [
254
- { id: 'g', llm: 'do it', max_retries: 1 },
255
- { id: 'after', type: 'assert', condition: 'true' }, // 不应执行
256
- ],
257
- };
258
-
259
- const events = await collect(runWorkflow(def, {}, ctx));
260
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
261
- expect(events.some((e) => e.type === 'error')).toBe(true);
262
- const startedIds = events
263
- .filter(
264
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
265
- e.type === 'workflow_step_start',
266
- )
267
- .map((e) => e.id);
268
- expect(startedIds).not.toContain('after');
269
- });
270
- });
@@ -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
- });
@@ -1,168 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
-
3
- import {
4
- ALL_TOOLS,
5
- type LoopEvent,
6
- type Provider,
7
- type ToolCallContext,
8
- type ToolResult,
9
- createAgentRuntimeContext,
10
- createSessionState,
11
- } from '../../../src/plugin-sdk.js';
12
- import { execToolStep } from '../src/stepExecutors/tool.js';
13
- import { type RunContext, type StepResult, VarStack } from '../src/types.js';
14
-
15
- const provider: Provider = {
16
- name: 'workflow-tool-test',
17
- baseURL: '',
18
- apiKey: '',
19
- model: 'fixture',
20
- contextWindow: 128_000,
21
- };
22
-
23
- async function collect(
24
- generator: AsyncGenerator<LoopEvent, StepResult, void>,
25
- ): Promise<{ events: LoopEvent[]; result: StepResult }> {
26
- const events: LoopEvent[] = [];
27
- while (true) {
28
- const next = await generator.next();
29
- if (next.done) return { events, result: next.value };
30
- events.push(next.value);
31
- }
32
- }
33
-
34
- function makeContext(
35
- executeTool: NonNullable<RunContext['executeTool']>,
36
- ): RunContext {
37
- const sessionState = createSessionState();
38
- sessionState.activeWorktree = {
39
- id: 'wt_test',
40
- path: '/tmp/workflow-active-worktree',
41
- branch: 'workflow/test',
42
- baseSha: 'deadbeef',
43
- gitRoot: '/tmp/workflow-root',
44
- };
45
- return {
46
- provider,
47
- history: [],
48
- cwd: '/tmp/workflow-root',
49
- tools: ALL_TOOLS,
50
- sessionState,
51
- runtimeContext: createAgentRuntimeContext({
52
- surface: 'workflow',
53
- profile: 'main',
54
- cwd: '/tmp/workflow-root',
55
- workspaceId: 'workspace_test',
56
- sessionId: 'session_test',
57
- owner: 'local-owner',
58
- memoryAccess: 'read-only',
59
- interactiveAsk: false,
60
- }),
61
- promptCache: {
62
- scopeKey: 'workflow-test-scope',
63
- conversationKey: 'workflow-test-conversation',
64
- },
65
- executeTool,
66
- };
67
- }
68
-
69
- describe('workflow deterministic tool runtime', () => {
70
- test('all registered tools use the same generic deterministic node dispatcher', async () => {
71
- const dispatched: string[] = [];
72
- const ctx = makeContext(async (name) => {
73
- dispatched.push(name);
74
- return { ok: true, content: `${name} ok` };
75
- });
76
-
77
- for (const tool of ALL_TOOLS) {
78
- const { result } = await collect(
79
- execToolStep(
80
- { id: `catalog_${tool.name}`, tool: tool.name, args: {} },
81
- new VarStack(),
82
- ctx,
83
- ),
84
- );
85
- expect(result.raw).toMatchObject({ content: `${tool.name} ok` });
86
- }
87
-
88
- expect(dispatched).toEqual(ALL_TOOLS.map((tool) => tool.name));
89
- expect(new Set(dispatched).size).toBe(ALL_TOOLS.length);
90
- });
91
-
92
- test('passes canonical runtime context and follows the active worktree cwd', async () => {
93
- let captured: ToolCallContext | undefined;
94
- const ctx = makeContext(async (_name, _args, _signal, context) => {
95
- captured = context;
96
- return { ok: true, content: 'ok' };
97
- });
98
-
99
- await collect(
100
- execToolStep(
101
- { id: 'context', tool: 'Read', args: { file_path: 'README.md' } },
102
- new VarStack(),
103
- ctx,
104
- ),
105
- );
106
-
107
- expect(captured).toBeDefined();
108
- expect(captured?.provider).toBe(provider);
109
- expect(captured?.history).toBe(ctx.history);
110
- expect(captured?.sessionState).toBe(ctx.sessionState);
111
- expect(captured?.workspaceId).toBe('workspace_test');
112
- expect(captured?.sessionId).toBe('session_test');
113
- expect(captured?.memoryAccess).toBe('read-only');
114
- expect(captured?.cwd).toBe('/tmp/workflow-active-worktree');
115
- expect(captured?.toolCallId).toBe('wf_context');
116
- expect(captured?.promptCache).toBe(ctx.promptCache);
117
- });
118
-
119
- test('streams tool progress and preserves structured result fields', async () => {
120
- const metadata = {
121
- kind: 'process_execution' as const,
122
- shell: 'bash' as const,
123
- mode: 'foreground' as const,
124
- commandKind: 'test' as const,
125
- status: 'completed' as const,
126
- exitCode: 0,
127
- };
128
- const ctx = makeContext(async (_name, _args, _signal, context) => {
129
- context?.reportProgress?.('running tests');
130
- await Promise.resolve();
131
- return {
132
- ok: true,
133
- content: 'tests passed',
134
- metadata,
135
- recovery: 'none',
136
- sensitivity: 'local',
137
- visionNote: 'verification image',
138
- } satisfies ToolResult;
139
- });
140
-
141
- const { events, result } = await collect(
142
- execToolStep(
143
- { id: 'progress', tool: 'Bash', args: { command: 'bun test' } },
144
- new VarStack(),
145
- ctx,
146
- ),
147
- );
148
-
149
- expect(events.map((event) => event.type)).toEqual([
150
- 'tool_start',
151
- 'tool_progress',
152
- 'tool_end',
153
- ]);
154
- expect(events[1]).toMatchObject({
155
- type: 'tool_progress',
156
- toolName: 'Bash',
157
- toolCallId: 'wf_progress',
158
- message: 'running tests',
159
- });
160
- expect(events[2]).toMatchObject({ type: 'tool_end', metadata });
161
- expect(result.raw).toMatchObject({
162
- metadata,
163
- recovery: 'none',
164
- sensitivity: 'local',
165
- visionNote: 'verification image',
166
- });
167
- });
168
- });