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,373 +0,0 @@
1
- /**
2
- * ============================================================
3
- * plugins/workflow-runner/test/agentLlmError.test.ts
4
- * ------------------------------------------------------------
5
- * agent 步的 llm_error 归因契约(P0-A 回归锚):
6
- *
7
- * runQuery 遇 LLM 超时/网络错是 yield error(code:'llm_error') 后 return(不 throw)。
8
- * 曾经 agent.ts 只侦测 'aborted',provider 失败被验证闸门误归因为
9
- * 「agent 步骤放弃: 没有产出任何结果」——与 llm/skill 步的诚实归因
10
- * 「LLM 调用失败且无产出(触发重试)」不一致(现场日志可见同一运行两种文案)。
11
- *
12
- * 本文件锁定三条语义:
13
- * 1. LLM 失败且无产出 → 抛「可重试失败」→ runner in-run retry → 重试成功则 done
14
- * 2. 重试耗尽 → halt 文案是「LLM 调用失败且无产出」,不是「步骤放弃」
15
- * 3. 用户中断(signal.aborted)→ 不触发任何重试(红线:aborted 不重试)
16
- *
17
- * 约定:DI 注入 ctx.chat(不 mock.module client/loop/plugin-sdk),走真实 runQuery。
18
- * ============================================================
19
- */
20
-
21
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
22
- import { mkdtempSync, rmSync } from 'node:fs';
23
- import { tmpdir } from 'node:os';
24
- import { join } from 'node:path';
25
-
26
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
27
- import type { LoopEvent, Provider } from '../../../src/types.js';
28
- import { runWorkflow } from '../src/runner.js';
29
- import type { RunContext, WorkflowDef, WorkflowEvent } from '../src/types.js';
30
-
31
- type WfOrLoop = WorkflowEvent | LoopEvent;
32
-
33
- const fakeProvider: Provider = {
34
- name: 'test',
35
- baseURL: '',
36
- apiKey: '',
37
- model: 'm',
38
- contextWindow: 128000,
39
- };
40
-
41
- async function collect(
42
- gen: AsyncGenerator<WfOrLoop, void, void>,
43
- ): Promise<WfOrLoop[]> {
44
- const out: WfOrLoop[] = [];
45
- for await (const ev of gen) out.push(ev);
46
- return out;
47
- }
48
-
49
- describe('workflows/agent llm_error 归因(P0-A)', () => {
50
- let tmp: string;
51
- let ctx: RunContext;
52
-
53
- beforeEach(() => {
54
- tmp = mkdtempSync(join(tmpdir(), 'wf-agent-llmerr-'));
55
- process.env.MINIMAL_AGENT_CWD = tmp;
56
- _resetWorkingDir();
57
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
58
- getWorkingDir: () => tmp,
59
- initWorkingDir: () => tmp,
60
- _resetWorkingDir: () => {},
61
- }));
62
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: [] };
63
- });
64
-
65
- afterEach(() => {
66
- delete process.env.MINIMAL_AGENT_CWD;
67
- _resetWorkingDir();
68
- rmSync(tmp, { recursive: true, force: true });
69
- });
70
-
71
- it('LLM 第一次失败(超时类)→ in-run retry 重跑 → 第二次成功 → workflow done', async () => {
72
- let call = 0;
73
- ctx.chat = async function* () {
74
- call++;
75
- if (call === 1) throw new Error('socket timeout');
76
- yield { type: 'text_delta', delta: 'real-result' };
77
- yield { type: 'done', stopReason: 'stop' };
78
- };
79
-
80
- const def: WorkflowDef = {
81
- name: 'agent-llmerr-retry',
82
- description: 'provider 抖动被 retry 救回',
83
- steps: [
84
- { id: 'a1', agent: '做点事', capture: { content: 'out' }, max_retries: 1 },
85
- { id: 'check', type: 'assert', condition: 'out == "real-result"' },
86
- ],
87
- };
88
- const events = await collect(runWorkflow(def, {}, ctx));
89
-
90
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
91
- // runQuery 的 error(llm_error) 事件会透传给 UI(红字照常显示),
92
- // 但不应出现 workflow halt(重试已救回)
93
- expect(
94
- events.some(
95
- (e) => e.type === 'error' && e.error.includes('Workflow halted'),
96
- ),
97
- ).toBe(false);
98
- // 重试 warning 必须出现,且文案是诚实归因(LLM 失败),不是「步骤放弃」
99
- const retryWarn = events.find(
100
- (e): e is { type: 'warning'; message: string } =>
101
- e.type === 'warning' && e.message.includes('重试 1/1'),
102
- );
103
- expect(retryWarn).toBeDefined();
104
- expect(retryWarn!.message).toContain('LLM 调用失败且无产出');
105
- expect(retryWarn!.message).not.toContain('步骤放弃');
106
- });
107
-
108
- it('LLM 持续失败 → 重试耗尽 → halt 文案为「LLM 调用失败且无产出」而非「步骤放弃」', async () => {
109
- ctx.chat = async function* () {
110
- throw new Error('connection refused');
111
- // biome-ignore lint/correctness/noUnreachable: 让 TS 认出 generator 形状
112
- yield { type: 'done', stopReason: 'stop' };
113
- };
114
-
115
- const def: WorkflowDef = {
116
- name: 'agent-llmerr-exhaust',
117
- description: 'provider 持续故障',
118
- steps: [{ id: 'a1', agent: '做点事', max_retries: 1 }],
119
- };
120
- const events = await collect(runWorkflow(def, {}, ctx));
121
-
122
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
123
- // 看 halt 事件(runQuery 透传的 error(llm_error) 是另一回事)
124
- const halt = events.find(
125
- (e): e is { type: 'error'; error: string } =>
126
- e.type === 'error' && e.error.includes('Workflow halted'),
127
- );
128
- expect(halt).toBeDefined();
129
- expect(halt!.error).toContain('LLM 调用失败且无产出');
130
- expect(halt!.error).not.toContain('步骤放弃');
131
- });
132
-
133
- it('halt 文案附带 provider 真实报错细节(落 progress.md 的持久证据)', async () => {
134
- ctx.chat = async function* () {
135
- throw new Error('ECONNRESET api.minimax.chat 端口 443');
136
- // biome-ignore lint/correctness/noUnreachable: stub
137
- yield { type: 'done', stopReason: 'stop' };
138
- };
139
-
140
- const def: WorkflowDef = {
141
- name: 'agent-llmerr-detail',
142
- description: '证据持久化',
143
- steps: [{ id: 'a1', agent: '做点事', max_retries: 0 }],
144
- };
145
- const events = await collect(runWorkflow(def, {}, ctx));
146
-
147
- const halt = events.find(
148
- (e): e is { type: 'error'; error: string } =>
149
- e.type === 'error' && e.error.includes('Workflow halted'),
150
- );
151
- expect(halt).toBeDefined();
152
- // 不再只有「无产出」四个字——provider 报错原文可排障
153
- expect(halt!.error).toContain('ECONNRESET');
154
- });
155
-
156
- it('self_heal.retry_delay_ms 退避生效(重试前等待,线性)', async () => {
157
- let call = 0;
158
- ctx.chat = async function* () {
159
- call++;
160
- if (call === 1) throw new Error('transient');
161
- yield { type: 'text_delta', delta: 'ok' };
162
- yield { type: 'done', stopReason: 'stop' };
163
- };
164
-
165
- const def: WorkflowDef = {
166
- name: 'agent-retry-delay',
167
- description: '退避重试',
168
- self_heal: { retry_delay_ms: 120 },
169
- steps: [{ id: 'a1', agent: '做点事', max_retries: 1 }],
170
- };
171
- const t0 = Date.now();
172
- const events = await collect(runWorkflow(def, {}, ctx));
173
- const elapsed = Date.now() - t0;
174
-
175
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
176
- expect(elapsed).toBeGreaterThanOrEqual(110); // 第 1 次重试应等 ~120ms
177
- // warning 文案可见化退避
178
- expect(
179
- events.some((e) => e.type === 'warning' && e.message.includes('120ms 后')),
180
- ).toBe(true);
181
- });
182
-
183
- it('agent 撞 maxTurns 截断 → 抛可重试失败 → 重试在共享 history 上续作成功(伪成功根除锚)', async () => {
184
- // 真事故:execute_plan 撞 25 轮被截断,半截产出被验证闸门当成功放行 →
185
- // 半成品 PPTX 被整条链当真交付。现在:截断 = 可重试失败,重试 = 续作。
186
- let chatCalls = 0;
187
- ctx.executeTool = async () => ({ ok: true, content: 'tool-ok' });
188
- ctx.chat = async function* () {
189
- chatCalls++;
190
- if (chatCalls <= 2) {
191
- // 前两次一直调工具 → 耗尽 maxTurns=2 被截断
192
- yield {
193
- type: 'tool_call_delta',
194
- index: 0,
195
- id: `t${chatCalls}`,
196
- name: 'Glob',
197
- argumentsDelta: '{"pattern":"*"}',
198
- };
199
- yield { type: 'done', stopReason: 'tool_calls' };
200
- return;
201
- }
202
- // 重试(续作):模型看到已有进度,直接给出最终交付
203
- yield { type: 'text_delta', delta: 'final-deliverable' };
204
- yield { type: 'done', stopReason: 'stop' };
205
- };
206
-
207
- const def: WorkflowDef = {
208
- name: 'agent-maxturns-cutoff',
209
- description: '截断诚实化',
210
- steps: [
211
- { id: 'a1', agent: '干活', maxTurns: 2, max_retries: 1, capture: { content: 'out' } },
212
- { id: 'chk', type: 'assert', condition: 'out == "final-deliverable"' },
213
- ],
214
- };
215
- const events = await collect(runWorkflow(def, {}, ctx));
216
-
217
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
218
- // 截断被诚实归因 + 触发了重试
219
- const retryWarn = events.find(
220
- (e): e is { type: 'warning'; message: string } =>
221
- e.type === 'warning' &&
222
- e.message.includes('轮数预算用尽') &&
223
- e.message.includes('续跑 1/1'),
224
- );
225
- expect(retryWarn).toBeDefined();
226
- expect(retryWarn!.message).not.toContain('提前结束');
227
- expect(retryWarn!.message).not.toContain('截断时产出不可信');
228
- expect(retryWarn!.message).not.toContain('__WF_MAX_TURNS_CUTOFF__');
229
- const retryProgress = events.find(
230
- (e): e is Extract<typeof e, { type: 'plugin_progress' }> & { message: string } =>
231
- e.type === 'plugin_progress' &&
232
- typeof e.message === 'string' &&
233
- e.message.includes('阶段轮数预算用尽'),
234
- );
235
- expect(retryProgress).toBeDefined();
236
- expect(retryProgress!.message).toContain('正在续跑 1/1');
237
- expect(retryProgress!.message).not.toContain('截断时产出不可信');
238
- expect(chatCalls).toBe(3);
239
- });
240
-
241
- it('self_heal.max_turns_retry_delay_ms 只影响 maxTurns 截断重试', async () => {
242
- let chatCalls = 0;
243
- ctx.executeTool = async () => ({ ok: true, content: 'tool-ok' });
244
- ctx.chat = async function* () {
245
- chatCalls++;
246
- if (chatCalls <= 2) {
247
- yield {
248
- type: 'tool_call_delta',
249
- index: 0,
250
- id: `mt-${chatCalls}`,
251
- name: 'Glob',
252
- argumentsDelta: '{"pattern":"*"}',
253
- };
254
- yield { type: 'done', stopReason: 'tool_calls' };
255
- return;
256
- }
257
- yield { type: 'text_delta', delta: 'done-after-delay' };
258
- yield { type: 'done', stopReason: 'stop' };
259
- };
260
-
261
- const def: WorkflowDef = {
262
- name: 'agent-maxturns-delay',
263
- description: '截断错峰续跑',
264
- self_heal: { retry_delay_ms: 0, max_turns_retry_delay_ms: 80 },
265
- steps: [{ id: 'a1', agent: '干活', maxTurns: 2, max_retries: 1 }],
266
- };
267
- const t0 = Date.now();
268
- const events = await collect(runWorkflow(def, {}, ctx));
269
- const elapsed = Date.now() - t0;
270
-
271
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
272
- expect(elapsed).toBeGreaterThanOrEqual(70);
273
- expect(
274
- events.some(
275
- (e) =>
276
- e.type === 'warning' &&
277
- e.message.includes('轮数预算用尽') &&
278
- e.message.includes('80ms 后'),
279
- ),
280
- ).toBe(true);
281
- });
282
-
283
- it('agent 撞 maxTurns 且重试耗尽 → halt 文案带「被截断」而非伪成功', async () => {
284
- ctx.executeTool = async () => ({ ok: true, content: 'tool-ok' });
285
- ctx.chat = async function* () {
286
- yield {
287
- type: 'tool_call_delta',
288
- index: 0,
289
- id: 'loop-forever',
290
- name: 'Glob',
291
- argumentsDelta: '{"pattern":"*"}',
292
- };
293
- yield { type: 'done', stopReason: 'tool_calls' };
294
- };
295
-
296
- const def: WorkflowDef = {
297
- name: 'agent-maxturns-exhaust',
298
- description: 'd',
299
- steps: [{ id: 'a1', agent: '干活', maxTurns: 2, max_retries: 0 }],
300
- };
301
- const events = await collect(runWorkflow(def, {}, ctx));
302
-
303
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
304
- const halt = events.find(
305
- (e): e is { type: 'error'; error: string } =>
306
- e.type === 'error' && e.error.includes('Workflow halted'),
307
- );
308
- expect(halt).toBeDefined();
309
- expect(halt!.error).toContain('被截断');
310
- expect(halt!.error).toContain('重试额度已用尽');
311
- expect(halt!.error).not.toContain('截断时产出不可信');
312
- });
313
-
314
- it('provider finish_reason=length → workflow step 视为截断失败,不把半截文本当交付', async () => {
315
- ctx.chat = async function* () {
316
- yield { type: 'text_delta', delta: 'partial deliverable' };
317
- yield { type: 'done', stopReason: 'length' };
318
- };
319
-
320
- const def: WorkflowDef = {
321
- name: 'agent-provider-length',
322
- description: 'provider max_tokens 截断',
323
- steps: [
324
- { id: 'a1', agent: '干活', max_retries: 0, capture: { content: 'out' } },
325
- { id: 'should_not_run', type: 'assert', condition: 'false' },
326
- ],
327
- };
328
- const events = await collect(runWorkflow(def, {}, ctx));
329
-
330
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
331
- const halt = events.find(
332
- (e): e is { type: 'error'; error: string } =>
333
- e.type === 'error' && e.error.includes('Workflow halted'),
334
- );
335
- expect(halt).toBeDefined();
336
- expect(halt!.error).toContain('被截断');
337
- const startedIds = events
338
- .filter(
339
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
340
- e.type === 'workflow_step_start',
341
- )
342
- .map((e) => e.id);
343
- expect(startedIds).not.toContain('should_not_run');
344
- });
345
-
346
- it('用户中断(signal.aborted)→ 不触发任何重试(aborted 不重试红线)', async () => {
347
- const ac = new AbortController();
348
- ctx.signal = ac.signal;
349
- ctx.chat = async function* () {
350
- // 模拟用户在 LLM 流式期间按 ESC:中断信号生效 + 流抛 AbortError
351
- ac.abort();
352
- const e = new Error('aborted');
353
- e.name = 'AbortError';
354
- throw e;
355
- // biome-ignore lint/correctness/noUnreachable: 让 TS 认出 generator 形状
356
- yield { type: 'done', stopReason: 'stop' };
357
- };
358
-
359
- const def: WorkflowDef = {
360
- name: 'agent-aborted',
361
- description: '中断不重试',
362
- steps: [{ id: 'a1', agent: '做点事', max_retries: 2 }],
363
- };
364
- const events = await collect(runWorkflow(def, {}, ctx));
365
-
366
- expect(events.some((e) => e.type === 'interrupted')).toBe(true);
367
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
368
- // 关键:没有任何重试 warning(runner 的 !signal.aborted 守卫生效)
369
- expect(
370
- events.some((e) => e.type === 'warning' && e.message.includes('重试')),
371
- ).toBe(false);
372
- });
373
- });
@@ -1,65 +0,0 @@
1
- /**
2
- * test/bashBlacklist.sweep.test.ts
3
- * ------------------------------------------------------------
4
- * 全库不变量:workflows/*.yaml 所有 tool:Bash 步的 command 文本
5
- * 不得命中 Bash 工具安全黑名单(checkForbidden)。
6
- *
7
- * 事故背书(2026-07-02):ppt.yaml stage_export 的 bash 注释「硬门 halt」
8
- * 被旧版整段裸词扫描误杀——整步执行前被拒 → onError:halt → 确定性死端
9
- * (resume 原样命令原样再拒),且要真机跑完前 21 阶段才暴露。
10
- * 本测试把「yaml 命令 × Bash 黑名单」这条集成缝隙压进 CI:
11
- * 任何 yaml 未来加注释/文案再撞任何黑名单模式,就地红灯。
12
- *
13
- * 说明:扫描的是 yaml 原文(含 ${} 插值占位)——作者手写的地雷都在原文里;
14
- * 运行时插值进来的值属运行数据,不在本测试职责内。
15
- */
16
-
17
- import { describe, expect, it } from 'bun:test';
18
- import { readdir } from 'node:fs/promises';
19
- import { join } from 'node:path';
20
-
21
- import { checkForbidden } from '../../../src/tools/bash/bash.js';
22
- import { parseWorkflowFile } from '../src/loader.js';
23
- import type { StepDef } from '../src/types.js';
24
-
25
- const workflowsDir = join(
26
- import.meta.dir.replace(/[/\\]test$/, ''), // plugins/workflow-runner
27
- '..', // plugins
28
- '..', // 仓库根
29
- 'workflows',
30
- );
31
-
32
- /** 递归收集所有嵌套步(loop.do / branch.then / branch.else)。 */
33
- function collectSteps(steps: StepDef[] | undefined): StepDef[] {
34
- if (!steps) return [];
35
- const out: StepDef[] = [];
36
- for (const s of steps) {
37
- out.push(s);
38
- out.push(...collectSteps(s.do), ...collectSteps(s.then), ...collectSteps(s.else));
39
- }
40
- return out;
41
- }
42
-
43
- describe('workflows/*.yaml × Bash 安全黑名单 sweep', () => {
44
- it('所有 tool:Bash 步的 command 不命中黑名单', async () => {
45
- const files = (await readdir(workflowsDir)).filter((f) => /\.ya?ml$/.test(f));
46
- expect(files.length).toBeGreaterThan(0);
47
-
48
- let scanned = 0;
49
- const hits: string[] = [];
50
- for (const file of files) {
51
- const def = await parseWorkflowFile(join(workflowsDir, file));
52
- for (const step of collectSteps(def.steps)) {
53
- if (step.tool?.toLowerCase() !== 'bash') continue;
54
- const command = (step.args as Record<string, unknown> | undefined)?.command;
55
- if (typeof command !== 'string') continue;
56
- scanned++;
57
- const reason = checkForbidden(command);
58
- if (reason) hits.push(`${file}::${step.id} → ${reason}`);
59
- }
60
- }
61
-
62
- expect(scanned).toBeGreaterThan(0); // 空扫描 = 收集逻辑坏了,别假绿
63
- expect(hits).toEqual([]);
64
- });
65
- });
@@ -1,99 +0,0 @@
1
- /**
2
- * ============================================================
3
- * capture 绑空了必须响亮说出来
4
- * ------------------------------------------------------------
5
- * `capture` 的写法是 `{ 结果字段: 变量名 }`。写反成 `{ 变量名: 结果字段 }`
6
- * 语法完全合法、加载期查不出来,运行时只是安静地绑一个 undefined。
7
- *
8
- * 真实代价(wechat-reading-shots 实测):`text: pager` 写反成 `pager: text` 后,
9
- * 下游 assert 判假,用户看到的是 onFail 里那句业务文案「三种翻页方式都不奏效」
10
- * —— 与真实原因(capture 写反)毫无关系,排查方向被彻底带偏,白跑一整轮。
11
- * 同一个坑 `adaptive-research.yaml` 也踩过一次(文件里留着注释
12
- * 「曾绑 content 导致 notes 恒 undefined」)。两次 → 够格进引擎。
13
- * ============================================================
14
- */
15
-
16
- import { describe, expect, mock, test } from 'bun:test';
17
- import { mkdtempSync } from 'node:fs';
18
- import { tmpdir } from 'node:os';
19
- import { join } from 'node:path';
20
- import { runWorkflow } from '../src/runner.js';
21
- import type { Provider } from '../../../src/types.js';
22
- import type { RunContext, WorkflowDef } from '../src/types.js';
23
-
24
- mock.module('../../../src/llm/client.js', () => ({
25
- chat: async function* () {
26
- yield { type: 'text_delta', delta: 'right' };
27
- yield { type: 'done', stopReason: 'stop' };
28
- },
29
- }));
30
-
31
- const provider: Provider = {
32
- name: 'test',
33
- baseURL: '',
34
- apiKey: '',
35
- model: 'm',
36
- contextWindow: 128000,
37
- };
38
-
39
- /**
40
- * ⚠️ **工作流名必须每次运行唯一。**
41
- *
42
- * 工作流状态目录锚的是 `getWorkingDir()`(进程级),**不是** `RunContext.cwd` ——
43
- * 见 `runner.ts` 里 `new WorkflowState(getWorkingDir(), def.name)`。
44
- * 所以给 ctx 传一个 mkdtemp 目录**隔离不了状态**:同名工作流第二次跑会命中
45
- * 「同名任务此前已完成」而**整条短路**,`workflow_done` 照发、步骤一个不跑 ——
46
- * 于是断言全部空过,测试在两种实现下都绿,什么都证明不了。
47
- *
48
- * 实测踩到:本文件的两条 capture 断言曾在「注入旧行为」时依然全绿,
49
- * 查下去才发现根本没执行到被测代码。用唯一名根治。
50
- */
51
- function uniqueName(base: string): string {
52
- return `${base}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
53
- }
54
-
55
- async function collectWarnings(def: WorkflowDef): Promise<string[]> {
56
- const ctx = {
57
- provider,
58
- history: [{ role: 'system', content: 'sys' }],
59
- // ⚠️ 每个 case 一个全新目录:工作流状态(.minimal-agent-workflow/<name>/)会让
60
- // 同名同 goal 的第二次运行走 resume 跳过已完成步 —— 那样 capture 根本不执行,
61
- // 测试第二次跑就"莫名其妙"变红。共用 cwd 的测试不是测试,是掷骰子。
62
- cwd: mkdtempSync(join(tmpdir(), 'wf-capture-')),
63
- } as unknown as RunContext;
64
- const warnings: string[] = [];
65
- for await (const event of runWorkflow(def, {}, ctx)) {
66
- if ((event as { type?: string }).type === 'warning') {
67
- warnings.push((event as { message: string }).message);
68
- }
69
- }
70
- return warnings;
71
- }
72
-
73
- describe('bindCapture 取不到字段时报 warning', () => {
74
- test('写反的 capture({变量名: 结果字段})被抓住,并报出实际可绑字段', async () => {
75
- const warnings = await collectWarnings({
76
- name: uniqueName('misbind'),
77
- steps: [
78
- // ⚠️ 写反:想把 raw.text 绑给变量 pager,却写成了 pager: text
79
- { id: 'probe', llm: '按哪个键翻页', capture: { pager: 'text' } },
80
- ],
81
- } as never);
82
-
83
- const hit = warnings.find((w) => w.includes('capture 取不到字段'));
84
- expect(hit).toBeDefined();
85
- // 四条信息缺一不可:取不到哪个字段、哪个变量被绑空、是哪一步、实际有什么可绑
86
- expect(hit).toContain('`pager`');
87
- expect(hit).toContain('`text`');
88
- expect(hit).toContain('probe');
89
- expect(hit).toContain('写反');
90
- });
91
-
92
- test('写对的 capture 不产生 warning —— 不能变成噪声', async () => {
93
- const warnings = await collectWarnings({
94
- name: uniqueName('ok'),
95
- steps: [{ id: 'probe', llm: '按哪个键翻页', capture: { text: 'pager' } }],
96
- } as never);
97
- expect(warnings.filter((w) => w.includes('capture 取不到字段'))).toHaveLength(0);
98
- });
99
- });
@@ -1,147 +0,0 @@
1
- /**
2
- * ============================================================
3
- * plugins/workflow-runner/test/cli.e2e.test.ts
4
- * ------------------------------------------------------------
5
- * 最外层 CLI 端到端:拉子进程跑 `bun src/main.tsx -p "/workflow ..."`,
6
- * 验证 stdout / stderr / 退出码 / 文件副作用 全链路。
7
- *
8
- * 覆盖 3 个用例:
9
- * 1. golden path:/workflow cli-e2e --input topic=world → exit 0 + 文件落盘
10
- * 2. /workflows 列出 cli-e2e
11
- * 3. 缺必填 input → exit 1 + 错误信息含 "topic"
12
- *
13
- * fake provider env:workflow 是 tool-only,永不调 API;fake env 仅满足
14
- * main.tsx 的 provider 配置校验。
15
- * ============================================================
16
- */
17
-
18
- import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
19
- import {
20
- copyFileSync,
21
- existsSync,
22
- mkdirSync,
23
- mkdtempSync,
24
- readFileSync,
25
- rmSync,
26
- } from 'node:fs';
27
- import { tmpdir } from 'node:os';
28
- import { join, resolve } from 'node:path';
29
-
30
- const REPO_ROOT = resolve(import.meta.dir, '..', '..', '..');
31
- const FIXTURE = join(import.meta.dir, 'fixtures', 'cli-e2e.yaml');
32
- const FIXTURE_ASK = join(import.meta.dir, 'fixtures', 'cli-ask-e2e.yaml');
33
- const FIXTURE_GREEDY = join(import.meta.dir, 'fixtures', 'greedy-e2e.yaml');
34
-
35
- const SPAWN_TIMEOUT = 60_000;
36
-
37
- interface SpawnResult {
38
- exitCode: number;
39
- stdout: string;
40
- stderr: string;
41
- }
42
-
43
- async function spawnMain(promptArg: string, cwd: string): Promise<SpawnResult> {
44
- const proc = Bun.spawn(
45
- ['bun', 'src/main.tsx', '-d', cwd, '-p', promptArg],
46
- {
47
- cwd: REPO_ROOT,
48
- env: {
49
- ...process.env,
50
- MINIMAL_AGENT_BASE_URL: 'http://fake.invalid',
51
- MINIMAL_AGENT_API_KEY: 'fake-key',
52
- MINIMAL_AGENT_MODEL: 'fake-model',
53
- MINIMAL_AGENT_CONTEXT_WINDOW: '128000',
54
- },
55
- stdout: 'pipe',
56
- stderr: 'pipe',
57
- },
58
- );
59
-
60
- const [stdout, stderr, exitCode] = await Promise.all([
61
- new Response(proc.stdout).text(),
62
- new Response(proc.stderr).text(),
63
- proc.exited,
64
- ]);
65
-
66
- return { exitCode, stdout, stderr };
67
- }
68
-
69
- describe('CLI 端到端 /workflow(拉子进程跑 main.tsx)', () => {
70
- let tmp: string;
71
-
72
- beforeEach(() => {
73
- tmp = mkdtempSync(join(tmpdir(), 'cli-e2e-'));
74
- mkdirSync(join(tmp, 'workflows'), { recursive: true });
75
- copyFileSync(FIXTURE, join(tmp, 'workflows', 'cli-e2e.yaml'));
76
- copyFileSync(FIXTURE_ASK, join(tmp, 'workflows', 'cli-ask-e2e.yaml'));
77
- copyFileSync(FIXTURE_GREEDY, join(tmp, 'workflows', 'greedy-e2e.yaml'));
78
- });
79
-
80
- afterEach(() => {
81
- rmSync(tmp, { recursive: true, force: true });
82
- });
83
-
84
- it(
85
- 'golden path:跑完 + 文件落盘 + exit 0',
86
- async () => {
87
- const r = await spawnMain(
88
- '/workflow cli-e2e --input topic=world',
89
- tmp,
90
- );
91
- expect(r.exitCode).toBe(0);
92
- const filePath = join(tmp, 'out', 'world', 'note.txt');
93
- expect(existsSync(filePath)).toBe(true);
94
- expect(readFileSync(filePath, 'utf8')).toBe('topic=world ok');
95
- },
96
- SPAWN_TIMEOUT,
97
- );
98
-
99
- it(
100
- '/workflows 列出 cli-e2e',
101
- async () => {
102
- const r = await spawnMain('/workflows', tmp);
103
- expect(r.exitCode).toBe(0);
104
- expect(r.stdout).toContain('cli-e2e');
105
- },
106
- SPAWN_TIMEOUT,
107
- );
108
-
109
- it(
110
- '缺必填 input → exit 1 + 错误信息含 "topic"',
111
- async () => {
112
- const r = await spawnMain('/workflow cli-e2e', tmp);
113
- expect(r.exitCode).toBe(1);
114
- expect(r.stderr).toContain('topic');
115
- },
116
- SPAWN_TIMEOUT,
117
- );
118
-
119
- // -p 非交互下「含 AskUserQuestion 的工作流」也能跑通:askBridge 自动选推荐项、不挂起。
120
- // 这是 ppt 工作流 stage0「样式推荐」在 -p / 宿主 spawn 下自动兜底那条路径的最小复现。
121
- it(
122
- '含 AskUserQuestion 的工作流在 -p 下自动选推荐项、不挂起、跑完 exit 0',
123
- async () => {
124
- const r = await spawnMain('/workflow cli-ask-e2e', tmp);
125
- expect(r.exitCode).toBe(0);
126
- // askBridge 非交互兜底:自动选每题首项(推荐项),stderr 注记
127
- expect(r.stderr).toContain('自动选推荐项');
128
- // echo 文本经 text 事件 + 末尾 turn_done 正常回到 -p stdout
129
- expect(r.stdout).toContain('ASK-E2E-DONE');
130
- },
131
- SPAWN_TIMEOUT,
132
- );
133
-
134
- // 贪婪首参:命令行里 workflow 名之后的整句(含空格分隔段)被 join 进首个 input,
135
- // 不逐位拆映射、不撞后面的 number/enum 输入。这是 ppt「打一句话自然语言就能跑」
136
- // 的根因修复——曾因严格 posN↔inputs[N] 把整句拆碎、pos2 撞 number 报「必须是数字」。
137
- it(
138
- 'greedy 首参把整句位置参数 join 进首个 input(不拆碎、不撞类型)',
139
- async () => {
140
- const r = await spawnMain('/workflow greedy-e2e 收集 资料 浅色', tmp);
141
- expect(r.exitCode).toBe(0);
142
- // 三段位置参数被空格 join 还原成整句进 brief,echo 原样回显
143
- expect(r.stdout).toContain('GREEDY-BRIEF=[收集 资料 浅色]');
144
- },
145
- SPAWN_TIMEOUT,
146
- );
147
- });