minimal-agent 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/README.md +6 -5
  2. package/package.json +60 -4
  3. package/plugins/computer_use/.claude-plugin/plugin.json +1 -1
  4. package/plugins/cron-runner/src/commands.js +4 -4
  5. package/plugins/cron-runner/src/commands.ts +4 -4
  6. package/plugins/workflow-runner/.claude-plugin/plugin.json +2 -2
  7. package/plugins/workflow-runner/commands/workflow.md +57 -90
  8. package/plugins/workflow-runner/commands/workflows.md +4 -4
  9. package/plugins/workflow-runner/plugin.js +24 -13
  10. package/plugins/workflow-runner/plugin.ts +28 -13
  11. package/plugins/workflow-runner/src/discovery.js +160 -0
  12. package/plugins/workflow-runner/src/discovery.ts +194 -0
  13. package/plugins/workflow-runner/src/goalAnchor.js +53 -0
  14. package/plugins/workflow-runner/src/goalAnchor.ts +59 -0
  15. package/plugins/workflow-runner/src/index.js +197 -206
  16. package/plugins/workflow-runner/src/index.ts +248 -249
  17. package/plugins/workflow-runner/src/inputCoercion.js +40 -0
  18. package/plugins/workflow-runner/src/inputCoercion.ts +43 -0
  19. package/plugins/workflow-runner/src/journal.js +224 -0
  20. package/plugins/workflow-runner/src/journal.ts +274 -0
  21. package/plugins/workflow-runner/src/jsonSchema.js +132 -0
  22. package/plugins/workflow-runner/src/jsonSchema.ts +162 -0
  23. package/plugins/workflow-runner/src/moduleResolution.js +64 -0
  24. package/plugins/workflow-runner/src/moduleResolution.ts +71 -0
  25. package/plugins/workflow-runner/src/resourceInputs.js +220 -0
  26. package/plugins/workflow-runner/src/resourceInputs.ts +300 -0
  27. package/plugins/workflow-runner/src/runner.js +400 -489
  28. package/plugins/workflow-runner/src/runner.ts +488 -560
  29. package/plugins/workflow-runner/src/runtime/config.js +46 -0
  30. package/plugins/workflow-runner/src/runtime/config.ts +69 -0
  31. package/plugins/workflow-runner/src/runtime/context.js +1304 -0
  32. package/plugins/workflow-runner/src/runtime/context.ts +1786 -0
  33. package/plugins/workflow-runner/src/runtime/exec.js +34 -0
  34. package/plugins/workflow-runner/src/runtime/exec.ts +53 -0
  35. package/plugins/workflow-runner/src/runtime/flow.js +8 -0
  36. package/plugins/workflow-runner/src/runtime/flow.ts +12 -0
  37. package/plugins/workflow-runner/src/runtime/fs.js +27 -0
  38. package/plugins/workflow-runner/src/runtime/fs.ts +41 -0
  39. package/plugins/workflow-runner/src/runtime/model.js +6 -0
  40. package/plugins/workflow-runner/src/runtime/model.ts +8 -0
  41. package/plugins/workflow-runner/src/runtime/output.js +7 -0
  42. package/plugins/workflow-runner/src/runtime/output.ts +21 -0
  43. package/plugins/workflow-runner/src/runtime/scheduler.js +141 -0
  44. package/plugins/workflow-runner/src/runtime/scheduler.ts +166 -0
  45. package/plugins/workflow-runner/src/runtime/state.js +16 -0
  46. package/plugins/workflow-runner/src/runtime/state.ts +19 -0
  47. package/plugins/workflow-runner/src/runtime/tools.js +3 -0
  48. package/plugins/workflow-runner/src/runtime/tools.ts +6 -0
  49. package/plugins/workflow-runner/src/sandbox.js +141 -0
  50. package/plugins/workflow-runner/src/sandbox.ts +182 -0
  51. package/plugins/workflow-runner/src/scriptGuard.d.mts +38 -0
  52. package/plugins/workflow-runner/src/scriptGuard.mjs +449 -0
  53. package/plugins/workflow-runner/src/taskIdentity.js +151 -307
  54. package/plugins/workflow-runner/src/taskIdentity.ts +207 -355
  55. package/plugins/workflow-runner/src/toolRuntime.js +29 -8
  56. package/plugins/workflow-runner/src/toolRuntime.ts +36 -11
  57. package/plugins/workflow-runner/src/types.js +7 -211
  58. package/plugins/workflow-runner/src/types.ts +154 -623
  59. package/plugins/workflow-runner/src/util.js +47 -0
  60. package/plugins/workflow-runner/src/util.ts +51 -0
  61. package/plugins/workflow-runner/src/workflowContext.js +20 -0
  62. package/plugins/workflow-runner/src/workflowContext.ts +58 -0
  63. package/plugins/workflow-runner/src/workflowDependencies.js +36 -0
  64. package/plugins/workflow-runner/src/workflowDependencies.ts +59 -0
  65. package/plugins/workflow-runner/src/workflowFingerprint.js +118 -0
  66. package/plugins/workflow-runner/src/workflowFingerprint.ts +122 -0
  67. package/plugins/workflow-runner/src/workflowState.js +474 -802
  68. package/plugins/workflow-runner/src/workflowState.ts +575 -970
  69. package/plugins/workflow-runner/test/api.test.ts +223 -0
  70. package/plugins/workflow-runner/test/apiCapabilities.test.ts +614 -0
  71. package/plugins/workflow-runner/test/apiConcurrencyGate.test.ts +104 -0
  72. package/plugins/workflow-runner/test/apiEcho.test.ts +210 -0
  73. package/plugins/workflow-runner/test/apiReadText.test.ts +178 -0
  74. package/plugins/workflow-runner/test/apiResourceLedger.test.ts +184 -0
  75. package/plugins/workflow-runner/test/childWorkflow.test.ts +304 -0
  76. package/plugins/workflow-runner/test/discovery.test.ts +234 -0
  77. package/plugins/workflow-runner/test/goalAnchor.test.ts +106 -0
  78. package/plugins/workflow-runner/test/goalController.test.ts +317 -0
  79. package/plugins/workflow-runner/test/journalLanes.test.ts +198 -0
  80. package/plugins/workflow-runner/test/listResources.test.ts +106 -0
  81. package/plugins/workflow-runner/test/resourceInputs.test.ts +294 -0
  82. package/plugins/workflow-runner/test/sandbox.test.ts +126 -0
  83. package/plugins/workflow-runner/test/scheduler.test.ts +70 -0
  84. package/plugins/workflow-runner/test/scriptGuard.test.ts +276 -0
  85. package/plugins/workflow-runner/test/skillDocSync.test.ts +78 -0
  86. package/plugins/workflow-runner/test/taskIdentity.test.ts +288 -179
  87. package/plugins/workflow-runner/test/workflowFingerprint.test.ts +106 -0
  88. package/plugins/workflow-runner/test/workflowState.test.ts +429 -0
  89. package/skills/pptx/examples/assets/cover-bg.svg +23 -0
  90. package/skills/pptx/examples/assets/icon-spark.svg +5 -0
  91. package/skills/ui-design/SKILL.md +5 -2
  92. package/skills/ui-design/references/layout-composition.md +1 -1
  93. package/skills/workflow-creator/SKILL.md +344 -0
  94. package/skills/workflow-creator/assets/template/workflow.mjs +48 -0
  95. package/skills/workflow-creator/references/api.md +216 -0
  96. package/skills/workflow-creator/references/migration.md +103 -0
  97. package/skills/workflow-creator/references/patterns.md +779 -0
  98. package/skills/workflow-creator/scripts/list-resources.mjs +205 -0
  99. package/skills/workflow-creator/scripts/scaffold.mjs +148 -0
  100. package/skills/workflow-creator/scripts/validate.mjs +275 -0
  101. package/skills/workflow-creator/scripts/workflow-creator.test.mjs +82 -0
  102. package/src/advisor/advisorCoordinator.js +536 -0
  103. package/src/advisor/advisorCoordinator.ts +693 -0
  104. package/src/cli/configMenu.tsx +0 -1
  105. package/src/cli/print.js +27 -6
  106. package/src/cli/print.ts +48 -4
  107. package/src/cli/quickModelSetup.js +12 -1
  108. package/src/cli/quickModelSetup.tsx +15 -3
  109. package/src/cli/streamJson.js +5 -6
  110. package/src/cli/streamJson.ts +8 -4
  111. package/src/cli/wizards/advisorWizard.js +4 -2
  112. package/src/cli/wizards/advisorWizard.tsx +8 -2
  113. package/src/cli/wizards/contextAdvisorWizard.js +5 -4
  114. package/src/cli/wizards/contextAdvisorWizard.tsx +7 -6
  115. package/src/cli/wizards/providerPresets.js +18 -8
  116. package/src/cli/wizards/providerPresets.ts +18 -8
  117. package/src/collaboration/taskFlow.js +115 -0
  118. package/src/collaboration/taskFlow.ts +169 -0
  119. package/src/config/configDefaults.js +41 -1
  120. package/src/config/configDefaults.ts +43 -1
  121. package/src/config/configDiagnostics.ts +2 -2
  122. package/src/config/configFile.js +40 -9
  123. package/src/config/configFile.ts +60 -11
  124. package/src/config/configService.js +419 -74
  125. package/src/config/configService.ts +703 -145
  126. package/src/config/numericLimits.js +22 -0
  127. package/src/config/numericLimits.ts +24 -0
  128. package/src/config.js +1 -0
  129. package/src/config.ts +3 -2
  130. package/src/context/budgetPlan.js +1 -1
  131. package/src/context/budgetPlan.ts +1 -1
  132. package/src/context/compact.js +7 -2
  133. package/src/context/compact.ts +9 -2
  134. package/src/context/microCompactLite.js +212 -13
  135. package/src/context/microCompactLite.ts +261 -12
  136. package/src/context/sessionRegistry.js +8 -1
  137. package/src/context/sessionRegistry.ts +18 -5
  138. package/src/context/toolResultArchive.js +72 -0
  139. package/src/context/toolResultArchive.ts +95 -0
  140. package/src/goal/errors.js +8 -0
  141. package/src/goal/errors.ts +18 -0
  142. package/src/goal/goalRuntime.js +344 -0
  143. package/src/goal/goalRuntime.ts +466 -0
  144. package/src/goal/goalStore.js +200 -0
  145. package/src/goal/goalStore.ts +219 -0
  146. package/src/goal/index.js +4 -0
  147. package/src/goal/index.ts +4 -0
  148. package/src/goal/statusMapping.js +71 -0
  149. package/src/goal/statusMapping.ts +95 -0
  150. package/src/goal/types.js +7 -0
  151. package/src/goal/types.ts +179 -0
  152. package/src/goal/workflowController.js +306 -0
  153. package/src/goal/workflowController.ts +360 -0
  154. package/src/harness/evidenceLedger.js +2 -0
  155. package/src/harness/evidenceLedger.ts +1 -0
  156. package/src/harness/stallGuard.js +9 -3
  157. package/src/harness/stallGuard.ts +7 -3
  158. package/src/images/imageResolver.js +161 -0
  159. package/src/images/imageResolver.ts +189 -0
  160. package/src/infra/verification.js +34 -5
  161. package/src/infra/verification.ts +39 -4
  162. package/src/llm/client.js +79 -21
  163. package/src/llm/client.ts +182 -35
  164. package/src/llm/gatewayClient.js +201 -0
  165. package/src/llm/gatewayClient.ts +299 -0
  166. package/src/llm/messageProvenance.js +46 -0
  167. package/src/llm/messageProvenance.ts +58 -0
  168. package/src/llm/modelProvider.js +1 -0
  169. package/src/llm/modelProvider.ts +22 -0
  170. package/src/llm/providers/anthropicFormat.js +108 -1
  171. package/src/llm/providers/anthropicFormat.ts +115 -4
  172. package/src/llm/providers/openaiFormat.js +9 -0
  173. package/src/llm/providers/openaiFormat.ts +12 -3
  174. package/src/loop.js +328 -55
  175. package/src/loop.ts +382 -58
  176. package/src/main.js +4 -1
  177. package/src/main.tsx +4 -1
  178. package/src/managedExecution/index.js +2 -0
  179. package/src/managedExecution/index.ts +2 -0
  180. package/src/managedExecution/registry.js +15 -0
  181. package/src/managedExecution/registry.ts +20 -0
  182. package/src/managedExecution/types.js +1 -0
  183. package/src/managedExecution/types.ts +86 -0
  184. package/src/modelRef.js +9 -0
  185. package/src/modelRef.ts +31 -0
  186. package/src/multimodal.js +14 -28
  187. package/src/multimodal.ts +17 -33
  188. package/src/net/lanDiscovery.js +65 -0
  189. package/src/net/lanDiscovery.ts +82 -0
  190. package/src/plugin-sdk.js +28 -3
  191. package/src/plugin-sdk.ts +39 -6
  192. package/src/plugins/pluginApi.ts +16 -1
  193. package/src/plugins/pluginLoader.js +4 -0
  194. package/src/plugins/pluginLoader.ts +6 -0
  195. package/src/plugins/pluginRunner.js +139 -7
  196. package/src/plugins/pluginRunner.ts +173 -9
  197. package/src/plugins/slashFallback.js +113 -0
  198. package/src/plugins/slashFallback.ts +137 -0
  199. package/src/prompts/policyRegistry.js +12 -32
  200. package/src/prompts/policyRegistry.ts +15 -32
  201. package/src/prompts/promptAssembly.js +103 -12
  202. package/src/prompts/promptAssembly.ts +114 -12
  203. package/src/prompts/skillList.js +21 -3
  204. package/src/prompts/skillList.ts +27 -2
  205. package/src/prompts/stableSystemPrompt.js +18 -0
  206. package/src/prompts/stableSystemPrompt.ts +33 -0
  207. package/src/runtime/agentRuntimeContext.js +8 -2
  208. package/src/runtime/agentRuntimeContext.ts +17 -4
  209. package/src/session/runAgentTurn.js +78 -12
  210. package/src/session/runAgentTurn.ts +105 -23
  211. package/src/session/runTurn.js +10 -9
  212. package/src/session/runTurn.ts +17 -8
  213. package/src/session/sessionState.ts +2 -0
  214. package/src/team/auth.js +186 -0
  215. package/src/team/auth.ts +298 -0
  216. package/src/team/cli.js +105 -0
  217. package/src/team/cli.ts +122 -0
  218. package/src/team/onlineToolContract.js +64 -0
  219. package/src/team/onlineToolContract.ts +109 -0
  220. package/src/team/toolPolicy.js +36 -0
  221. package/src/team/toolPolicy.ts +75 -0
  222. package/src/tools/advisor/advisor.js +115 -50
  223. package/src/tools/advisor/advisor.ts +124 -51
  224. package/src/tools/advisor/advisorDecision.js +71 -0
  225. package/src/tools/advisor/advisorDecision.ts +85 -0
  226. package/src/tools/agent/agent.js +18 -5
  227. package/src/tools/agent/agent.ts +21 -7
  228. package/src/tools/agent/agentControl.js +246 -0
  229. package/src/tools/agent/agentControl.ts +284 -0
  230. package/src/tools/agent/agentTaskService.js +40 -1
  231. package/src/tools/agent/agentTaskService.ts +44 -1
  232. package/src/tools/agent/agentTypes.js +14 -2
  233. package/src/tools/agent/agentTypes.ts +15 -2
  234. package/src/tools/applypatch/applyPatch.js +362 -0
  235. package/src/tools/applypatch/applyPatch.ts +428 -0
  236. package/src/tools/bash/bash.js +22 -15
  237. package/src/tools/bash/bash.ts +23 -17
  238. package/src/tools/capabilities.js +10 -5
  239. package/src/tools/capabilities.ts +10 -5
  240. package/src/tools/computeruse/computerIntent.js +32 -0
  241. package/src/tools/computeruse/computerIntent.ts +46 -0
  242. package/src/tools/computeruse/telemetryLog.js +12 -0
  243. package/src/tools/computeruse/telemetryLog.ts +16 -0
  244. package/src/tools/computeruse/vision/telemetry.js +1 -0
  245. package/src/tools/computeruse/vision/telemetry.ts +1 -0
  246. package/src/tools/effectiveToolSet.js +4 -0
  247. package/src/tools/effectiveToolSet.ts +4 -0
  248. package/src/tools/index.js +21 -2
  249. package/src/tools/index.ts +33 -2
  250. package/src/tools/presentresult/presentresult.js +6 -15
  251. package/src/tools/presentresult/presentresult.ts +6 -15
  252. package/src/tools/read/read.js +62 -9
  253. package/src/tools/read/read.ts +63 -9
  254. package/src/tools/shared/fileUtils.js +1 -2
  255. package/src/tools/shared/fileUtils.ts +1 -2
  256. package/src/tools/shared/toolOutputStore.js +23 -1
  257. package/src/tools/shared/toolOutputStore.ts +22 -1
  258. package/src/tools/skill/skill.js +9 -3
  259. package/src/tools/skill/skill.ts +8 -4
  260. package/src/tools/toolPromptGuides.js +125 -0
  261. package/src/tools/toolPromptGuides.ts +146 -0
  262. package/src/tools/webbrowser/agentBrowserPath.js +19 -9
  263. package/src/tools/webbrowser/agentBrowserPath.ts +70 -28
  264. package/src/tools/webbrowser/browser.js +27 -11
  265. package/src/tools/webbrowser/browser.ts +68 -24
  266. package/src/tools/webbrowser/browserAutomation.js +329 -0
  267. package/src/tools/webbrowser/browserAutomation.ts +467 -0
  268. package/src/tools/webbrowser/browserAxState.js +97 -0
  269. package/src/tools/webbrowser/browserAxState.ts +142 -0
  270. package/src/tools/webbrowser/browserBatch.js +1578 -0
  271. package/src/tools/webbrowser/browserBatch.ts +2382 -0
  272. package/src/tools/webbrowser/browserCdp.js +208 -0
  273. package/src/tools/webbrowser/browserCdp.ts +255 -0
  274. package/src/tools/webbrowser/browserConditions.js +24 -0
  275. package/src/tools/webbrowser/browserConditions.ts +45 -0
  276. package/src/tools/webbrowser/browserContent.js +281 -0
  277. package/src/tools/webbrowser/browserContent.ts +438 -0
  278. package/src/tools/webbrowser/browserControl.js +131 -34
  279. package/src/tools/webbrowser/browserControl.ts +210 -56
  280. package/src/tools/webbrowser/browserDaemon.js +22 -14
  281. package/src/tools/webbrowser/browserDaemon.ts +54 -21
  282. package/src/tools/webbrowser/browserFrames.js +47 -0
  283. package/src/tools/webbrowser/browserFrames.ts +54 -0
  284. package/src/tools/webbrowser/browserInteractionResolver.js +17 -0
  285. package/src/tools/webbrowser/browserInteractionResolver.ts +40 -0
  286. package/src/tools/webbrowser/browserLocator.js +140 -0
  287. package/src/tools/webbrowser/browserLocator.ts +194 -0
  288. package/src/tools/webbrowser/browserOutcome.js +10 -17
  289. package/src/tools/webbrowser/browserOutcome.ts +48 -31
  290. package/src/tools/webbrowser/browserRecovery.js +58 -0
  291. package/src/tools/webbrowser/browserRecovery.ts +83 -0
  292. package/src/tools/webbrowser/browserRunRegistry.js +35 -3
  293. package/src/tools/webbrowser/browserRunRegistry.ts +91 -15
  294. package/src/tools/webbrowser/browserService.js +28 -2
  295. package/src/tools/webbrowser/browserService.ts +49 -9
  296. package/src/tools/webbrowser/browserStream.js +132 -33
  297. package/src/tools/webbrowser/browserStream.ts +224 -50
  298. package/src/tools/webbrowser/browserTabs.js +48 -15
  299. package/src/tools/webbrowser/browserTabs.ts +178 -96
  300. package/src/tools/webbrowser/webbrowser.js +679 -144
  301. package/src/tools/webbrowser/webbrowser.ts +975 -236
  302. package/src/tools/webfetch/preapproved.js +0 -2
  303. package/src/tools/webfetch/preapproved.ts +0 -2
  304. package/src/tools/websearch/websearch.js +129 -8
  305. package/src/tools/websearch/websearch.ts +138 -6
  306. package/src/types.ts +459 -40
  307. package/src/ui/App.js +377 -58
  308. package/src/ui/App.tsx +576 -111
  309. package/src/ui/LiveArea.js +14 -8
  310. package/src/ui/LiveArea.tsx +14 -10
  311. package/src/ui/MessageList.js +63 -20
  312. package/src/ui/MessageList.tsx +101 -16
  313. package/src/ui/ModelPicker.js +7 -4
  314. package/src/ui/ModelPicker.tsx +55 -8
  315. package/src/ui/hooks/useChat.js +152 -163
  316. package/src/ui/hooks/useChat.ts +396 -334
  317. package/src/ui/loginCommand.js +56 -0
  318. package/src/ui/loginCommand.ts +63 -0
  319. package/src/ui/toolProgress.js +41 -0
  320. package/src/ui/toolProgress.ts +44 -0
  321. package/src/web/browserBridge.js +20 -2
  322. package/src/web/browserBridge.ts +20 -2
  323. package/src/web/protocol.ts +1897 -194
  324. package/workflows/adaptive-research/workflow.mjs +86 -0
  325. package/workflows/e2e-capabilities/workflow.mjs +102 -0
  326. package/workflows/e2e-llm/workflow.mjs +52 -0
  327. package/workflows/e2e-smoke/workflow.mjs +59 -0
  328. package/workflows/e2e-vision-schema/README.md +48 -0
  329. package/workflows/e2e-vision-schema/workflow.mjs +149 -0
  330. package/workflows/e2e-write-greet/workflow.mjs +37 -0
  331. package/workflows/file-census/README.md +14 -0
  332. package/workflows/file-census/scripts/.gitkeep +2 -0
  333. package/workflows/file-census/workflow.mjs +110 -0
  334. package/workflows/goal/README.md +166 -0
  335. package/workflows/goal/prompts/audit.md +57 -0
  336. package/workflows/goal/prompts/contract.md +56 -0
  337. package/workflows/goal/prompts/iterate.md +37 -0
  338. package/workflows/goal/workflow.mjs +501 -0
  339. package/workflows/illustrate/README.md +90 -0
  340. package/workflows/illustrate/assets/engines.json +20 -0
  341. package/workflows/illustrate/assets/extract-baidu.js +21 -0
  342. package/workflows/illustrate/assets/extract-bing.js +33 -0
  343. package/workflows/illustrate/assets/extract-google.js +31 -0
  344. package/workflows/illustrate/workflow.mjs +301 -0
  345. package/workflows/plan/workflow.mjs +389 -0
  346. package/workflows/question-crops/README.md +35 -0
  347. package/workflows/question-crops/prompts/inventory.md +23 -0
  348. package/workflows/question-crops/scripts/image-ops.mjs +305 -0
  349. package/workflows/question-crops/scripts/image-ops.test.mjs +95 -0
  350. package/workflows/question-crops/workflow.mjs +172 -0
  351. package/workflows/ralph-loop/workflow.mjs +162 -0
  352. package/workflows/research/README.md +74 -0
  353. package/workflows/research/prompts/s0-goal.md +43 -0
  354. package/workflows/research/prompts/s1-early-exit.md +22 -0
  355. package/workflows/research/prompts/s1-map.md +58 -0
  356. package/workflows/research/prompts/s2-options.md +53 -0
  357. package/workflows/research/prompts/s3-deep-dive.md +56 -0
  358. package/workflows/research/prompts/s4-verify.md +74 -0
  359. package/workflows/research/prompts/s5-synthesis.md +81 -0
  360. package/workflows/research/prompts/s5b-fill-gaps.md +32 -0
  361. package/workflows/research/prompts/s6-package.md +32 -0
  362. package/workflows/research/scripts/build-report.mjs +98 -0
  363. package/workflows/research/workflow.mjs +288 -0
  364. package/workflows/wechat-reading-shots/prompts/collect-params.md +16 -0
  365. package/workflows/wechat-reading-shots/prompts/evaluate.md +20 -0
  366. package/workflows/wechat-reading-shots/prompts/open-book.md +28 -0
  367. package/workflows/wechat-reading-shots/prompts/read-page.md +13 -0
  368. package/workflows/wechat-reading-shots/prompts/turn-batch.md +24 -0
  369. package/workflows/wechat-reading-shots/test/control-flow.test.ts +329 -0
  370. package/workflows/wechat-reading-shots/workflow.mjs +266 -0
  371. package/workflows/wrong-question-docx/README.md +55 -0
  372. package/workflows/wrong-question-docx/prompts/figure-qa.md +8 -0
  373. package/workflows/wrong-question-docx/prompts/transcribe.md +25 -0
  374. package/workflows/wrong-question-docx/scripts/workbook.mjs +857 -0
  375. package/workflows/wrong-question-docx/test/control-flow.test.ts +165 -0
  376. package/workflows/wrong-question-docx/test/workbook.test.mjs +303 -0
  377. package/workflows/wrong-question-docx/workflow.mjs +485 -0
  378. package/plugins/workflow-runner/src/agentCommon.js +0 -354
  379. package/plugins/workflow-runner/src/agentCommon.ts +0 -435
  380. package/plugins/workflow-runner/src/controlFlow/branch.js +0 -40
  381. package/plugins/workflow-runner/src/controlFlow/branch.ts +0 -46
  382. package/plugins/workflow-runner/src/controlFlow/loop.js +0 -211
  383. package/plugins/workflow-runner/src/controlFlow/loop.ts +0 -248
  384. package/plugins/workflow-runner/src/controlFlow/pause.js +0 -129
  385. package/plugins/workflow-runner/src/controlFlow/pause.ts +0 -141
  386. package/plugins/workflow-runner/src/controlFlow/signal.js +0 -21
  387. package/plugins/workflow-runner/src/controlFlow/signal.ts +0 -29
  388. package/plugins/workflow-runner/src/controlFlow/types.js +0 -18
  389. package/plugins/workflow-runner/src/controlFlow/types.ts +0 -63
  390. package/plugins/workflow-runner/src/dslManifest.js +0 -72
  391. package/plugins/workflow-runner/src/dslManifest.ts +0 -127
  392. package/plugins/workflow-runner/src/expressions.js +0 -639
  393. package/plugins/workflow-runner/src/expressions.ts +0 -640
  394. package/plugins/workflow-runner/src/loader.js +0 -573
  395. package/plugins/workflow-runner/src/loader.ts +0 -721
  396. package/plugins/workflow-runner/src/multimodal.js +0 -38
  397. package/plugins/workflow-runner/src/multimodal.ts +0 -64
  398. package/plugins/workflow-runner/src/recovery.js +0 -126
  399. package/plugins/workflow-runner/src/recovery.ts +0 -156
  400. package/plugins/workflow-runner/src/stepExecutors/agent.js +0 -173
  401. package/plugins/workflow-runner/src/stepExecutors/agent.ts +0 -234
  402. package/plugins/workflow-runner/src/stepExecutors/assert.js +0 -42
  403. package/plugins/workflow-runner/src/stepExecutors/assert.ts +0 -52
  404. package/plugins/workflow-runner/src/stepExecutors/echo.js +0 -31
  405. package/plugins/workflow-runner/src/stepExecutors/echo.ts +0 -38
  406. package/plugins/workflow-runner/src/stepExecutors/llm.js +0 -99
  407. package/plugins/workflow-runner/src/stepExecutors/llm.ts +0 -133
  408. package/plugins/workflow-runner/src/stepExecutors/set.js +0 -49
  409. package/plugins/workflow-runner/src/stepExecutors/set.ts +0 -56
  410. package/plugins/workflow-runner/src/stepExecutors/skill.js +0 -111
  411. package/plugins/workflow-runner/src/stepExecutors/skill.ts +0 -140
  412. package/plugins/workflow-runner/src/stepExecutors/tool.js +0 -227
  413. package/plugins/workflow-runner/src/stepExecutors/tool.ts +0 -274
  414. package/plugins/workflow-runner/src/stepExecutors/verify.js +0 -61
  415. package/plugins/workflow-runner/src/stepExecutors/verify.ts +0 -72
  416. package/plugins/workflow-runner/src/stepPipeline.js +0 -277
  417. package/plugins/workflow-runner/src/stepPipeline.ts +0 -366
  418. package/plugins/workflow-runner/test/agent.test.ts +0 -587
  419. package/plugins/workflow-runner/test/agentLlmError.test.ts +0 -373
  420. package/plugins/workflow-runner/test/bashBlacklist.sweep.test.ts +0 -65
  421. package/plugins/workflow-runner/test/captureMisbind.test.ts +0 -99
  422. package/plugins/workflow-runner/test/cli.e2e.test.ts +0 -167
  423. package/plugins/workflow-runner/test/context-files.test.ts +0 -320
  424. package/plugins/workflow-runner/test/e2e.test.ts +0 -370
  425. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +0 -314
  426. package/plugins/workflow-runner/test/engineRobustness.test.ts +0 -234
  427. package/plugins/workflow-runner/test/expressions.test.ts +0 -439
  428. package/plugins/workflow-runner/test/foundation.test.ts +0 -126
  429. package/plugins/workflow-runner/test/graceful.test.ts +0 -139
  430. package/plugins/workflow-runner/test/greedyInputs.load.test.ts +0 -47
  431. package/plugins/workflow-runner/test/hostCapability.test.ts +0 -108
  432. package/plugins/workflow-runner/test/illustrate.load.test.ts +0 -183
  433. package/plugins/workflow-runner/test/jsonPayload.test.ts +0 -83
  434. package/plugins/workflow-runner/test/loader.test.ts +0 -617
  435. package/plugins/workflow-runner/test/maxTurnsRetryDelay.test.ts +0 -33
  436. package/plugins/workflow-runner/test/multimodal.test.ts +0 -342
  437. package/plugins/workflow-runner/test/output-schema.test.ts +0 -213
  438. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +0 -106
  439. package/plugins/workflow-runner/test/pluginRunner.isolation.test.ts +0 -269
  440. package/plugins/workflow-runner/test/ppt.load.test.ts +0 -1220
  441. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +0 -221
  442. package/plugins/workflow-runner/test/recovery.test.ts +0 -265
  443. package/plugins/workflow-runner/test/research.load.test.ts +0 -328
  444. package/plugins/workflow-runner/test/runner.test.ts +0 -911
  445. package/plugins/workflow-runner/test/runnerPreflight.test.ts +0 -436
  446. package/plugins/workflow-runner/test/skillTurnDone.test.ts +0 -71
  447. package/plugins/workflow-runner/test/stateLifecycle.test.ts +0 -198
  448. package/plugins/workflow-runner/test/stepPipeline.test.ts +0 -114
  449. package/plugins/workflow-runner/test/taskArbitration.test.ts +0 -354
  450. package/plugins/workflow-runner/test/taskLifecycle.test.ts +0 -324
  451. package/plugins/workflow-runner/test/toolArtifactOverwrite.test.ts +0 -221
  452. package/plugins/workflow-runner/test/toolCapabilityBoundary.test.ts +0 -29
  453. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +0 -168
  454. package/plugins/workflow-runner/test/webppt.load.test.ts +0 -250
  455. package/plugins/workflow-runner/test/word.load.test.ts +0 -208
  456. package/plugins/workflow-runner/test/workflows.smoke.test.ts +0 -76
  457. package/plugins/workflow-runner/test/yamlGuardConditions.test.ts +0 -207
  458. package/src/advisorState.js +0 -22
  459. package/src/cli/configWizard.js +0 -293
  460. package/src/tools/toolProgressBridge.js +0 -48
  461. package/workflows/adaptive-research.yaml +0 -50
  462. package/workflows/book-review-short.yaml +0 -125
  463. package/workflows/e2e-write-greet.yaml +0 -31
  464. package/workflows/illustrate.yaml +0 -227
  465. package/workflows/plan.yaml +0 -470
  466. package/workflows/ppt.yaml +0 -1670
  467. package/workflows/ralph-loop.yaml +0 -201
  468. package/workflows/research.yaml +0 -873
  469. package/workflows/schema.json +0 -176
  470. package/workflows/webppt.yaml +0 -496
  471. package/workflows/wechat-reading-shots.yaml +0 -315
  472. package/workflows/word.yaml +0 -720
  473. package/workflows/youtube-shorts.yaml +0 -202
  474. /package/workflows/{research.md → research/DESIGN.md} +0 -0
@@ -0,0 +1,306 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isUsageLimitError } from '../llm/gatewayClient.js';
3
+ import { GoalRuntime, GoalRuntimeError, } from './index.js';
4
+ import { OUTCOME_TO_ATTEMPT } from './statusMapping.js';
5
+ function scopeFor(options) {
6
+ const workspaceId = options.runtimeContext?.workspaceId
7
+ ?? `path-${createHash('sha256').update(options.cwd).digest('hex').slice(0, 20)}`;
8
+ return {
9
+ workspaceId,
10
+ sessionId: options.runtimeContext?.sessionId?.trim() || 'default',
11
+ };
12
+ }
13
+ function criteriaFrom(inputs) {
14
+ const checks = String(inputs.checks ?? '')
15
+ .split(',')
16
+ .map((item) => item.trim())
17
+ .filter(Boolean);
18
+ return checks.length > 0
19
+ ? checks
20
+ : ['按照确认的目标与交付物完成,并提供可检查的验证证据'];
21
+ }
22
+ function render(goal, runtime) {
23
+ const contract = runtime.currentContract(goal);
24
+ const latest = goal.attempts.at(-1);
25
+ const lines = [
26
+ `Goal ${goal.goalId}`,
27
+ `状态:${goal.status}`,
28
+ `目标:${contract.objective}`,
29
+ `契约:v${contract.version} (${contract.hash.slice(0, 12)})`,
30
+ `执行:${goal.attempts.length} 次${latest ? `,最近 ${latest.status}` : ''}`,
31
+ ];
32
+ if (goal.statusReason)
33
+ lines.push(`原因:${goal.statusReason}`);
34
+ if (goal.status === 'ready_for_acceptance') {
35
+ lines.push('成果已通过 Agent 自检,等待指定人类验收;Agent 不会自行标记完成。');
36
+ }
37
+ return `${lines.join('\n')}\n`;
38
+ }
39
+ function handled(goal, runtime, prefix) {
40
+ return {
41
+ handled: true,
42
+ inputs: {},
43
+ events: [
44
+ { type: 'text', delta: `${prefix ? `${prefix}\n` : ''}${render(goal, runtime)}` },
45
+ { type: 'turn_done' },
46
+ ],
47
+ };
48
+ }
49
+ function error(message) {
50
+ return { handled: true, inputs: {}, events: [{ type: 'error', error: message }] };
51
+ }
52
+ /** `/workflow goal` 的外层生命周期控制;返回 execute=false 时不会进入脚本。 */
53
+ export async function prepareGoalCommand(rawInputs, options) {
54
+ const runtime = options.runtime ?? new GoalRuntime();
55
+ const scope = scopeFor(options);
56
+ const actorId = options.actorId ?? 'local-human';
57
+ const action = String(rawInputs.action ?? '').trim();
58
+ const objective = String(rawInputs.objective ?? '').trim();
59
+ let current = await runtime.get(scope);
60
+ const inferredSource = options.source ?? (typeof rawInputs.group_id === 'string' && rawInputs.group_id.trim()
61
+ && typeof rawInputs.task_id === 'string' && rawInputs.task_id.trim()
62
+ ? {
63
+ kind: 'group-task',
64
+ groupId: rawInputs.group_id.trim(),
65
+ taskId: rawInputs.task_id.trim(),
66
+ ...(typeof rawInputs.agent_member_id === 'string' && rawInputs.agent_member_id.trim()
67
+ ? { assigneeAgentId: rawInputs.agent_member_id.trim() }
68
+ : {}),
69
+ }
70
+ : undefined);
71
+ try {
72
+ if (action === 'status' || (!action && !objective)) {
73
+ return current
74
+ ? handled(current, runtime)
75
+ : error('当前 Session 没有 Goal。用 /workflow goal <目标> 创建。');
76
+ }
77
+ if (action === 'cancel') {
78
+ if (!current)
79
+ return error('当前 Session 没有可取消的 Goal。');
80
+ current = await runtime.transition(scope, current.goalId, current.revision, 'cancelled', {
81
+ reason: String(rawInputs.reason ?? '用户取消'), actorId,
82
+ });
83
+ return handled(current, runtime, 'Goal 已取消,历史与产物仍保留。');
84
+ }
85
+ if (action === 'pause') {
86
+ if (!current)
87
+ return error('当前 Session 没有可暂停的 Goal。');
88
+ current = await runtime.transition(scope, current.goalId, current.revision, 'paused', {
89
+ reason: String(rawInputs.reason ?? '用户暂停'), actorId,
90
+ });
91
+ return handled(current, runtime, 'Goal 已暂停,现场已保留。');
92
+ }
93
+ if (action === 'accept') {
94
+ if (!current)
95
+ return error('当前 Session 没有待验收 Goal。');
96
+ current = await runtime.transition(scope, current.goalId, current.revision, 'accepted', { actorId });
97
+ return handled(current, runtime, '人类验收已通过。');
98
+ }
99
+ if (action === 'update') {
100
+ if (!current)
101
+ return error('当前 Session 没有可更新的 Goal。');
102
+ if (!objective)
103
+ return error('update 必须提供新的 objective。');
104
+ const patch = {
105
+ objective,
106
+ confirmedBy: actorId,
107
+ };
108
+ // 未提供 checks 时保留原验收标准;只有显式传入才替换。
109
+ if (Object.prototype.hasOwnProperty.call(rawInputs, 'checks')) {
110
+ patch.acceptanceCriteria = criteriaFrom(rawInputs);
111
+ }
112
+ // 预算也是版本化契约的一部分。显式传 0/非法值表示清除预算;未传时
113
+ // 由 Runtime 的合并规则保留旧值,避免 update 误清空预算。
114
+ if (Object.prototype.hasOwnProperty.call(rawInputs, 'token_budget')) {
115
+ const budget = Number(rawInputs.token_budget);
116
+ patch.tokenBudget = Number.isFinite(budget) && budget > 0 ? budget : null;
117
+ }
118
+ current = await runtime.revise(scope, current.goalId, current.revision, patch);
119
+ }
120
+ else if (action === 'resume' || action === 'rework') {
121
+ if (!current)
122
+ return error('当前 Session 没有可继续的 Goal。');
123
+ current = await runtime.transition(scope, current.goalId, current.revision, 'active', {
124
+ reason: action === 'rework'
125
+ ? String(rawInputs.reason ?? '人类要求返工')
126
+ : '用户继续执行',
127
+ actorId,
128
+ });
129
+ rawInputs.objective = runtime.currentContract(current).objective;
130
+ }
131
+ else if (action && action !== 'start') {
132
+ return error(`未知 Goal action:${action}`);
133
+ }
134
+ else if (!current || current.status === 'accepted' || current.status === 'cancelled') {
135
+ if (!objective)
136
+ return error('创建 Goal 必须提供 objective。');
137
+ current = await runtime.create({
138
+ scope,
139
+ contract: {
140
+ objective,
141
+ acceptanceCriteria: criteriaFrom(rawInputs),
142
+ confirmedBy: actorId,
143
+ },
144
+ source: inferredSource,
145
+ createdBy: actorId,
146
+ acceptorHumanIds: options.acceptorHumanIds ?? [actorId],
147
+ });
148
+ }
149
+ else {
150
+ const existingObjective = runtime.currentContract(current).objective;
151
+ if (existingObjective !== objective) {
152
+ return error(`当前 Session 已有未完成 Goal「${existingObjective}」。` +
153
+ '请用 --input action=update 显式修改,或先 action=cancel。');
154
+ }
155
+ if (current.status !== 'active')
156
+ return handled(current, runtime);
157
+ }
158
+ // 除非这次调用显式传了新预算,否则沿用当前契约里已有的预算 ——
159
+ // workflow.mjs 每次都无条件把 args.token_budget 写进新契约版本(预算挂在
160
+ // 版本化契约上是刻意设计,见脚本内注释),如果这里不兜底,任何一次「不带
161
+ // token_budget 重跑」(resume/rework/update,甚至只是同目标再跑一轮)都会把
162
+ // 预算悄悄写成 null(不限),「用尽后加预算续跑」的断点设计就形同虚设——
163
+ // 用户以为在续跑同一个受限任务,实际上预算闸已经被静默关掉了。
164
+ if (!Object.prototype.hasOwnProperty.call(rawInputs, 'token_budget') &&
165
+ !(Number(rawInputs.token_budget) > 0)) {
166
+ const existingBudget = runtime.currentContract(current).tokenBudget;
167
+ if (typeof existingBudget === 'number' && existingBudget > 0) {
168
+ rawInputs.token_budget = existingBudget;
169
+ }
170
+ }
171
+ const started = await runtime.startAttempt(scope, current.goalId, current.revision, 'goal');
172
+ current = started.goal;
173
+ const execution = started.execution;
174
+ const managedExecution = {
175
+ executionId: execution.goalId,
176
+ version: execution.contractVersion,
177
+ runId: execution.attemptId,
178
+ anchor: renderExecutionAnchor(execution),
179
+ correlations: {
180
+ ...(execution.groupId ? { groupId: execution.groupId } : {}),
181
+ ...(execution.taskId ? { taskId: execution.taskId } : {}),
182
+ },
183
+ };
184
+ const bridge = {
185
+ updateContract: async (rawInput) => {
186
+ const input = rawInput;
187
+ const latest = await runtime.get(scope);
188
+ if (!latest || latest.goalId !== execution.goalId) {
189
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
190
+ }
191
+ const updated = await runtime.materializeAttemptContract(scope, latest.goalId, latest.revision, execution.attemptId, { ...input, confirmedBy: actorId });
192
+ const contract = runtime.currentContract(updated);
193
+ execution.contractVersion = contract.version;
194
+ execution.contract = contract;
195
+ return {
196
+ version: contract.version,
197
+ anchor: renderExecutionAnchor(execution),
198
+ value: contract,
199
+ };
200
+ },
201
+ /**
202
+ * 资源记账。累计值落在 `goal.usage`(事件溯源 + 持久化)而不是进程内 ——
203
+ * 断点续跑时账本重放**不会重新执行** agent/llm 调用,进程内计数会从 0 开始,
204
+ * 于是「已经花掉的钱」凭空消失、预算闸永远不触发。
205
+ *
206
+ * ⚠️ 上限取**最新契约**的 tokenBudget,而用量**累计不重置**:
207
+ * 「把预算从 10 万改到 20 万」因此是自然的「加预算继续跑」,
208
+ * 而不是偷偷把已花的清零。
209
+ */
210
+ recordUsage: async (input) => {
211
+ const latest = await runtime.get(scope);
212
+ if (!latest || latest.goalId !== execution.goalId) {
213
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
214
+ }
215
+ const updated = await runtime.recordUsage(scope, latest.goalId, latest.revision, { inputTokens: input.inputTokens, outputTokens: input.outputTokens });
216
+ return {
217
+ inputTokens: updated.usage.inputTokens,
218
+ outputTokens: updated.usage.outputTokens,
219
+ limit: runtime.currentContract(updated).tokenBudget ?? null,
220
+ };
221
+ },
222
+ finish: async (input) => {
223
+ const latest = await runtime.get(scope);
224
+ if (!latest || latest.goalId !== execution.goalId) {
225
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
226
+ }
227
+ const attempt = latest.attempts.find((item) => item.attemptId === execution.attemptId);
228
+ if (!attempt || attempt.status !== 'running')
229
+ return latest;
230
+ // Runner 传来的 status 是它自己视角的通用默认值(异常路径恒 'failed')——
231
+ // 它不认识 'budget_limited' 这种具体工作流结局,也不该认识(三层解耦)。
232
+ // 这里按 statusMapping.ts::OUTCOME_TO_ATTEMPT 把工作流自己贴在 Error 上的
233
+ // outcome 精化成真实该记的 attempt 状态:budget_limited 是主动停在安全边界、
234
+ // 现场完好可续跑,要记 'stopped' 而不是 'failed'——记成 'failed' 会让
235
+ // finishAttempt 把 Goal 派生成 blocked,而 TRANSITIONS 里根本没有
236
+ // blocked → budget_limited 这条边,budget_limited 永远到不了(此前正是这样:
237
+ // 状态在类型和 TRANSITIONS 里都声明了,却没有任何代码路径能真正推到它)。
238
+ const outcome = typeof input.outcome === 'string'
239
+ ? input.outcome : undefined;
240
+ const attemptStatus = outcome && Object.hasOwn(OUTCOME_TO_ATTEMPT, outcome)
241
+ ? OUTCOME_TO_ATTEMPT[outcome]
242
+ : input.status;
243
+ const finished = await runtime.finishAttempt({
244
+ scope,
245
+ expectedGoalId: latest.goalId,
246
+ expectedRevision: latest.revision,
247
+ attemptId: execution.attemptId,
248
+ status: attemptStatus,
249
+ artifacts: input.artifacts,
250
+ evidence: input.evidence,
251
+ blocker: input.blocker,
252
+ });
253
+ // ── 用户设的 token 预算用尽 → budget_limited ────────────────────
254
+ // finishAttempt 把 'stopped' 统一派生成 Goal.paused(与用户主动 action=pause
255
+ // 共用同一落点);这里识别出「这次 stopped 是因为预算」后再精化一步,
256
+ // 避免「用户暂停」与「系统按预算停」被压成同一个状态、桌面端分不清、
257
+ // 用户也不知道该不该加预算再续。
258
+ if (outcome === 'budget_limited' && finished.status === 'paused') {
259
+ return runtime.transition(scope, finished.goalId, finished.revision, 'budget_limited', { reason: input.blocker, actorId });
260
+ }
261
+ // ── 服务端配额/授权不给了 → usage_limited ──────────────────────
262
+ // 识别放在这里而不是具体工作流里:usage_limited 是 Goal 外层生命周期,
263
+ // 工作流只报告通用失败信息;Goal 状态本来就归控制器管理。
264
+ //
265
+ // ⚠️ 与 budget_limited 分工不同,别合并:
266
+ // budget_limited = 用户自己设的额度用完 → 加预算即可继续;
267
+ // usage_limited = 服务端配额/授权不给了 → 加预算没用,要去解决授权。
268
+ // attempt 失败会先把 Goal 推到 blocked;识别出配额类原因后再精化成
269
+ // usage_limited(TRANSITIONS 里显式允许这条精化边)。
270
+ if (input.status === 'failed' &&
271
+ isUsageLimitError(input.blocker ?? '') &&
272
+ finished.status === 'blocked') {
273
+ return runtime.transition(scope, finished.goalId, finished.revision, 'usage_limited', { reason: input.blocker, actorId });
274
+ }
275
+ return finished;
276
+ },
277
+ };
278
+ return {
279
+ handled: false,
280
+ events: [],
281
+ inputs: rawInputs,
282
+ execution: managedExecution,
283
+ bridge,
284
+ };
285
+ }
286
+ catch (caught) {
287
+ return error(caught instanceof GoalRuntimeError
288
+ ? caught.message
289
+ : `Goal Runtime 失败:${caught instanceof Error ? caught.message : String(caught)}`);
290
+ }
291
+ }
292
+ function renderExecutionAnchor(execution) {
293
+ const contract = execution.contract;
294
+ return [
295
+ `🎯 Goal ${execution.goalId} · 契约 v${contract.version}`,
296
+ `目标:${contract.objective}`,
297
+ contract.deliverables.length
298
+ ? `交付物:\n${contract.deliverables.map((item) => `- ${item}`).join('\n')}`
299
+ : '',
300
+ contract.acceptanceCriteria.length
301
+ ? `验收标准:\n${contract.acceptanceCriteria.map((item) => `- ${item}`).join('\n')}`
302
+ : '',
303
+ contract.scope ? `工作范围:${contract.scope}` : '',
304
+ '只有指定人类可以最终验收;Agent 只能提交可核查证据并进入待验收。',
305
+ ].filter(Boolean).join('\n\n');
306
+ }
@@ -0,0 +1,360 @@
1
+ import { createHash } from 'node:crypto';
2
+
3
+ import { isUsageLimitError } from '../llm/gatewayClient.js';
4
+ import type { AgentRuntimeContext, LoopEvent } from '../plugin-sdk.js';
5
+ import {
6
+ GoalRuntime,
7
+ GoalRuntimeError,
8
+ type Goal,
9
+ type GoalContractInput,
10
+ type GoalExecutionContext,
11
+ type GoalScope,
12
+ type GoalSource,
13
+ } from './index.js';
14
+ import { OUTCOME_TO_ATTEMPT, type WorkflowOutcome } from './statusMapping.js';
15
+ import type {
16
+ ManagedExecutionBridge,
17
+ ManagedExecutionContext,
18
+ PreparedManagedCommand,
19
+ } from '../managedExecution/types.js';
20
+
21
+ export interface GoalCommandOptions {
22
+ cwd: string;
23
+ runtimeContext?: AgentRuntimeContext;
24
+ actorId?: string;
25
+ acceptorHumanIds?: string[];
26
+ source?: GoalSource;
27
+ runtime?: GoalRuntime;
28
+ }
29
+
30
+ function scopeFor(options: GoalCommandOptions): GoalScope {
31
+ const workspaceId = options.runtimeContext?.workspaceId
32
+ ?? `path-${createHash('sha256').update(options.cwd).digest('hex').slice(0, 20)}`;
33
+ return {
34
+ workspaceId,
35
+ sessionId: options.runtimeContext?.sessionId?.trim() || 'default',
36
+ };
37
+ }
38
+
39
+ function criteriaFrom(inputs: Record<string, unknown>): string[] {
40
+ const checks = String(inputs.checks ?? '')
41
+ .split(',')
42
+ .map((item) => item.trim())
43
+ .filter(Boolean);
44
+ return checks.length > 0
45
+ ? checks
46
+ : ['按照确认的目标与交付物完成,并提供可检查的验证证据'];
47
+ }
48
+
49
+ function render(goal: Goal, runtime: GoalRuntime): string {
50
+ const contract = runtime.currentContract(goal);
51
+ const latest = goal.attempts.at(-1);
52
+ const lines = [
53
+ `Goal ${goal.goalId}`,
54
+ `状态:${goal.status}`,
55
+ `目标:${contract.objective}`,
56
+ `契约:v${contract.version} (${contract.hash.slice(0, 12)})`,
57
+ `执行:${goal.attempts.length} 次${latest ? `,最近 ${latest.status}` : ''}`,
58
+ ];
59
+ if (goal.statusReason) lines.push(`原因:${goal.statusReason}`);
60
+ if (goal.status === 'ready_for_acceptance') {
61
+ lines.push('成果已通过 Agent 自检,等待指定人类验收;Agent 不会自行标记完成。');
62
+ }
63
+ return `${lines.join('\n')}\n`;
64
+ }
65
+
66
+ function handled(goal: Goal, runtime: GoalRuntime, prefix?: string): PreparedManagedCommand {
67
+ return {
68
+ handled: true,
69
+ inputs: {},
70
+ events: [
71
+ { type: 'text', delta: `${prefix ? `${prefix}\n` : ''}${render(goal, runtime)}` },
72
+ { type: 'turn_done' },
73
+ ],
74
+ };
75
+ }
76
+
77
+ function error(message: string): PreparedManagedCommand {
78
+ return { handled: true, inputs: {}, events: [{ type: 'error', error: message }] };
79
+ }
80
+
81
+ /** `/workflow goal` 的外层生命周期控制;返回 execute=false 时不会进入脚本。 */
82
+ export async function prepareGoalCommand(
83
+ rawInputs: Record<string, unknown>,
84
+ options: GoalCommandOptions,
85
+ ): Promise<PreparedManagedCommand> {
86
+ const runtime = options.runtime ?? new GoalRuntime();
87
+ const scope = scopeFor(options);
88
+ const actorId = options.actorId ?? 'local-human';
89
+ const action = String(rawInputs.action ?? '').trim();
90
+ const objective = String(rawInputs.objective ?? '').trim();
91
+ let current = await runtime.get(scope);
92
+ const inferredSource: GoalSource | undefined = options.source ?? (
93
+ typeof rawInputs.group_id === 'string' && rawInputs.group_id.trim()
94
+ && typeof rawInputs.task_id === 'string' && rawInputs.task_id.trim()
95
+ ? {
96
+ kind: 'group-task',
97
+ groupId: rawInputs.group_id.trim(),
98
+ taskId: rawInputs.task_id.trim(),
99
+ ...(typeof rawInputs.agent_member_id === 'string' && rawInputs.agent_member_id.trim()
100
+ ? { assigneeAgentId: rawInputs.agent_member_id.trim() }
101
+ : {}),
102
+ }
103
+ : undefined
104
+ );
105
+
106
+ try {
107
+ if (action === 'status' || (!action && !objective)) {
108
+ return current
109
+ ? handled(current, runtime)
110
+ : error('当前 Session 没有 Goal。用 /workflow goal <目标> 创建。');
111
+ }
112
+
113
+ if (action === 'cancel') {
114
+ if (!current) return error('当前 Session 没有可取消的 Goal。');
115
+ current = await runtime.transition(scope, current.goalId, current.revision, 'cancelled', {
116
+ reason: String(rawInputs.reason ?? '用户取消'), actorId,
117
+ });
118
+ return handled(current, runtime, 'Goal 已取消,历史与产物仍保留。');
119
+ }
120
+
121
+ if (action === 'pause') {
122
+ if (!current) return error('当前 Session 没有可暂停的 Goal。');
123
+ current = await runtime.transition(scope, current.goalId, current.revision, 'paused', {
124
+ reason: String(rawInputs.reason ?? '用户暂停'), actorId,
125
+ });
126
+ return handled(current, runtime, 'Goal 已暂停,现场已保留。');
127
+ }
128
+
129
+ if (action === 'accept') {
130
+ if (!current) return error('当前 Session 没有待验收 Goal。');
131
+ current = await runtime.transition(scope, current.goalId, current.revision, 'accepted', { actorId });
132
+ return handled(current, runtime, '人类验收已通过。');
133
+ }
134
+
135
+ if (action === 'update') {
136
+ if (!current) return error('当前 Session 没有可更新的 Goal。');
137
+ if (!objective) return error('update 必须提供新的 objective。');
138
+ const patch: GoalContractInput = {
139
+ objective,
140
+ confirmedBy: actorId,
141
+ };
142
+ // 未提供 checks 时保留原验收标准;只有显式传入才替换。
143
+ if (Object.prototype.hasOwnProperty.call(rawInputs, 'checks')) {
144
+ patch.acceptanceCriteria = criteriaFrom(rawInputs);
145
+ }
146
+ // 预算也是版本化契约的一部分。显式传 0/非法值表示清除预算;未传时
147
+ // 由 Runtime 的合并规则保留旧值,避免 update 误清空预算。
148
+ if (Object.prototype.hasOwnProperty.call(rawInputs, 'token_budget')) {
149
+ const budget = Number(rawInputs.token_budget);
150
+ patch.tokenBudget = Number.isFinite(budget) && budget > 0 ? budget : null;
151
+ }
152
+ current = await runtime.revise(scope, current.goalId, current.revision, patch);
153
+ } else if (action === 'resume' || action === 'rework') {
154
+ if (!current) return error('当前 Session 没有可继续的 Goal。');
155
+ current = await runtime.transition(scope, current.goalId, current.revision, 'active', {
156
+ reason: action === 'rework'
157
+ ? String(rawInputs.reason ?? '人类要求返工')
158
+ : '用户继续执行',
159
+ actorId,
160
+ });
161
+ rawInputs.objective = runtime.currentContract(current).objective;
162
+ } else if (action && action !== 'start') {
163
+ return error(`未知 Goal action:${action}`);
164
+ } else if (!current || current.status === 'accepted' || current.status === 'cancelled') {
165
+ if (!objective) return error('创建 Goal 必须提供 objective。');
166
+ current = await runtime.create({
167
+ scope,
168
+ contract: {
169
+ objective,
170
+ acceptanceCriteria: criteriaFrom(rawInputs),
171
+ confirmedBy: actorId,
172
+ },
173
+ source: inferredSource,
174
+ createdBy: actorId,
175
+ acceptorHumanIds: options.acceptorHumanIds ?? [actorId],
176
+ });
177
+ } else {
178
+ const existingObjective = runtime.currentContract(current).objective;
179
+ if (existingObjective !== objective) {
180
+ return error(
181
+ `当前 Session 已有未完成 Goal「${existingObjective}」。` +
182
+ '请用 --input action=update 显式修改,或先 action=cancel。',
183
+ );
184
+ }
185
+ if (current.status !== 'active') return handled(current, runtime);
186
+ }
187
+
188
+ // 除非这次调用显式传了新预算,否则沿用当前契约里已有的预算 ——
189
+ // workflow.mjs 每次都无条件把 args.token_budget 写进新契约版本(预算挂在
190
+ // 版本化契约上是刻意设计,见脚本内注释),如果这里不兜底,任何一次「不带
191
+ // token_budget 重跑」(resume/rework/update,甚至只是同目标再跑一轮)都会把
192
+ // 预算悄悄写成 null(不限),「用尽后加预算续跑」的断点设计就形同虚设——
193
+ // 用户以为在续跑同一个受限任务,实际上预算闸已经被静默关掉了。
194
+ if (
195
+ !Object.prototype.hasOwnProperty.call(rawInputs, 'token_budget') &&
196
+ !(Number(rawInputs.token_budget) > 0)
197
+ ) {
198
+ const existingBudget = runtime.currentContract(current).tokenBudget;
199
+ if (typeof existingBudget === 'number' && existingBudget > 0) {
200
+ rawInputs.token_budget = existingBudget;
201
+ }
202
+ }
203
+
204
+ const started = await runtime.startAttempt(scope, current.goalId, current.revision, 'goal');
205
+ current = started.goal;
206
+ const execution = started.execution;
207
+ const managedExecution: ManagedExecutionContext = {
208
+ executionId: execution.goalId,
209
+ version: execution.contractVersion,
210
+ runId: execution.attemptId,
211
+ anchor: renderExecutionAnchor(execution),
212
+ correlations: {
213
+ ...(execution.groupId ? { groupId: execution.groupId } : {}),
214
+ ...(execution.taskId ? { taskId: execution.taskId } : {}),
215
+ },
216
+ };
217
+ const bridge: ManagedExecutionBridge = {
218
+ updateContract: async (rawInput) => {
219
+ const input = rawInput as GoalContractInput;
220
+ const latest = await runtime.get(scope);
221
+ if (!latest || latest.goalId !== execution.goalId) {
222
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
223
+ }
224
+ const updated = await runtime.materializeAttemptContract(
225
+ scope, latest.goalId, latest.revision, execution.attemptId,
226
+ { ...input, confirmedBy: actorId },
227
+ );
228
+ const contract = runtime.currentContract(updated);
229
+ execution.contractVersion = contract.version;
230
+ execution.contract = contract;
231
+ return {
232
+ version: contract.version,
233
+ anchor: renderExecutionAnchor(execution),
234
+ value: contract,
235
+ };
236
+ },
237
+ /**
238
+ * 资源记账。累计值落在 `goal.usage`(事件溯源 + 持久化)而不是进程内 ——
239
+ * 断点续跑时账本重放**不会重新执行** agent/llm 调用,进程内计数会从 0 开始,
240
+ * 于是「已经花掉的钱」凭空消失、预算闸永远不触发。
241
+ *
242
+ * ⚠️ 上限取**最新契约**的 tokenBudget,而用量**累计不重置**:
243
+ * 「把预算从 10 万改到 20 万」因此是自然的「加预算继续跑」,
244
+ * 而不是偷偷把已花的清零。
245
+ */
246
+ recordUsage: async (input) => {
247
+ const latest = await runtime.get(scope);
248
+ if (!latest || latest.goalId !== execution.goalId) {
249
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
250
+ }
251
+ const updated = await runtime.recordUsage(
252
+ scope,
253
+ latest.goalId,
254
+ latest.revision,
255
+ { inputTokens: input.inputTokens, outputTokens: input.outputTokens },
256
+ );
257
+ return {
258
+ inputTokens: updated.usage.inputTokens,
259
+ outputTokens: updated.usage.outputTokens,
260
+ limit: runtime.currentContract(updated).tokenBudget ?? null,
261
+ };
262
+ },
263
+ finish: async (input) => {
264
+ const latest = await runtime.get(scope);
265
+ if (!latest || latest.goalId !== execution.goalId) {
266
+ throw new GoalRuntimeError('GOAL_NOT_FOUND', 'Goal 在执行期间已改变。');
267
+ }
268
+ const attempt = latest.attempts.find((item) => item.attemptId === execution.attemptId);
269
+ if (!attempt || attempt.status !== 'running') return latest;
270
+
271
+ // Runner 传来的 status 是它自己视角的通用默认值(异常路径恒 'failed')——
272
+ // 它不认识 'budget_limited' 这种具体工作流结局,也不该认识(三层解耦)。
273
+ // 这里按 statusMapping.ts::OUTCOME_TO_ATTEMPT 把工作流自己贴在 Error 上的
274
+ // outcome 精化成真实该记的 attempt 状态:budget_limited 是主动停在安全边界、
275
+ // 现场完好可续跑,要记 'stopped' 而不是 'failed'——记成 'failed' 会让
276
+ // finishAttempt 把 Goal 派生成 blocked,而 TRANSITIONS 里根本没有
277
+ // blocked → budget_limited 这条边,budget_limited 永远到不了(此前正是这样:
278
+ // 状态在类型和 TRANSITIONS 里都声明了,却没有任何代码路径能真正推到它)。
279
+ const outcome = typeof input.outcome === 'string'
280
+ ? (input.outcome as WorkflowOutcome) : undefined;
281
+ const attemptStatus = outcome && Object.hasOwn(OUTCOME_TO_ATTEMPT, outcome)
282
+ ? OUTCOME_TO_ATTEMPT[outcome]
283
+ : input.status;
284
+
285
+ const finished = await runtime.finishAttempt({
286
+ scope,
287
+ expectedGoalId: latest.goalId,
288
+ expectedRevision: latest.revision,
289
+ attemptId: execution.attemptId,
290
+ status: attemptStatus,
291
+ artifacts: input.artifacts,
292
+ evidence: input.evidence,
293
+ blocker: input.blocker,
294
+ });
295
+
296
+ // ── 用户设的 token 预算用尽 → budget_limited ────────────────────
297
+ // finishAttempt 把 'stopped' 统一派生成 Goal.paused(与用户主动 action=pause
298
+ // 共用同一落点);这里识别出「这次 stopped 是因为预算」后再精化一步,
299
+ // 避免「用户暂停」与「系统按预算停」被压成同一个状态、桌面端分不清、
300
+ // 用户也不知道该不该加预算再续。
301
+ if (outcome === 'budget_limited' && finished.status === 'paused') {
302
+ return runtime.transition(
303
+ scope, finished.goalId, finished.revision, 'budget_limited',
304
+ { reason: input.blocker, actorId },
305
+ );
306
+ }
307
+
308
+ // ── 服务端配额/授权不给了 → usage_limited ──────────────────────
309
+ // 识别放在这里而不是具体工作流里:usage_limited 是 Goal 外层生命周期,
310
+ // 工作流只报告通用失败信息;Goal 状态本来就归控制器管理。
311
+ //
312
+ // ⚠️ 与 budget_limited 分工不同,别合并:
313
+ // budget_limited = 用户自己设的额度用完 → 加预算即可继续;
314
+ // usage_limited = 服务端配额/授权不给了 → 加预算没用,要去解决授权。
315
+ // attempt 失败会先把 Goal 推到 blocked;识别出配额类原因后再精化成
316
+ // usage_limited(TRANSITIONS 里显式允许这条精化边)。
317
+ if (
318
+ input.status === 'failed' &&
319
+ isUsageLimitError(input.blocker ?? '') &&
320
+ finished.status === 'blocked'
321
+ ) {
322
+ return runtime.transition(
323
+ scope, finished.goalId, finished.revision, 'usage_limited',
324
+ { reason: input.blocker, actorId },
325
+ );
326
+ }
327
+ return finished;
328
+ },
329
+ };
330
+ return {
331
+ handled: false,
332
+ events: [],
333
+ inputs: rawInputs,
334
+ execution: managedExecution,
335
+ bridge,
336
+ };
337
+ } catch (caught) {
338
+ return error(
339
+ caught instanceof GoalRuntimeError
340
+ ? caught.message
341
+ : `Goal Runtime 失败:${caught instanceof Error ? caught.message : String(caught)}`,
342
+ );
343
+ }
344
+ }
345
+
346
+ function renderExecutionAnchor(execution: GoalExecutionContext): string {
347
+ const contract = execution.contract;
348
+ return [
349
+ `🎯 Goal ${execution.goalId} · 契约 v${contract.version}`,
350
+ `目标:${contract.objective}`,
351
+ contract.deliverables.length
352
+ ? `交付物:\n${contract.deliverables.map((item) => `- ${item}`).join('\n')}`
353
+ : '',
354
+ contract.acceptanceCriteria.length
355
+ ? `验收标准:\n${contract.acceptanceCriteria.map((item) => `- ${item}`).join('\n')}`
356
+ : '',
357
+ contract.scope ? `工作范围:${contract.scope}` : '',
358
+ '只有指定人类可以最终验收;Agent 只能提交可核查证据并进入待验收。',
359
+ ].filter(Boolean).join('\n\n');
360
+ }
@@ -27,6 +27,8 @@ export class EvidenceLedger {
27
27
  #toolCalls = 0;
28
28
  #failedToolCalls = 0;
29
29
  record(toolName, argsJson, result) {
30
+ if (!result.ok && result.disposition === 'deferred')
31
+ return;
30
32
  this.#toolCalls += 1;
31
33
  if (!result.ok)
32
34
  this.#failedToolCalls += 1;