minimal-agent 0.13.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 (470) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +503 -0
  103. package/src/advisor/advisorCoordinator.ts +657 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/streamJson.js +5 -6
  108. package/src/cli/streamJson.ts +8 -4
  109. package/src/cli/wizards/advisorWizard.js +4 -2
  110. package/src/cli/wizards/advisorWizard.tsx +8 -2
  111. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  112. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  113. package/src/collaboration/taskFlow.js +115 -0
  114. package/src/collaboration/taskFlow.ts +169 -0
  115. package/src/config/configDefaults.js +41 -1
  116. package/src/config/configDefaults.ts +43 -1
  117. package/src/config/configDiagnostics.ts +2 -2
  118. package/src/config/configFile.js +40 -9
  119. package/src/config/configFile.ts +60 -11
  120. package/src/config/configService.js +419 -74
  121. package/src/config/configService.ts +703 -145
  122. package/src/config/numericLimits.js +22 -0
  123. package/src/config/numericLimits.ts +24 -0
  124. package/src/config.js +1 -0
  125. package/src/config.ts +3 -2
  126. package/src/context/budgetPlan.js +1 -1
  127. package/src/context/budgetPlan.ts +1 -1
  128. package/src/context/compact.js +7 -2
  129. package/src/context/compact.ts +9 -2
  130. package/src/context/microCompactLite.js +212 -13
  131. package/src/context/microCompactLite.ts +261 -12
  132. package/src/context/sessionRegistry.js +8 -1
  133. package/src/context/sessionRegistry.ts +18 -5
  134. package/src/context/toolResultArchive.js +72 -0
  135. package/src/context/toolResultArchive.ts +95 -0
  136. package/src/goal/errors.js +8 -0
  137. package/src/goal/errors.ts +18 -0
  138. package/src/goal/goalRuntime.js +344 -0
  139. package/src/goal/goalRuntime.ts +466 -0
  140. package/src/goal/goalStore.js +200 -0
  141. package/src/goal/goalStore.ts +219 -0
  142. package/src/goal/index.js +4 -0
  143. package/src/goal/index.ts +4 -0
  144. package/src/goal/statusMapping.js +71 -0
  145. package/src/goal/statusMapping.ts +95 -0
  146. package/src/goal/types.js +7 -0
  147. package/src/goal/types.ts +179 -0
  148. package/src/goal/workflowController.js +306 -0
  149. package/src/goal/workflowController.ts +360 -0
  150. package/src/harness/evidenceLedger.js +2 -0
  151. package/src/harness/evidenceLedger.ts +1 -0
  152. package/src/harness/stallGuard.js +9 -3
  153. package/src/harness/stallGuard.ts +7 -3
  154. package/src/images/imageResolver.js +161 -0
  155. package/src/images/imageResolver.ts +189 -0
  156. package/src/infra/verification.js +34 -5
  157. package/src/infra/verification.ts +39 -4
  158. package/src/llm/client.js +79 -21
  159. package/src/llm/client.ts +182 -35
  160. package/src/llm/gatewayClient.js +201 -0
  161. package/src/llm/gatewayClient.ts +299 -0
  162. package/src/llm/messageProvenance.js +46 -0
  163. package/src/llm/messageProvenance.ts +58 -0
  164. package/src/llm/modelProvider.js +1 -0
  165. package/src/llm/modelProvider.ts +22 -0
  166. package/src/llm/providers/anthropicFormat.js +108 -1
  167. package/src/llm/providers/anthropicFormat.ts +115 -4
  168. package/src/llm/providers/openaiFormat.js +9 -0
  169. package/src/llm/providers/openaiFormat.ts +12 -3
  170. package/src/loop.js +319 -54
  171. package/src/loop.ts +373 -57
  172. package/src/main.js +4 -1
  173. package/src/main.tsx +4 -1
  174. package/src/managedExecution/index.js +2 -0
  175. package/src/managedExecution/index.ts +2 -0
  176. package/src/managedExecution/registry.js +15 -0
  177. package/src/managedExecution/registry.ts +20 -0
  178. package/src/managedExecution/types.js +1 -0
  179. package/src/managedExecution/types.ts +86 -0
  180. package/src/modelRef.js +9 -0
  181. package/src/modelRef.ts +31 -0
  182. package/src/multimodal.js +14 -28
  183. package/src/multimodal.ts +17 -33
  184. package/src/net/lanDiscovery.js +65 -0
  185. package/src/net/lanDiscovery.ts +82 -0
  186. package/src/plugin-sdk.js +28 -3
  187. package/src/plugin-sdk.ts +39 -6
  188. package/src/plugins/pluginApi.ts +16 -1
  189. package/src/plugins/pluginLoader.js +4 -0
  190. package/src/plugins/pluginLoader.ts +6 -0
  191. package/src/plugins/pluginRunner.js +139 -7
  192. package/src/plugins/pluginRunner.ts +173 -9
  193. package/src/plugins/slashFallback.js +113 -0
  194. package/src/plugins/slashFallback.ts +137 -0
  195. package/src/prompts/policyRegistry.js +12 -32
  196. package/src/prompts/policyRegistry.ts +15 -32
  197. package/src/prompts/promptAssembly.js +103 -12
  198. package/src/prompts/promptAssembly.ts +114 -12
  199. package/src/prompts/skillList.js +21 -3
  200. package/src/prompts/skillList.ts +27 -2
  201. package/src/prompts/stableSystemPrompt.js +18 -0
  202. package/src/prompts/stableSystemPrompt.ts +33 -0
  203. package/src/runtime/agentRuntimeContext.js +8 -2
  204. package/src/runtime/agentRuntimeContext.ts +17 -4
  205. package/src/session/runAgentTurn.js +78 -12
  206. package/src/session/runAgentTurn.ts +105 -23
  207. package/src/session/runTurn.js +10 -9
  208. package/src/session/runTurn.ts +17 -8
  209. package/src/session/sessionState.ts +2 -0
  210. package/src/team/auth.js +186 -0
  211. package/src/team/auth.ts +298 -0
  212. package/src/team/cli.js +105 -0
  213. package/src/team/cli.ts +122 -0
  214. package/src/team/onlineToolContract.js +64 -0
  215. package/src/team/onlineToolContract.ts +109 -0
  216. package/src/team/toolPolicy.js +36 -0
  217. package/src/team/toolPolicy.ts +75 -0
  218. package/src/tools/advisor/advisor.js +90 -46
  219. package/src/tools/advisor/advisor.ts +100 -47
  220. package/src/tools/advisor/advisorDecision.js +71 -0
  221. package/src/tools/advisor/advisorDecision.ts +85 -0
  222. package/src/tools/agent/agent.js +18 -5
  223. package/src/tools/agent/agent.ts +21 -7
  224. package/src/tools/agent/agentControl.js +246 -0
  225. package/src/tools/agent/agentControl.ts +284 -0
  226. package/src/tools/agent/agentTaskService.js +40 -1
  227. package/src/tools/agent/agentTaskService.ts +44 -1
  228. package/src/tools/agent/agentTypes.js +14 -2
  229. package/src/tools/agent/agentTypes.ts +15 -2
  230. package/src/tools/applypatch/applyPatch.js +362 -0
  231. package/src/tools/applypatch/applyPatch.ts +428 -0
  232. package/src/tools/bash/bash.js +22 -15
  233. package/src/tools/bash/bash.ts +23 -17
  234. package/src/tools/capabilities.js +10 -5
  235. package/src/tools/capabilities.ts +10 -5
  236. package/src/tools/computeruse/computerIntent.js +32 -0
  237. package/src/tools/computeruse/computerIntent.ts +46 -0
  238. package/src/tools/computeruse/telemetryLog.js +12 -0
  239. package/src/tools/computeruse/telemetryLog.ts +16 -0
  240. package/src/tools/computeruse/vision/telemetry.js +1 -0
  241. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  242. package/src/tools/effectiveToolSet.js +4 -0
  243. package/src/tools/effectiveToolSet.ts +4 -0
  244. package/src/tools/index.js +21 -2
  245. package/src/tools/index.ts +33 -2
  246. package/src/tools/presentresult/presentresult.js +6 -15
  247. package/src/tools/presentresult/presentresult.ts +6 -15
  248. package/src/tools/read/read.js +62 -9
  249. package/src/tools/read/read.ts +63 -9
  250. package/src/tools/shared/fileUtils.js +1 -2
  251. package/src/tools/shared/fileUtils.ts +1 -2
  252. package/src/tools/shared/toolOutputStore.js +23 -1
  253. package/src/tools/shared/toolOutputStore.ts +22 -1
  254. package/src/tools/skill/skill.js +9 -3
  255. package/src/tools/skill/skill.ts +8 -4
  256. package/src/tools/toolPromptGuides.js +117 -0
  257. package/src/tools/toolPromptGuides.ts +137 -0
  258. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  259. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  260. package/src/tools/webbrowser/browser.js +27 -11
  261. package/src/tools/webbrowser/browser.ts +68 -24
  262. package/src/tools/webbrowser/browserAutomation.js +329 -0
  263. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  264. package/src/tools/webbrowser/browserAxState.js +97 -0
  265. package/src/tools/webbrowser/browserAxState.ts +142 -0
  266. package/src/tools/webbrowser/browserBatch.js +1578 -0
  267. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  268. package/src/tools/webbrowser/browserCdp.js +208 -0
  269. package/src/tools/webbrowser/browserCdp.ts +255 -0
  270. package/src/tools/webbrowser/browserConditions.js +24 -0
  271. package/src/tools/webbrowser/browserConditions.ts +45 -0
  272. package/src/tools/webbrowser/browserContent.js +281 -0
  273. package/src/tools/webbrowser/browserContent.ts +438 -0
  274. package/src/tools/webbrowser/browserControl.js +131 -34
  275. package/src/tools/webbrowser/browserControl.ts +210 -56
  276. package/src/tools/webbrowser/browserDaemon.js +22 -14
  277. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  278. package/src/tools/webbrowser/browserFrames.js +47 -0
  279. package/src/tools/webbrowser/browserFrames.ts +54 -0
  280. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  281. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  282. package/src/tools/webbrowser/browserLocator.js +140 -0
  283. package/src/tools/webbrowser/browserLocator.ts +194 -0
  284. package/src/tools/webbrowser/browserOutcome.js +10 -17
  285. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  286. package/src/tools/webbrowser/browserRecovery.js +58 -0
  287. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  288. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  289. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  290. package/src/tools/webbrowser/browserService.js +28 -2
  291. package/src/tools/webbrowser/browserService.ts +49 -9
  292. package/src/tools/webbrowser/browserStream.js +132 -33
  293. package/src/tools/webbrowser/browserStream.ts +224 -50
  294. package/src/tools/webbrowser/browserTabs.js +48 -15
  295. package/src/tools/webbrowser/browserTabs.ts +178 -96
  296. package/src/tools/webbrowser/webbrowser.js +679 -144
  297. package/src/tools/webbrowser/webbrowser.ts +975 -236
  298. package/src/tools/webfetch/preapproved.js +0 -2
  299. package/src/tools/webfetch/preapproved.ts +0 -2
  300. package/src/tools/websearch/websearch.js +129 -8
  301. package/src/tools/websearch/websearch.ts +138 -6
  302. package/src/types.ts +440 -38
  303. package/src/ui/App.js +377 -58
  304. package/src/ui/App.tsx +576 -111
  305. package/src/ui/LiveArea.js +14 -8
  306. package/src/ui/LiveArea.tsx +14 -10
  307. package/src/ui/MessageList.js +63 -20
  308. package/src/ui/MessageList.tsx +101 -16
  309. package/src/ui/ModelPicker.js +7 -4
  310. package/src/ui/ModelPicker.tsx +55 -8
  311. package/src/ui/hooks/useChat.js +152 -163
  312. package/src/ui/hooks/useChat.ts +396 -334
  313. package/src/ui/loginCommand.js +56 -0
  314. package/src/ui/loginCommand.ts +63 -0
  315. package/src/ui/toolProgress.js +41 -0
  316. package/src/ui/toolProgress.ts +44 -0
  317. package/src/web/browserBridge.js +20 -2
  318. package/src/web/browserBridge.ts +20 -2
  319. package/src/web/protocol.ts +1897 -194
  320. package/workflows/adaptive-research/workflow.mjs +86 -0
  321. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  322. package/workflows/e2e-llm/workflow.mjs +52 -0
  323. package/workflows/e2e-smoke/workflow.mjs +59 -0
  324. package/workflows/e2e-vision-schema/README.md +48 -0
  325. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  326. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  327. package/workflows/file-census/README.md +14 -0
  328. package/workflows/file-census/scripts/.gitkeep +2 -0
  329. package/workflows/file-census/workflow.mjs +110 -0
  330. package/workflows/goal/README.md +166 -0
  331. package/workflows/goal/prompts/audit.md +57 -0
  332. package/workflows/goal/prompts/contract.md +56 -0
  333. package/workflows/goal/prompts/iterate.md +37 -0
  334. package/workflows/goal/workflow.mjs +501 -0
  335. package/workflows/illustrate/README.md +90 -0
  336. package/workflows/illustrate/assets/engines.json +20 -0
  337. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  338. package/workflows/illustrate/assets/extract-bing.js +33 -0
  339. package/workflows/illustrate/assets/extract-google.js +31 -0
  340. package/workflows/illustrate/workflow.mjs +301 -0
  341. package/workflows/plan/workflow.mjs +389 -0
  342. package/workflows/question-crops/README.md +35 -0
  343. package/workflows/question-crops/prompts/inventory.md +23 -0
  344. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  345. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  346. package/workflows/question-crops/workflow.mjs +172 -0
  347. package/workflows/ralph-loop/workflow.mjs +162 -0
  348. package/workflows/research/README.md +74 -0
  349. package/workflows/research/prompts/s0-goal.md +43 -0
  350. package/workflows/research/prompts/s1-early-exit.md +22 -0
  351. package/workflows/research/prompts/s1-map.md +58 -0
  352. package/workflows/research/prompts/s2-options.md +53 -0
  353. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  354. package/workflows/research/prompts/s4-verify.md +74 -0
  355. package/workflows/research/prompts/s5-synthesis.md +81 -0
  356. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  357. package/workflows/research/prompts/s6-package.md +32 -0
  358. package/workflows/research/scripts/build-report.mjs +98 -0
  359. package/workflows/research/workflow.mjs +288 -0
  360. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  361. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  362. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  363. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  364. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  365. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  366. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  367. package/workflows/wrong-question-docx/README.md +55 -0
  368. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  369. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  370. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  371. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  372. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  373. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  374. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  375. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  376. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  377. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  378. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  379. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  380. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  381. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  382. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  383. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  384. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  385. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  386. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  387. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  388. package/plugins/workflow-runner/src/expressions.js +0 -639
  389. package/plugins/workflow-runner/src/expressions.ts +0 -640
  390. package/plugins/workflow-runner/src/loader.js +0 -573
  391. package/plugins/workflow-runner/src/loader.ts +0 -721
  392. package/plugins/workflow-runner/src/multimodal.js +0 -38
  393. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  394. package/plugins/workflow-runner/src/recovery.js +0 -126
  395. package/plugins/workflow-runner/src/recovery.ts +0 -156
  396. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  397. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  398. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  399. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  400. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  401. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  402. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  403. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  404. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  405. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  406. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  407. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  408. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  409. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  410. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  411. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  412. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  413. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  414. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  415. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  416. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  417. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  418. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  419. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  420. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  421. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  422. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  423. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  424. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  425. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  426. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  427. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  428. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  429. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  430. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  431. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  432. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  433. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  434. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  435. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  436. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  437. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  438. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  439. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  440. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  441. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  442. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  443. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  444. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  445. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  446. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  447. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  448. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  449. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  450. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  451. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  452. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  453. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  454. package/src/advisorState.js +0 -22
  455. package/src/cli/configWizard.js +0 -293
  456. package/src/tools/toolProgressBridge.js +0 -48
  457. package/workflows/adaptive-research.yaml +0 -50
  458. package/workflows/book-review-short.yaml +0 -125
  459. package/workflows/e2e-write-greet.yaml +0 -31
  460. package/workflows/illustrate.yaml +0 -227
  461. package/workflows/plan.yaml +0 -470
  462. package/workflows/ppt.yaml +0 -1670
  463. package/workflows/ralph-loop.yaml +0 -201
  464. package/workflows/research.yaml +0 -873
  465. package/workflows/schema.json +0 -176
  466. package/workflows/webppt.yaml +0 -496
  467. package/workflows/wechat-reading-shots.yaml +0 -315
  468. package/workflows/word.yaml +0 -720
  469. package/workflows/youtube-shorts.yaml +0 -202
  470. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -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
- });