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,203 +1,266 @@
1
- import { createHash } from 'node:crypto';
2
- import { existsSync, readFileSync } from 'node:fs';
3
- import { join } from 'node:path';
1
+ /**
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/taskIdentity.ts —— 任务身份与状态目录布局
4
+ * ------------------------------------------------------------
5
+ * 状态根目录优先级:
6
+ * 1. 环境变量 MINIMAL_AGENT_WORKFLOW_STATE_DIR(全局统一目录)
7
+ * 2. <cwd>/.minimal-agent-workflow/(默认)
8
+ *
9
+ * 目录结构(四级):
10
+ * <stateRoot>/<workflow>/<sessionId>/<taskId>/ ← 活动任务实例
11
+ * <stateRoot>/<workflow>/<sessionId>/<taskId>.done/ ← 成功归档
12
+ * <stateRoot>/<workflow>/<sessionId>/<taskId>.trash/ ← 产物淘汰回收
13
+ *
14
+ * ------------------------------------------------------------
15
+ * ⚠️ **为什么是 session 与 taskId 两层,而不是二选一**(这条改之前务必读完)
16
+ *
17
+ * legacy 的演进history是这样的:
18
+ * - Phase 2:加 taskId 实例层,根治「同名工作流跑新任务把旧状态清掉」
19
+ * - Phase 3:实例目录名**改成** sessionId,taskId 降级为记录字段,换来多
20
+ * session 真正并行
21
+ *
22
+ * Phase 3 用「换掉」而不是「叠加」,于是 Phase 2 解决的问题原样回来了:同一个
23
+ * session 里连着研究两个不同主题,第二次启动时前一次的声明产物会被归档进
24
+ * `.trash/`,工作目录里只剩最新一份。
25
+ *
26
+ * legacy 对此的补偿是「宿主没给显式 session 就自动生成一个带时间戳的」,但那让
27
+ * resume 彻底失效 —— 时间每次都不同,于是**每次运行都是一个新 session**,
28
+ * 断点续跑、completed 判定、语义仲裁全部够不着。实测复现过:同一个 goal 连跑
29
+ * 两次,产生两个独立的 `.done` 目录,第二次没有命中 completed 而是从头重跑。
30
+ *
31
+ * 两个维度本来就是正交的,不该二选一:
32
+ * - sessionId 管**并行隔离**(不同会话互不干扰)
33
+ * - taskId 管**任务身份**(同一件事 → 同一个目录 → 能 resume)
34
+ * 两层都留下,三个需求同时成立:
35
+ * 同 session 同 goal → 同目录 → resume ✓
36
+ * 同 session 换主题 → 不同目录 → **不覆盖** ✓
37
+ * 不同 session → 不同目录 → 并行 ✓
38
+ *
39
+ * 相应地本文件**不提供** `generateDefaultSessionId`:宿主给什么 session 就用
40
+ * 什么(含 `default`)。它当初存在的理由已由 taskId 层从结构上消除。
41
+ * ============================================================
42
+ */
43
+
44
+ import { createHash, randomUUID } from 'node:crypto';
45
+ import { isAbsolute, join, resolve } from 'node:path';
4
46
 
5
47
  import {
6
48
  chat as sdkChat,
7
49
  executeTool as sdkExecuteTool,
8
50
  } from '../../../src/plugin-sdk.js';
9
51
  import type { Provider } from '../../../src/plugin-sdk.js';
10
- import { truncate } from './agentCommon.js';
11
52
  import { extractJsonPayload } from './jsonPayload.js';
12
- import type { RunContext } from './types.js';
53
+ import type { InputDef, RunContext } from './types.js';
54
+ import { truncate } from './util.js';
13
55
 
14
- // ============================================================
15
- // 工作流状态目录布局(E6 修复:按 workflow 名隔离)
16
- // ------------------------------------------------------------
17
- // <cwd>/.minimal-agent-workflow/<name>/ ← 每个工作流独立状态
18
- // <cwd>/.minimal-agent-workflow/<name>.done/ ← 成功归档
19
- // 曾经一个 cwd 单例目录:A(如 /plan)未完成时跑不同名工作流 B,
20
- // init 的 new-task 路径会清掉 A 的声明产物 + 整个状态目录,A 永久失去
21
- // resume 能力——与「不同任务中间文件互不干扰」需求直接冲突。
22
- // 按名隔离后跨工作流互不可见,互踩从结构上消失。
23
- // /new 的前缀清理(.minimal-agent*)作用于父目录,行为不变。
24
- // ============================================================
25
-
26
- /** 工作流状态目录的父目录名(/new 按 .minimal-agent 前缀整体清理)。 */
56
+ /** 工作流状态目录的父目录名(落在 cwd 下时使用)。 */
27
57
  export const WF_STATE_PARENT = '.minimal-agent-workflow';
28
58
 
29
- /** 把 workflow 名清洗成安全的目录名(保留字母数字._-,其余替换为 -)。 */
59
+ /** 全局统一状态目录的环境变量名。 */
60
+ export const WF_STATE_DIR_ENV = 'MINIMAL_AGENT_WORKFLOW_STATE_DIR';
61
+
62
+ /** 宿主未指定 session 时的缺省名。**不再**据此自动生成带时间戳的 session。 */
63
+ export const DEFAULT_SESSION_ID = 'default';
64
+
65
+ /**
66
+ * 解析状态根目录(绝对路径)。
67
+ * 环境变量允许写相对路径(用户可能写 `.wflow` 这类值),基于 process.cwd() 展开。
68
+ */
69
+ export function resolveStateRoot(workingDir: string): string {
70
+ const envDir = process.env[WF_STATE_DIR_ENV];
71
+ if (envDir?.trim()) {
72
+ const p = envDir.trim();
73
+ return isAbsolute(p) ? p : resolve(p);
74
+ }
75
+ return join(workingDir, WF_STATE_PARENT);
76
+ }
77
+
78
+ /** 清洗成安全目录名(保留字母数字 . _ -,其余换成 -)。 */
30
79
  export function sanitizeWorkflowDirName(name: string): string {
31
80
  return name.replace(/[^\w.-]/g, '-');
32
81
  }
33
82
 
34
- /** 某 workflow 的状态目录绝对路径。workflowState / taskIdentity 共用唯一权威实现。 */
35
- export function workflowStateDir(workingDir: string, workflowName: string): string {
36
- return join(workingDir, WF_STATE_PARENT, sanitizeWorkflowDirName(workflowName));
83
+ /** 某工作流的状态目录(其下按 session 再分)。 */
84
+ export function workflowStateDir(
85
+ workingDir: string,
86
+ workflowName: string,
87
+ ): string {
88
+ return join(
89
+ resolveStateRoot(workingDir),
90
+ sanitizeWorkflowDirName(workflowName),
91
+ );
92
+ }
93
+
94
+ /** 某工作流在某 session 下的目录(其下按 taskId 再分)。 */
95
+ export function sessionStateDir(
96
+ workingDir: string,
97
+ workflowName: string,
98
+ sessionId: string,
99
+ ): string {
100
+ return join(
101
+ workflowStateDir(workingDir, workflowName),
102
+ sanitizeWorkflowDirName(sessionId),
103
+ );
104
+ }
105
+
106
+ /**
107
+ * 一个具体任务实例的状态目录。
108
+ * 成功后改名 `<taskId>.done/`;产物淘汰归档到 `<taskId>.trash/`。
109
+ */
110
+ export function taskInstanceDir(
111
+ workingDir: string,
112
+ workflowName: string,
113
+ sessionId: string,
114
+ taskId: string,
115
+ ): string {
116
+ return join(
117
+ sessionStateDir(workingDir, workflowName, sessionId),
118
+ sanitizeWorkflowDirName(taskId),
119
+ );
37
120
  }
38
121
 
39
122
  /**
40
- * 任务身份判定结果
123
+ * 归一化 goal:小写 → 去标点(保留中日韩/字母/数字/空格)→ 压缩空格 → 截断 200。
124
+ *
125
+ * 截断是刻意的:超长输入里靠后的细微差异不该让「同一件事」算成两个任务。
41
126
  */
42
- export interface TaskIdentityResult {
43
- /** 归一化后的 hash(16 位 hex) */
44
- hash: string;
45
- /** 是否与磁盘上记录的 taskId 匹配 */
46
- isSameTask: boolean;
47
- /** 判定依据:'hash_match' | 'hash_diff' | 'different_workflow' | 'no_previous' */
48
- reason: string;
127
+ function normalizeGoal(raw: string): string {
128
+ return raw
129
+ .toLowerCase()
130
+ .replace(/[^\p{L}\p{N}\s]/gu, '')
131
+ .replace(/\s+/g, ' ')
132
+ .trim()
133
+ .slice(0, 200);
49
134
  }
50
135
 
51
136
  /**
52
- * 计算任务身份 hash。
137
+ * 任务身份 = SHA256(工作流名 + 归一化 goal) 前 16 位。
53
138
  *
54
- * 策略(内容 hash 是【唯一权威信号】):
55
- * - 对「workflow 名 + 归一化 goal」做 SHA256 → 取前 16 位 = taskId。
56
- * - 同 hash → 同一任务(无论隔了多久);hash 不同 → 不同任务。
57
- * - recency(上次 startedAt 的时间窗口)【不】参与身份判定:30 分钟内换一个
58
- * 完全不同的 goal 重跑同名 workflow,必须判「全新任务」清理重开,而不是
59
- * 错误地 resume 旧任务把旧变量混进新目标(需求 3.2「不相关新任务自动清理重开」)。
60
- * 旧版「时间窗口覆盖 hash 差异」是 bug,已移除。
139
+ * **纯函数,不读盘** —— 这是四级布局带来的简化:taskId 就是目录名,「是不是同一个
140
+ * 任务」等价于「那个目录在不在」,不必再扫描实例目录逐个比对记录字段。
61
141
  *
62
- * 归一化规则:
63
- * - 转小写
64
- * - 去除所有标点符号(保留中文、英文、数字、空格)
65
- * - 去除多余空格(连续空格→单空格,首尾 trim)
66
- * - 截断到 200 字符(防止超长输入导致不必要的差异)
142
+ * ⚠️ 时间**不参与**身份判定。半小时内换一个完全不同的 goal 重跑同名工作流,
143
+ * 必须判成全新任务,而不是 resume 旧任务把旧变量混进新目标里。legacy 早期
144
+ * 「时间窗口覆盖 hash 差异」的写法是 bug,已移除,别加回来。
67
145
  */
68
146
  export function computeTaskId(
69
147
  workflowName: string,
70
148
  inputs: Record<string, unknown>,
71
- workingDir?: string,
72
- ): TaskIdentityResult {
73
- // 1. 提取 goal 文本(与 buildGoalAnchor 同策略)
74
- const rawGoal = extractGoal(inputs);
75
-
76
- // 2. 归一化 goal
77
- const normalizedGoal = normalizeGoal(rawGoal);
78
-
79
- // 3. 计算 contentHash = SHA256(`${workflowName}::${normalizedGoal}`)[:16]
80
- const contentHash = createHash('sha256')
81
- .update(`${workflowName}::${normalizedGoal}`)
82
- .digest('hex')
83
- .slice(0, 16);
84
-
85
- // 4. 如果没有提供 workingDir,只返回 hash,不做比较
86
- if (!workingDir) {
87
- return {
88
- hash: contentHash,
89
- isSameTask: false,
90
- reason: 'no_previous',
91
- };
92
- }
93
-
94
- // 5. 尝试读取旧状态文件(按 workflow 名隔离的状态目录)
95
- const stateFilePath = join(workflowStateDir(workingDir, workflowName), 'current.json');
96
-
97
- if (!existsSync(stateFilePath)) {
98
- return {
99
- hash: contentHash,
100
- isSameTask: false,
101
- reason: 'no_previous',
102
- };
103
- }
104
-
105
- try {
106
- const stateContent = readFileSync(stateFilePath, 'utf-8');
107
- const prevState = JSON.parse(stateContent) as {
108
- taskId?: string;
109
- name?: string;
110
- startedAt?: string;
111
- };
112
-
113
- // a. 不同 workflow 名 → 不同任务
114
- if (prevState.name && prevState.name !== workflowName) {
115
- return {
116
- hash: contentHash,
117
- isSameTask: false,
118
- reason: 'different_workflow',
119
- };
120
- }
121
-
122
- // b. 内容 hash 一致 → 同一任务(唯一权威信号,与时间无关)
123
- if (prevState.taskId === contentHash) {
124
- return {
125
- hash: contentHash,
126
- isSameTask: true,
127
- reason: 'hash_match',
128
- };
129
- }
130
-
131
- // c. hash 不一致 → 不同任务(goal 变了)。recency 不覆盖此判定(见函数头注)。
132
- return {
133
- hash: contentHash,
134
- isSameTask: false,
135
- reason: 'hash_diff',
136
- };
137
- } catch {
138
- // 解析失败时返回默认结果
139
- return {
140
- hash: contentHash,
141
- isSameTask: false,
142
- reason: 'no_previous',
143
- };
144
- }
149
+ defs?: InputDef[],
150
+ ): string {
151
+ const goal = normalizeGoal(extractGoal(inputs, defs));
152
+ const resourceFingerprint =
153
+ typeof inputs.__resource_fingerprint === 'string'
154
+ ? inputs.__resource_fingerprint.trim()
155
+ : '';
156
+ // Typed resource workflows also have processing parameters (format, range,
157
+ // language, etc.). Equal source bytes with different parameters must not hit
158
+ // completed before the script can observe the new arguments. Keep the legacy
159
+ // goal-only identity for workflows without resource bindings.
160
+ const parameters = resourceFingerprint
161
+ ? (defs ?? [])
162
+ .filter(
163
+ (d) =>
164
+ d.type !== 'resource' && !['goal', 'requestText'].includes(d.name),
165
+ )
166
+ .map((d) => [d.name, inputs[d.name] ?? d.default ?? null] as const)
167
+ .sort(([a], [b]) => a.localeCompare(b))
168
+ : [];
169
+ // 资源是任务身份的一部分,而不是目标锚的一部分。这样模型仍只看到人类可读
170
+ // 目标,但同一句“帮我整理成 Word”配不同附件不会误命中上一份已完成产物。
171
+ const identity = resourceFingerprint
172
+ ? `${workflowName} ${goal}\nresource:${resourceFingerprint}${parameters.length ? '\nparameters:' + JSON.stringify(parameters) : ''}`
173
+ : `${workflowName} ${goal}`;
174
+ return createHash('sha256').update(identity).digest('hex').slice(0, 16);
145
175
  }
146
176
 
147
177
  /**
148
- * 从 inputs 中提取 goal 文本
178
+ * 从 inputs 里提取「目标」文本。**任务身份与目标锚共用这一份规则** ——
179
+ * 两处各写一套会让「拿来算 taskId 的目标」和「注入给模型的目标」指向不同的东西。
149
180
  *
150
- * 策略:
151
- * - 优先 inputs.goal
152
- * - 其次第一个 length > 2 的 string 值
153
- * - 最后 JSON.stringify 整个 inputs
181
+ * 取值顺序:
182
+ * ① 名为 `goal` 的输入
183
+ * ② 第一个 **required** 的字符串输入(作者用 required 表达了「这是主要输入」)
184
+ * ③ 第一个非空字符串输入
185
+ * ④ 整体 JSON(保证恒有确定值)
186
+ *
187
+ * ⚠️ 第 ③ 条曾经写的是「长度 **> 2** 的字符串」。那条阈值是照拉丁文本想的
188
+ * (跳过 `ab`、语言代码之类),**对中文直接失效** —— `世界`、`调研` 这种两个字的
189
+ * 目标太常见了,会被跳过去落到 ④,于是 current.json 里记的目标变成一坨 JSON、
190
+ * 仲裁时喂给 LLM 的也是那坨 JSON。端到端实跑复现过(/workflow e2e-smoke 世界)。
154
191
  */
155
- export function extractGoal(inputs: Record<string, unknown>): string {
156
- // 优先级1:直接使用 inputs.goal
157
- if (typeof inputs.goal === 'string') {
192
+ export function extractGoal(
193
+ inputs: Record<string, unknown>,
194
+ defs?: InputDef[],
195
+ ): string {
196
+ if (typeof inputs.goal === 'string' && inputs.goal.trim()) {
158
197
  return inputs.goal;
159
198
  }
160
-
161
- // 优先级2:查找第一个长度 > 2 的字符串值
162
- for (const value of Object.values(inputs)) {
163
- if (typeof value === 'string' && value.length > 2) {
164
- return value;
165
- }
199
+ for (const def of defs ?? []) {
200
+ const v = inputs[def.name];
201
+ if (
202
+ def.type !== 'resource' &&
203
+ def.required &&
204
+ typeof v === 'string' &&
205
+ v.trim()
206
+ )
207
+ return v;
166
208
  }
167
-
168
- // 优先级3:JSON 序列化整个 inputs
169
- return JSON.stringify(inputs);
209
+ if (typeof inputs.requestText === 'string' && inputs.requestText.trim())
210
+ return inputs.requestText;
211
+ const resourceNames = new Set(
212
+ (defs ?? []).filter((d) => d.type === 'resource').map((d) => d.name),
213
+ );
214
+ for (const [name, value] of Object.entries(inputs)) {
215
+ if (resourceNames.has(name) || name === '__resource_fingerprint') continue;
216
+ if (typeof value === 'string' && value.trim()) return value;
217
+ }
218
+ if (
219
+ typeof inputs.__resource_fingerprint === 'string' &&
220
+ inputs.__resource_fingerprint.trim()
221
+ ) {
222
+ return `resource:${inputs.__resource_fingerprint}`;
223
+ }
224
+ const sanitized = { ...inputs };
225
+ for (const name of resourceNames)
226
+ if (name in sanitized) sanitized[name] = '<resource>';
227
+ return JSON.stringify(sanitized);
170
228
  }
171
229
 
172
230
  // ============================================================
173
- // 任务身份语义仲裁层(hash 不等 + 旧任务未完成时的二审)
231
+ // 任务身份语义仲裁(hash 不等 + 旧任务未完成时的二审)
174
232
  // ------------------------------------------------------------
175
- // hash 仍是「同任务」的权威信号(相等 → resume/completed,与时间无关)。
176
- // 但 hash 不等不再一票否决:用户输入「继续」这类延续指令,goal 文本必然
177
- // 与旧任务不同,按旧规则会被误判 new-task 把没做完的产物清掉重开。
178
- // 仲裁链(逐级降级,零 yaml 耦合,所有工作流自动获益):
179
- // a. 延续短语快路径(继续/接着/continue/resume…)→ resume,不花 LLM
233
+ // hash 相等仍是「同任务」的权威信号。但 hash 不等**不再一票否决**:用户输入
234
+ // 「继续」这类延续指令时,goal 文本必然与旧任务不同,按裸 hash 规则会被误判成
235
+ // 全新任务、把没做完的产物清掉重开。
236
+ //
237
+ // 仲裁链逐级降级(零脚本耦合,所有工作流自动获益):
238
+ // a. 延续短语快路径(继续/接着/continue…)→ resume,不花 LLM
180
239
  // b. LLM 单轮仲裁(旧 goal + 新输入 + 进度摘要 → JSON verdict)
181
- // c. verdict=unsure / LLM 不可用 → AskUserQuestion 问用户
240
+ // c. unsure / LLM 不可用 → AskUserQuestion 问用户
182
241
  // (TUI 弹界面;-p/gateway 由 askBridge 自动选推荐项,不挂起)
183
- // d. 提问也失败 → 兜底 new-task(= 旧红线行为,最小惊讶)
242
+ // d. 提问也失败 → 兜底 new-task(最小惊讶)
184
243
  // ============================================================
185
244
 
186
- /** 仲裁输入:引擎已有信息,不依赖任何具体 yaml。 */
245
+ /** 仲裁输入:全部来自引擎已有信息,不依赖任何具体工作流。 */
187
246
  export interface TaskArbitrationContext {
188
247
  workflowName: string;
189
- /** 旧任务的原始 goal(来自状态目录 inputs.json) */
248
+ /** 旧任务的原始 goal。 */
190
249
  prevGoal: string;
191
- /** 本次调用的新 goal 文本 */
250
+ /** 本次调用的新 goal 文本。 */
192
251
  newGoal: string;
193
- /** 旧任务已完成的步骤 id(按顺序) */
194
- completedStepIds: string[];
195
- totalSteps: number;
196
- /** 旧任务声明的产物路径 */
252
+ /**
253
+ * 旧任务已完成的**引擎中介调用数**。
254
+ *
255
+ * legacy 这里是 `completedStepIds[] / totalSteps` —— 代码形态没有「步骤」,
256
+ * 也无法预知总数(控制流由 JS 决定),所以只报已完成数量。
257
+ */
258
+ completedCalls: number;
259
+ /** 旧任务已产出的声明产物路径。 */
197
260
  artifacts: string[];
198
261
  }
199
262
 
200
- /** 仲裁器:'resume' = 新输入是旧任务的延续;'new' = 全新任务(清理重开)。 */
263
+ /** 'resume' = 新输入是旧任务的延续;'new' = 全新任务(归档旧产物重开)。 */
201
264
  export type TaskArbitrator = (
202
265
  actx: TaskArbitrationContext,
203
266
  ) => Promise<'resume' | 'new'>;
@@ -223,37 +286,33 @@ const CONTINUATION_PHRASES = new Set([
223
286
  'carry on',
224
287
  ]);
225
288
 
226
- /** 新输入是否是「延续上次任务」的指令(仲裁快路径,不花 LLM)。 */
289
+ /** 新输入是否是「延续上次任务」的指令(快路径,不花 LLM)。 */
227
290
  export function isContinuationPhrase(rawGoal: string): boolean {
228
291
  const norm = normalizeGoal(rawGoal);
229
292
  if (!norm) return false;
230
293
  if (CONTINUATION_PHRASES.has(norm)) return true;
231
- // 短输入且以延续词开头(如「继续干活」「continue please」)也算
232
- if (
294
+ // 短输入且以延续词开头(「继续干活」「continue please」)也算
295
+ return (
233
296
  norm.length <= 12 &&
234
297
  (norm.startsWith('继续') ||
235
298
  norm.startsWith('接着') ||
236
299
  norm.startsWith('continue') ||
237
300
  norm.startsWith('resume'))
238
- ) {
239
- return true;
240
- }
241
- return false;
301
+ );
242
302
  }
243
303
 
244
- /** 仲裁器依赖(chat/executeTool 走 DI 优先、plugin-sdk 真实现兜底,同 RunContext 约定)。 */
304
+ /** 仲裁器依赖:chat/executeTool 走 DI 优先、plugin-sdk 真实现兜底。 */
245
305
  export interface TaskArbitratorDeps {
246
306
  provider: Provider;
247
307
  chat?: RunContext['chat'];
248
308
  executeTool?: RunContext['executeTool'];
249
309
  signal?: AbortSignal;
250
- /** 仲裁过程的人话记录(runner 在 init 返回后统一 yield warning,因 init 非 generator) */
310
+ /** 仲裁过程的人话记录,由调用方统一报给用户(仲裁本身不是 generator)。 */
251
311
  notes?: string[];
252
312
  }
253
313
 
254
314
  /**
255
- * 构建复合仲裁器(短语快路径 → LLM 单轮仲裁 → AskUserQuestion → 兜底 new)。
256
- * runner 在 state.init 前构建并传入;任何一级抛错都降级到下一级,绝不让仲裁本身 halt 工作流。
315
+ * 构建复合仲裁器。任何一级抛错都降级到下一级 —— **仲裁本身绝不 halt 工作流**。
257
316
  */
258
317
  export function buildTaskArbitrator(deps: TaskArbitratorDeps): TaskArbitrator {
259
318
  const note = (m: string): void => {
@@ -261,7 +320,6 @@ export function buildTaskArbitrator(deps: TaskArbitratorDeps): TaskArbitrator {
261
320
  };
262
321
 
263
322
  return async (actx) => {
264
- // a. 延续短语快路径
265
323
  if (isContinuationPhrase(actx.newGoal)) {
266
324
  note(
267
325
  `任务仲裁:新输入「${truncate(actx.newGoal, 40)}」命中延续短语 → 继续旧任务(目标:${truncate(actx.prevGoal, 60)})`,
@@ -269,12 +327,11 @@ export function buildTaskArbitrator(deps: TaskArbitratorDeps): TaskArbitrator {
269
327
  return 'resume';
270
328
  }
271
329
 
272
- // b. LLM 单轮仲裁
273
330
  try {
274
331
  const verdict = await llmArbitrate(deps, actx);
275
332
  if (verdict !== 'unsure') {
276
333
  note(
277
- `任务仲裁:LLM 判定新输入${verdict === 'resume' ? '是旧任务的延续 → 续跑' : '是全新任务 → 清理旧产物重开'}`,
334
+ `任务仲裁:LLM 判定新输入${verdict === 'resume' ? '是旧任务的延续 → 续跑' : '是全新任务 → 归档旧产物重开'}`,
278
335
  );
279
336
  return verdict;
280
337
  }
@@ -282,7 +339,6 @@ export function buildTaskArbitrator(deps: TaskArbitratorDeps): TaskArbitrator {
282
339
  // LLM 不可用 → 降级到提问
283
340
  }
284
341
 
285
- // c. AskUserQuestion(TUI 弹界面;非交互宿主 askBridge 自动选推荐项=全新开始)
286
342
  try {
287
343
  const verdict = await askUserArbitrate(deps, actx);
288
344
  note(
@@ -293,25 +349,23 @@ export function buildTaskArbitrator(deps: TaskArbitratorDeps): TaskArbitrator {
293
349
  // 提问被取消/不可用 → 兜底
294
350
  }
295
351
 
296
- // d. 兜底 = 旧红线行为(hash 不等 → new-task),最小惊讶
297
352
  note('任务仲裁:无法判定(LLM 与提问均不可用)→ 按全新任务处理');
298
353
  return 'new';
299
354
  };
300
355
  }
301
356
 
302
- /** LLM 单轮仲裁:旧 goal + 新输入 + 进度摘要 → {verdict, reason}。解析失败按 unsure。 */
357
+ /** LLM 单轮仲裁 → {verdict, reason}。解析失败一律按 unsure,不猜。 */
303
358
  async function llmArbitrate(
304
359
  deps: TaskArbitratorDeps,
305
360
  actx: TaskArbitrationContext,
306
361
  ): Promise<'resume' | 'new' | 'unsure'> {
307
362
  const chatFn = deps.chat ?? sdkChat;
308
- const progress = `${actx.completedStepIds.length}/${actx.totalSteps}`;
309
363
  const prompt = [
310
364
  `你是工作流引擎的任务身份仲裁器。同名工作流「${actx.workflowName}」存在一个未完成的旧任务,`,
311
- `用户刚发起了一次新调用,新输入的文本与旧任务目标不同。请判断新输入是「旧任务的延续指令」还是「全新任务」。`,
365
+ '用户刚发起了一次新调用,新输入的文本与旧任务目标不同。请判断新输入是「旧任务的延续指令」还是「全新任务」。',
312
366
  '',
313
367
  `旧任务目标:${truncate(actx.prevGoal, 300)}`,
314
- `旧任务进度:已完成 ${progress} 步${actx.completedStepIds.length ? `(${actx.completedStepIds.join(', ')})` : ''}`,
368
+ `旧任务进度:已完成 ${actx.completedCalls} 次调用`,
315
369
  actx.artifacts.length ? `旧任务产物:${actx.artifacts.join(', ')}` : '',
316
370
  `新输入:${truncate(actx.newGoal, 300)}`,
317
371
  '',
@@ -326,7 +380,12 @@ async function llmArbitrate(
326
380
  for await (const ev of chatFn({
327
381
  provider: deps.provider,
328
382
  messages: [
329
- { role: 'user', content: prompt, timestamp: Date.now(), id: crypto.randomUUID() },
383
+ {
384
+ role: 'user',
385
+ content: prompt,
386
+ timestamp: Date.now(),
387
+ id: randomUUID(),
388
+ },
330
389
  ],
331
390
  tools: [],
332
391
  signal: deps.signal,
@@ -347,24 +406,23 @@ async function llmArbitrate(
347
406
  return 'unsure';
348
407
  }
349
408
 
350
- /** 经 AskUserQuestion 问用户(推荐项=全新开始,与兜底语义一致;非交互自动按推荐项)。 */
409
+ /** 问用户。推荐项 = 全新开始(与兜底语义一致);非交互宿主自动按推荐项。 */
351
410
  async function askUserArbitrate(
352
411
  deps: TaskArbitratorDeps,
353
412
  actx: TaskArbitrationContext,
354
413
  ): Promise<'resume' | 'new'> {
355
414
  const exec = deps.executeTool ?? sdkExecuteTool;
356
- const progress = `${actx.completedStepIds.length}/${actx.totalSteps}`;
357
415
  const args = {
358
416
  questions: [
359
417
  {
360
418
  question:
361
419
  `检测到工作流「${actx.workflowName}」有一个未完成的任务(目标:${truncate(actx.prevGoal, 80)},` +
362
- `进度 ${progress} 步)。本次输入「${truncate(actx.newGoal, 80)}」是要继续该任务,还是开始全新任务?`,
420
+ `已完成 ${actx.completedCalls} 次调用)。本次输入「${truncate(actx.newGoal, 80)}」是要继续该任务,还是开始全新任务?`,
363
421
  header: '任务仲裁',
364
422
  options: [
365
423
  {
366
424
  label: '全新开始 (推荐)',
367
- description: '清理旧任务的中间产物,按本次输入重新规划执行',
425
+ description: '归档旧任务的中间产物,按本次输入重新规划执行',
368
426
  },
369
427
  {
370
428
  label: '继续上次任务',
@@ -378,28 +436,3 @@ async function askUserArbitrate(
378
436
  if (!r.ok) throw new Error(r.error);
379
437
  return r.content.includes('继续上次任务') ? 'resume' : 'new';
380
438
  }
381
-
382
- /**
383
- * 归一化 goal 字符串
384
- *
385
- * 规则:
386
- * - toLowerCase()
387
- * - 去除所有标点符号(保留中文、英文、数字、空格)
388
- * - 去除多余空格(连续空格→单空格)
389
- * - 首尾 trim
390
- * - 截断到 200 字符
391
- */
392
- function normalizeGoal(raw: string): string {
393
- return (
394
- raw
395
- .toLowerCase()
396
- // 保留中文、英文、数字、空格,去除其他字符(标点等)
397
- .replace(/[^\p{L}\p{N}\s]/gu, '')
398
- // 连续空格替换为单空格
399
- .replace(/\s+/g, ' ')
400
- // 首尾去空格
401
- .trim()
402
- // 截断到 200 字符
403
- .slice(0, 200)
404
- );
405
- }
@@ -1,12 +1,33 @@
1
1
  /**
2
- * The workflow identity stays anchored to the registered workspace, while file
3
- * and process tools follow a session worktree as soon as EnterWorktree creates
4
- * one. Keeping this decision in one helper prevents executors from drifting.
2
+ * ============================================================
3
+ * plugins/workflow-runner/src/toolRuntime.ts —— 工具调用的运行上下文
4
+ * ------------------------------------------------------------
5
+ * 宿主能力由每次工具调用的显式 `uses` 数组收敛 ——
6
+ * 代码形态里没有「step」这个东西,宿主能力由调用点在 `tool()`/`agent()` 的
7
+ * 选项里显式声明。
8
+ *
9
+ * ⚠️ `effectiveWorkflowCwd` 是**红线级**的单一出处,别在别处再算一次:
10
+ * 会话可能在运行途中进入 worktree(模型可自主调 EnterWorktree),此后写文件的
11
+ * 工具跟着 worktree 走。验收侧(verify/exists/readJson)必须用**同一个**函数取 cwd,
12
+ * 否则就是「产物写进 worktree、验收去原工作区的空目录里找」——条件恒 false,
13
+ * 引擎反复重试后莫名失败,而产物其实好好躺在 worktree 里。
14
+ *
15
+ * 也正因为 worktree 是**运行途中**才进入的,取 cwd 必须在**每次调用时**现算,
16
+ * 不能在运行开始时快照一次存起来。
17
+ * ============================================================
5
18
  */
19
+ /** 当前有效工作目录 —— 进了 worktree 就跟着走。见文件头注的红线说明。 */
6
20
  export function effectiveWorkflowCwd(ctx) {
7
21
  return ctx.sessionState?.activeWorktree?.path ?? ctx.cwd;
8
22
  }
9
- export function buildWorkflowToolContext(step, ctx, toolCallId, reportProgress) {
23
+ /**
24
+ * 组装一次工具调用的 ToolCallContext。
25
+ *
26
+ * @param uses 本次调用显式声明需要的宿主能力;缺省表示不需要任何授权切片。
27
+ * @returns 成功返回上下文;宿主没提供所声明的能力时返回 `{ error }`(不抛,
28
+ * 让调用方把原因当 tool_result 回填给模型)。
29
+ */
30
+ export function buildWorkflowToolContext(ctx, toolCallId, reportProgress, uses) {
10
31
  const context = {
11
32
  ...ctx.toolContext,
12
33
  history: ctx.history,
@@ -21,12 +42,12 @@ export function buildWorkflowToolContext(step, ctx, toolCallId, reportProgress)
21
42
  toolCallId,
22
43
  reportProgress,
23
44
  };
24
- for (const capability of step.uses ?? []) {
45
+ for (const capability of uses ?? []) {
25
46
  if (capability === 'computer') {
26
47
  if (!ctx.host?.computerRun) {
27
48
  return {
28
- error: 'uses:[computer] 声明了需要电脑操控能力,但本次运行的宿主没有提供 —— ' +
29
- '请在支持 Computer Use 的宿主启动,或去掉该步的 uses 声明。',
49
+ error: "声明了 uses:['computer'](需要电脑操控能力),但本次运行的宿主没有提供 —— " +
50
+ '请在支持 Computer Use 的宿主里启动,或去掉该声明。',
30
51
  };
31
52
  }
32
53
  context.computerRun = ctx.host.computerRun;
@@ -38,7 +59,7 @@ export function buildWorkflowToolContext(step, ctx, toolCallId, reportProgress)
38
59
  if (capability === 'browser') {
39
60
  if (!ctx.host?.browserRun) {
40
61
  return {
41
- error: 'uses:[browser] 声明了需要浏览器授权上下文,但本次运行的宿主没有提供。',
62
+ error: "声明了 uses:['browser'](需要浏览器授权上下文),但本次运行的宿主没有提供。",
42
63
  };
43
64
  }
44
65
  context.browserRun = ctx.host.browserRun;