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
@@ -59,7 +59,7 @@ import {
59
59
  worktreeChangedFiles,
60
60
  worktreeDiffStat,
61
61
  } from './worktree.js';
62
- import { appendAgentEvent, loadAgentRecord, saveAgentRecord, type AgentTaskRecord, type LiveAgentTask } from './agentTaskService.js';
62
+ import { appendAgentEvent, attachAgentHistory, loadAgentRecord, saveAgentRecord, type AgentTaskRecord, type LiveAgentTask } from './agentTaskService.js';
63
63
 
64
64
  // ---------------- 0. 环内模块懒加载(见文件头「循环依赖纪律」) ----------------
65
65
 
@@ -120,7 +120,7 @@ const inputSchema = z.object({
120
120
  run_in_background: z.boolean().optional().describe('立即返回 agent_id,子任务在后台运行;用 TaskOutput/TaskStop 管理'),
121
121
  resume_agent_id: z.string().regex(/^agent_[0-9a-f-]{36}$/i).optional().describe('继续当前会话中此前完成、中断或失败的 Agent 历史'),
122
122
  });
123
- type AgentInput = z.infer<typeof inputSchema>;
123
+ export type AgentInput = z.infer<typeof inputSchema>;
124
124
 
125
125
  const parameters = toToolParameters(inputSchema);
126
126
 
@@ -227,7 +227,8 @@ export interface AgentTaskDeps {
227
227
  chat?: RunQueryOptions['chat'];
228
228
  executeTool?: RunQueryOptions['executeTool'];
229
229
  initialHistory?: RunQueryOptions['history'];
230
- captureHistory?: (history:RunQueryOptions['history'])=>void|Promise<void>;
230
+ captureHistory?: (history: RunQueryOptions['history']) => void | Promise<void>;
231
+ onHistoryReady?: (history: RunQueryOptions['history']) => void;
231
232
  existingWorktree?: AgentWorktree;
232
233
  onWorktreeCreated?: (worktree: AgentWorktree) => void | Promise<void>;
233
234
  }
@@ -296,7 +297,10 @@ export async function runAgentTask(
296
297
  const { runQuery, ALL_TOOLS, executeTool } = await loadCore();
297
298
 
298
299
  const def = resolveAgentType(input.agent_type);
299
- // 轮数上限:AGENT_TOOL_MAX_TURNS 可统一覆盖两种类型(默认 explore 50 / general 100)。
300
+ // 轮数上限:AGENT_TOOL_MAX_TURNS 可统一覆盖两种类型。默认值的唯一真值在
301
+ // config/configDefaults.ts::DEFAULT_SUBAGENTS_CONFIG(现为 explore 200 / general 100,
302
+ // 那里写了「只读的给宽、能写的给窄」的理由)。这条注释以前写着「explore 50」,
303
+ // 而代码早已是 200 —— 注释里复述数字必然漂移,所以现在只留指针。
300
304
  const maxTurns = positiveInt(process.env.AGENT_TOOL_MAX_TURNS)
301
305
  ?? (def.type === 'explore' ? ctx.subagentConfig?.exploreMaxTurns : ctx.subagentConfig?.generalMaxTurns)
302
306
  ?? def.maxTurns;
@@ -377,6 +381,7 @@ export async function runAgentTask(
377
381
  const history: RunQueryOptions['history'] = deps.initialHistory?.length ? [...deps.initialHistory] : [
378
382
  { role: 'system', content: await buildSubSystemPrompt(cwd, def, subTools) },
379
383
  ];
384
+ deps.onHistoryReady?.(history);
380
385
  const historyLenBefore = history.length;
381
386
  const maxConcurrent = positiveInt(process.env.AGENT_TOOL_MAX_CONCURRENT) ?? ctx.subagentConfig?.maxConcurrent ?? 3;
382
387
  let releaseLease: (() => void) | null = null;
@@ -469,8 +474,8 @@ export async function runAgentTask(
469
474
  let parsed: Record<string, unknown> = {};
470
475
  try { parsed = JSON.parse(args) as Record<string, unknown>; } catch { /* executeTool will report malformed input */ }
471
476
  const rawPath = typeof parsed.file_path === 'string' ? parsed.file_path : typeof parsed.path === 'string' ? parsed.path : undefined;
472
- if (def.type === 'general' && !wt && name === 'Bash' && writeScopes[0] !== rootScope[0]) {
473
- return { ok: false as const, error: '声明了局部 write_scopes 时禁止 Bash:无法可靠证明命令只写入批准范围。请改用文件工具或使用整个工作目录范围。' };
477
+ if (def.type === 'general' && !wt && ['Bash', 'ApplyPatch'].includes(name) && writeScopes[0] !== rootScope[0]) {
478
+ return { ok: false as const, error: `声明了局部 write_scopes 时禁止 ${name}:无法可靠证明一次调用只写入批准范围。请改用单文件工具或使用整个工作目录范围。` };
474
479
  }
475
480
  if (def.type === 'general' && rawPath) {
476
481
  if (isAbsolute(rawPath)) return { ok: false as const, error: `${name} 必须使用工作目录相对路径:${rawPath}` };
@@ -483,7 +488,14 @@ export async function runAgentTask(
483
488
  changedFiles.add(relative(cwd, resolve(cwd, rawPath)).split(sep).join('/'));
484
489
  }
485
490
  }
486
- return baseExecute(name, args, s, c);
491
+ const result = await baseExecute(name, args, s, c);
492
+ if (result.metadata?.kind === 'file_activity') {
493
+ for (const file of result.metadata.files) {
494
+ if (['created', 'modified', 'generated', 'deleted'].includes(file.activity))
495
+ changedFiles.add(file.relativePath);
496
+ }
497
+ }
498
+ return result;
487
499
  };
488
500
 
489
501
  // ---- 事件消费:子 LoopEvent 一律不外泄,折算成统计 + 步内进度 ----
@@ -737,6 +749,7 @@ export async function runManagedAgentTask(
737
749
  abort,
738
750
  completion,
739
751
  events: new EventEmitter(),
752
+ inbox: [],
740
753
  };
741
754
  ctx.sessionState.agentTasks.tasks.set(id, task);
742
755
  await saveAgentRecord(ctx, task);
@@ -769,6 +782,7 @@ export async function runManagedAgentTask(
769
782
  await saveAgentRecord(ctx, task);
770
783
  },
771
784
  captureHistory: (history) => { captured = [...history]; },
785
+ onHistoryReady: (history) => attachAgentHistory(task, history),
772
786
  });
773
787
  task.result = result;
774
788
  task.history = captured;
@@ -0,0 +1,246 @@
1
+ import { z } from 'zod';
2
+ import { toToolParameters } from '../../utils/zodToJson.js';
3
+ import { runManagedAgentTask } from './agent.js';
4
+ import { appendAgentEvent, enqueueAgentMessage, getLiveAgentTask, listAgentRecords, loadAgentRecord, saveAgentRecord, } from './agentTaskService.js';
5
+ const agentId = z.string().regex(/^agent_[0-9a-f-]{36}$/i);
6
+ function needsContext(context) {
7
+ if (!context.sessionState)
8
+ return { ok: false, error: 'Agent 控制工具需要当前 Session 运行状态。' };
9
+ return undefined;
10
+ }
11
+ function snapshot(record) {
12
+ return {
13
+ agent_id: record.id,
14
+ status: record.status,
15
+ description: record.description,
16
+ progress: record.progress,
17
+ created_at: record.createdAt,
18
+ updated_at: record.updatedAt,
19
+ result: record.result
20
+ ? record.result.ok
21
+ ? record.result.content.slice(0, 4_000)
22
+ : `Error: ${record.result.error.slice(0, 4_000)}`
23
+ : undefined,
24
+ };
25
+ }
26
+ const messageSchema = z.object({
27
+ agent_id: agentId,
28
+ message: z.string().min(1).max(100_000),
29
+ });
30
+ export const agentMessageTool = {
31
+ name: 'AgentMessage',
32
+ description: 'Sends additional context or a correction to one running sub-agent by stable agent_id. ' +
33
+ 'The message is inserted at the next model boundary without cancelling its current tool call. ' +
34
+ 'Use AgentFollowup instead when the agent is already idle or completed.',
35
+ inputSchema: messageSchema,
36
+ parameters: toToolParameters(messageSchema),
37
+ isReadOnly: false,
38
+ isConcurrencySafe: true,
39
+ call: async () => ({
40
+ ok: false,
41
+ error: 'AgentMessage requires session context',
42
+ }),
43
+ callWithContext: async (input, _signal, context) => {
44
+ const missing = needsContext(context);
45
+ if (missing)
46
+ return missing;
47
+ const task = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
48
+ if (!task || task.status !== 'running') {
49
+ const saved = await loadAgentRecord(context, input.agent_id);
50
+ return saved
51
+ ? {
52
+ ok: false,
53
+ error: `Agent ${input.agent_id} 当前为 ${saved.status};请使用 AgentFollowup 启动后续回合。`,
54
+ }
55
+ : { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
56
+ }
57
+ enqueueAgentMessage(task, input.message);
58
+ await saveAgentRecord(context, task);
59
+ await appendAgentEvent(context, task.id, {
60
+ phase: 'message',
61
+ message: input.message,
62
+ });
63
+ return {
64
+ ok: true,
65
+ content: `消息已发送给 ${task.id},将在下一个模型边界生效。`,
66
+ };
67
+ },
68
+ };
69
+ const listSchema = z.object({
70
+ include_completed: z.boolean().optional(),
71
+ });
72
+ export const agentListTool = {
73
+ name: 'AgentList',
74
+ description: 'Lists sub-agents owned by the current Session, including stable IDs, status and latest progress.',
75
+ inputSchema: listSchema,
76
+ parameters: toToolParameters(listSchema),
77
+ isReadOnly: true,
78
+ isConcurrencySafe: true,
79
+ call: async () => ({
80
+ ok: false,
81
+ error: 'AgentList requires session context',
82
+ }),
83
+ callWithContext: async (input, _signal, context) => {
84
+ const missing = needsContext(context);
85
+ if (missing)
86
+ return missing;
87
+ const records = (await listAgentRecords(context)).filter((record) => input.include_completed !== false || record.status === 'running');
88
+ return {
89
+ ok: true,
90
+ content: records.length
91
+ ? JSON.stringify(records.map(snapshot), null, 2)
92
+ : '当前 Session 没有符合条件的子 Agent。',
93
+ };
94
+ },
95
+ };
96
+ const waitSchema = z.object({
97
+ agent_ids: z.array(agentId).min(1).max(8),
98
+ timeout_ms: z.number().int().min(0).max(120_000).optional(),
99
+ });
100
+ export const agentWaitTool = {
101
+ name: 'AgentWait',
102
+ description: 'Waits efficiently until any selected running sub-agent finishes or the timeout expires, then returns fresh snapshots for all selected IDs. Do not poll repeatedly.',
103
+ inputSchema: waitSchema,
104
+ parameters: toToolParameters(waitSchema),
105
+ isReadOnly: true,
106
+ isConcurrencySafe: true,
107
+ interruptBehavior: () => 'cancel',
108
+ call: async () => ({
109
+ ok: false,
110
+ error: 'AgentWait requires session context',
111
+ }),
112
+ callWithContext: async (input, signal, context) => {
113
+ const missing = needsContext(context);
114
+ if (missing)
115
+ return missing;
116
+ const live = input.agent_ids
117
+ .map((id) => getLiveAgentTask(context.sessionState.agentTasks, id))
118
+ .filter((task) => Boolean(task?.status === 'running'));
119
+ const timeoutMs = input.timeout_ms ?? 30_000;
120
+ if (live.length && timeoutMs > 0) {
121
+ let timer;
122
+ let onAbort;
123
+ const timeout = new Promise((resolve) => {
124
+ timer = setTimeout(resolve, timeoutMs);
125
+ timer.unref?.();
126
+ });
127
+ const aborted = new Promise((resolve) => {
128
+ if (!signal)
129
+ return;
130
+ onAbort = () => resolve();
131
+ if (signal.aborted)
132
+ resolve();
133
+ else
134
+ signal.addEventListener('abort', onAbort, { once: true });
135
+ });
136
+ await Promise.race([
137
+ ...live.map((task) => task.completion),
138
+ timeout,
139
+ aborted,
140
+ ]);
141
+ if (timer)
142
+ clearTimeout(timer);
143
+ if (signal && onAbort)
144
+ signal.removeEventListener('abort', onAbort);
145
+ if (signal?.aborted)
146
+ return { ok: false, error: 'aborted' };
147
+ }
148
+ const records = [];
149
+ const missingIds = [];
150
+ for (const id of input.agent_ids) {
151
+ const record = getLiveAgentTask(context.sessionState.agentTasks, id) ??
152
+ (await loadAgentRecord(context, id));
153
+ if (record)
154
+ records.push(record);
155
+ else
156
+ missingIds.push(id);
157
+ }
158
+ return {
159
+ ok: true,
160
+ content: JSON.stringify({ agents: records.map(snapshot), missing: missingIds }, null, 2),
161
+ };
162
+ },
163
+ };
164
+ const interruptSchema = z.object({ agent_id: agentId });
165
+ export const agentInterruptTool = {
166
+ name: 'AgentInterrupt',
167
+ description: 'Interrupts one running sub-agent owned by the current Session. Its private history, progress and worktree are preserved for a later AgentFollowup.',
168
+ inputSchema: interruptSchema,
169
+ parameters: toToolParameters(interruptSchema),
170
+ isReadOnly: false,
171
+ isConcurrencySafe: true,
172
+ call: async () => ({
173
+ ok: false,
174
+ error: 'AgentInterrupt requires session context',
175
+ }),
176
+ callWithContext: async (input, _signal, context) => {
177
+ const missing = needsContext(context);
178
+ if (missing)
179
+ return missing;
180
+ const live = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
181
+ if (!live || live.status !== 'running') {
182
+ const saved = await loadAgentRecord(context, input.agent_id);
183
+ return saved
184
+ ? {
185
+ ok: true,
186
+ content: `Agent ${input.agent_id} 已经是 ${saved.status},未执行中断。`,
187
+ }
188
+ : { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
189
+ }
190
+ const previous = live.status;
191
+ live.abort.abort(new Error('interrupted-by-parent-agent'));
192
+ await Promise.race([
193
+ live.completion,
194
+ new Promise((resolve) => setTimeout(resolve, 5_000)),
195
+ ]);
196
+ return {
197
+ ok: true,
198
+ content: `已中断 ${live.id}(先前状态:${previous};当前状态:${live.status})。`,
199
+ };
200
+ },
201
+ };
202
+ const followupSchema = z.object({
203
+ agent_id: agentId,
204
+ message: z.string().min(1).max(100_000),
205
+ run_in_background: z.boolean().optional(),
206
+ });
207
+ export const agentFollowupTool = {
208
+ name: 'AgentFollowup',
209
+ description: 'Adds a follow-up task to a stable sub-agent. If it is running, delivers the message at the next model boundary; if idle, resumes its persisted private history and starts a new turn.',
210
+ inputSchema: followupSchema,
211
+ parameters: toToolParameters(followupSchema),
212
+ isReadOnly: false,
213
+ isConcurrencySafe: true,
214
+ interruptBehavior: () => 'block',
215
+ call: async () => ({
216
+ ok: false,
217
+ error: 'AgentFollowup requires session context',
218
+ }),
219
+ callWithContext: async (input, signal, context) => {
220
+ const missing = needsContext(context);
221
+ if (missing)
222
+ return missing;
223
+ const live = getLiveAgentTask(context.sessionState.agentTasks, input.agent_id);
224
+ if (live?.status === 'running') {
225
+ enqueueAgentMessage(live, input.message);
226
+ await saveAgentRecord(context, live);
227
+ await appendAgentEvent(context, live.id, {
228
+ phase: 'followup',
229
+ message: input.message,
230
+ });
231
+ return { ok: true, content: `后续任务已发送给运行中的 ${live.id}。` };
232
+ }
233
+ const saved = await loadAgentRecord(context, input.agent_id);
234
+ if (!saved)
235
+ return {
236
+ ok: false,
237
+ error: `当前 Session 中不存在 Agent ${input.agent_id}`,
238
+ };
239
+ return runManagedAgentTask({
240
+ description: saved.description,
241
+ prompt: input.message,
242
+ resume_agent_id: input.agent_id,
243
+ run_in_background: input.run_in_background ?? true,
244
+ }, signal, context);
245
+ },
246
+ };
@@ -0,0 +1,284 @@
1
+ import { z } from 'zod';
2
+
3
+ import type { Tool, ToolCallContext, ToolResult } from '../../types.js';
4
+ import { toToolParameters } from '../../utils/zodToJson.js';
5
+ import { runManagedAgentTask } from './agent.js';
6
+ import {
7
+ type AgentTaskRecord,
8
+ appendAgentEvent,
9
+ enqueueAgentMessage,
10
+ getLiveAgentTask,
11
+ listAgentRecords,
12
+ loadAgentRecord,
13
+ saveAgentRecord,
14
+ } from './agentTaskService.js';
15
+
16
+ const agentId = z.string().regex(/^agent_[0-9a-f-]{36}$/i);
17
+
18
+ function needsContext(context: ToolCallContext): ToolResult | undefined {
19
+ if (!context.sessionState)
20
+ return { ok: false, error: 'Agent 控制工具需要当前 Session 运行状态。' };
21
+ return undefined;
22
+ }
23
+
24
+ function snapshot(record: AgentTaskRecord) {
25
+ return {
26
+ agent_id: record.id,
27
+ status: record.status,
28
+ description: record.description,
29
+ progress: record.progress,
30
+ created_at: record.createdAt,
31
+ updated_at: record.updatedAt,
32
+ result: record.result
33
+ ? record.result.ok
34
+ ? record.result.content.slice(0, 4_000)
35
+ : `Error: ${record.result.error.slice(0, 4_000)}`
36
+ : undefined,
37
+ };
38
+ }
39
+
40
+ const messageSchema = z.object({
41
+ agent_id: agentId,
42
+ message: z.string().min(1).max(100_000),
43
+ });
44
+
45
+ export const agentMessageTool: Tool<z.infer<typeof messageSchema>> = {
46
+ name: 'AgentMessage',
47
+ description:
48
+ 'Sends additional context or a correction to one running sub-agent by stable agent_id. ' +
49
+ 'The message is inserted at the next model boundary without cancelling its current tool call. ' +
50
+ 'Use AgentFollowup instead when the agent is already idle or completed.',
51
+ inputSchema: messageSchema,
52
+ parameters: toToolParameters(messageSchema),
53
+ isReadOnly: false,
54
+ isConcurrencySafe: true,
55
+ call: async () => ({
56
+ ok: false,
57
+ error: 'AgentMessage requires session context',
58
+ }),
59
+ callWithContext: async (input, _signal, context) => {
60
+ const missing = needsContext(context);
61
+ if (missing) return missing;
62
+ const task = getLiveAgentTask(
63
+ context.sessionState!.agentTasks,
64
+ input.agent_id,
65
+ );
66
+ if (!task || task.status !== 'running') {
67
+ const saved = await loadAgentRecord(context, input.agent_id);
68
+ return saved
69
+ ? {
70
+ ok: false,
71
+ error: `Agent ${input.agent_id} 当前为 ${saved.status};请使用 AgentFollowup 启动后续回合。`,
72
+ }
73
+ : { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
74
+ }
75
+ enqueueAgentMessage(task, input.message);
76
+ await saveAgentRecord(context, task);
77
+ await appendAgentEvent(context, task.id, {
78
+ phase: 'message',
79
+ message: input.message,
80
+ });
81
+ return {
82
+ ok: true,
83
+ content: `消息已发送给 ${task.id},将在下一个模型边界生效。`,
84
+ };
85
+ },
86
+ };
87
+
88
+ const listSchema = z.object({
89
+ include_completed: z.boolean().optional(),
90
+ });
91
+
92
+ export const agentListTool: Tool<z.infer<typeof listSchema>> = {
93
+ name: 'AgentList',
94
+ description:
95
+ 'Lists sub-agents owned by the current Session, including stable IDs, status and latest progress.',
96
+ inputSchema: listSchema,
97
+ parameters: toToolParameters(listSchema),
98
+ isReadOnly: true,
99
+ isConcurrencySafe: true,
100
+ call: async () => ({
101
+ ok: false,
102
+ error: 'AgentList requires session context',
103
+ }),
104
+ callWithContext: async (input, _signal, context) => {
105
+ const missing = needsContext(context);
106
+ if (missing) return missing;
107
+ const records = (await listAgentRecords(context)).filter(
108
+ (record) =>
109
+ input.include_completed !== false || record.status === 'running',
110
+ );
111
+ return {
112
+ ok: true,
113
+ content: records.length
114
+ ? JSON.stringify(records.map(snapshot), null, 2)
115
+ : '当前 Session 没有符合条件的子 Agent。',
116
+ };
117
+ },
118
+ };
119
+
120
+ const waitSchema = z.object({
121
+ agent_ids: z.array(agentId).min(1).max(8),
122
+ timeout_ms: z.number().int().min(0).max(120_000).optional(),
123
+ });
124
+
125
+ export const agentWaitTool: Tool<z.infer<typeof waitSchema>> = {
126
+ name: 'AgentWait',
127
+ description:
128
+ 'Waits efficiently until any selected running sub-agent finishes or the timeout expires, then returns fresh snapshots for all selected IDs. Do not poll repeatedly.',
129
+ inputSchema: waitSchema,
130
+ parameters: toToolParameters(waitSchema),
131
+ isReadOnly: true,
132
+ isConcurrencySafe: true,
133
+ interruptBehavior: () => 'cancel',
134
+ call: async () => ({
135
+ ok: false,
136
+ error: 'AgentWait requires session context',
137
+ }),
138
+ callWithContext: async (input, signal, context) => {
139
+ const missing = needsContext(context);
140
+ if (missing) return missing;
141
+ const live = input.agent_ids
142
+ .map((id) => getLiveAgentTask(context.sessionState!.agentTasks, id))
143
+ .filter((task): task is NonNullable<typeof task> =>
144
+ Boolean(task?.status === 'running'),
145
+ );
146
+ const timeoutMs = input.timeout_ms ?? 30_000;
147
+ if (live.length && timeoutMs > 0) {
148
+ let timer: ReturnType<typeof setTimeout> | undefined;
149
+ let onAbort: (() => void) | undefined;
150
+ const timeout = new Promise<void>((resolve) => {
151
+ timer = setTimeout(resolve, timeoutMs);
152
+ timer.unref?.();
153
+ });
154
+ const aborted = new Promise<void>((resolve) => {
155
+ if (!signal) return;
156
+ onAbort = () => resolve();
157
+ if (signal.aborted) resolve();
158
+ else signal.addEventListener('abort', onAbort, { once: true });
159
+ });
160
+ await Promise.race([
161
+ ...live.map((task) => task.completion),
162
+ timeout,
163
+ aborted,
164
+ ]);
165
+ if (timer) clearTimeout(timer);
166
+ if (signal && onAbort) signal.removeEventListener('abort', onAbort);
167
+ if (signal?.aborted) return { ok: false, error: 'aborted' };
168
+ }
169
+ const records: AgentTaskRecord[] = [];
170
+ const missingIds: string[] = [];
171
+ for (const id of input.agent_ids) {
172
+ const record =
173
+ getLiveAgentTask(context.sessionState!.agentTasks, id) ??
174
+ (await loadAgentRecord(context, id));
175
+ if (record) records.push(record);
176
+ else missingIds.push(id);
177
+ }
178
+ return {
179
+ ok: true,
180
+ content: JSON.stringify(
181
+ { agents: records.map(snapshot), missing: missingIds },
182
+ null,
183
+ 2,
184
+ ),
185
+ };
186
+ },
187
+ };
188
+
189
+ const interruptSchema = z.object({ agent_id: agentId });
190
+
191
+ export const agentInterruptTool: Tool<z.infer<typeof interruptSchema>> = {
192
+ name: 'AgentInterrupt',
193
+ description:
194
+ 'Interrupts one running sub-agent owned by the current Session. Its private history, progress and worktree are preserved for a later AgentFollowup.',
195
+ inputSchema: interruptSchema,
196
+ parameters: toToolParameters(interruptSchema),
197
+ isReadOnly: false,
198
+ isConcurrencySafe: true,
199
+ call: async () => ({
200
+ ok: false,
201
+ error: 'AgentInterrupt requires session context',
202
+ }),
203
+ callWithContext: async (input, _signal, context) => {
204
+ const missing = needsContext(context);
205
+ if (missing) return missing;
206
+ const live = getLiveAgentTask(
207
+ context.sessionState!.agentTasks,
208
+ input.agent_id,
209
+ );
210
+ if (!live || live.status !== 'running') {
211
+ const saved = await loadAgentRecord(context, input.agent_id);
212
+ return saved
213
+ ? {
214
+ ok: true,
215
+ content: `Agent ${input.agent_id} 已经是 ${saved.status},未执行中断。`,
216
+ }
217
+ : { ok: false, error: `当前 Session 中不存在 Agent ${input.agent_id}` };
218
+ }
219
+ const previous = live.status;
220
+ live.abort.abort(new Error('interrupted-by-parent-agent'));
221
+ await Promise.race([
222
+ live.completion,
223
+ new Promise<void>((resolve) => setTimeout(resolve, 5_000)),
224
+ ]);
225
+ return {
226
+ ok: true,
227
+ content: `已中断 ${live.id}(先前状态:${previous};当前状态:${live.status})。`,
228
+ };
229
+ },
230
+ };
231
+
232
+ const followupSchema = z.object({
233
+ agent_id: agentId,
234
+ message: z.string().min(1).max(100_000),
235
+ run_in_background: z.boolean().optional(),
236
+ });
237
+
238
+ export const agentFollowupTool: Tool<z.infer<typeof followupSchema>> = {
239
+ name: 'AgentFollowup',
240
+ description:
241
+ 'Adds a follow-up task to a stable sub-agent. If it is running, delivers the message at the next model boundary; if idle, resumes its persisted private history and starts a new turn.',
242
+ inputSchema: followupSchema,
243
+ parameters: toToolParameters(followupSchema),
244
+ isReadOnly: false,
245
+ isConcurrencySafe: true,
246
+ interruptBehavior: () => 'block',
247
+ call: async () => ({
248
+ ok: false,
249
+ error: 'AgentFollowup requires session context',
250
+ }),
251
+ callWithContext: async (input, signal, context) => {
252
+ const missing = needsContext(context);
253
+ if (missing) return missing;
254
+ const live = getLiveAgentTask(
255
+ context.sessionState!.agentTasks,
256
+ input.agent_id,
257
+ );
258
+ if (live?.status === 'running') {
259
+ enqueueAgentMessage(live, input.message);
260
+ await saveAgentRecord(context, live);
261
+ await appendAgentEvent(context, live.id, {
262
+ phase: 'followup',
263
+ message: input.message,
264
+ });
265
+ return { ok: true, content: `后续任务已发送给运行中的 ${live.id}。` };
266
+ }
267
+ const saved = await loadAgentRecord(context, input.agent_id);
268
+ if (!saved)
269
+ return {
270
+ ok: false,
271
+ error: `当前 Session 中不存在 Agent ${input.agent_id}`,
272
+ };
273
+ return runManagedAgentTask(
274
+ {
275
+ description: saved.description,
276
+ prompt: input.message,
277
+ resume_agent_id: input.agent_id,
278
+ run_in_background: input.run_in_background ?? true,
279
+ },
280
+ signal,
281
+ context,
282
+ );
283
+ },
284
+ };
@@ -1,4 +1,4 @@
1
- import { appendFile, mkdir } from 'node:fs/promises';
1
+ import { appendFile, mkdir, readdir } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { readRuntimeJson, sessionRuntimeDir, withRuntimeFileLock, writeRuntimeJson, } from '../../session/runtimeStore.js';
4
4
  export function createAgentTaskState() {
@@ -49,6 +49,45 @@ export async function loadAgentRecord(ctx, id) {
49
49
  export function getLiveAgentTask(state, id) {
50
50
  return state?.tasks.get(id);
51
51
  }
52
+ /** List the durable tasks owned by this Session, with process-local state winning. */
53
+ export async function listAgentRecords(ctx) {
54
+ const root = join(sessionRuntimeDir(ctx), 'agents');
55
+ const entries = await readdir(root, { withFileTypes: true }).catch(() => []);
56
+ const records = new Map();
57
+ for (const entry of entries) {
58
+ if (!entry.isDirectory() || !/^agent_[0-9a-f-]{36}$/i.test(entry.name))
59
+ continue;
60
+ const record = await loadAgentRecord(ctx, entry.name);
61
+ if (record)
62
+ records.set(record.id, record);
63
+ }
64
+ for (const live of ctx.sessionState?.agentTasks.tasks.values() ?? [])
65
+ records.set(live.id, live);
66
+ return [...records.values()].sort((a, b) => b.updatedAt - a.updatedAt);
67
+ }
68
+ export function agentMessage(message) {
69
+ return {
70
+ role: 'user',
71
+ content: `[主 Agent 后续消息]\n${message}`,
72
+ timestamp: Date.now(),
73
+ };
74
+ }
75
+ /** Deliver at the next model-message boundary without aborting the active turn. */
76
+ export function enqueueAgentMessage(task, message) {
77
+ if (task.history)
78
+ task.history.push(agentMessage(message));
79
+ else
80
+ task.inbox.push(message);
81
+ task.updatedAt = Date.now();
82
+ task.events.emit('change');
83
+ }
84
+ /** Attach the live private history and flush messages accepted during startup. */
85
+ export function attachAgentHistory(task, history) {
86
+ task.history = history;
87
+ for (const message of task.inbox.splice(0))
88
+ history.push(agentMessage(message));
89
+ task.events.emit('change');
90
+ }
52
91
  export async function stopAllAgentTasks(state) {
53
92
  const running = [...state.tasks.values()].filter((t) => t.status === 'running');
54
93
  running.forEach((t) => t.abort.abort());