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
@@ -4,7 +4,7 @@
4
4
  * ------------------------------------------------------------
5
5
  * 独立配置的第二个 LLM,供主循环的模型在关键判断点(方案/诊断成型后动手写改之前、
6
6
  * 受阻或要改方向时、收尾汇报之前)主动调用,拿到一个不同模型的第二意见。
7
- * 时机规则的真身在 `prompts/promptAssembly.ts` 的 Advisor 工具规则 + 本文件的
7
+ * 时机规则的真身在 `prompts/policyRegistry.ts` 的 `capability.advisor` 能力块 + 本文件的
8
8
  * `description`;配额曲线在 `loop.ts::advisorQuotaFor`。
9
9
  *
10
10
  * 设计要点(吸收自 Claude Code 官方 /advisor 的架构,但按 minimal-agent
@@ -27,10 +27,17 @@ import { z } from 'zod';
27
27
 
28
28
  import { configService } from '../../config/configService.js';
29
29
  import { CONFIG_LIMITS, normalizeLimited } from '../../config/numericLimits.js';
30
+ import { DEFAULT_ADVISOR_CONFIG } from '../../config/configDefaults.js';
30
31
  import { countMessagesTokens } from '../../context/tokenCounter.js';
31
32
  import { chat } from '../../llm/client.js';
32
33
  import { derivePromptCacheContext } from '../../llm/promptCache.js';
33
- import type { Message, Tool, ToolCallContext, ToolResult } from '../../types.js';
34
+ import type {
35
+ AdvisorContextPacket,
36
+ Message,
37
+ Tool,
38
+ ToolCallContext,
39
+ ToolResult,
40
+ } from '../../types.js';
34
41
  import { toToolParameters } from '../../utils/zodToJson.js';
35
42
  import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
36
43
 
@@ -38,10 +45,14 @@ import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
38
45
  const inputSchema = z.object({
39
46
  note: z
40
47
  .string()
41
- .max(2000, 'note 太长(>2000 字)')
48
+ // 上限只做护栏,不做实用约束:note 是顾问唯一能看到的「模型主动强调的证据」,
49
+ // 卡太低(曾经 2000 字符)会让完整方案+关键代码原文根本塞不进去。真正的预算
50
+ // 闸门在 buildAdvisorMessages -> fitAdvisorBudget(inputTokenBudget 配置 +
51
+ // 顾问 contextWindow 推导),note 超预算只会挤掉历史消息,不会炸请求。
52
+ .max(100_000, 'note 太长(>100000 字符)')
42
53
  .optional()
43
54
  .describe(
44
- '可选。大多数情况下不需要填——你此前说过的方案/诊断已经在会话历史里,顾问会自动看到。' +
55
+ '可选。大多数情况下不需要填--你此前说过的方案/诊断已经在会话历史里,顾问会自动看到。' +
45
56
  '只有需要额外强调、历史里没体现的点时才填一句话。',
46
57
  ),
47
58
  });
@@ -50,24 +61,10 @@ type AdvisorInput = z.infer<typeof inputSchema>;
50
61
  const parameters = toToolParameters(inputSchema);
51
62
 
52
63
  // ---------------- 2. Description(给 LLM 看的工具说明) ----------------
53
- const description = `- Consults an independent, separately-configured second LLM ("顾问模型" / advisor) for a second opinion on your current plan, diagnosis, or progress.
54
- - Call with no arguments in most cases — the advisor receives a bounded, relevant view of the current session (the original request, recent discussion, current plan/diagnosis, and key tool results). Always pass key evidence (original code snippets, raw data, full plan text) in \`note\`, not just your summary — the advisor cannot verify things you never wrote down.
55
- - Exception: if your current plan/diagnosis relies on things you saw in images (screenshots, photos, diagrams), summarize the key visual facts in \`note\` in 1-2 sentences (what each image shows and what you concluded from it) — the advisor may not be able to see the images themselves.
56
- - **Call it BEFORE substantive work, not after things go wrong.** The advisor is worth the most before an approach hardens — once you have written the code, the plan is expensive to abandon.
57
- - Orientation is NOT substantive work: finding files, reading code, running a command to see the current state. Do that first, then consult.
58
- - Substantive work IS: writing or editing files, committing to an interpretation, building on an assumption, declaring an answer.
59
- - **MUST call Advisor in all 5 of these situations — do not wait for errors or user prompts:**
60
- 1. After a plan / development plan is finalized, **before** executing it (get critique first, avoid discovering wrong direction halfway)
61
- 2. **Before** submitting final results to the user (before PresentResult): code reviews, assessment reports, technical selections, refactoring plans — any time you "deliver a conclusion"
62
- 3. The same error occurs 2+ times in a row, or fixes are not converging (early sign of infinite loop — switch approach immediately)
63
- 4. The user gives unsatisfied feedback a **second time** in the same turn (stop spinning in place, get a fresh perspective first)
64
- 5. Decisions involving security, data loss, or irreversible operations (advisor double-check)
65
- - **Make your work durable BEFORE calling in situation 2.** Write the file, save the result. This call takes time; if the turn ends during it, a written file survives and an unwritten answer does not.
66
- - On a long task, consult at least twice: once before the approach is locked in, once before you declare it done. On a short reactive task whose next step is dictated by output you just read, one call is enough — the advisor adds most of its value early.
67
- - **Take the advice seriously, but do not obey it blindly.** Adapt if you follow a step and it empirically fails, or you hold primary-source evidence contradicting a specific claim (the file says X, the test output says Y). A passing self-test is NOT evidence the advice is wrong — it is evidence your test does not check what the advice checks.
68
- - **If the advisor contradicts evidence you already gathered, do not silently switch.** Call Advisor once more stating the conflict outright ("I measured X, you advise Y — which constraint breaks the tie?"). The advisor saw your evidence but may have underweighted it; one reconciling call is far cheaper than committing to the wrong branch.
69
- - The advisor has no tool access and does a single read-only pass over the transcript — it cannot verify anything itself, only reason about what it's shown.
70
- - If this tool errors (advisor not configured in shared settings, disabled, manual-only, or a call failure), that's not a signal to stop — treat it as "no second opinion available this time" and continue with your own judgment, but **explicitly note "not cross-verified by advisor" in your final output**. Do not block or retry in a loop.`;
64
+ const description = `Consult an independently configured, read-only advisor model for a second opinion.
65
+ The advisor receives a bounded view of the current session. Usually omit note; use it only for decisive evidence or visual facts that are absent or easy to miss in history.
66
+ The result includes a full consultationId. After a successful automatic consultation, record the main Agent's evidence-based accept/partial/reject judgment with AdvisorDecision.
67
+ The advisor is neither a fact source nor an authority. If it is unavailable or fails, follow the returned degradation guidance and do not retry in a loop.`;
71
68
 
72
69
  // ---------------- 3. 顾问 persona system prompt ----------------
73
70
  const ADVISOR_SYSTEM_PROMPT = `你是一位经验丰富的全栈开发专家技术顾问,为正在独立执行任务的另一个 AI 助手提供第二意见评审。
@@ -117,8 +114,20 @@ const ADVISOR_SYSTEM_PROMPT = `你是一位经验丰富的全栈开发专家技
117
114
  */
118
115
  const MAX_TOOL_RESULT_CHARS = 12_000;
119
116
 
117
+ /**
118
+ * 工具调用参数与思维链的截断上限——与 `fitAdvisorBudget` 的预算裁剪是两回事:
119
+ * 那个只在总量超预算时才生效、按消息整条丢弃;这两个是每条消息内部无条件应用的
120
+ * 字段级上限,不看当前预算是否宽裕。思维链截得比正文更狠:重思考模型的
121
+ * reasoning 常比 content 长几倍,不设限会把预算吃光、挤掉更该保留的工具结果原文。
122
+ * 未发现过当前取值导致顾问漏判的实例,因此只命名、不改值——真出现具体案例
123
+ * 再调,不做没有证据支撑的预防性放宽。
124
+ */
125
+ const ADVISOR_TOOL_ARGS_TRUNCATE_CHARS = 2_000;
126
+ const ADVISOR_REASONING_TRUNCATE_CHARS = 2_000;
127
+
120
128
  /** 归一化后的工具结果前缀;裁剪统计要靠它反查,两处必须共用同一常量。 */
121
129
  const TOOL_RESULT_PREFIX = '[工具结果 ';
130
+ const CONTEXT_PACKET_PREFIX = '[Advisor 结构化上下文包]';
122
131
 
123
132
  function truncateMiddle(value: string, limit = MAX_TOOL_RESULT_CHARS): string {
124
133
  if (value.length <= limit) return value;
@@ -221,19 +230,17 @@ function normalizeAdvisorMessage(
221
230
  }
222
231
  if (message.role === 'assistant') {
223
232
  const calls = message.tool_calls?.map((call) =>
224
- `[调用工具 ${call.function.name}] ${truncateMiddle(call.function.arguments, 2000)}`,
233
+ `[调用工具 ${call.function.name}] ${truncateMiddle(call.function.arguments, ADVISOR_TOOL_ARGS_TRUNCATE_CHARS)}`,
225
234
  ).join('\n');
226
235
  // 思维链一并送给顾问:评审「方案对不对」很大程度上要看**它是怎么想到这个方案的**——
227
236
  // 推理里的跳跃(把推断当已验证、跳过一个没排除的可能)在最终结论文本里往往看不出来。
228
- // 截断比正文更狠(2000):重思考模型的 reasoning 常比 content 长几倍,不设限会把
229
- // 预算吃光、反而挤掉更该保留的工具结果原文。
230
237
  // reasoning_details(结构化数组)不传:结构因 provider 而异,既无法可靠脱敏也无法
231
238
  // 稳定转成文本,传过去只会变成噪声。
232
239
  const thinking = typeof message.reasoning_content === 'string' && message.reasoning_content.length > 0
233
240
  ? message.reasoning_content
234
241
  : (typeof message.reasoning === 'string' ? message.reasoning : '');
235
242
  const thinkingLine = thinking.length > 0
236
- ? `[思考过程]\n${truncateMiddle(thinking, 2000)}`
243
+ ? `[思考过程]\n${truncateMiddle(thinking, ADVISOR_REASONING_TRUNCATE_CHARS)}`
237
244
  : '';
238
245
  return {
239
246
  role: 'assistant',
@@ -255,13 +262,19 @@ function fitAdvisorBudget(messages: Message[], inputBudget: number): Message[] {
255
262
  const system = messages[0]!;
256
263
  const closing = messages[messages.length - 1]!;
257
264
  const body = messages.slice(1, -1);
258
- const firstUserIndex = body.findIndex((message) => message.role === 'user');
265
+ const packetIndex = body.findIndex((message) =>
266
+ message.role === 'user'
267
+ && typeof message.content === 'string'
268
+ && message.content.startsWith(CONTEXT_PACKET_PREFIX));
269
+ const firstUserIndex = body.findIndex((message, index) =>
270
+ index !== packetIndex && message.role === 'user');
259
271
  const selected: Message[] = [];
260
272
  let used = countMessagesTokens([system, closing]);
261
- if (firstUserIndex >= 0) {
262
- const first = body[firstUserIndex]!;
263
- selected.push(first);
264
- used += countMessagesTokens([first]);
273
+ for (const index of [packetIndex, firstUserIndex]) {
274
+ if (index < 0) continue;
275
+ const pinned = body[index]!;
276
+ selected.push(pinned);
277
+ used += countMessagesTokens([pinned]);
265
278
  }
266
279
  // 从最近往前收,**装不下就停**(break,不是 continue)。
267
280
  //
@@ -272,7 +285,7 @@ function fitAdvisorBudget(messages: Message[], inputBudget: number): Message[] {
272
285
  // 宁可少给,不可给错:连续的尾部 + 如实说明从哪里开始省略。
273
286
  const recent: Message[] = [];
274
287
  for (let index = body.length - 1; index >= 0; index--) {
275
- if (index === firstUserIndex) continue;
288
+ if (index === firstUserIndex || index === packetIndex) continue;
276
289
  const message = body[index]!;
277
290
  const cost = countMessagesTokens([message]);
278
291
  if (used + cost > inputBudget) break;
@@ -310,6 +323,7 @@ export function buildAdvisorMessages(
310
323
  contextWindow?: number;
311
324
  maxTokens?: number;
312
325
  inputTokenBudget?: number;
326
+ contextPacket?: AdvisorContextPacket;
313
327
  } = {},
314
328
  ): Message[] {
315
329
  const imageBudget: AdvisorImageBudget = { count: 0, encodedBytes: 0 };
@@ -332,13 +346,19 @@ export function buildAdvisorMessages(
332
346
 
333
347
  const messages: Message[] = [
334
348
  { role: 'system', content: ADVISOR_SYSTEM_PROMPT },
349
+ ...(options.contextPacket
350
+ ? [{
351
+ role: 'user' as const,
352
+ content: `${CONTEXT_PACKET_PREFIX}\n${JSON.stringify(options.contextPacket, null, 2)}`,
353
+ }]
354
+ : []),
335
355
  ...nonSystem,
336
356
  { role: 'user', content: closing },
337
357
  ];
338
358
  const contextWindow = options.contextWindow ?? 128_000;
339
359
  const maxTokens = options.maxTokens ?? 4096;
340
360
  const configuredBudget = normalizeLimited(
341
- options.inputTokenBudget, CONFIG_LIMITS.advisorInputTokenBudget, 128_000);
361
+ options.inputTokenBudget, CONFIG_LIMITS.advisorInputTokenBudget, DEFAULT_ADVISOR_CONFIG.inputTokenBudget);
342
362
  const providerBudget = Math.max(CONFIG_LIMITS.advisorInputTokenBudget.min, contextWindow - maxTokens - 4096);
343
363
  const inputBudget = Math.min(configuredBudget, providerBudget);
344
364
  return fitAdvisorBudget(messages, inputBudget);
@@ -378,46 +398,93 @@ export async function runAdvisor(
378
398
  chatFn: typeof chat = chat,
379
399
  runtime: { timeoutMs?: number } = {},
380
400
  ): Promise<ToolResult> {
401
+ const consultation = ctx?.advisorInvocation === 'agent'
402
+ ? ctx.advisorRuntime?.beginConsultation()
403
+ : undefined;
404
+ const finish = (result: ToolResult): ToolResult => {
405
+ if (!consultation || !ctx?.advisorRuntime) return result;
406
+ const metadata = ctx.advisorRuntime.finishConsultation(consultation, result.ok);
407
+ return {
408
+ ...result,
409
+ ...(result.ok
410
+ ? {
411
+ content: `consultationId: ${metadata.consultationId}\n调用 AdvisorDecision 时必须原样使用上面的完整 consultationId。\n\n${result.content}`,
412
+ }
413
+ : {}),
414
+ metadata,
415
+ };
416
+ };
381
417
  const advisor = await configService.advisor();
382
418
  if (!advisor) {
383
- return {
419
+ return finish({
384
420
  ok: false,
385
421
  error:
386
422
  '顾问模型未配置。请在设置 → 模型中完成专家顾问配置。' +
387
423
  '本回合后续不要再次尝试调用 Advisor;可继续凭自己判断推进,不必等待顾问。',
388
- };
424
+ });
389
425
  }
390
426
 
391
427
  if (!advisor.enabled) {
392
- return {
428
+ return finish({
393
429
  ok: false,
394
430
  error:
395
431
  '顾问模型当前已关闭(/advisor on 开启)。' +
396
432
  '本回合后续不要再次尝试调用 Advisor;可继续凭自己判断推进,不必等待顾问。',
397
- };
433
+ });
398
434
  }
399
435
 
400
436
  if (advisor.mode === 'manual' && ctx?.advisorInvocation !== 'manual') {
401
- return {
437
+ return finish({
402
438
  ok: false,
403
439
  error:
404
440
  '顾问模型当前为"仅手动"模式;请使用 /advisor ask 发起咨询。' +
405
441
  '本回合后续不要再次尝试自动调用 Advisor。',
406
- };
442
+ });
407
443
  }
408
444
 
409
- if (ctx?.advisorCalls && ctx.advisorCalls.used >= ctx.advisorCalls.max) {
445
+ // 复核豁免:有一个已成功、还没被 AdvisorDecision 结清的咨询时,这次调用是对它
446
+ // 的复核而不是一次新检查点的咨询——工具说明书要求"顾问意见与证据冲突时再问一次",
447
+ // 若复核也照常计费/受配额拦截,短任务(配额恒为 1)会在第二次调用直接撞墙,
448
+ // 而配额耗尽的处理是把这次咨询标记失败并**顺带结清 #pending 指向的检查点**——
449
+ // 模型想认真复核,反而因为差一点配额把本该把关的高风险检查点悄悄放行了。
450
+ // 豁免只覆盖第一次复核:协调器按 checkpoint 记录成功咨询次数,完成一次复核后
451
+ // canReconcileConsultation 会变为 false,后续调用重新受正常配额约束。
452
+ const isReconcile = ctx?.advisorInvocation === 'agent'
453
+ && Boolean(ctx.advisorRuntime?.pendingConsultationId)
454
+ && ctx.advisorRuntime?.canReconcileConsultation === true;
455
+
456
+ // 检查点强制咨询 vs 自愿咨询分池计费:宿主主动拦下模型、强制它咨询的这一次
457
+ // 调用(hasActiveGate === true)走独立的 mandatoryUsed/mandatoryMax 池,
458
+ // 永远不会被自愿/复核性质的咨询挤占配额。旧版只有一个共享池,配额起点为 1
459
+ // 时一个回合里第二个检查点几乎必然撞墙——这不是顾问后端配置问题,是结构性的。
460
+ const isMandated = ctx?.advisorInvocation === 'agent'
461
+ && ctx.advisorRuntime?.hasActiveGate === true;
462
+ const quota = ctx?.advisorCalls;
463
+ const usesMandatoryPool = isMandated && quota?.mandatoryMax !== undefined;
464
+ const quotaUsed = usesMandatoryPool ? (quota!.mandatoryUsed ?? 0) : quota?.used;
465
+ const quotaMax = usesMandatoryPool ? quota!.mandatoryMax! : quota?.max;
466
+
467
+ if (!isReconcile && quota && quotaUsed !== undefined && quotaMax !== undefined && quotaUsed >= quotaMax) {
410
468
  // ⚠️ 必须说明「配额会增长」:配额随本回合工作量上调(loop.ts::advisorQuotaFor),
411
469
  // 若这里只说「已达上限」,模型会当成本回合的硬上限而不再尝试 —— 那样长回合里
412
470
  // 「批次做完再复核一次」的配额永远不会被用到,增长机制等于没做。
413
- return {
471
+ // ⚠️ 只有确实存在一个待结清的咨询(pendingConsultationId)时才能说"按已有
472
+ // 意见继续"——否则这一步可能压根没有产生过任何意见,那句话就是误导。
473
+ const hasPendingAdvice = ctx?.advisorRuntime?.pendingConsultationId !== undefined;
474
+ const poolLabel = usesMandatoryPool ? '检查点强制咨询配额' : '顾问咨询配额';
475
+ const guidance = hasPendingAdvice
476
+ ? '配额会随本回合的工作量增长,继续推进一段后可以再次咨询;现在请按已有意见继续。'
477
+ : '配额会随本回合的工作量增长,继续推进一段后可以再次咨询;这一步目前没有可参考的顾问意见,' +
478
+ '请基于代码、测试等一手证据自行判断,并在汇报时如实说明这一步未获得第二意见背书。';
479
+ return finish({
414
480
  ok: false,
415
- error:
416
- `本回合顾问咨询配额暂时用完(当前 ${ctx.advisorCalls.max} 次)。` +
417
- '配额会随本回合的工作量增长,继续推进一段后可以再次咨询;现在请按已有意见继续。',
418
- };
481
+ error: `本回合${poolLabel}暂时用完(当前 ${quotaMax} 次)。${guidance}`,
482
+ });
483
+ }
484
+ if (!isReconcile && quota) {
485
+ if (usesMandatoryPool) quota.mandatoryUsed = (quota.mandatoryUsed ?? 0) + 1;
486
+ else quota.used++;
419
487
  }
420
- if (ctx?.advisorCalls) ctx.advisorCalls.used++;
421
488
 
422
489
  const provider = advisor.provider;
423
490
  const snapshot = await configService.getSnapshot();
@@ -437,6 +504,9 @@ export async function runAdvisor(
437
504
  contextWindow: provider.contextWindow,
438
505
  maxTokens: provider.maxTokens,
439
506
  inputTokenBudget: advisor.inputTokenBudget,
507
+ ...(ctx?.advisorRuntime
508
+ ? { contextPacket: ctx.advisorRuntime.contextPacket(input.note) }
509
+ : {}),
440
510
  });
441
511
 
442
512
  // Advisor 是可降级的第二意见:使用独立、可配置的总时限,不影响主模型的流式时限。
@@ -500,23 +570,26 @@ export async function runAdvisor(
500
570
  contextWindow: provider.contextWindow,
501
571
  maxTokens: provider.maxTokens,
502
572
  inputTokenBudget: advisor.inputTokenBudget,
573
+ ...(ctx?.advisorRuntime
574
+ ? { contextPacket: ctx.advisorRuntime.contextPacket(input.note) }
575
+ : {}),
503
576
  }),
504
577
  );
505
578
  degradedWithoutImages = true;
506
579
  }
507
580
  } catch (e) {
508
581
  if (timeoutController.signal.aborted && !signal?.aborted) {
509
- return {
582
+ return finish({
510
583
  ok: false,
511
584
  error:
512
585
  `顾问模型响应超过 ${Math.round(timeoutMs / 1000)}s 未完成,已跳过。` +
513
586
  '可继续凭自己判断推进,不必等待顾问。',
514
- };
587
+ });
515
588
  }
516
- return {
589
+ return finish({
517
590
  ok: false,
518
591
  error: `${classifyAdvisorError(e as Error)} 可继续凭自己判断推进,不必等待顾问。`,
519
- };
592
+ });
520
593
  } finally {
521
594
  clearTimeout(timer);
522
595
  }
@@ -532,7 +605,7 @@ export async function runAdvisor(
532
605
  `\n\n... (输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符,已截断)`;
533
606
  }
534
607
 
535
- return { ok: true, content };
608
+ return finish({ ok: true, content });
536
609
  }
537
610
 
538
611
  // 无宿主上下文的调用视为用户手动咨询;生产主循环使用 callWithContext。
@@ -0,0 +1,71 @@
1
+ import { z } from 'zod';
2
+ import { configService } from '../../config/configService.js';
3
+ import { toToolParameters } from '../../utils/zodToJson.js';
4
+ const inputSchema = z
5
+ .object({
6
+ consultationId: z
7
+ .string()
8
+ .min(1)
9
+ .describe('Advisor 结果元数据中的 consultationId'),
10
+ decision: z.enum(['accept', 'partial', 'reject']),
11
+ rationale: z
12
+ .string()
13
+ .min(8)
14
+ .max(20_000)
15
+ .describe('主 Agent 基于代码、测试和用户约束作出的判断依据'),
16
+ acceptedPoints: z.array(z.string().min(1).max(4_000)).max(20).optional(),
17
+ rejectedPoints: z.array(z.string().min(1).max(4_000)).max(20).optional(),
18
+ verificationPlan: z.array(z.string().min(1).max(4_000)).max(20).optional(),
19
+ })
20
+ .superRefine((value, ctx) => {
21
+ if (value.decision === 'partial' &&
22
+ (!value.acceptedPoints?.length || !value.rejectedPoints?.length)) {
23
+ ctx.addIssue({
24
+ code: z.ZodIssueCode.custom,
25
+ path: ['decision'],
26
+ message: 'partial 必须同时列出 acceptedPoints 和 rejectedPoints',
27
+ });
28
+ }
29
+ if (value.decision === 'reject' && !value.rejectedPoints?.length) {
30
+ ctx.addIssue({
31
+ code: z.ZodIssueCode.custom,
32
+ path: ['rejectedPoints'],
33
+ message: 'reject 必须列出被拒绝的顾问意见',
34
+ });
35
+ }
36
+ });
37
+ async function callWithContext(input, _signal, context) {
38
+ if (!context.advisorRuntime) {
39
+ return { ok: false, error: '当前运行没有待处理的 Advisor 协调器状态。' };
40
+ }
41
+ return context.advisorRuntime.recordDecision(input);
42
+ }
43
+ export const advisorDecisionTool = {
44
+ name: 'AdvisorDecision',
45
+ description: "Records the main Agent's evidence-based decision after a successful Advisor consultation. " +
46
+ 'Call it before resuming a deferred write, irreversible action, or final delivery. ' +
47
+ 'The Advisor is a second opinion, not an authority: choose accept, partial, or reject based on primary evidence. ' +
48
+ 'For partial/reject, explicitly identify rejected points and explain the code/test/user-constraint evidence.',
49
+ inputSchema,
50
+ parameters: toToolParameters(inputSchema),
51
+ isReadOnly: true,
52
+ isConcurrencySafe: false,
53
+ interruptBehavior: () => 'cancel',
54
+ resolveAvailability() {
55
+ const avail = configService.advisorAvailabilitySync();
56
+ if (avail.configured && (!avail.enabled || avail.mode === 'manual')) {
57
+ return {
58
+ available: false,
59
+ signature: avail.enabled ? 'manual-only' : 'disabled',
60
+ };
61
+ }
62
+ return { available: true, signature: avail.modelId ?? 'initializing' };
63
+ },
64
+ async call() {
65
+ return {
66
+ ok: false,
67
+ error: 'AdvisorDecision 只能在主 Agent 会话的 Advisor 咨询后调用。',
68
+ };
69
+ },
70
+ callWithContext,
71
+ };
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod';
2
+
3
+ import { configService } from '../../config/configService.js';
4
+ import type { Tool, ToolCallContext, ToolResult } from '../../types.js';
5
+ import { toToolParameters } from '../../utils/zodToJson.js';
6
+
7
+ const inputSchema = z
8
+ .object({
9
+ consultationId: z
10
+ .string()
11
+ .min(1)
12
+ .describe('Advisor 结果元数据中的 consultationId'),
13
+ decision: z.enum(['accept', 'partial', 'reject']),
14
+ rationale: z
15
+ .string()
16
+ .min(8)
17
+ .max(20_000)
18
+ .describe('主 Agent 基于代码、测试和用户约束作出的判断依据'),
19
+ acceptedPoints: z.array(z.string().min(1).max(4_000)).max(20).optional(),
20
+ rejectedPoints: z.array(z.string().min(1).max(4_000)).max(20).optional(),
21
+ verificationPlan: z.array(z.string().min(1).max(4_000)).max(20).optional(),
22
+ })
23
+ .superRefine((value, ctx) => {
24
+ if (
25
+ value.decision === 'partial' &&
26
+ (!value.acceptedPoints?.length || !value.rejectedPoints?.length)
27
+ ) {
28
+ ctx.addIssue({
29
+ code: z.ZodIssueCode.custom,
30
+ path: ['decision'],
31
+ message: 'partial 必须同时列出 acceptedPoints 和 rejectedPoints',
32
+ });
33
+ }
34
+ if (value.decision === 'reject' && !value.rejectedPoints?.length) {
35
+ ctx.addIssue({
36
+ code: z.ZodIssueCode.custom,
37
+ path: ['rejectedPoints'],
38
+ message: 'reject 必须列出被拒绝的顾问意见',
39
+ });
40
+ }
41
+ });
42
+
43
+ type AdvisorDecisionInput = z.infer<typeof inputSchema>;
44
+
45
+ async function callWithContext(
46
+ input: AdvisorDecisionInput,
47
+ _signal: AbortSignal | undefined,
48
+ context: ToolCallContext,
49
+ ): Promise<ToolResult> {
50
+ if (!context.advisorRuntime) {
51
+ return { ok: false, error: '当前运行没有待处理的 Advisor 协调器状态。' };
52
+ }
53
+ return context.advisorRuntime.recordDecision(input);
54
+ }
55
+
56
+ export const advisorDecisionTool: Tool<AdvisorDecisionInput> = {
57
+ name: 'AdvisorDecision',
58
+ description:
59
+ "Records the main Agent's evidence-based decision after a successful Advisor consultation. " +
60
+ 'Call it before resuming a deferred write, irreversible action, or final delivery. ' +
61
+ 'The Advisor is a second opinion, not an authority: choose accept, partial, or reject based on primary evidence. ' +
62
+ 'For partial/reject, explicitly identify rejected points and explain the code/test/user-constraint evidence.',
63
+ inputSchema,
64
+ parameters: toToolParameters(inputSchema),
65
+ isReadOnly: true,
66
+ isConcurrencySafe: false,
67
+ interruptBehavior: () => 'cancel',
68
+ resolveAvailability() {
69
+ const avail = configService.advisorAvailabilitySync();
70
+ if (avail.configured && (!avail.enabled || avail.mode === 'manual')) {
71
+ return {
72
+ available: false,
73
+ signature: avail.enabled ? 'manual-only' : 'disabled',
74
+ };
75
+ }
76
+ return { available: true, signature: avail.modelId ?? 'initializing' };
77
+ },
78
+ async call(): Promise<ToolResult> {
79
+ return {
80
+ ok: false,
81
+ error: 'AdvisorDecision 只能在主 Agent 会话的 Advisor 咨询后调用。',
82
+ };
83
+ },
84
+ callWithContext,
85
+ };
@@ -41,7 +41,7 @@ import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
41
41
  import { SUBAGENT_EXCLUDED_TOOLS, resolveAgentType } from './agentTypes.js';
42
42
  import { acquireSubagentLease, normalizeWriteScopes } from './coordinator.js';
43
43
  import { commitWorktreeChanges, createAgentWorktree, hasWorktreeChanges, removeAgentWorktree, worktreeChangedFiles, worktreeDiffStat, } from './worktree.js';
44
- import { appendAgentEvent, loadAgentRecord, saveAgentRecord } from './agentTaskService.js';
44
+ import { appendAgentEvent, attachAgentHistory, loadAgentRecord, saveAgentRecord } from './agentTaskService.js';
45
45
  let corePromise = null;
46
46
  /** 首次调用时才真正加载 loop/tools——此刻模块图早已初始化完毕,环安全。 */
47
47
  function loadCore() {
@@ -234,7 +234,10 @@ export async function runAgentTask(input, signal, ctx, deps = {}) {
234
234
  ctx.agentCalls.used++;
235
235
  const { runQuery, ALL_TOOLS, executeTool } = await loadCore();
236
236
  const def = resolveAgentType(input.agent_type);
237
- // 轮数上限:AGENT_TOOL_MAX_TURNS 可统一覆盖两种类型(默认 explore 50 / general 100)。
237
+ // 轮数上限:AGENT_TOOL_MAX_TURNS 可统一覆盖两种类型。默认值的唯一真值在
238
+ // config/configDefaults.ts::DEFAULT_SUBAGENTS_CONFIG(现为 explore 200 / general 100,
239
+ // 那里写了「只读的给宽、能写的给窄」的理由)。这条注释以前写着「explore 50」,
240
+ // 而代码早已是 200 —— 注释里复述数字必然漂移,所以现在只留指针。
238
241
  const maxTurns = positiveInt(process.env.AGENT_TOOL_MAX_TURNS)
239
242
  ?? (def.type === 'explore' ? ctx.subagentConfig?.exploreMaxTurns : ctx.subagentConfig?.generalMaxTurns)
240
243
  ?? def.maxTurns;
@@ -312,6 +315,7 @@ export async function runAgentTask(input, signal, ctx, deps = {}) {
312
315
  const history = deps.initialHistory?.length ? [...deps.initialHistory] : [
313
316
  { role: 'system', content: await buildSubSystemPrompt(cwd, def, subTools) },
314
317
  ];
318
+ deps.onHistoryReady?.(history);
315
319
  const historyLenBefore = history.length;
316
320
  const maxConcurrent = positiveInt(process.env.AGENT_TOOL_MAX_CONCURRENT) ?? ctx.subagentConfig?.maxConcurrent ?? 3;
317
321
  let releaseLease = null;
@@ -407,8 +411,8 @@ export async function runAgentTask(input, signal, ctx, deps = {}) {
407
411
  }
408
412
  catch { /* executeTool will report malformed input */ }
409
413
  const rawPath = typeof parsed.file_path === 'string' ? parsed.file_path : typeof parsed.path === 'string' ? parsed.path : undefined;
410
- if (def.type === 'general' && !wt && name === 'Bash' && writeScopes[0] !== rootScope[0]) {
411
- return { ok: false, error: '声明了局部 write_scopes 时禁止 Bash:无法可靠证明命令只写入批准范围。请改用文件工具或使用整个工作目录范围。' };
414
+ if (def.type === 'general' && !wt && ['Bash', 'ApplyPatch'].includes(name) && writeScopes[0] !== rootScope[0]) {
415
+ return { ok: false, error: `声明了局部 write_scopes 时禁止 ${name}:无法可靠证明一次调用只写入批准范围。请改用单文件工具或使用整个工作目录范围。` };
412
416
  }
413
417
  if (def.type === 'general' && rawPath) {
414
418
  if (isAbsolute(rawPath))
@@ -427,7 +431,14 @@ export async function runAgentTask(input, signal, ctx, deps = {}) {
427
431
  changedFiles.add(relative(cwd, resolve(cwd, rawPath)).split(sep).join('/'));
428
432
  }
429
433
  }
430
- return baseExecute(name, args, s, c);
434
+ const result = await baseExecute(name, args, s, c);
435
+ if (result.metadata?.kind === 'file_activity') {
436
+ for (const file of result.metadata.files) {
437
+ if (['created', 'modified', 'generated', 'deleted'].includes(file.activity))
438
+ changedFiles.add(file.relativePath);
439
+ }
440
+ }
441
+ return result;
431
442
  };
432
443
  // ---- 事件消费:子 LoopEvent 一律不外泄,折算成统计 + 步内进度 ----
433
444
  let turns = 0;
@@ -672,6 +683,7 @@ export async function runManagedAgentTask(input, signal, ctx, deps = {}) {
672
683
  abort,
673
684
  completion,
674
685
  events: new EventEmitter(),
686
+ inbox: [],
675
687
  };
676
688
  ctx.sessionState.agentTasks.tasks.set(id, task);
677
689
  await saveAgentRecord(ctx, task);
@@ -703,6 +715,7 @@ export async function runManagedAgentTask(input, signal, ctx, deps = {}) {
703
715
  await saveAgentRecord(ctx, task);
704
716
  },
705
717
  captureHistory: (history) => { captured = [...history]; },
718
+ onHistoryReady: (history) => attachAgentHistory(task, history),
706
719
  });
707
720
  task.result = result;
708
721
  task.history = captured;
@@ -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;