minimal-agent 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. package/README.md +6 -5
  2. package/package.json +62 -5
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +204 -185
  16. package/plugins/workflow-runner/src/index.ts +249 -224
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +404 -467
  28. package/plugins/workflow-runner/src/runner.ts +491 -535
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +172 -152
  54. package/plugins/workflow-runner/src/taskIdentity.ts +233 -200
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -105
  58. package/plugins/workflow-runner/src/types.ts +155 -520
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +542 -469
  68. package/plugins/workflow-runner/src/workflowState.ts +639 -589
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/skill-creator/scripts/run_eval.py +3 -2
  92. package/skills/ui-design/SKILL.md +5 -2
  93. package/skills/ui-design/references/layout-composition.md +1 -1
  94. package/skills/workflow-creator/SKILL.md +344 -0
  95. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  96. package/skills/workflow-creator/references/api.md +216 -0
  97. package/skills/workflow-creator/references/migration.md +103 -0
  98. package/skills/workflow-creator/references/patterns.md +779 -0
  99. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  100. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  101. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  102. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  103. package/src/advisor/advisorCoordinator.js +503 -0
  104. package/src/advisor/advisorCoordinator.ts +657 -0
  105. package/src/cli/configMenu.tsx +0 -1
  106. package/src/cli/print.js +44 -6
  107. package/src/cli/print.ts +73 -4
  108. package/src/cli/streamJson.js +5 -6
  109. package/src/cli/streamJson.ts +8 -4
  110. package/src/cli/wizards/advisorWizard.js +4 -2
  111. package/src/cli/wizards/advisorWizard.tsx +8 -2
  112. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  113. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  114. package/src/collaboration/taskFlow.js +115 -0
  115. package/src/collaboration/taskFlow.ts +169 -0
  116. package/src/config/configDefaults.js +41 -1
  117. package/src/config/configDefaults.ts +43 -1
  118. package/src/config/configDiagnostics.ts +2 -2
  119. package/src/config/configFile.js +40 -9
  120. package/src/config/configFile.ts +60 -11
  121. package/src/config/configService.js +443 -74
  122. package/src/config/configService.ts +723 -142
  123. package/src/config/numericLimits.js +22 -0
  124. package/src/config/numericLimits.ts +24 -0
  125. package/src/config.js +1 -0
  126. package/src/config.ts +3 -2
  127. package/src/context/budgetPlan.js +1 -1
  128. package/src/context/budgetPlan.ts +1 -1
  129. package/src/context/compact.js +7 -2
  130. package/src/context/compact.ts +9 -2
  131. package/src/context/microCompactLite.js +212 -13
  132. package/src/context/microCompactLite.ts +261 -12
  133. package/src/context/sessionRegistry.js +8 -1
  134. package/src/context/sessionRegistry.ts +18 -5
  135. package/src/context/toolResultArchive.js +72 -0
  136. package/src/context/toolResultArchive.ts +95 -0
  137. package/src/goal/errors.js +8 -0
  138. package/src/goal/errors.ts +18 -0
  139. package/src/goal/goalRuntime.js +344 -0
  140. package/src/goal/goalRuntime.ts +466 -0
  141. package/src/goal/goalStore.js +200 -0
  142. package/src/goal/goalStore.ts +219 -0
  143. package/src/goal/index.js +4 -0
  144. package/src/goal/index.ts +4 -0
  145. package/src/goal/statusMapping.js +71 -0
  146. package/src/goal/statusMapping.ts +95 -0
  147. package/src/goal/types.js +7 -0
  148. package/src/goal/types.ts +179 -0
  149. package/src/goal/workflowController.js +306 -0
  150. package/src/goal/workflowController.ts +360 -0
  151. package/src/harness/evidenceLedger.js +2 -0
  152. package/src/harness/evidenceLedger.ts +1 -0
  153. package/src/harness/stallGuard.js +9 -3
  154. package/src/harness/stallGuard.ts +7 -3
  155. package/src/images/imageResolver.js +161 -0
  156. package/src/images/imageResolver.ts +189 -0
  157. package/src/infra/verification.js +56 -20
  158. package/src/infra/verification.ts +87 -20
  159. package/src/llm/client.js +79 -21
  160. package/src/llm/client.ts +182 -35
  161. package/src/llm/gatewayClient.js +201 -0
  162. package/src/llm/gatewayClient.ts +299 -0
  163. package/src/llm/messageProvenance.js +46 -0
  164. package/src/llm/messageProvenance.ts +58 -0
  165. package/src/llm/modelProvider.js +1 -0
  166. package/src/llm/modelProvider.ts +22 -0
  167. package/src/llm/providers/anthropicFormat.js +108 -1
  168. package/src/llm/providers/anthropicFormat.ts +115 -4
  169. package/src/llm/providers/openaiFormat.js +9 -0
  170. package/src/llm/providers/openaiFormat.ts +12 -3
  171. package/src/loop.js +319 -54
  172. package/src/loop.ts +373 -57
  173. package/src/main.js +4 -1
  174. package/src/main.tsx +4 -1
  175. package/src/managedExecution/index.js +2 -0
  176. package/src/managedExecution/index.ts +2 -0
  177. package/src/managedExecution/registry.js +15 -0
  178. package/src/managedExecution/registry.ts +20 -0
  179. package/src/managedExecution/types.js +1 -0
  180. package/src/managedExecution/types.ts +86 -0
  181. package/src/modelRef.js +9 -0
  182. package/src/modelRef.ts +31 -0
  183. package/src/multimodal.js +14 -28
  184. package/src/multimodal.ts +17 -33
  185. package/src/net/lanDiscovery.js +65 -0
  186. package/src/net/lanDiscovery.ts +82 -0
  187. package/src/plugin-sdk.js +28 -3
  188. package/src/plugin-sdk.ts +39 -6
  189. package/src/plugins/pluginApi.ts +16 -1
  190. package/src/plugins/pluginLoader.js +4 -0
  191. package/src/plugins/pluginLoader.ts +6 -0
  192. package/src/plugins/pluginRunner.js +152 -9
  193. package/src/plugins/pluginRunner.ts +186 -8
  194. package/src/plugins/slashFallback.js +113 -0
  195. package/src/plugins/slashFallback.ts +137 -0
  196. package/src/prompts/policyRegistry.js +15 -8
  197. package/src/prompts/policyRegistry.ts +18 -8
  198. package/src/prompts/promptAssembly.js +103 -12
  199. package/src/prompts/promptAssembly.ts +114 -12
  200. package/src/prompts/skillList.js +21 -3
  201. package/src/prompts/skillList.ts +27 -2
  202. package/src/prompts/stableSystemPrompt.js +18 -0
  203. package/src/prompts/stableSystemPrompt.ts +33 -0
  204. package/src/runtime/agentRuntimeContext.js +8 -2
  205. package/src/runtime/agentRuntimeContext.ts +17 -4
  206. package/src/session/runAgentTurn.js +78 -12
  207. package/src/session/runAgentTurn.ts +105 -23
  208. package/src/session/runTurn.js +10 -9
  209. package/src/session/runTurn.ts +17 -8
  210. package/src/session/sessionState.ts +2 -0
  211. package/src/team/auth.js +186 -0
  212. package/src/team/auth.ts +298 -0
  213. package/src/team/cli.js +105 -0
  214. package/src/team/cli.ts +122 -0
  215. package/src/team/onlineToolContract.js +64 -0
  216. package/src/team/onlineToolContract.ts +109 -0
  217. package/src/team/toolPolicy.js +36 -0
  218. package/src/team/toolPolicy.ts +75 -0
  219. package/src/tools/advisor/advisor.js +148 -37
  220. package/src/tools/advisor/advisor.ts +161 -38
  221. package/src/tools/advisor/advisorDecision.js +71 -0
  222. package/src/tools/advisor/advisorDecision.ts +85 -0
  223. package/src/tools/agent/agent.js +18 -5
  224. package/src/tools/agent/agent.ts +21 -7
  225. package/src/tools/agent/agentControl.js +246 -0
  226. package/src/tools/agent/agentControl.ts +284 -0
  227. package/src/tools/agent/agentTaskService.js +40 -1
  228. package/src/tools/agent/agentTaskService.ts +44 -1
  229. package/src/tools/agent/agentTypes.js +14 -2
  230. package/src/tools/agent/agentTypes.ts +15 -2
  231. package/src/tools/applypatch/applyPatch.js +362 -0
  232. package/src/tools/applypatch/applyPatch.ts +428 -0
  233. package/src/tools/bash/bash.js +70 -18
  234. package/src/tools/bash/bash.ts +75 -20
  235. package/src/tools/capabilities.js +10 -5
  236. package/src/tools/capabilities.ts +10 -5
  237. package/src/tools/computeruse/computerIntent.js +32 -0
  238. package/src/tools/computeruse/computerIntent.ts +46 -0
  239. package/src/tools/computeruse/telemetryLog.js +12 -0
  240. package/src/tools/computeruse/telemetryLog.ts +16 -0
  241. package/src/tools/computeruse/vision/telemetry.js +1 -0
  242. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  243. package/src/tools/effectiveToolSet.js +4 -0
  244. package/src/tools/effectiveToolSet.ts +4 -0
  245. package/src/tools/index.js +21 -2
  246. package/src/tools/index.ts +33 -2
  247. package/src/tools/powershell/powershell.js +18 -1
  248. package/src/tools/powershell/powershell.ts +18 -2
  249. package/src/tools/presentresult/presentresult.js +6 -15
  250. package/src/tools/presentresult/presentresult.ts +6 -15
  251. package/src/tools/read/read.js +69 -11
  252. package/src/tools/read/read.ts +70 -11
  253. package/src/tools/shared/fileUtils.js +1 -2
  254. package/src/tools/shared/fileUtils.ts +1 -2
  255. package/src/tools/shared/permanentDeleteGuard.js +34 -3
  256. package/src/tools/shared/permanentDeleteGuard.ts +43 -6
  257. package/src/tools/shared/toolOutputStore.js +23 -1
  258. package/src/tools/shared/toolOutputStore.ts +22 -1
  259. package/src/tools/skill/skill.js +9 -3
  260. package/src/tools/skill/skill.ts +8 -4
  261. package/src/tools/toolPromptGuides.js +117 -0
  262. package/src/tools/toolPromptGuides.ts +137 -0
  263. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  264. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  265. package/src/tools/webbrowser/browser.js +27 -11
  266. package/src/tools/webbrowser/browser.ts +68 -24
  267. package/src/tools/webbrowser/browserAutomation.js +329 -0
  268. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  269. package/src/tools/webbrowser/browserAxState.js +97 -0
  270. package/src/tools/webbrowser/browserAxState.ts +142 -0
  271. package/src/tools/webbrowser/browserBatch.js +1578 -0
  272. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  273. package/src/tools/webbrowser/browserCdp.js +208 -0
  274. package/src/tools/webbrowser/browserCdp.ts +255 -0
  275. package/src/tools/webbrowser/browserConditions.js +24 -0
  276. package/src/tools/webbrowser/browserConditions.ts +45 -0
  277. package/src/tools/webbrowser/browserContent.js +281 -0
  278. package/src/tools/webbrowser/browserContent.ts +438 -0
  279. package/src/tools/webbrowser/browserControl.js +131 -30
  280. package/src/tools/webbrowser/browserControl.ts +210 -50
  281. package/src/tools/webbrowser/browserDaemon.js +22 -14
  282. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  283. package/src/tools/webbrowser/browserFrames.js +47 -0
  284. package/src/tools/webbrowser/browserFrames.ts +54 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  286. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  287. package/src/tools/webbrowser/browserLocator.js +140 -0
  288. package/src/tools/webbrowser/browserLocator.ts +194 -0
  289. package/src/tools/webbrowser/browserOutcome.js +10 -17
  290. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  291. package/src/tools/webbrowser/browserRecovery.js +58 -0
  292. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  293. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  294. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  295. package/src/tools/webbrowser/browserService.js +28 -2
  296. package/src/tools/webbrowser/browserService.ts +49 -9
  297. package/src/tools/webbrowser/browserStream.js +132 -33
  298. package/src/tools/webbrowser/browserStream.ts +224 -50
  299. package/src/tools/webbrowser/browserTabs.js +48 -15
  300. package/src/tools/webbrowser/browserTabs.ts +178 -96
  301. package/src/tools/webbrowser/webbrowser.js +683 -144
  302. package/src/tools/webbrowser/webbrowser.ts +979 -236
  303. package/src/tools/webfetch/preapproved.js +0 -2
  304. package/src/tools/webfetch/preapproved.ts +0 -2
  305. package/src/tools/websearch/websearch.js +129 -8
  306. package/src/tools/websearch/websearch.ts +138 -6
  307. package/src/types.ts +450 -42
  308. package/src/ui/App.js +377 -58
  309. package/src/ui/App.tsx +576 -111
  310. package/src/ui/LiveArea.js +14 -8
  311. package/src/ui/LiveArea.tsx +14 -10
  312. package/src/ui/MessageList.js +63 -20
  313. package/src/ui/MessageList.tsx +101 -16
  314. package/src/ui/ModelPicker.js +7 -4
  315. package/src/ui/ModelPicker.tsx +55 -8
  316. package/src/ui/hooks/useChat.js +152 -163
  317. package/src/ui/hooks/useChat.ts +396 -334
  318. package/src/ui/loginCommand.js +56 -0
  319. package/src/ui/loginCommand.ts +63 -0
  320. package/src/ui/toolProgress.js +41 -0
  321. package/src/ui/toolProgress.ts +44 -0
  322. package/src/web/browserBridge.js +20 -2
  323. package/src/web/browserBridge.ts +20 -2
  324. package/src/web/protocol.ts +1897 -194
  325. package/workflows/adaptive-research/workflow.mjs +86 -0
  326. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  327. package/workflows/e2e-llm/workflow.mjs +52 -0
  328. package/workflows/e2e-smoke/workflow.mjs +59 -0
  329. package/workflows/e2e-vision-schema/README.md +48 -0
  330. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  331. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  332. package/workflows/file-census/README.md +14 -0
  333. package/workflows/file-census/scripts/.gitkeep +2 -0
  334. package/workflows/file-census/workflow.mjs +110 -0
  335. package/workflows/goal/README.md +166 -0
  336. package/workflows/goal/prompts/audit.md +57 -0
  337. package/workflows/goal/prompts/contract.md +56 -0
  338. package/workflows/goal/prompts/iterate.md +37 -0
  339. package/workflows/goal/workflow.mjs +501 -0
  340. package/workflows/illustrate/README.md +90 -0
  341. package/workflows/illustrate/assets/engines.json +20 -0
  342. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  343. package/workflows/illustrate/assets/extract-bing.js +33 -0
  344. package/workflows/illustrate/assets/extract-google.js +31 -0
  345. package/workflows/illustrate/workflow.mjs +301 -0
  346. package/workflows/plan/workflow.mjs +389 -0
  347. package/workflows/question-crops/README.md +35 -0
  348. package/workflows/question-crops/prompts/inventory.md +23 -0
  349. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  350. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  351. package/workflows/question-crops/workflow.mjs +172 -0
  352. package/workflows/ralph-loop/workflow.mjs +162 -0
  353. package/workflows/research/DESIGN.md +449 -0
  354. package/workflows/research/README.md +74 -0
  355. package/workflows/research/prompts/s0-goal.md +43 -0
  356. package/workflows/research/prompts/s1-early-exit.md +22 -0
  357. package/workflows/research/prompts/s1-map.md +58 -0
  358. package/workflows/research/prompts/s2-options.md +53 -0
  359. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  360. package/workflows/research/prompts/s4-verify.md +74 -0
  361. package/workflows/research/prompts/s5-synthesis.md +81 -0
  362. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  363. package/workflows/research/prompts/s6-package.md +32 -0
  364. package/workflows/research/scripts/build-report.mjs +98 -0
  365. package/workflows/research/workflow.mjs +288 -0
  366. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  367. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  368. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  369. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  370. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  371. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  372. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  373. package/workflows/wrong-question-docx/README.md +55 -0
  374. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  375. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  376. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  377. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  378. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  379. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  380. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  381. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  382. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  383. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  384. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  385. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  386. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  387. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  388. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  389. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  390. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  391. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  392. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  393. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  394. package/plugins/workflow-runner/src/expressions.js +0 -618
  395. package/plugins/workflow-runner/src/expressions.ts +0 -622
  396. package/plugins/workflow-runner/src/loader.js +0 -573
  397. package/plugins/workflow-runner/src/loader.ts +0 -721
  398. package/plugins/workflow-runner/src/multimodal.js +0 -38
  399. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  400. package/plugins/workflow-runner/src/recovery.js +0 -119
  401. package/plugins/workflow-runner/src/recovery.ts +0 -149
  402. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  403. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  404. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -41
  405. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -50
  406. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  407. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  408. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  409. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  410. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  411. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  412. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  413. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  414. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -208
  415. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -256
  416. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -58
  417. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -68
  418. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  419. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  420. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  421. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  422. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  423. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  424. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -147
  425. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  426. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  427. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -226
  428. package/plugins/workflow-runner/test/expressions.test.ts +0 -397
  429. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  430. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  431. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  432. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  433. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  434. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  435. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  436. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  437. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  438. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  439. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -87
  440. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  441. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  442. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -220
  443. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -379
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -150
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -338
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -270
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -199
  468. package/workflows/schema.json +0 -176
  469. package/workflows/webppt.yaml +0 -496
  470. package/workflows/wechat-reading-shots.yaml +0 -315
  471. package/workflows/word.yaml +0 -720
  472. package/workflows/youtube-shorts.yaml +0 -202
@@ -1,573 +0,0 @@
1
- /**
2
- * ============================================================
3
- * plugins/workflow-runner/src/loader.ts —— workflow yaml 双源加载 + 校验
4
- * ------------------------------------------------------------
5
- * - 扫描 cwd/workflows/ 与 packageRoot/workflows/(cwd 优先,复用
6
- * getResourceSearchPaths 契约)
7
- * - 一个坏 yaml 不应拖累其它工作流(catch 单文件错误,继续扫描)
8
- * - 目录不存在 / 为空 → 静默返回 [](默认 T-A-O-R 不受影响)
9
- *
10
- * 不引 AJV:下面手写校验器(validate/validateSteps),覆盖结构性硬错误并对
11
- * 每条 step 字段做类型/一致性校验——
12
- * - name / description / steps 必填且类型正确;steps 非空
13
- * - 每个 step 必须有且只有一个动作字段(tool / skill / llm / agent / type)
14
- * - 控制流字段一致性 + ADR-05 的 llm-only 字段(output_schema/context_files/
15
- * allowed_tools)准入 + 断点续跑字段(artifacts/max_retries)类型
16
- * 手写而非 schema 库:依赖少、错误信息可中文化、按减法不为「完整 schema」引依赖。
17
- * ============================================================
18
- */
19
- import { readFile, readdir } from 'node:fs/promises';
20
- import { basename, join } from 'node:path';
21
- import { parse as parseYamlLib } from 'yaml';
22
- import { getResourceSearchPaths } from '../../../src/plugin-sdk.js';
23
- export class WorkflowLoadError extends Error {
24
- file;
25
- constructor(message, file) {
26
- super(message);
27
- this.file = file;
28
- this.name = 'WorkflowLoadError';
29
- }
30
- }
31
- /**
32
- * 扫描双源目录,返回所有 *.yaml / *.yml 解析后的 workflow。
33
- * 永远不抛;坏文件 console.warn 并跳过。
34
- */
35
- export async function listWorkflows(workingDir) {
36
- const out = [];
37
- const seen = new Set();
38
- const roots = getResourceSearchPaths('workflows', import.meta.url, workingDir);
39
- for (const root of roots) {
40
- let entries;
41
- try {
42
- entries = await readdir(root);
43
- }
44
- catch {
45
- continue;
46
- }
47
- for (const f of entries) {
48
- if (!f.endsWith('.yaml') && !f.endsWith('.yml'))
49
- continue;
50
- const full = join(root, f);
51
- try {
52
- const def = await parseWorkflowFile(full);
53
- if (!seen.has(def.name)) {
54
- seen.add(def.name);
55
- out.push(def);
56
- }
57
- }
58
- catch (e) {
59
- // eslint-disable-next-line no-console
60
- console.warn(`[workflows] 忽略损坏的 yaml ${full}: ${e.message}`);
61
- }
62
- }
63
- }
64
- return out;
65
- }
66
- /** 按 name 查找。找不到返回 null —— 调用方决定如何提示用户。 */
67
- export async function findWorkflowByName(name, workingDir) {
68
- const all = await listWorkflows(workingDir);
69
- const normalized = normalizeWorkflowLookupName(name);
70
- return all.find((w) => w.name === normalized || workflowFileBaseName(w) === normalized) ?? null;
71
- }
72
- function stripYamlExt(name) {
73
- return name.replace(/\.ya?ml$/i, '');
74
- }
75
- function normalizeWorkflowLookupName(name) {
76
- return stripYamlExt(basename(name));
77
- }
78
- function workflowFileBaseName(workflow) {
79
- if (!workflow.__source)
80
- return null;
81
- return stripYamlExt(basename(workflow.__source));
82
- }
83
- /** 读单个 yaml 文件 → 解析 → 校验。失败抛 WorkflowLoadError。 */
84
- export async function parseWorkflowFile(file) {
85
- let raw;
86
- try {
87
- raw = await readFile(file, 'utf8');
88
- }
89
- catch (e) {
90
- throw new WorkflowLoadError(`无法读取 ${file}: ${e.message}`, file);
91
- }
92
- let data;
93
- try {
94
- data = parseYamlLib(raw);
95
- }
96
- catch (e) {
97
- throw new WorkflowLoadError(`yaml 语法错误: ${e.message}`, file);
98
- }
99
- if (!data || typeof data !== 'object') {
100
- throw new WorkflowLoadError('yaml 根节点必须是对象', file);
101
- }
102
- validate(data, file);
103
- const def = data;
104
- def.__source = file;
105
- return def;
106
- }
107
- // ---------------- 手写最小校验 ----------------
108
- function validate(obj, file) {
109
- if (typeof obj.name !== 'string' || obj.name.length === 0) {
110
- throw new WorkflowLoadError("缺少必填字段 'name'(string)", file);
111
- }
112
- if (typeof obj.description !== 'string' || obj.description.length === 0) {
113
- throw new WorkflowLoadError("缺少必填字段 'description'(string)", file);
114
- }
115
- if (!Array.isArray(obj.steps) || obj.steps.length === 0) {
116
- throw new WorkflowLoadError("缺少必填字段 'steps' 或为空数组", file);
117
- }
118
- validateSteps(obj.steps, file, '');
119
- // self_heal 校验(可选)
120
- if (obj.self_heal !== undefined) {
121
- const sh = obj.self_heal;
122
- if (typeof sh !== 'object' || sh === null || Array.isArray(sh)) {
123
- throw new WorkflowLoadError("'self_heal' 必须是对象", file);
124
- }
125
- if (sh.backoff !== undefined) {
126
- if (typeof sh.backoff !== 'number' || !Number.isInteger(sh.backoff) || sh.backoff < 0) {
127
- throw new WorkflowLoadError("self_heal.backoff 必须是 >= 0 的整数", file);
128
- }
129
- }
130
- if (sh.max_retries !== undefined) {
131
- if (typeof sh.max_retries !== 'number' || !Number.isInteger(sh.max_retries) || sh.max_retries < 1) {
132
- throw new WorkflowLoadError("self_heal.max_retries 必须是 >= 1 的整数", file);
133
- }
134
- }
135
- if (sh.retry_delay_ms !== undefined) {
136
- if (typeof sh.retry_delay_ms !== 'number' || !Number.isFinite(sh.retry_delay_ms) || sh.retry_delay_ms < 0) {
137
- throw new WorkflowLoadError("self_heal.retry_delay_ms 必须是 >= 0 的数字(毫秒)", file);
138
- }
139
- }
140
- if (sh.max_turns_retry_delay_ms !== undefined) {
141
- if (typeof sh.max_turns_retry_delay_ms !== 'number' || !Number.isFinite(sh.max_turns_retry_delay_ms) || sh.max_turns_retry_delay_ms < 0) {
142
- throw new WorkflowLoadError("self_heal.max_turns_retry_delay_ms 必须是 >= 0 的数字(毫秒)", file);
143
- }
144
- }
145
- }
146
- // artifacts 校验(WorkflowDef 级别,可选)
147
- if (obj.artifacts !== undefined) {
148
- if (!Array.isArray(obj.artifacts) || !obj.artifacts.every((x) => typeof x === 'string' && x.length > 0)) {
149
- throw new WorkflowLoadError("'artifacts' 必须是非空字符串数组", file);
150
- }
151
- }
152
- if (obj.inputs !== undefined) {
153
- if (!Array.isArray(obj.inputs)) {
154
- throw new WorkflowLoadError("'inputs' 必须是数组", file);
155
- }
156
- for (const [i, item] of obj.inputs.entries()) {
157
- if (!item || typeof item !== 'object') {
158
- throw new WorkflowLoadError(`inputs[${i}] 必须是对象`, file);
159
- }
160
- const r = item;
161
- if (typeof r.name !== 'string' || r.name.length === 0) {
162
- throw new WorkflowLoadError(`inputs[${i}].name 必填`, file);
163
- }
164
- if (r.type !== undefined && r.type !== 'string' && r.type !== 'number' && r.type !== 'enum') {
165
- throw new WorkflowLoadError(`inputs[${i}].type 必须是 string/number/enum`, file);
166
- }
167
- if (r.type === 'enum' && (!Array.isArray(r.values) || r.values.length === 0)) {
168
- throw new WorkflowLoadError(`inputs[${i}].values 必填(type=enum 时)`, file);
169
- }
170
- // greedy 首参:只许 boolean,且只能标在第一个 input(语义=吸收全部位置参数,
171
- // 标在非首位无意义且会误导,响亮拒绝)。
172
- if (r.greedy !== undefined && typeof r.greedy !== 'boolean') {
173
- throw new WorkflowLoadError(`inputs[${i}].greedy 必须是 boolean`, file);
174
- }
175
- if (r.greedy === true && i !== 0) {
176
- throw new WorkflowLoadError(`inputs[${i}].greedy 只能标在第一个 input 上`, file);
177
- }
178
- }
179
- }
180
- }
181
- // ADR-05: 控制流 type 集合——这些节点的"动作"由 type 自身定义,
182
- // 因此不能附带 tool/skill/llm 也不能配 output_schema / context_files / allowed_tools。
183
- // 导出供「editor ↔ 后端」schema 一致性测试比对(test/workflowEditorSchemaSync.test.ts)。
184
- // editor 因 D2 红线禁止 import 后端、手抄了同一份;后端在此演进时该测试会红,提示同步 editor。
185
- export const CONTROL_FLOW_TYPES = new Set([
186
- 'assert',
187
- 'verify',
188
- 'set',
189
- 'branch',
190
- 'loop',
191
- 'break',
192
- 'continue',
193
- 'echo',
194
- 'pause',
195
- ]);
196
- /**
197
- * `uses:` 的合法取值。与 `types.ts::HostCapability` 同源 —— 加新能力要两处一起改,
198
- * 单测钉住二者一致(漏改的表现是 yaml 写了却静默不生效)。
199
- */
200
- export const VALID_HOST_CAPABILITIES = new Set(['browser', 'computer']);
201
- export const VALID_STEP_TYPES = new Set([
202
- 'assert',
203
- 'verify',
204
- 'set',
205
- 'branch',
206
- 'loop',
207
- 'break',
208
- 'continue',
209
- 'echo',
210
- 'pause',
211
- ]);
212
- // 动作字段里「自带 kind 含义」的那几个(不含 type —— type 的 kind 由其值决定)。
213
- // 单一来源:validateSteps 的 actionFields + test/workflowEditorSchemaSync.test.ts 都从这里取,
214
- // 新增动作 kind 只改这一处(并同步 editor 手抄镜像 + 该测试快照)。
215
- export const ACTION_KINDS = ['tool', 'skill', 'agent', 'llm'];
216
- // onError 合法值(单一来源:onError 校验 + editor schema 同步测试)。
217
- export const ON_ERROR_VALUES = ['halt', 'continue', 'recover'];
218
- function isValidMaxIterations(value) {
219
- return ((typeof value === 'number' && Number.isInteger(value) && value > 0) ||
220
- (typeof value === 'string' && (value.includes('${') || /^\d+$/.test(value.trim()))));
221
- }
222
- function isValidImageDetail(value) {
223
- return value === 'low' || value === 'default' || value === 'high';
224
- }
225
- function assertLlmOrAgentMultimodalField(s, key, p, file) {
226
- if (s.llm === undefined && s.agent === undefined) {
227
- throw new WorkflowLoadError(`${p}.${key} 仅支持 llm / agent 节点`, file);
228
- }
229
- }
230
- function assertHistoryModeField(s, p, file) {
231
- if (s.llm === undefined && s.agent === undefined && s.skill === undefined) {
232
- throw new WorkflowLoadError(`${p}.history_mode 只能用在 llm / agent / skill 节点上`, file);
233
- }
234
- }
235
- function requireNonEmptyString(s, key, p, file, typeName) {
236
- if (typeof s[key] !== 'string' || String(s[key]).length === 0) {
237
- throw new WorkflowLoadError(`${p} type=${typeName} requires non-empty '${key}'`, file);
238
- }
239
- }
240
- function validateSteps(steps, file, pathPrefix) {
241
- const seenIds = new Set();
242
- for (const [i, item] of steps.entries()) {
243
- const p = pathPrefix ? `${pathPrefix}.steps[${i}]` : `steps[${i}]`;
244
- if (!item || typeof item !== 'object') {
245
- throw new WorkflowLoadError(`${p} 必须是对象`, file);
246
- }
247
- const s = item;
248
- if (typeof s.id !== 'string' || s.id.length === 0) {
249
- throw new WorkflowLoadError(`${p}.id 必填`, file);
250
- }
251
- // id 唯一仅在同级 steps 数组内强制
252
- if (seenIds.has(s.id)) {
253
- throw new WorkflowLoadError(`${p}.id "${s.id}" 在当前 steps 列表中重复`, file);
254
- }
255
- seenIds.add(s.id);
256
- // type 枚举校验(提前于动作互斥,给更准确的错误信息)
257
- if (s.type !== undefined && (typeof s.type !== 'string' || !VALID_STEP_TYPES.has(s.type))) {
258
- throw new WorkflowLoadError(`${p}.type "${String(s.type)}" 非法;合法值: ${[...VALID_STEP_TYPES].join(' / ')}`, file);
259
- }
260
- // 动作字段恰好一个(ACTION_KINDS 单一来源 + 控制流 type)
261
- const actionFields = [...ACTION_KINDS, 'type'];
262
- const present = actionFields.filter((k) => s[k] !== undefined);
263
- if (present.length === 0) {
264
- throw new WorkflowLoadError(`${p} 必须有以下字段之一: ${actionFields.join(' / ')}`, file);
265
- }
266
- if (present.length > 1) {
267
- throw new WorkflowLoadError(`${p} 同时设置了 ${present.join(', ')};只允许其中一个`, file);
268
- }
269
- // onError 枚举校验:runner 只认 halt/continue/recover,typo 会被静默当 halt,
270
- // 故在加载期拦掉,给作者明确错误。
271
- if (s.onError !== undefined &&
272
- !ON_ERROR_VALUES.includes(s.onError)) {
273
- throw new WorkflowLoadError(`${p}.onError "${String(s.onError)}" 非法;合法值: ${ON_ERROR_VALUES.join(' / ')}`, file);
274
- }
275
- // recover_hint 必须是字符串(仅 onError:'recover' 时有意义,但不强制配对)
276
- if (s.recover_hint !== undefined && typeof s.recover_hint !== 'string') {
277
- throw new WorkflowLoadError(`${p}.recover_hint 必须是 string`, file);
278
- }
279
- // uses:宿主能力声明。写错的代价是「这一步安静地拿不到能力」,而工具的报错
280
- // (「当前宿主未启用 Computer Use」)完全指不向拼错的 yaml —— 所以在加载期拦掉。
281
- if (s.uses !== undefined) {
282
- if (!Array.isArray(s.uses)) {
283
- throw new WorkflowLoadError(`${p}.uses 必须是数组,如 uses: [computer]`, file);
284
- }
285
- for (const capability of s.uses) {
286
- if (!VALID_HOST_CAPABILITIES.has(capability)) {
287
- throw new WorkflowLoadError(`${p}.uses 含非法能力 "${String(capability)}";合法值: ${[...VALID_HOST_CAPABILITIES].join(' / ')}`, file);
288
- }
289
- }
290
- // uses 只对确定性 tool 步有意义:llm/agent/skill 走 runQuery,工具上下文由
291
- // 主循环提供;控制流步根本不调工具。声明在这些步上是作者的误解,早点说破。
292
- if (s.tool === undefined) {
293
- throw new WorkflowLoadError(`${p}.uses 只能用在 tool 步上(当前步不是 tool 步)。`
294
- + `agent/llm/skill 步的工具上下文由主循环提供,无需也不能在此声明。`, file);
295
- }
296
- }
297
- if (s.free_text !== undefined) {
298
- if (s.type !== 'pause') {
299
- throw new WorkflowLoadError(`${p}.free_text 只能用在 type=pause 节点上`, file);
300
- }
301
- if (s.free_text !== 'halt' && s.free_text !== 'approve') {
302
- throw new WorkflowLoadError(`${p}.free_text "${String(s.free_text)}" 非法;合法值: halt / approve`, file);
303
- }
304
- }
305
- // 数字字段类型校验:yaml 给字符串会静默进入运行时算术(NaN footgun),加载期拦掉
306
- if (s.maxTurns !== undefined &&
307
- (typeof s.maxTurns !== 'number' || !Number.isInteger(s.maxTurns) || s.maxTurns < 1)) {
308
- throw new WorkflowLoadError(`${p}.maxTurns 必须是 >= 1 的整数`, file);
309
- }
310
- if (s.max_retries !== undefined &&
311
- (typeof s.max_retries !== 'number' || !Number.isInteger(s.max_retries) || s.max_retries < 0)) {
312
- throw new WorkflowLoadError(`${p}.max_retries 必须是 >= 0 的整数`, file);
313
- }
314
- // 多模态图片输入:仅 llm / agent 节点支持;skill/控制流/确定性 tool 节点
315
- // 不接收图片字段,避免 yaml 作者以为图片已传给模型但实际被静默忽略。
316
- const multimodalFields = [
317
- 'images',
318
- 'parse_inline_images',
319
- 'image_detail',
320
- 'image_max_long_side_pixel',
321
- ];
322
- for (const key of multimodalFields) {
323
- if (s[key] !== undefined)
324
- assertLlmOrAgentMultimodalField(s, key, p, file);
325
- }
326
- if (s.images !== undefined) {
327
- if (!Array.isArray(s.images)) {
328
- throw new WorkflowLoadError(`${p}.images 必须是数组`, file);
329
- }
330
- for (const [j, item] of s.images.entries()) {
331
- if (typeof item === 'string') {
332
- if (item.length === 0) {
333
- throw new WorkflowLoadError(`${p}.images[${j}] 必须是非空 string`, file);
334
- }
335
- continue;
336
- }
337
- if (!item || typeof item !== 'object' || Array.isArray(item)) {
338
- throw new WorkflowLoadError(`${p}.images[${j}] 必须是 string 或 { source, detail?, max_long_side_pixel? }`, file);
339
- }
340
- const r = item;
341
- if (typeof r.source !== 'string' || r.source.length === 0) {
342
- throw new WorkflowLoadError(`${p}.images[${j}].source 必须是非空 string`, file);
343
- }
344
- if (r.detail !== undefined && !isValidImageDetail(r.detail)) {
345
- throw new WorkflowLoadError(`${p}.images[${j}].detail 必须是 low/default/high`, file);
346
- }
347
- if (r.max_long_side_pixel !== undefined &&
348
- (typeof r.max_long_side_pixel !== 'number' ||
349
- !Number.isInteger(r.max_long_side_pixel) ||
350
- r.max_long_side_pixel < 1)) {
351
- throw new WorkflowLoadError(`${p}.images[${j}].max_long_side_pixel 必须是正整数`, file);
352
- }
353
- }
354
- }
355
- if (s.parse_inline_images !== undefined &&
356
- typeof s.parse_inline_images !== 'boolean') {
357
- throw new WorkflowLoadError(`${p}.parse_inline_images 必须是 boolean`, file);
358
- }
359
- if (s.image_detail !== undefined && !isValidImageDetail(s.image_detail)) {
360
- throw new WorkflowLoadError(`${p}.image_detail 必须是 low/default/high`, file);
361
- }
362
- if (s.image_max_long_side_pixel !== undefined &&
363
- (typeof s.image_max_long_side_pixel !== 'number' ||
364
- !Number.isInteger(s.image_max_long_side_pixel) ||
365
- s.image_max_long_side_pixel < 1)) {
366
- throw new WorkflowLoadError(`${p}.image_max_long_side_pixel 必须是正整数`, file);
367
- }
368
- if (s.history_mode !== undefined) {
369
- assertHistoryModeField(s, p, file);
370
- if (s.history_mode !== 'shared' && s.history_mode !== 'isolated') {
371
- throw new WorkflowLoadError(`${p}.history_mode "${String(s.history_mode)}" 非法;合法值: shared / isolated`, file);
372
- }
373
- }
374
- // 控制流字段一致性
375
- if (s.type === 'branch' && s.condition === undefined) {
376
- throw new WorkflowLoadError(`${p} type=branch 必须带 'condition'`, file);
377
- }
378
- if (s.type === 'loop') {
379
- const hasOver = s.over !== undefined;
380
- const hasMaxIter = s.max_iterations !== undefined;
381
- // 两种模式互斥:for-each(over 必填)或 while(max_iterations 必填)
382
- if (!hasOver && !hasMaxIter) {
383
- throw new WorkflowLoadError(`${p} type=loop: for-each 模式需 'over',while 模式需 'max_iterations',二者必选其一`, file);
384
- }
385
- if (hasOver) {
386
- // for-each 模式
387
- if (typeof s.as !== 'string' || s.as.length === 0) {
388
- throw new WorkflowLoadError(`${p} type=loop for-each 模式必须带 'as'`, file);
389
- }
390
- }
391
- else {
392
- // while 模式:as 可选(不设则不注入迭代变量)
393
- if (s.as !== undefined && (typeof s.as !== 'string' || s.as.length === 0)) {
394
- throw new WorkflowLoadError(`${p} type=loop while 模式的 'as' 必须是非空字符串`, file);
395
- }
396
- // max_iterations:正整数 或 含 ${} 的模板字符串(运行时插值 + coerce,
397
- // 失败响亮报错)。裸字符串数字("50")也容忍。其它一律加载期拦掉——
398
- // 曾有 "${max_iterations}" 不被插值直接参与 < 比较 → NaN → 静默 0 次迭代。
399
- const mi = s.max_iterations;
400
- if (!isValidMaxIterations(mi)) {
401
- throw new WorkflowLoadError(`${p}.max_iterations 必须是正整数或含 \${} 的模板字符串,得到: ${JSON.stringify(mi)}`, file);
402
- }
403
- }
404
- if (!Array.isArray(s.do)) {
405
- throw new WorkflowLoadError(`${p} type=loop 必须带 'do' 数组`, file);
406
- }
407
- validateSteps(s.do, file, `${p}.do`);
408
- }
409
- if (s.type === 'break') {
410
- // break 是循环退出信号,通常配合 when 条件使用
411
- // 无额外必填字段;when 缺失时等价于无条件跳出(极少用)
412
- }
413
- // continue:跳到(目标)循环的下一轮迭代;与 break 同族(when 可选)
414
- // echo:确定性输出 message(支持 ${} 插值),不烧 LLM
415
- if (s.type === 'echo') {
416
- requireNonEmptyString(s, 'message', p, file, 'echo');
417
- }
418
- else if (s.message !== undefined) {
419
- throw new WorkflowLoadError(`${p}.message 只能用在 type=echo 节点上`, file);
420
- }
421
- // target:仅 break/continue 的标签语义(指定要穿透到哪一层循环)
422
- if (s.target !== undefined) {
423
- if (s.type !== 'break' && s.type !== 'continue') {
424
- throw new WorkflowLoadError(`${p}.target 只能用在 type=break / type=continue 节点上`, file);
425
- }
426
- if (typeof s.target !== 'string' || s.target.length === 0) {
427
- throw new WorkflowLoadError(`${p}.target 必须是非空 string(目标循环的 id)`, file);
428
- }
429
- }
430
- // title:任意步可选的人话进度显示名(声明后状态行显示它、不显示块内相对序号)
431
- if (s.title !== undefined && (typeof s.title !== 'string' || s.title.length === 0)) {
432
- throw new WorkflowLoadError(`${p}.title 必须是非空 string(进度显示名)`, file);
433
- }
434
- // goal_supplement:动作步与 pause 可声明(产出作为用户补充要求贯穿后续步骤)
435
- if (s.goal_supplement !== undefined) {
436
- if (typeof s.goal_supplement !== 'boolean') {
437
- throw new WorkflowLoadError(`${p}.goal_supplement 必须是 boolean`, file);
438
- }
439
- const isActionStep = ACTION_KINDS.some((k) => s[k] !== undefined);
440
- if (!isActionStep && s.type !== 'pause') {
441
- throw new WorkflowLoadError(`${p}.goal_supplement 只能用在动作步(${ACTION_KINDS.join('/')})或 type=pause 节点上`, file);
442
- }
443
- }
444
- // done_when:仅 agent 步可选(确定性完成条件,引擎 nudge 兜底 announce-not-do 烂尾)
445
- if (s.done_when !== undefined) {
446
- if (typeof s.done_when !== 'string' || s.done_when.trim().length === 0) {
447
- throw new WorkflowLoadError(`${p}.done_when 必须是非空 string(白名单表达式)`, file);
448
- }
449
- if (s.agent === undefined) {
450
- throw new WorkflowLoadError(`${p}.done_when 仅支持 agent 节点`, file);
451
- }
452
- }
453
- if (s.type === 'assert' && s.condition === undefined) {
454
- throw new WorkflowLoadError(`${p} type=assert 必须带 'condition'`, file);
455
- }
456
- // set:确定性变量赋值(曾有 yaml 用 llm:"PLAN" 当赋值——模型自由回复非确定,set 是根治)
457
- if (s.type === 'set') {
458
- if (!s.set ||
459
- typeof s.set !== 'object' ||
460
- Array.isArray(s.set) ||
461
- Object.keys(s.set).length === 0) {
462
- throw new WorkflowLoadError(`${p} type=set 必须带非空对象 'set'({ 变量名: 值 },值支持 \${} 插值)`, file);
463
- }
464
- }
465
- if (s.type === 'verify') {
466
- // 兼容两种格式:YAML 数组 或逗号分隔字符串
467
- const rawChecks = Array.isArray(s.checks)
468
- ? s.checks
469
- : typeof s.checks === 'string'
470
- ? s.checks.split(',').map((x) => x.trim()).filter(Boolean)
471
- : [];
472
- if (rawChecks.length === 0) {
473
- throw new WorkflowLoadError(`${p} type=verify 必须带 checks(数组或逗号分隔字符串)`, file);
474
- }
475
- for (const [ci, c] of rawChecks.entries()) {
476
- if (typeof c !== 'string') {
477
- throw new WorkflowLoadError(`${p}.checks[${ci}] 必须是字符串`, file);
478
- }
479
- // 含 ${...} 模板的 check(如 checks: "${verify_checks}")在运行时插值后才知道真实值,
480
- // 加载期跳过格式校验,交给 verify.ts 在插值后解析。否则这类合法的动态配置会被
481
- // 误判为"损坏 yaml"而整个工作流加载失败(ralph-loop 的 run_verify 即如此)。
482
- if (c.includes('${'))
483
- continue;
484
- if (!c.includes(':')) {
485
- throw new WorkflowLoadError(`${p}.checks[${ci}] 格式错误,应为 "type:value"(如 "file_exists:./x")`, file);
486
- }
487
- }
488
- }
489
- if (s.type === 'branch') {
490
- if (s.then !== undefined && !Array.isArray(s.then)) {
491
- throw new WorkflowLoadError(`${p}.then 必须是数组`, file);
492
- }
493
- if (s.else !== undefined && !Array.isArray(s.else)) {
494
- throw new WorkflowLoadError(`${p}.else 必须是数组`, file);
495
- }
496
- if (Array.isArray(s.then))
497
- validateSteps(s.then, file, `${p}.then`);
498
- if (Array.isArray(s.else))
499
- validateSteps(s.else, file, `${p}.else`);
500
- }
501
- // ---------------- ADR-05 新增校验 ----------------
502
- // output_schema:必须是 object;不能用在控制流节点上
503
- if (s.output_schema !== undefined) {
504
- if (typeof s.output_schema !== 'object' ||
505
- s.output_schema === null ||
506
- Array.isArray(s.output_schema)) {
507
- throw new WorkflowLoadError(`${p}.output_schema 必须是对象`, file);
508
- }
509
- if (typeof s.type === 'string' && CONTROL_FLOW_TYPES.has(s.type)) {
510
- throw new WorkflowLoadError(`${p}.output_schema 不能用在 type=${s.type} 控制流节点上`, file);
511
- }
512
- // P3:output_schema 在 skill 节点上是静默 no-op(execSkillStep 无视它)。
513
- // 与其悄悄丢弃,不如 loader 直接拒绝——仅 llm 节点支持 structured output。
514
- if (s.skill !== undefined) {
515
- throw new WorkflowLoadError(`${p}.output_schema 暂不支持 skill 节点(仅 llm 节点生效)`, file);
516
- }
517
- }
518
- // context_files:[{ path, hint? }];不能用在控制流节点上
519
- if (s.context_files !== undefined) {
520
- if (!Array.isArray(s.context_files)) {
521
- throw new WorkflowLoadError(`${p}.context_files 必须是数组`, file);
522
- }
523
- for (const [j, cf] of s.context_files.entries()) {
524
- if (!cf || typeof cf !== 'object' || Array.isArray(cf)) {
525
- throw new WorkflowLoadError(`${p}.context_files[${j}] 必须是 { path: string, hint?: string } 对象`, file);
526
- }
527
- const r = cf;
528
- if (typeof r.path !== 'string' || r.path.length === 0) {
529
- throw new WorkflowLoadError(`${p}.context_files[${j}].path 必填(非空 string)`, file);
530
- }
531
- if (r.hint !== undefined && typeof r.hint !== 'string') {
532
- throw new WorkflowLoadError(`${p}.context_files[${j}].hint 必须是 string`, file);
533
- }
534
- }
535
- if (typeof s.type === 'string' && CONTROL_FLOW_TYPES.has(s.type)) {
536
- throw new WorkflowLoadError(`${p}.context_files 不能用在 type=${s.type} 控制流节点上`, file);
537
- }
538
- // P3:context_files 同样是 skill 节点的静默 no-op(execSkillStep 无视它),
539
- // 仅 llm 节点经 runQuery 生效——loader 直接拒绝,避免悄悄丢弃。
540
- if (s.skill !== undefined) {
541
- throw new WorkflowLoadError(`${p}.context_files 暂不支持 skill 节点(仅 llm 节点生效)`, file);
542
- }
543
- }
544
- // allowed_tools:string[];不能用在控制流节点上
545
- if (s.allowed_tools !== undefined) {
546
- if (!Array.isArray(s.allowed_tools) ||
547
- !s.allowed_tools.every((x) => typeof x === 'string' && x.length > 0)) {
548
- throw new WorkflowLoadError(`${p}.allowed_tools 必须是非空 string 数组`, file);
549
- }
550
- if (typeof s.type === 'string' && CONTROL_FLOW_TYPES.has(s.type)) {
551
- throw new WorkflowLoadError(`${p}.allowed_tools 不能用在 type=${s.type} 控制流节点上`, file);
552
- }
553
- // P3:allowed_tools 与 context_files 配对,skill 节点上同样无效——一并拒绝。
554
- if (s.skill !== undefined) {
555
- throw new WorkflowLoadError(`${p}.allowed_tools 暂不支持 skill 节点(仅 llm 节点生效)`, file);
556
- }
557
- }
558
- // ---------------- Phase 1: 断点续执行 / 自愈字段校验 ----------------
559
- // step.artifacts: string[](可选)
560
- if (s.artifacts !== undefined) {
561
- if (!Array.isArray(s.artifacts) || !s.artifacts.every((x) => typeof x === 'string' && x.length > 0)) {
562
- throw new WorkflowLoadError(`${p}.artifacts 必须是非空字符串数组`, file);
563
- }
564
- }
565
- // step.max_retries: number(可选,>= 0 的整数)
566
- if (s.max_retries !== undefined) {
567
- const mr = s.max_retries;
568
- if (typeof mr !== 'number' || !Number.isInteger(mr) || mr < 0) {
569
- throw new WorkflowLoadError(`${p}.max_retries 必须是 >= 0 的整数`, file);
570
- }
571
- }
572
- }
573
- }