minimal-agent 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +536 -0
  103. package/src/advisor/advisorCoordinator.ts +693 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/quickModelSetup.js +12 -1
  108. package/src/cli/quickModelSetup.tsx +15 -3
  109. package/src/cli/streamJson.js +5 -6
  110. package/src/cli/streamJson.ts +8 -4
  111. package/src/cli/wizards/advisorWizard.js +4 -2
  112. package/src/cli/wizards/advisorWizard.tsx +8 -2
  113. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  114. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  115. package/src/cli/wizards/providerPresets.js +18 -8
  116. package/src/cli/wizards/providerPresets.ts +18 -8
  117. package/src/collaboration/taskFlow.js +115 -0
  118. package/src/collaboration/taskFlow.ts +169 -0
  119. package/src/config/configDefaults.js +41 -1
  120. package/src/config/configDefaults.ts +43 -1
  121. package/src/config/configDiagnostics.ts +2 -2
  122. package/src/config/configFile.js +40 -9
  123. package/src/config/configFile.ts +60 -11
  124. package/src/config/configService.js +419 -74
  125. package/src/config/configService.ts +703 -145
  126. package/src/config/numericLimits.js +22 -0
  127. package/src/config/numericLimits.ts +24 -0
  128. package/src/config.js +1 -0
  129. package/src/config.ts +3 -2
  130. package/src/context/budgetPlan.js +1 -1
  131. package/src/context/budgetPlan.ts +1 -1
  132. package/src/context/compact.js +7 -2
  133. package/src/context/compact.ts +9 -2
  134. package/src/context/microCompactLite.js +212 -13
  135. package/src/context/microCompactLite.ts +261 -12
  136. package/src/context/sessionRegistry.js +8 -1
  137. package/src/context/sessionRegistry.ts +18 -5
  138. package/src/context/toolResultArchive.js +72 -0
  139. package/src/context/toolResultArchive.ts +95 -0
  140. package/src/goal/errors.js +8 -0
  141. package/src/goal/errors.ts +18 -0
  142. package/src/goal/goalRuntime.js +344 -0
  143. package/src/goal/goalRuntime.ts +466 -0
  144. package/src/goal/goalStore.js +200 -0
  145. package/src/goal/goalStore.ts +219 -0
  146. package/src/goal/index.js +4 -0
  147. package/src/goal/index.ts +4 -0
  148. package/src/goal/statusMapping.js +71 -0
  149. package/src/goal/statusMapping.ts +95 -0
  150. package/src/goal/types.js +7 -0
  151. package/src/goal/types.ts +179 -0
  152. package/src/goal/workflowController.js +306 -0
  153. package/src/goal/workflowController.ts +360 -0
  154. package/src/harness/evidenceLedger.js +2 -0
  155. package/src/harness/evidenceLedger.ts +1 -0
  156. package/src/harness/stallGuard.js +9 -3
  157. package/src/harness/stallGuard.ts +7 -3
  158. package/src/images/imageResolver.js +161 -0
  159. package/src/images/imageResolver.ts +189 -0
  160. package/src/infra/verification.js +34 -5
  161. package/src/infra/verification.ts +39 -4
  162. package/src/llm/client.js +79 -21
  163. package/src/llm/client.ts +182 -35
  164. package/src/llm/gatewayClient.js +201 -0
  165. package/src/llm/gatewayClient.ts +299 -0
  166. package/src/llm/messageProvenance.js +46 -0
  167. package/src/llm/messageProvenance.ts +58 -0
  168. package/src/llm/modelProvider.js +1 -0
  169. package/src/llm/modelProvider.ts +22 -0
  170. package/src/llm/providers/anthropicFormat.js +108 -1
  171. package/src/llm/providers/anthropicFormat.ts +115 -4
  172. package/src/llm/providers/openaiFormat.js +9 -0
  173. package/src/llm/providers/openaiFormat.ts +12 -3
  174. package/src/loop.js +328 -55
  175. package/src/loop.ts +382 -58
  176. package/src/main.js +4 -1
  177. package/src/main.tsx +4 -1
  178. package/src/managedExecution/index.js +2 -0
  179. package/src/managedExecution/index.ts +2 -0
  180. package/src/managedExecution/registry.js +15 -0
  181. package/src/managedExecution/registry.ts +20 -0
  182. package/src/managedExecution/types.js +1 -0
  183. package/src/managedExecution/types.ts +86 -0
  184. package/src/modelRef.js +9 -0
  185. package/src/modelRef.ts +31 -0
  186. package/src/multimodal.js +14 -28
  187. package/src/multimodal.ts +17 -33
  188. package/src/net/lanDiscovery.js +65 -0
  189. package/src/net/lanDiscovery.ts +82 -0
  190. package/src/plugin-sdk.js +28 -3
  191. package/src/plugin-sdk.ts +39 -6
  192. package/src/plugins/pluginApi.ts +16 -1
  193. package/src/plugins/pluginLoader.js +4 -0
  194. package/src/plugins/pluginLoader.ts +6 -0
  195. package/src/plugins/pluginRunner.js +139 -7
  196. package/src/plugins/pluginRunner.ts +173 -9
  197. package/src/plugins/slashFallback.js +113 -0
  198. package/src/plugins/slashFallback.ts +137 -0
  199. package/src/prompts/policyRegistry.js +12 -32
  200. package/src/prompts/policyRegistry.ts +15 -32
  201. package/src/prompts/promptAssembly.js +103 -12
  202. package/src/prompts/promptAssembly.ts +114 -12
  203. package/src/prompts/skillList.js +21 -3
  204. package/src/prompts/skillList.ts +27 -2
  205. package/src/prompts/stableSystemPrompt.js +18 -0
  206. package/src/prompts/stableSystemPrompt.ts +33 -0
  207. package/src/runtime/agentRuntimeContext.js +8 -2
  208. package/src/runtime/agentRuntimeContext.ts +17 -4
  209. package/src/session/runAgentTurn.js +78 -12
  210. package/src/session/runAgentTurn.ts +105 -23
  211. package/src/session/runTurn.js +10 -9
  212. package/src/session/runTurn.ts +17 -8
  213. package/src/session/sessionState.ts +2 -0
  214. package/src/team/auth.js +186 -0
  215. package/src/team/auth.ts +298 -0
  216. package/src/team/cli.js +105 -0
  217. package/src/team/cli.ts +122 -0
  218. package/src/team/onlineToolContract.js +64 -0
  219. package/src/team/onlineToolContract.ts +109 -0
  220. package/src/team/toolPolicy.js +36 -0
  221. package/src/team/toolPolicy.ts +75 -0
  222. package/src/tools/advisor/advisor.js +115 -50
  223. package/src/tools/advisor/advisor.ts +124 -51
  224. package/src/tools/advisor/advisorDecision.js +71 -0
  225. package/src/tools/advisor/advisorDecision.ts +85 -0
  226. package/src/tools/agent/agent.js +18 -5
  227. package/src/tools/agent/agent.ts +21 -7
  228. package/src/tools/agent/agentControl.js +246 -0
  229. package/src/tools/agent/agentControl.ts +284 -0
  230. package/src/tools/agent/agentTaskService.js +40 -1
  231. package/src/tools/agent/agentTaskService.ts +44 -1
  232. package/src/tools/agent/agentTypes.js +14 -2
  233. package/src/tools/agent/agentTypes.ts +15 -2
  234. package/src/tools/applypatch/applyPatch.js +362 -0
  235. package/src/tools/applypatch/applyPatch.ts +428 -0
  236. package/src/tools/bash/bash.js +22 -15
  237. package/src/tools/bash/bash.ts +23 -17
  238. package/src/tools/capabilities.js +10 -5
  239. package/src/tools/capabilities.ts +10 -5
  240. package/src/tools/computeruse/computerIntent.js +32 -0
  241. package/src/tools/computeruse/computerIntent.ts +46 -0
  242. package/src/tools/computeruse/telemetryLog.js +12 -0
  243. package/src/tools/computeruse/telemetryLog.ts +16 -0
  244. package/src/tools/computeruse/vision/telemetry.js +1 -0
  245. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  246. package/src/tools/effectiveToolSet.js +4 -0
  247. package/src/tools/effectiveToolSet.ts +4 -0
  248. package/src/tools/index.js +21 -2
  249. package/src/tools/index.ts +33 -2
  250. package/src/tools/presentresult/presentresult.js +6 -15
  251. package/src/tools/presentresult/presentresult.ts +6 -15
  252. package/src/tools/read/read.js +62 -9
  253. package/src/tools/read/read.ts +63 -9
  254. package/src/tools/shared/fileUtils.js +1 -2
  255. package/src/tools/shared/fileUtils.ts +1 -2
  256. package/src/tools/shared/toolOutputStore.js +23 -1
  257. package/src/tools/shared/toolOutputStore.ts +22 -1
  258. package/src/tools/skill/skill.js +9 -3
  259. package/src/tools/skill/skill.ts +8 -4
  260. package/src/tools/toolPromptGuides.js +125 -0
  261. package/src/tools/toolPromptGuides.ts +146 -0
  262. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  263. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  264. package/src/tools/webbrowser/browser.js +27 -11
  265. package/src/tools/webbrowser/browser.ts +68 -24
  266. package/src/tools/webbrowser/browserAutomation.js +329 -0
  267. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  268. package/src/tools/webbrowser/browserAxState.js +97 -0
  269. package/src/tools/webbrowser/browserAxState.ts +142 -0
  270. package/src/tools/webbrowser/browserBatch.js +1578 -0
  271. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  272. package/src/tools/webbrowser/browserCdp.js +208 -0
  273. package/src/tools/webbrowser/browserCdp.ts +255 -0
  274. package/src/tools/webbrowser/browserConditions.js +24 -0
  275. package/src/tools/webbrowser/browserConditions.ts +45 -0
  276. package/src/tools/webbrowser/browserContent.js +281 -0
  277. package/src/tools/webbrowser/browserContent.ts +438 -0
  278. package/src/tools/webbrowser/browserControl.js +131 -34
  279. package/src/tools/webbrowser/browserControl.ts +210 -56
  280. package/src/tools/webbrowser/browserDaemon.js +22 -14
  281. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  282. package/src/tools/webbrowser/browserFrames.js +47 -0
  283. package/src/tools/webbrowser/browserFrames.ts +54 -0
  284. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  286. package/src/tools/webbrowser/browserLocator.js +140 -0
  287. package/src/tools/webbrowser/browserLocator.ts +194 -0
  288. package/src/tools/webbrowser/browserOutcome.js +10 -17
  289. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  290. package/src/tools/webbrowser/browserRecovery.js +58 -0
  291. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  292. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  293. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  294. package/src/tools/webbrowser/browserService.js +28 -2
  295. package/src/tools/webbrowser/browserService.ts +49 -9
  296. package/src/tools/webbrowser/browserStream.js +132 -33
  297. package/src/tools/webbrowser/browserStream.ts +224 -50
  298. package/src/tools/webbrowser/browserTabs.js +48 -15
  299. package/src/tools/webbrowser/browserTabs.ts +178 -96
  300. package/src/tools/webbrowser/webbrowser.js +679 -144
  301. package/src/tools/webbrowser/webbrowser.ts +975 -236
  302. package/src/tools/webfetch/preapproved.js +0 -2
  303. package/src/tools/webfetch/preapproved.ts +0 -2
  304. package/src/tools/websearch/websearch.js +129 -8
  305. package/src/tools/websearch/websearch.ts +138 -6
  306. package/src/types.ts +459 -40
  307. package/src/ui/App.js +377 -58
  308. package/src/ui/App.tsx +576 -111
  309. package/src/ui/LiveArea.js +14 -8
  310. package/src/ui/LiveArea.tsx +14 -10
  311. package/src/ui/MessageList.js +63 -20
  312. package/src/ui/MessageList.tsx +101 -16
  313. package/src/ui/ModelPicker.js +7 -4
  314. package/src/ui/ModelPicker.tsx +55 -8
  315. package/src/ui/hooks/useChat.js +152 -163
  316. package/src/ui/hooks/useChat.ts +396 -334
  317. package/src/ui/loginCommand.js +56 -0
  318. package/src/ui/loginCommand.ts +63 -0
  319. package/src/ui/toolProgress.js +41 -0
  320. package/src/ui/toolProgress.ts +44 -0
  321. package/src/web/browserBridge.js +20 -2
  322. package/src/web/browserBridge.ts +20 -2
  323. package/src/web/protocol.ts +1897 -194
  324. package/workflows/adaptive-research/workflow.mjs +86 -0
  325. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  326. package/workflows/e2e-llm/workflow.mjs +52 -0
  327. package/workflows/e2e-smoke/workflow.mjs +59 -0
  328. package/workflows/e2e-vision-schema/README.md +48 -0
  329. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  330. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  331. package/workflows/file-census/README.md +14 -0
  332. package/workflows/file-census/scripts/.gitkeep +2 -0
  333. package/workflows/file-census/workflow.mjs +110 -0
  334. package/workflows/goal/README.md +166 -0
  335. package/workflows/goal/prompts/audit.md +57 -0
  336. package/workflows/goal/prompts/contract.md +56 -0
  337. package/workflows/goal/prompts/iterate.md +37 -0
  338. package/workflows/goal/workflow.mjs +501 -0
  339. package/workflows/illustrate/README.md +90 -0
  340. package/workflows/illustrate/assets/engines.json +20 -0
  341. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  342. package/workflows/illustrate/assets/extract-bing.js +33 -0
  343. package/workflows/illustrate/assets/extract-google.js +31 -0
  344. package/workflows/illustrate/workflow.mjs +301 -0
  345. package/workflows/plan/workflow.mjs +389 -0
  346. package/workflows/question-crops/README.md +35 -0
  347. package/workflows/question-crops/prompts/inventory.md +23 -0
  348. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  349. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  350. package/workflows/question-crops/workflow.mjs +172 -0
  351. package/workflows/ralph-loop/workflow.mjs +162 -0
  352. package/workflows/research/README.md +74 -0
  353. package/workflows/research/prompts/s0-goal.md +43 -0
  354. package/workflows/research/prompts/s1-early-exit.md +22 -0
  355. package/workflows/research/prompts/s1-map.md +58 -0
  356. package/workflows/research/prompts/s2-options.md +53 -0
  357. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  358. package/workflows/research/prompts/s4-verify.md +74 -0
  359. package/workflows/research/prompts/s5-synthesis.md +81 -0
  360. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  361. package/workflows/research/prompts/s6-package.md +32 -0
  362. package/workflows/research/scripts/build-report.mjs +98 -0
  363. package/workflows/research/workflow.mjs +288 -0
  364. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  365. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  366. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  367. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  368. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  369. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  370. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  371. package/workflows/wrong-question-docx/README.md +55 -0
  372. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  373. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  374. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  375. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  376. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  377. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  378. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  379. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  380. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  381. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  382. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  383. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  384. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  385. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  386. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  387. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  388. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  389. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  390. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  391. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  392. package/plugins/workflow-runner/src/expressions.js +0 -639
  393. package/plugins/workflow-runner/src/expressions.ts +0 -640
  394. package/plugins/workflow-runner/src/loader.js +0 -573
  395. package/plugins/workflow-runner/src/loader.ts +0 -721
  396. package/plugins/workflow-runner/src/multimodal.js +0 -38
  397. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  398. package/plugins/workflow-runner/src/recovery.js +0 -126
  399. package/plugins/workflow-runner/src/recovery.ts +0 -156
  400. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  401. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  402. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  403. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  404. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  405. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  406. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  407. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  408. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  409. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  410. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  411. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  412. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  413. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  414. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  415. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  416. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  417. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  418. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  419. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  420. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  421. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  422. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  423. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  424. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  425. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  426. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  427. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  428. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  429. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  430. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  431. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  432. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  433. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  434. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  435. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  436. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  437. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  438. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  439. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  440. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  441. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  442. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  443. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -201
  468. package/workflows/research.yaml +0 -873
  469. package/workflows/schema.json +0 -176
  470. package/workflows/webppt.yaml +0 -496
  471. package/workflows/wechat-reading-shots.yaml +0 -315
  472. package/workflows/word.yaml +0 -720
  473. package/workflows/youtube-shorts.yaml +0 -202
  474. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -1,587 +0,0 @@
1
- /**
2
- * ============================================================
3
- * plugins/workflow-runner/test/agent.test.ts —— agent: 节点(受工作流指导的有界 TAOR)
4
- * ------------------------------------------------------------
5
- * 验证「节点级 agency 旋钮」:
6
- * - agent 节点完成任务 → capture 绑定 → workflow 继续到 done;step kind 报 'agent'
7
- * - agent 显式放弃(__AGENT_GIVEUP__)→ 抛错 → 默认 halt(带原因)
8
- * - agent 放弃 + onError:recover → 恢复 agent 再救回 → 继续到 done(机制与其它动作 step 一致)
9
- * - agent + output_schema → 结构化产出按字段 capture
10
- * - agent + allowed_tools → 只把白名单工具下发给 LLM
11
- *
12
- * 策略(同 recovery.test.ts):agent 节点底层经 execAgentStep → runMiniReAct → chat,
13
- * mock client.js 控制其输出。
14
- * ============================================================
15
- */
16
-
17
- import { afterEach, beforeEach, describe, expect, it, mock } from 'bun:test';
18
- import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
19
- import { tmpdir } from 'node:os';
20
- import { join } from 'node:path';
21
-
22
- import { _resetWorkingDir } from '../../../src/bootstrap/workingDir.js';
23
- import type { LoopEvent, Provider } from '../../../src/types.js';
24
- import { ALL_TOOLS } from '../../../src/tools/index.js';
25
- import { runWorkflow } from '../src/runner.js';
26
- import type { RunContext, WorkflowDef, WorkflowEvent } from '../src/types.js';
27
- import { interpretMiniReActResult, parseGiveup, GIVEUP_MARKER } from '../src/agentCommon.js';
28
- import type { StepResult } from '../src/types.js';
29
-
30
- type WfOrLoop = WorkflowEvent | LoopEvent;
31
-
32
- const fakeProvider: Provider = {
33
- name: 'test',
34
- baseURL: '',
35
- apiKey: '',
36
- model: 'm',
37
- contextWindow: 128000,
38
- };
39
-
40
- async function collect(
41
- gen: AsyncGenerator<WfOrLoop, void, void>,
42
- ): Promise<WfOrLoop[]> {
43
- const out: WfOrLoop[] = [];
44
- for await (const ev of gen) out.push(ev);
45
- return out;
46
- }
47
-
48
- describe('workflows/agent (agent: 节点)', () => {
49
- let tmp: string;
50
- let ctx: RunContext;
51
-
52
- beforeEach(() => {
53
- tmp = mkdtempSync(join(tmpdir(), 'wf-agent-'));
54
- process.env.MINIMAL_AGENT_CWD = tmp;
55
- _resetWorkingDir();
56
- mock.module('../../../src/bootstrap/workingDir.js', () => ({
57
- getWorkingDir: () => tmp,
58
- initWorkingDir: () => tmp,
59
- _resetWorkingDir: () => {},
60
- }));
61
- ctx = { provider: fakeProvider, history: [], cwd: tmp, tools: ALL_TOOLS };
62
- });
63
-
64
- afterEach(() => {
65
- delete process.env.MINIMAL_AGENT_CWD;
66
- _resetWorkingDir();
67
- rmSync(tmp, { recursive: true, force: true });
68
- });
69
-
70
- it('agent 节点完成任务 → capture 绑定 → workflow 跑完;kind 报 agent', async () => {
71
- mock.module('../../../src/llm/client.js', () => ({
72
- chat: async function* () {
73
- yield { type: 'text_delta', delta: 'csv-summary-ok' };
74
- yield { type: 'done', stopReason: 'stop' };
75
- },
76
- }));
77
-
78
- const def: WorkflowDef = {
79
- name: 'agent-ok',
80
- description: '把任务交给 agent 自主完成',
81
- steps: [
82
- { id: 'a1', agent: '把 data 转成 summary', capture: { content: 'out' } },
83
- { id: 'check', type: 'assert', condition: 'out == "csv-summary-ok"' },
84
- ],
85
- };
86
- const events = await collect(runWorkflow(def, {}, ctx));
87
-
88
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
89
- expect(events.some((e) => e.type === 'error')).toBe(false);
90
- const a1Start = events.find(
91
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
92
- e.type === 'workflow_step_start' && e.id === 'a1',
93
- );
94
- expect(a1Start?.kind).toBe('agent');
95
- const a1End = events.find(
96
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_end' }> =>
97
- e.type === 'workflow_step_end' && e.id === 'a1',
98
- );
99
- expect(a1End?.ok).toBe(true);
100
- });
101
-
102
- it('agent 显式放弃(GIVEUP)→ 默认 halt 且错误带原因', async () => {
103
- mock.module('../../../src/llm/client.js', () => ({
104
- chat: async function* () {
105
- yield { type: 'text_delta', delta: '__AGENT_GIVEUP__: 任务无法完成' };
106
- yield { type: 'done', stopReason: 'stop' };
107
- },
108
- }));
109
-
110
- const def: WorkflowDef = {
111
- name: 'agent-giveup',
112
- description: 'agent 放弃则 halt',
113
- steps: [
114
- { id: 'a1', agent: '做不到的事' },
115
- { id: 'after', type: 'assert', condition: 'true' }, // 不应执行
116
- ],
117
- };
118
- const events = await collect(runWorkflow(def, {}, ctx));
119
-
120
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
121
- const err = events.find(
122
- (e): e is { type: 'error'; error: string } => e.type === 'error',
123
- );
124
- expect(err).toBeDefined();
125
- expect(err!.error).toContain('任务无法完成'); // 放弃原因透传进 halt 文案
126
- const startedIds = events
127
- .filter(
128
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_start' }> =>
129
- e.type === 'workflow_step_start',
130
- )
131
- .map((e) => e.id);
132
- expect(startedIds).not.toContain('after');
133
- });
134
-
135
- it('agent 放弃 + onError:recover → 恢复 agent 再救回 → 继续到 done', async () => {
136
- // 第 1 次 chat(agent 节点)放弃;第 2 次 chat(recover)给真结果。
137
- let call = 0;
138
- mock.module('../../../src/llm/client.js', () => ({
139
- chat: async function* () {
140
- call++;
141
- yield {
142
- type: 'text_delta',
143
- delta: call === 1 ? '__AGENT_GIVEUP__: 先放弃' : 'rescued-value',
144
- };
145
- yield { type: 'done', stopReason: 'stop' };
146
- },
147
- }));
148
-
149
- const def: WorkflowDef = {
150
- name: 'agent-recover',
151
- description: 'agent 放弃后被 recover 救回',
152
- steps: [
153
- {
154
- id: 'a1',
155
- agent: '困难任务',
156
- onError: 'recover',
157
- capture: { content: 'out' },
158
- },
159
- { id: 'check', type: 'assert', condition: 'out == "rescued-value"' },
160
- ],
161
- };
162
- const events = await collect(runWorkflow(def, {}, ctx));
163
-
164
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
165
- expect(events.some((e) => e.type === 'error')).toBe(false);
166
- expect(
167
- events.some((e) => e.type === 'warning' && e.message.includes('自适应恢复')),
168
- ).toBe(true);
169
- const a1End = events.find(
170
- (e): e is Extract<WorkflowEvent, { type: 'workflow_step_end' }> =>
171
- e.type === 'workflow_step_end' && e.id === 'a1',
172
- );
173
- expect(a1End?.ok).toBe(true);
174
- expect(a1End?.output).toContain('recovered');
175
- });
176
-
177
- it('agent + output_schema → 结构化产出按字段 capture', async () => {
178
- mock.module('../../../src/llm/client.js', () => ({
179
- chat: async function* () {
180
- yield { type: 'text_delta', delta: '{"title":"T","score":9}' };
181
- yield { type: 'done', stopReason: 'stop' };
182
- },
183
- }));
184
-
185
- const def: WorkflowDef = {
186
- name: 'agent-schema',
187
- description: 'agent 结构化产出',
188
- steps: [
189
- {
190
- id: 'a1',
191
- agent: '评估并给结构化结果',
192
- output_schema: {
193
- type: 'object',
194
- properties: { title: { type: 'string' }, score: { type: 'number' } },
195
- required: ['title', 'score'],
196
- },
197
- // v0.9 后 agent 步委托 runQuery(TAOR) 执行,schema 模式下 raw 结果暂为
198
- // { text, result, content } 三键别名(与 llm 步的 JSON 解析行为不同)。
199
- // 此处先用 result(完整 JSON 文本)做 capture,待 agent.ts 对齐 llm.ts 的
200
- // extractJsonPayload + JSON.parse 后可恢复字段级 capture: { title: 'the_title' }。
201
- capture: { result: 'the_title' },
202
- },
203
- // result 字段包含模型返回的完整 JSON 文本,验证 capture 绑定了非空值
204
- { id: 'check', type: 'assert', condition: 'length(the_title) > 0' },
205
- ],
206
- };
207
- const events = await collect(runWorkflow(def, {}, ctx));
208
-
209
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
210
- expect(events.some((e) => e.type === 'error')).toBe(false);
211
- });
212
-
213
- it('agent + allowed_tools → 只把白名单工具下发给 LLM', async () => {
214
- let seenTools: string[] = [];
215
- mock.module('../../../src/llm/client.js', () => ({
216
- chat: async function* (args: { tools?: { name: string }[] }) {
217
- seenTools = (args.tools ?? []).map((t) => t.name);
218
- yield { type: 'text_delta', delta: 'ok' };
219
- yield { type: 'done', stopReason: 'stop' };
220
- },
221
- }));
222
-
223
- const def: WorkflowDef = {
224
- name: 'agent-allowed',
225
- description: 'agent 工具收窄',
226
- steps: [
227
- { id: 'a1', agent: '只用 Read', allowed_tools: ['Read'], capture: { content: 'out' } },
228
- ],
229
- };
230
- const events = await collect(runWorkflow(def, {}, ctx));
231
-
232
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
233
- expect(seenTools).toEqual(['Read']);
234
- });
235
-
236
- it('流式:agent 节点把 text 与 tool_start/tool_end 事件透传到 runWorkflow', async () => {
237
- // 第 1 轮发起一个工具调用(Glob),第 2 轮给最终文本收尾。
238
- // 验证 miniReAct 的事件经 execAgentStep → dispatchActionStep → runWorkflow 一路 yield 出来。
239
- let call = 0;
240
- mock.module('../../../src/llm/client.js', () => ({
241
- chat: async function* () {
242
- call++;
243
- if (call === 1) {
244
- yield {
245
- type: 'tool_call_delta',
246
- index: 0,
247
- id: 'tc1',
248
- name: 'Glob',
249
- argumentsDelta: '{"pattern":"*"}',
250
- };
251
- yield { type: 'done', stopReason: 'tool_calls' };
252
- } else {
253
- yield { type: 'text_delta', delta: 'done-streaming' };
254
- yield { type: 'done', stopReason: 'stop' };
255
- }
256
- },
257
- }));
258
-
259
- const def: WorkflowDef = {
260
- name: 'agent-stream',
261
- description: '验证 agent 节点事件流式透传',
262
- steps: [{ id: 'a1', agent: '先用工具看看再答', capture: { content: 'out' } }],
263
- };
264
- const events = await collect(runWorkflow(def, {}, ctx));
265
-
266
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
267
- // 流式透传:text + tool_start(Glob) + tool_end(Glob) 都应出现在事件流里
268
- expect(events.some((e) => e.type === 'text')).toBe(true);
269
- expect(
270
- events.some((e) => e.type === 'tool_start' && e.toolName === 'Glob'),
271
- ).toBe(true);
272
- expect(
273
- events.some((e) => e.type === 'tool_end' && e.toolName === 'Glob'),
274
- ).toBe(true);
275
- // stage_change 透传:thinking(每轮)/ tool_executing(轮1有工具)/ streaming(轮2有文本)。
276
- // 缺它们时 TUI LiveArea 在 idle 整块隐藏,上面 text/tool 事件发了也看不见(本轮修复点)。
277
- const stages = events
278
- .filter(
279
- (e): e is Extract<LoopEvent, { type: 'stage_change' }> =>
280
- e.type === 'stage_change',
281
- )
282
- .map((e) => e.stage);
283
- expect(stages).toContain('thinking');
284
- expect(stages).toContain('tool_executing');
285
- expect(stages).toContain('streaming');
286
- });
287
-
288
- it('done_when 满足优先:Write 已落盘但最终无文本输出 → workflow 成功', async () => {
289
- let call = 0;
290
- mock.module('../../../src/llm/client.js', () => ({
291
- chat: async function* () {
292
- call++;
293
- if (call === 1) {
294
- yield {
295
- type: 'tool_call_delta',
296
- index: 0,
297
- id: 'write-draft',
298
- name: 'Write',
299
- argumentsDelta: '{"file_path":"./build/draft.md","content":"# 深度稿件\\n\\n已经落盘"}',
300
- };
301
- yield { type: 'done', stopReason: 'tool_calls' };
302
- return;
303
- }
304
- yield { type: 'done', stopReason: 'stop' };
305
- },
306
- }));
307
-
308
- const def: WorkflowDef = {
309
- name: 'agent-done-when-empty-final',
310
- description: 'done_when 是强验收条件',
311
- steps: [
312
- {
313
- id: 'stage_research',
314
- agent: '写 draft.md',
315
- done_when: "fileExists('./build/draft.md')",
316
- capture: { content: 'report' },
317
- },
318
- { id: 'check', type: 'assert', condition: 'includes(report, "完成条件已满足")' },
319
- ],
320
- };
321
-
322
- const events = await collect(runWorkflow(def, {}, ctx));
323
-
324
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
325
- expect(existsSync(join(tmp, 'build/draft.md'))).toBe(true);
326
- expect(readFileSync(join(tmp, 'build/draft.md'), 'utf8')).toContain('已经落盘');
327
- expect(events.some((e) => e.type === 'error')).toBe(false);
328
- });
329
-
330
- it('done_when 未满足时不因空产出直接放弃:nudge 后 Write 落盘 → workflow 成功', async () => {
331
- let call = 0;
332
- mock.module('../../../src/llm/client.js', () => ({
333
- chat: async function* () {
334
- call++;
335
- if (call === 1) {
336
- yield { type: 'text_delta', delta: '我现在创建目录并开始写稿。' };
337
- yield { type: 'done', stopReason: 'stop' };
338
- return;
339
- }
340
- if (call === 2) {
341
- yield {
342
- type: 'tool_call_delta',
343
- index: 0,
344
- id: 'write-after-nudge',
345
- name: 'Write',
346
- argumentsDelta: '{"file_path":"./build/draft.md","content":"# 被 nudge 后真正写入"}',
347
- };
348
- yield { type: 'done', stopReason: 'tool_calls' };
349
- return;
350
- }
351
- yield { type: 'done', stopReason: 'stop' };
352
- },
353
- }));
354
-
355
- const def: WorkflowDef = {
356
- name: 'agent-done-when-nudge',
357
- description: '宣告不算完成',
358
- steps: [
359
- {
360
- id: 'stage_research',
361
- agent: '写 draft.md',
362
- done_when: "fileExists('./build/draft.md')",
363
- },
364
- ],
365
- };
366
-
367
- const events = await collect(runWorkflow(def, {}, ctx));
368
-
369
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
370
- expect(existsSync(join(tmp, 'build/draft.md'))).toBe(true);
371
- expect(
372
- events.some(
373
- (e) => e.type === 'warning' && e.message.includes('完成条件未满足'),
374
- ),
375
- ).toBe(true);
376
- });
377
-
378
- it('done_when 多轮仍不满足 → halt 归因为完成条件未满足,而不是没有产出任何结果', async () => {
379
- mock.module('../../../src/llm/client.js', () => ({
380
- chat: async function* () {
381
- yield { type: 'done', stopReason: 'stop' };
382
- },
383
- }));
384
-
385
- const def: WorkflowDef = {
386
- name: 'agent-done-when-exhaust',
387
- description: '空答不落盘',
388
- steps: [
389
- {
390
- id: 'stage_research',
391
- agent: '写 draft.md',
392
- done_when: "fileExists('./build/draft.md')",
393
- },
394
- ],
395
- };
396
-
397
- const events = await collect(runWorkflow(def, {}, ctx));
398
- const halt = events.find(
399
- (e) => e.type === 'error' && e.error.includes('Workflow halted'),
400
- ) as { type: 'error'; error: string } | undefined;
401
-
402
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
403
- expect(halt).toBeDefined();
404
- expect(halt!.error).toContain('完成条件未满足');
405
- expect(halt!.error).not.toContain('没有产出任何结果');
406
- expect(halt!.error).toContain('没有观察到工具调用');
407
- });
408
-
409
- it('没有 done_when 的 agent 空输出仍按没有产出任何结果失败', async () => {
410
- mock.module('../../../src/llm/client.js', () => ({
411
- chat: async function* () {
412
- yield { type: 'done', stopReason: 'stop' };
413
- },
414
- }));
415
-
416
- const def: WorkflowDef = {
417
- name: 'agent-empty-no-done-when',
418
- description: '旧语义保持',
419
- steps: [{ id: 'a1', agent: '做点事' }],
420
- };
421
-
422
- const events = await collect(runWorkflow(def, {}, ctx));
423
- const halt = events.find(
424
- (e) => e.type === 'error' && e.error.includes('Workflow halted'),
425
- ) as { type: 'error'; error: string } | undefined;
426
-
427
- expect(events.some((e) => e.type === 'workflow_done')).toBe(false);
428
- expect(halt).toBeDefined();
429
- expect(halt!.error).toContain('没有产出任何结果');
430
- });
431
-
432
- it('agent + output_schema → 不把 JSON 原文当 text 流式回显(对齐 llm.ts 克制)', async () => {
433
- mock.module('../../../src/llm/client.js', () => ({
434
- chat: async function* () {
435
- yield { type: 'text_delta', delta: '{"k":"v"}' };
436
- yield { type: 'done', stopReason: 'stop' };
437
- },
438
- }));
439
-
440
- const def: WorkflowDef = {
441
- name: 'agent-schema-silent',
442
- description: 'schema 模式不刷 JSON',
443
- steps: [
444
- {
445
- id: 'a1',
446
- agent: '产出结构化结果',
447
- output_schema: {
448
- type: 'object',
449
- properties: { k: { type: 'string' } },
450
- required: ['k'],
451
- },
452
- capture: { k: 'out' },
453
- },
454
- ],
455
- };
456
- const events = await collect(runWorkflow(def, {}, ctx));
457
-
458
- expect(events.some((e) => e.type === 'workflow_done')).toBe(true);
459
- // v0.9 后 agent 步委托 runQuery(TAOR) 执行,text_delta 自然透传为 text 事件(不再像旧
460
- // miniReAct 那样在 schema 模式下抑制 text 回显)。schema 约束通过 prompt 嵌入传达给模型,
461
- // 但事件流仍会包含原始文本。
462
- expect(events.some((e) => e.type === 'text')).toBe(true);
463
- const stages = events
464
- .filter(
465
- (e): e is Extract<LoopEvent, { type: 'stage_change' }> =>
466
- e.type === 'stage_change',
467
- )
468
- .map((e) => e.stage);
469
- expect(stages).toContain('streaming');
470
- });
471
- });
472
-
473
- // ============================================================
474
- // interpretMiniReActResult 单元测试(GIVEUP 标记 + 误报过滤)
475
- // ============================================================
476
-
477
- describe('workflows/agent::GIVEUP 标记检测与误报过滤', () => {
478
- function makeStepResult(text: string): StepResult {
479
- return { raw: { text, result: text }, preview: text.slice(0, 200) };
480
- }
481
-
482
- it('新标记 [wf-internal-abort-do-not-generate] 被正确识别为放弃', () => {
483
- const r = interpretMiniReActResult(makeStepResult(`一些前文\n[wf-internal-abort-do-not-generate]: 任务太复杂`), false);
484
- expect(r.ok).toBe(false);
485
- if (!r.ok) expect(r.reason).toBe('任务太复杂');
486
- });
487
-
488
- it('旧标记 __AGENT_GIVEUP__ 向后兼容(仍被识别)', () => {
489
- const r = interpretMiniReActResult(makeStepResult(`前文\n__AGENT_GIVEUP__: 无法完成`), false);
490
- expect(r.ok).toBe(false);
491
- if (!r.ok) expect(r.reason).toContain('无法完成');
492
- });
493
-
494
- it('无任何标记 → 正常交付', () => {
495
- const r = interpretMiniReActResult(makeStepResult('这是正常的工作成果输出'), false);
496
- expect(r.ok).toBe(true);
497
- if (r.ok) expect(r.value.raw.text).toBe('这是正常的工作成果输出');
498
- });
499
-
500
- it('误报防护:reason > 80 字符 → 降级为成功交付(去掉标记后的内容)', () => {
501
- // 模拟用户遇到的场景:LLM 输出中碰巧包含旧标记,后面跟着大量实质内容
502
- const longContent = 'since I did the work and have findings. I\'ll output the research report directly.\n\n## 代码探索报告\n\n### 相关文件\n- src/main.ts\n- src/loop.ts\n\n### 现有架构概要\n三层结构设计...';
503
- const r = interpretMiniReActResult(makeStepResult(`前序分析完成。\n__AGENT_GIVEUP__: ${longContent}`), false);
504
- expect(r.ok).toBe(true); // 关键:不被判为放弃!
505
- if (r.ok) {
506
- expect(r.value.raw.text).toContain('代码探索报告');
507
- expect(r.value.raw.text).not.toContain('__AGENT_GIVEUP__'); // 标记已被清除
508
- }
509
- });
510
-
511
- it('误报防护降级时标记出现多次 → 全部清除不残留(replaceAll)', () => {
512
- // LLM 在长输出中误触发标记两次(新旧各一):降级为成功后,
513
- // cleanText 不应残留任何标记(replace 只删首个的回归锚)
514
- const r = interpretMiniReActResult(
515
- makeStepResult(
516
- `[wf-internal-abort-do-not-generate]: ## 研究报告\n\n### 发现1\n内容…\n__AGENT_GIVEUP__\n更多内容\n[wf-internal-abort-do-not-generate]`,
517
- ),
518
- false,
519
- );
520
- expect(r.ok).toBe(true); // 含 ## 标题 → 误报降级为成功
521
- if (r.ok) {
522
- expect(r.value.raw.text).not.toContain('[wf-internal-abort-do-not-generate]');
523
- expect(r.value.raw.text).not.toContain('__AGENT_GIVEUP__');
524
- expect(r.value.raw.text).toContain('研究报告');
525
- }
526
- });
527
-
528
- it('误报防护:reason 包含 markdown 标题(##)→ 视为误报', () => {
529
- const r = interpretMiniReActResult(
530
- makeStepResult(`工作完成。\n[wf-internal-abort-do-not-generate]: ## 研究报告\n\n### 发现1\n内容...`),
531
- false,
532
- );
533
- expect(r.ok).toBe(true); // 含 ## 标题 → 误报
534
- if (r.ok) expect(r.value.raw.text).toContain('研究报告');
535
- });
536
-
537
- it('误报防护:reason 包含 markdown 列表项(- )→ 视为误报', () => {
538
- const r = interpretMiniReActResult(
539
- makeStepResult(`[wf-internal-abort-do-not-generate]: - 发现 A\n- 发现 B\n- 发现 C`),
540
- false,
541
- );
542
- expect(r.ok).toBe(true); // 含列表项 → 误报
543
- });
544
-
545
- it('真正放弃:reason 短且无结构化内容 → 仍判为放弃', () => {
546
- const r = interpretMiniReActResult(
547
- makeStepResult(`[wf-internal-abort-do-not-generate]: 无法访问数据库`),
548
- false,
549
- );
550
- expect(r.ok).toBe(false);
551
- if (!r.ok) expect(r.reason).toBe('无法访问数据库');
552
- });
553
-
554
- it('真正放弃:reason 为空字符串 → 显示默认原因', () => {
555
- const r = interpretMiniReActResult(makeStepResult('结束[wf-internal-abort-do-not-generate]'), false);
556
- expect(r.ok).toBe(false);
557
- if (!r.ok) expect(r.reason).toBe('显式放弃(未给原因)');
558
- });
559
-
560
- it('schema 模式不受 GIVEUP 影响(schema 走独立解析路径)', () => {
561
- const r = interpretMiniReActResult(
562
- makeStepResult('{"result": "ok"}\n[wf-internal-abort-do-not-generate]: 假放弃'),
563
- true, // hasSchema=true
564
- );
565
- expect(r.ok).toBe(true); // schema 模式不检查 GIVEUP
566
- });
567
-
568
- it('空产出 → 放弃(非 GIVEUP,而是没有结果)', () => {
569
- const r = interpretMiniReActResult(makeStepResult(''), false);
570
- expect(r.ok).toBe(false);
571
- if (!r.ok) expect(r.reason).toBe('没有产出任何结果');
572
- });
573
-
574
- it('parseGiveup 新标记优先于旧标记(新标记先出现时)', () => {
575
- // 新标记先出现 → 应取新标记后的内容(到字符串末尾,包含后续旧标记文本)
576
- const text = `文本\n[wf-internal-abort-do-not-generate]: 新原因\n更多文本 __AGENT_GIVEUP__: 旧原因`;
577
- const reason = parseGiveup(text);
578
- // parseGiveup 返回标记后的全部内容(不截断到下一个标记)
579
- expect(reason).toContain('新原因'); // 至少以新原因开头
580
- expect(reason).not.toContain('[wf-internal-abort-do-not-generate]'); // 标记本身不在 reason 中
581
- });
582
-
583
- it('parseGiveup 旧标记兜底(只有旧标记时)', () => {
584
- const reason = parseGiveup('一些文字 __AGENT_GIVEUP__: 只有旧标记');
585
- expect(reason).toBe('只有旧标记');
586
- });
587
- });