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
@@ -0,0 +1,299 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import type { ConversationMode } from '../runtime/agentRuntimeContext.js';
3
+ import { onlineToolCategory } from '../team/toolPolicy.js';
4
+ import type {
5
+ GatewayProvider,
6
+ LlmStreamEvent,
7
+ Message,
8
+ Tool,
9
+ } from '../types.js';
10
+ import { prepareMessagesForProvider } from './messageProvenance.js';
11
+
12
+ const IDLE_TIMEOUT_MS =
13
+ Number(process.env.MINIMAL_AGENT_GATEWAY_IDLE_TIMEOUT_MS) > 0
14
+ ? Number(process.env.MINIMAL_AGENT_GATEWAY_IDLE_TIMEOUT_MS)
15
+ : 120_000;
16
+ const DEADLINE_MS =
17
+ Number(process.env.MINIMAL_AGENT_GATEWAY_DEADLINE_MS) > 0
18
+ ? Number(process.env.MINIMAL_AGENT_GATEWAY_DEADLINE_MS)
19
+ : 15 * 60_000;
20
+
21
+ function gatewayTools(
22
+ tools: Tool[],
23
+ allowedCategories?: readonly string[],
24
+ ): Array<{
25
+ type: 'function';
26
+ category: NonNullable<ReturnType<typeof onlineToolCategory>>;
27
+ function: {
28
+ name: string;
29
+ description?: string;
30
+ parameters: Record<string, unknown>;
31
+ };
32
+ }> {
33
+ const allowed = allowedCategories ? new Set(allowedCategories) : null;
34
+ return tools.flatMap((tool) => {
35
+ const category = onlineToolCategory(tool.name);
36
+ if (!category || (allowed && !allowed.has(category))) return [];
37
+ return [
38
+ {
39
+ type: 'function' as const,
40
+ category,
41
+ function: {
42
+ name: tool.name,
43
+ ...(typeof tool.description === 'string'
44
+ ? { description: tool.description }
45
+ : {}),
46
+ parameters: tool.parameters as Record<string, unknown>,
47
+ },
48
+ },
49
+ ];
50
+ });
51
+ }
52
+
53
+ function safeMessages(messages: Message[]): unknown[] {
54
+ return messages.map((message) => {
55
+ const {
56
+ id: _id,
57
+ timestamp: _timestamp,
58
+ attachments: _attachments,
59
+ browserReferences: _browserReferences,
60
+ provenance: _provenance,
61
+ display_metadata: _displayMetadata,
62
+ tool_result_policy: _toolResultPolicy,
63
+ _ephemeral,
64
+ ...safe
65
+ } = message as Message & Record<string, unknown>;
66
+ return safe;
67
+ });
68
+ }
69
+
70
+ type GatewayEvent = {
71
+ type?: string;
72
+ code?: string;
73
+ retryable?: boolean;
74
+ message?: string;
75
+ };
76
+
77
+ export class GatewayClientError extends Error {
78
+ constructor(
79
+ public readonly code: string,
80
+ public readonly retryable: boolean,
81
+ message: string,
82
+ ) {
83
+ // ⚠️ code 必须烘进 message 文本,不能只存在 .code 属性上:这个错误穿过
84
+ // loop.ts(只取 `.message`)→ 引擎 runner(转成纯字符串 blocker)→
85
+ // workflowController 的 isUsageLimitError 文本兜底,每一层都只剩字符串。
86
+ // 不烘进去,`isUsageLimitError` 的「同时认 code 与文本」这句注释就是一句空话——
87
+ // 之前正是这样:message 是纯人话(如「设备授权不存在或已过期」),从不包含
88
+ // DEVICE_REVOKED 之类的码,文本兜底恒为 false,usage_limited 在真实调用链上
89
+ // 从未被触发过。
90
+ super(`[${code}] ${message}`);
91
+ this.name = 'GatewayClientError';
92
+ }
93
+ }
94
+
95
+ /**
96
+ * 服务端「配额/授权不给了」的错误码 —— **唯一真值**。
97
+ *
98
+ * 与 Goal 的 `usage_limited` 状态一一对应,也正是它与 `budget_limited` 的分界:
99
+ * · `budget_limited` = **用户自己设的** token 额度用完 → 加预算即可继续。
100
+ * · `usage_limited` = **服务端配额/授权**不给了 → 加预算没用,要去解决授权或等周期重置。
101
+ * 两者都可 resume,但恢复动作完全不同,所以不能合并成一个状态。
102
+ *
103
+ * 服务端侧的产出点:`minimal-server/src/core/gatewayInference.ts`。
104
+ */
105
+ const USAGE_LIMIT_CODES = new Set([
106
+ 'REQUEST_QUOTA_EXHAUSTED',
107
+ 'TOKEN_QUOTA_EXHAUSTED',
108
+ 'CONCURRENCY_EXCEEDED',
109
+ 'GRANT_REVOKED',
110
+ 'DEVICE_REVOKED',
111
+ ]);
112
+
113
+ /**
114
+ * 判断一个错误是不是「服务端配额/授权不给了」。
115
+ *
116
+ * ⚠️ 同时认 `GatewayClientError.code` 与错误文本:错误穿过 loop → 引擎 → 工作流
117
+ * 这几层之后往往只剩一个字符串(`llm_error` 事件带的是 message),
118
+ * 只认 code 会在真实链路上恒为 false。
119
+ */
120
+ export function isUsageLimitError(error: unknown): boolean {
121
+ if (error instanceof GatewayClientError)
122
+ return USAGE_LIMIT_CODES.has(error.code);
123
+ const text = error instanceof Error ? error.message : String(error ?? '');
124
+ return [...USAGE_LIMIT_CODES].some((code) => text.includes(code));
125
+ }
126
+
127
+ function combinedSignal(signal?: AbortSignal): AbortSignal {
128
+ const timeout = AbortSignal.timeout(DEADLINE_MS);
129
+ return signal ? AbortSignal.any([signal, timeout]) : timeout;
130
+ }
131
+
132
+ async function readWithIdleTimeout<T>(
133
+ promise: Promise<T>,
134
+ signal: AbortSignal,
135
+ ): Promise<T> {
136
+ let timer: ReturnType<typeof setTimeout> | undefined;
137
+ let onAbort: (() => void) | undefined;
138
+ try {
139
+ return await Promise.race([
140
+ promise,
141
+ new Promise<T>((_, reject) => {
142
+ timer = setTimeout(
143
+ () =>
144
+ reject(
145
+ new GatewayClientError(
146
+ 'PROVIDER_TIMEOUT',
147
+ true,
148
+ '在线模型流式响应超时',
149
+ ),
150
+ ),
151
+ IDLE_TIMEOUT_MS,
152
+ );
153
+ onAbort = () => reject(new DOMException('aborted', 'AbortError'));
154
+ signal.addEventListener('abort', onAbort, { once: true });
155
+ }),
156
+ ]);
157
+ } finally {
158
+ if (timer) clearTimeout(timer);
159
+ if (onAbort) signal.removeEventListener('abort', onAbort);
160
+ }
161
+ }
162
+
163
+ /** Gateway transport only. The caller retains the existing Agent/tool loop. */
164
+ export async function* chatGateway(args: {
165
+ provider: GatewayProvider;
166
+ messages: Message[];
167
+ tools: Tool[];
168
+ signal?: AbortSignal;
169
+ conversationMode?: ConversationMode;
170
+ responseFormat?: {
171
+ type: 'json_schema';
172
+ json_schema: {
173
+ name: string;
174
+ schema: Record<string, unknown>;
175
+ strict?: boolean;
176
+ };
177
+ };
178
+ }): AsyncGenerator<LlmStreamEvent> {
179
+ const {
180
+ provider,
181
+ messages,
182
+ tools,
183
+ signal: parentSignal,
184
+ conversationMode,
185
+ responseFormat,
186
+ } = args;
187
+ if (!provider.gatewayUrl || !provider.gatewayToken || !provider.remoteModelId)
188
+ throw new GatewayClientError(
189
+ 'DEVICE_REVOKED',
190
+ false,
191
+ '在线模型设备授权不存在或已过期',
192
+ );
193
+ const url = `${provider.gatewayUrl.replace(/\/$/, '')}/api/inference/chat/stream`;
194
+ const payload = JSON.stringify({
195
+ requestId: randomUUID(),
196
+ modelId: provider.remoteModelId,
197
+ // Keep the gateway payload limited to provider-facing protocol content.
198
+ // Session IDs, provenance metadata, display metadata, and local-only
199
+ // fields must never cross the remote inference boundary.
200
+ messages: safeMessages(
201
+ prepareMessagesForProvider(messages, conversationMode ?? 'private'),
202
+ ),
203
+ tools: gatewayTools(
204
+ tools,
205
+ provider.gatewayToolCategories ??
206
+ provider.gatewayDefaultToolCategories ??
207
+ provider.gatewayMaxToolCategories,
208
+ ),
209
+ toolCategories:
210
+ provider.gatewayToolCategories ?? provider.gatewayMaxToolCategories ?? [],
211
+ ...(responseFormat ? { responseFormat } : {}),
212
+ });
213
+ let activeReader: { cancel(): Promise<void> } | undefined;
214
+ const signal = combinedSignal(parentSignal);
215
+ try {
216
+ const response = await fetch(url, {
217
+ method: 'POST',
218
+ signal,
219
+ headers: {
220
+ 'content-type': 'application/json',
221
+ authorization: `Bearer ${provider.gatewayToken}`,
222
+ },
223
+ body: payload,
224
+ });
225
+ if (!response.ok) {
226
+ const body = (await response.json().catch(() => ({}))) as {
227
+ error?: string;
228
+ code?: string;
229
+ retryable?: boolean;
230
+ };
231
+ // ⚠️ 服务端**明确表态**优先,状态码只是它没表态时的推断。
232
+ // 曾经写成 `body.retryable === true || status === 429 || …`:服务端发
233
+ // `{code:'TOKEN_QUOTA_EXHAUSTED', retryable:false}` 配 HTTP 429 时,
234
+ // `retryable:false` 被 `|| 429` 直接覆盖 —— 于是「额度用完了,别重试」
235
+ // 被当成限流反复重试,既拖慢失败反馈,也把真正的原因埋掉。
236
+ // 配额耗尽与限流是两回事:前者要去加额度,后者等一会儿就好。
237
+ const retryable =
238
+ typeof body.retryable === 'boolean'
239
+ ? body.retryable
240
+ : response.status === 408 ||
241
+ response.status === 425 ||
242
+ response.status === 429 ||
243
+ response.status >= 500;
244
+ throw new GatewayClientError(
245
+ body.code ?? `HTTP_${response.status}`,
246
+ retryable,
247
+ body.error ?? `在线模型请求失败(${response.status})`,
248
+ );
249
+ }
250
+ if (!response.body)
251
+ throw new GatewayClientError(
252
+ 'PROVIDER_UNAVAILABLE',
253
+ true,
254
+ '在线模型未返回流式响应',
255
+ );
256
+ const reader = response.body.getReader();
257
+ activeReader = reader;
258
+ const decoder = new TextDecoder();
259
+ let buffer = '';
260
+ while (true) {
261
+ const next = await readWithIdleTimeout(reader.read(), signal);
262
+ if (next.done) break;
263
+ buffer += decoder.decode(next.value, { stream: true });
264
+ const frames = buffer.split(/\n\n/);
265
+ buffer = frames.pop() ?? '';
266
+ for (const frame of frames) {
267
+ const line = frame
268
+ .split(/\r?\n/)
269
+ .find((item) => item.startsWith('data:'));
270
+ if (!line) continue;
271
+ let event: GatewayEvent;
272
+ try {
273
+ event = JSON.parse(line.slice(5).trim());
274
+ } catch {
275
+ continue;
276
+ }
277
+ if (event.type === 'error')
278
+ throw new GatewayClientError(
279
+ event.code ?? 'PROVIDER_UNAVAILABLE',
280
+ event.retryable === true,
281
+ event.message ?? '在线模型流式调用失败',
282
+ );
283
+ if (event.type === 'usage') {
284
+ yield event as LlmStreamEvent;
285
+ continue;
286
+ }
287
+ if (event.type === 'done') return;
288
+ yield event as LlmStreamEvent;
289
+ }
290
+ }
291
+ return;
292
+ } finally {
293
+ // Release the response body on both normal `done` and error/abort paths.
294
+ // Without this, a completed stream can keep an HTTP connection/socket
295
+ // alive until the runtime's garbage collector notices it.
296
+ await activeReader?.cancel().catch(() => {});
297
+ activeReader = undefined;
298
+ }
299
+ }
@@ -0,0 +1,46 @@
1
+ function provenanceLabel(provenance) {
2
+ if (provenance.mode === 'private') {
3
+ return '[历史来源:主人私聊,仅限内部使用;群聊中不得复述或公开]';
4
+ }
5
+ const fields = [
6
+ '历史来源:群聊公开消息',
7
+ provenance.groupId ? `群=${provenance.groupId}` : '',
8
+ provenance.senderName ? `发送者=${provenance.senderName}` : '',
9
+ provenance.senderId ? `发送者ID=${provenance.senderId}` : '',
10
+ provenance.taskId ? `父任务=${provenance.taskId}` : '',
11
+ ].filter(Boolean);
12
+ return `[${fields.join(';')}]`;
13
+ }
14
+ function decorateContent(content, provenance) {
15
+ if (!provenance || content === null)
16
+ return content;
17
+ const label = provenanceLabel(provenance);
18
+ if (typeof content === 'string')
19
+ return `${label}\n${content}`;
20
+ const firstText = content.findIndex((part) => part.type === 'text');
21
+ if (firstText < 0)
22
+ return [{ type: 'text', text: label }, ...content];
23
+ return content.map((part, index) => index === firstText && part.type === 'text'
24
+ ? { ...part, text: `${label}\n${part.text}` }
25
+ : part);
26
+ }
27
+ /** Clone messages for a provider request without leaking local UI/provenance fields. */
28
+ export function prepareMessagesForProvider(messages, conversationMode = 'private') {
29
+ return messages
30
+ .filter((message) => !(message.role === 'system' && message._ephemeral === true))
31
+ .map((message) => {
32
+ const { id, timestamp, attachments, browserReferences, display_metadata, tool_result_policy, provenance, ...rest } = message;
33
+ if (rest.role === 'user' || rest.role === 'assistant') {
34
+ // 旧 Session 在引入 provenance 之前没有来源元数据。进入群聊时必须保守地
35
+ // 把这些历史当作主人私聊,而不是让模型误以为它们已经公开。
36
+ const effectiveProvenance = provenance ?? (conversationMode === 'group'
37
+ ? { mode: 'private', visibility: 'owner-private' }
38
+ : undefined);
39
+ return {
40
+ ...rest,
41
+ content: decorateContent(rest.content, effectiveProvenance),
42
+ };
43
+ }
44
+ return rest;
45
+ });
46
+ }
@@ -0,0 +1,58 @@
1
+ import type { ChatContentPart, ConversationProvenance, Message } from '../types.js';
2
+
3
+ function provenanceLabel(provenance: ConversationProvenance): string {
4
+ if (provenance.mode === 'private') {
5
+ return '[历史来源:主人私聊,仅限内部使用;群聊中不得复述或公开]';
6
+ }
7
+ const fields = [
8
+ '历史来源:群聊公开消息',
9
+ provenance.groupId ? `群=${provenance.groupId}` : '',
10
+ provenance.senderName ? `发送者=${provenance.senderName}` : '',
11
+ provenance.senderId ? `发送者ID=${provenance.senderId}` : '',
12
+ provenance.taskId ? `父任务=${provenance.taskId}` : '',
13
+ ].filter(Boolean);
14
+ return `[${fields.join(';')}]`;
15
+ }
16
+
17
+ function decorateContent(
18
+ content: string | ChatContentPart[] | null,
19
+ provenance: ConversationProvenance | undefined,
20
+ ): string | ChatContentPart[] | null {
21
+ if (!provenance || content === null) return content;
22
+ const label = provenanceLabel(provenance);
23
+ if (typeof content === 'string') return `${label}\n${content}`;
24
+ const firstText = content.findIndex((part) => part.type === 'text');
25
+ if (firstText < 0) return [{ type: 'text', text: label }, ...content];
26
+ return content.map((part, index) => index === firstText && part.type === 'text'
27
+ ? { ...part, text: `${label}\n${part.text}` }
28
+ : part);
29
+ }
30
+
31
+ /** Clone messages for a provider request without leaking local UI/provenance fields. */
32
+ export function prepareMessagesForProvider(
33
+ messages: readonly Message[],
34
+ conversationMode: 'private' | 'group' = 'private',
35
+ ): Message[] {
36
+ return messages
37
+ .filter((message) => !(message.role === 'system' && message._ephemeral === true))
38
+ .map((message) => {
39
+ const {
40
+ id, timestamp, attachments, browserReferences, display_metadata, tool_result_policy, provenance, ...rest
41
+ } = message as Message & Record<string, unknown>;
42
+ if (rest.role === 'user' || rest.role === 'assistant') {
43
+ // 旧 Session 在引入 provenance 之前没有来源元数据。进入群聊时必须保守地
44
+ // 把这些历史当作主人私聊,而不是让模型误以为它们已经公开。
45
+ const effectiveProvenance = provenance ?? (conversationMode === 'group'
46
+ ? { mode: 'private' as const, visibility: 'owner-private' as const }
47
+ : undefined);
48
+ return {
49
+ ...rest,
50
+ content: decorateContent(
51
+ rest.content as string | ChatContentPart[] | null,
52
+ effectiveProvenance,
53
+ ),
54
+ } as Message;
55
+ }
56
+ return rest as Message;
57
+ });
58
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { ConversationMode } from '../runtime/agentRuntimeContext.js';
2
+ import type { CacheEditsState, LlmStreamEvent, Message, Provider, PromptCacheContext, Tool } from '../types.js';
3
+
4
+ export interface NormalizedModelRequest {
5
+ provider: Provider;
6
+ messages: Message[];
7
+ tools: Tool[];
8
+ signal?: AbortSignal;
9
+ responseFormat?: { type: 'json_schema'; json_schema: { name: string; schema: Record<string, unknown>; strict?: boolean } };
10
+ promptCache?: PromptCacheContext;
11
+ conversationMode?: ConversationMode;
12
+ cacheEdits?: CacheEditsState;
13
+ /** Current-turn images must not be silently removed when they are required. */
14
+ visionPolicy?: 'required' | 'optional-history';
15
+ }
16
+
17
+ /** Both local and gateway transports consume the same normalized request. */
18
+ export interface ModelProvider {
19
+ readonly source: 'local' | 'gateway';
20
+ readonly descriptor: Provider;
21
+ stream(request: NormalizedModelRequest): AsyncGenerator<LlmStreamEvent, void, void>;
22
+ }
@@ -134,9 +134,11 @@ export function buildAnthropicUrl(provider) {
134
134
  return url;
135
135
  }
136
136
  export function buildAnthropicRequest(args) {
137
- const { provider, cleanedMessages, tools } = args;
137
+ const { provider, cleanedMessages, tools, cacheEdits } = args;
138
138
  const { system, messages } = toAnthropicMessages(cleanedMessages);
139
139
  const anthropicTools = toAnthropicTools(tools);
140
+ if (cacheEdits)
141
+ applyCacheEdits(messages, cacheEdits);
140
142
  const body = {
141
143
  model: provider.model,
142
144
  ...(system ? { system } : {}),
@@ -160,6 +162,101 @@ export function buildAnthropicRequest(args) {
160
162
  body: JSON.stringify(body),
161
163
  };
162
164
  }
165
+ // ==================== cache_edits 式回收(对齐 kakadeai Cached MC) ====================
166
+ /**
167
+ * 把 cache_edits 回收决策落到请求体上(原地修改翻译后的 messages)。
168
+ *
169
+ * 处理顺序(顺序即正确性,调整会破坏协议约束):
170
+ * 1. 最后一条消息的最后一个 block 打 cache_control 标记——这是 Anthropic 公开的
171
+ * prompt caching 前提:没有缓存前缀,"在缓存内删除"无从谈起。
172
+ * 2. pinned 批次原位重发:服务端无状态,删除指令必须随每个请求重申;且必须
173
+ * 重发在**原 userMessageIndex**——cache_edits block 自身也是前缀的一部分,
174
+ * 挪位 = 前缀变化 = 它本要保护的缓存被它自己破坏。
175
+ * 3. pendingNew 作为新批次插入当前最后一条 user message,然后 pin 住该下标。
176
+ * 4. 给「严格早于 cache_control 标记消息」的 tool_result 加 cache_reference
177
+ * (协议要求 cache_reference 出现在最后 cache_control 之前;用严格早于规避
178
+ * cache_edits 插入改变 content 数组长度带来的下标边界问题)。
179
+ *
180
+ * 下标稳定性依赖:history append-only + toAnthropicMessages 纯函数。compact 后
181
+ * 必须 resetCacheEdits(loop.ts 已挂钩),否则 pin 的下标指向错误消息。
182
+ *
183
+ * dedup:同一 tool_use_id 全请求只允许出现一次删除指令(跨 pinned 批次去重)。
184
+ */
185
+ function applyCacheEdits(messages, edits) {
186
+ if (messages.length === 0)
187
+ return;
188
+ // 1. 基础 prompt caching:最后一条消息的最后一个 block 打标记
189
+ const lastMsg = messages[messages.length - 1];
190
+ if (lastMsg.content.length > 0) {
191
+ const lastBlock = lastMsg.content[lastMsg.content.length - 1];
192
+ lastBlock.cache_control = { type: 'ephemeral' };
193
+ }
194
+ // 跨批次去重集:同一 cache_reference 不重复删
195
+ const seenDeleteRefs = new Set();
196
+ // wire 形状:整个 {type:'cache_edits', edits:[...]} 作为 user message 里的一个
197
+ // content block 追加(对齐 kakadeai addCacheBreakpoints 的 insertBlockAfterToolResults)。
198
+ const appendEditsBlock = (msg, toolUseIds) => {
199
+ msg.content.push({
200
+ type: 'cache_edits',
201
+ edits: toolUseIds.map((id) => ({ type: 'delete', cache_reference: id })),
202
+ });
203
+ };
204
+ const dedupe = (ids) => {
205
+ const unique = [];
206
+ for (const id of ids) {
207
+ if (seenDeleteRefs.has(id))
208
+ continue;
209
+ seenDeleteRefs.add(id);
210
+ unique.push(id);
211
+ }
212
+ return unique;
213
+ };
214
+ // 2. pinned 批次原位重发
215
+ for (const pinned of edits.pinned) {
216
+ const msg = messages[pinned.userMessageIndex];
217
+ if (!msg || msg.role !== 'user')
218
+ continue; // 下标失位(compact 后未 reset)→ 跳过该批,fail-safe
219
+ const unique = dedupe(pinned.toolUseIds);
220
+ if (unique.length > 0)
221
+ appendEditsBlock(msg, unique);
222
+ }
223
+ // 3. pendingNew:插入当前最后一条 user message 并 pin
224
+ if (edits.pendingNew.length > 0) {
225
+ const unique = dedupe(edits.pendingNew);
226
+ if (unique.length > 0) {
227
+ for (let i = messages.length - 1; i >= 0; i--) {
228
+ if (messages[i].role !== 'user')
229
+ continue;
230
+ appendEditsBlock(messages[i], unique);
231
+ edits.pinned.push({ userMessageIndex: i, toolUseIds: unique });
232
+ break;
233
+ }
234
+ }
235
+ edits.pendingNew.length = 0; // 已消费(无论是否成功插入,都清空防止下轮重复插入)
236
+ }
237
+ // 4. cache_reference 标注:找最后含 cache_control 的消息,给它**严格之前**的 tool_result 加引用
238
+ let lastCCMsgIndex = -1;
239
+ for (let i = 0; i < messages.length; i++) {
240
+ for (const block of messages[i].content) {
241
+ if (block && typeof block === 'object' && 'cache_control' in block) {
242
+ lastCCMsgIndex = i;
243
+ break;
244
+ }
245
+ }
246
+ }
247
+ if (lastCCMsgIndex < 0)
248
+ return;
249
+ for (let i = 0; i < lastCCMsgIndex; i++) {
250
+ const msg = messages[i];
251
+ if (msg.role !== 'user')
252
+ continue;
253
+ for (const block of msg.content) {
254
+ if (block.type === 'tool_result' && typeof block.tool_use_id === 'string') {
255
+ block.cache_reference = block.tool_use_id;
256
+ }
257
+ }
258
+ }
259
+ }
163
260
  /**
164
261
  * 每个请求一个新实例;把逐条 SSE `data:` 行的内容转换成 LlmStreamEvent(0..N 个)。
165
262
  *
@@ -171,6 +268,7 @@ export function buildAnthropicRequest(args) {
171
268
  export function createAnthropicSSEParser() {
172
269
  let stopReason = 'unknown';
173
270
  let usagePromptTokens;
271
+ let usageOutputTokens;
174
272
  let usageCachedTokens;
175
273
  let usageCacheWriteTokens;
176
274
  let promptCacheUsage = { reported: false };
@@ -178,6 +276,7 @@ export function createAnthropicSSEParser() {
178
276
  type: 'done',
179
277
  stopReason,
180
278
  promptTokens: usagePromptTokens,
279
+ outputTokens: usageOutputTokens,
181
280
  ...(promptCacheUsage.reported
182
281
  ? {
183
282
  ...(usageCachedTokens !== undefined ? { cachedPromptTokens: usageCachedTokens } : {}),
@@ -250,6 +349,14 @@ export function createAnthropicSSEParser() {
250
349
  return [];
251
350
  }
252
351
  case 'message_delta': {
352
+ // 输出侧计量:Anthropic 把 output_tokens 放在 message_delta 的**顶层 usage** 下
353
+ // (不在 delta 里),且给的是**到目前为止的累计值** —— 直接覆盖即可,不要累加。
354
+ // 与 input_tokens 不同:那个要把缓存三段相加(见 message_start 分支)。
355
+ // ⚠️ 非有限值/负数一律当「没报」,绝不退化成 0(0 会让预算闸永不触发)。
356
+ const out = data.usage?.output_tokens;
357
+ if (typeof out === 'number' && Number.isFinite(out) && out >= 0) {
358
+ usageOutputTokens = out;
359
+ }
253
360
  // ⚠️ stop_reason 嵌套在 delta.stop_reason 下,不是 message_delta 顶层。
254
361
  const sr = data.delta?.stop_reason;
255
362
  if (sr === 'end_turn' || sr === 'stop_sequence')