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
@@ -1,7 +1,51 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { readMinimalAgentConfig, updateMinimalAgentConfig, defaultMaxTokens, DEFAULT_SUBAGENTS_CONFIG, DEFAULT_BROWSER_CONFIG, DEFAULT_COMPUTER_USE_CONFIG, } from './configFile.js';
2
+ import { modelRefFromLegacy, } from '../modelRef.js';
3
+ import { fetchOnlineModels, loadTeamCredentials, resolveOnlineModel, } from '../team/auth.js';
4
+ import { DEFAULT_ADVISOR_CONFIG, DEFAULT_BROWSER_CONFIG, DEFAULT_COMPUTER_USE_CONFIG, DEFAULT_SUBAGENTS_CONFIG, defaultMaxTokens, readMinimalAgentConfig, updateMinimalAgentConfig, } from './configFile.js';
3
5
  import { CONFIG_LIMITS, normalizeLimited } from './numericLimits.js';
4
6
  const DEFAULT_CONTEXT_WINDOW = 128_000;
7
+ function gatewayFallbackReason(model, error) {
8
+ const state = model?.availability?.state;
9
+ if (state === 'quota_exhausted' || state === 'concurrency_exceeded')
10
+ return 'quota_exhausted';
11
+ if (state === 'model_disabled' || state === 'disabled')
12
+ return 'model_disabled';
13
+ if (state === 'device_expired')
14
+ return 'credential_expired';
15
+ if (state === 'not_authorized')
16
+ return 'grant_revoked';
17
+ if (state === 'server_offline' || state === 'offline')
18
+ return 'offline';
19
+ const message = error instanceof Error ? error.message : '';
20
+ if (message.includes('DEVICE_REVOKED') || message.includes('401'))
21
+ return 'credential_expired';
22
+ if (message.includes('MODEL_UNAVAILABLE') || message.includes('403'))
23
+ return 'grant_revoked';
24
+ return 'offline';
25
+ }
26
+ function gatewayProviderFromModel(credentials, model) {
27
+ return {
28
+ name: model.displayName || model.model,
29
+ source: 'gateway',
30
+ remoteModelId: model.id,
31
+ gatewayUrl: credentials.serverUrl,
32
+ gatewayToken: credentials.deviceToken,
33
+ gatewayMaxToolCategories: model.maxToolCategories,
34
+ gatewayDefaultToolCategories: model.defaultToolCategories,
35
+ // Deprecated compatibility field: before the explicit max/default/session
36
+ // split this field was used as the provider boundary. Keep its safe
37
+ // default as the server maximum; the current Session selection is applied
38
+ // per turn by runAgentTurn/useChat.
39
+ gatewayToolCategories: model.maxToolCategories,
40
+ model: model.model,
41
+ contextWindow: model.contextWindow,
42
+ maxTokens: model.maxTokens,
43
+ apiFormat: model.apiFormat,
44
+ supportsVision: model.supportsVision,
45
+ gatewayCapabilities: model.capabilities,
46
+ promptCache: { mode: 'disabled' },
47
+ };
48
+ }
5
49
  function positiveInt(value, fallback) {
6
50
  const parsed = Number.parseInt(value ?? '', 10);
7
51
  return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
@@ -26,14 +70,20 @@ function configFromEnv() {
26
70
  return null;
27
71
  const tools = {};
28
72
  if (process.env.TAVILY_API_KEY)
29
- tools.webSearch = { provider: 'tavily', apiKey: process.env.TAVILY_API_KEY };
30
- if (process.env.OPENAI_IMAGE_BASE_URL && process.env.OPENAI_IMAGE_API_KEY && process.env.OPENAI_IMAGE_MODEL) {
73
+ tools.webSearch = {
74
+ provider: 'tavily',
75
+ apiKey: process.env.TAVILY_API_KEY,
76
+ };
77
+ if (process.env.OPENAI_IMAGE_BASE_URL &&
78
+ process.env.OPENAI_IMAGE_API_KEY &&
79
+ process.env.OPENAI_IMAGE_MODEL) {
31
80
  tools.imageGeneration = {
32
81
  provider: process.env.OPENAI_IMAGE_PROVIDER ?? 'openai',
33
82
  baseURL: process.env.OPENAI_IMAGE_BASE_URL,
34
83
  apiKey: process.env.OPENAI_IMAGE_API_KEY,
35
84
  model: process.env.OPENAI_IMAGE_MODEL,
36
- protocol: process.env.OPENAI_IMAGE_PROTOCOL === 'chat' || process.env.OPENAI_IMAGE_PROTOCOL === 'images'
85
+ protocol: process.env.OPENAI_IMAGE_PROTOCOL === 'chat' ||
86
+ process.env.OPENAI_IMAGE_PROTOCOL === 'images'
37
87
  ? process.env.OPENAI_IMAGE_PROTOCOL
38
88
  : 'auto',
39
89
  };
@@ -41,7 +91,11 @@ function configFromEnv() {
41
91
  if (process.env.OPENROUTER_API_KEY)
42
92
  tools.openRouter = { apiKey: process.env.OPENROUTER_API_KEY };
43
93
  if (process.env.MINIMAX_API_KEY && process.env.MINIMAX_GROUP_ID) {
44
- tools.textToSpeech = { provider: 'minimax', apiKey: process.env.MINIMAX_API_KEY, groupId: process.env.MINIMAX_GROUP_ID };
94
+ tools.textToSpeech = {
95
+ provider: 'minimax',
96
+ apiKey: process.env.MINIMAX_API_KEY,
97
+ groupId: process.env.MINIMAX_GROUP_ID,
98
+ };
45
99
  }
46
100
  const compactRatio = Number(process.env.MINIMAL_AGENT_COMPACT_RATIO);
47
101
  const name = process.env.MINIMAL_AGENT_PROVIDER ?? 'env';
@@ -70,13 +124,14 @@ function configFromEnv() {
70
124
  version: 4,
71
125
  models: [envModel],
72
126
  baseModelId: envModel.id,
127
+ teamServerUrl: process.env.KAKADEAI_SOCIAL_SERVER_URL?.trim() || null,
73
128
  ...(compactRatio > 0 && compactRatio <= 1 ? { compactRatio } : {}),
74
129
  subagents: {
75
130
  ...DEFAULT_SUBAGENTS_CONFIG,
76
131
  maxCallsPerTurn: positiveInt(process.env.AGENT_TOOL_MAX_CALLS_PER_TURN, 6),
77
132
  maxConcurrent: positiveInt(process.env.AGENT_TOOL_MAX_CONCURRENT, 3),
78
133
  timeoutMs: positiveInt(process.env.AGENT_TOOL_TIMEOUT_MS, 1_800_000),
79
- exploreMaxTurns: positiveInt(process.env.AGENT_TOOL_EXPLORE_MAX_TURNS, 50),
134
+ exploreMaxTurns: positiveInt(process.env.AGENT_TOOL_EXPLORE_MAX_TURNS, 200),
80
135
  generalMaxTurns: positiveInt(process.env.AGENT_TOOL_GENERAL_MAX_TURNS, 100),
81
136
  },
82
137
  browser: DEFAULT_BROWSER_CONFIG,
@@ -92,6 +147,7 @@ function configFromEnv() {
92
147
  }
93
148
  function resolveProvider(entry, compactRatio) {
94
149
  return {
150
+ source: 'local',
95
151
  name: entry.displayName ?? entry.model,
96
152
  baseURL: entry.baseURL,
97
153
  apiKey: entry.apiKey,
@@ -100,15 +156,26 @@ function resolveProvider(entry, compactRatio) {
100
156
  maxTokens: entry.maxTokens ?? defaultMaxTokens(entry.contextWindow),
101
157
  apiFormat: entry.apiFormat,
102
158
  supportsVision: entry.supportsVision !== false,
159
+ ...(entry.supportsJsonSchema !== undefined
160
+ ? { supportsJsonSchema: entry.supportsJsonSchema }
161
+ : {}),
103
162
  promptCache: entry.promptCache ?? { mode: 'auto' },
104
163
  ...(compactRatio !== undefined ? { compactRatio } : {}),
164
+ // cache_edits 式回收:仅 Anthropic 格式 + 显式 env 开启时生效(非公开协议,
165
+ // 依赖支持该扩展的网关端点;语义与默认值说明见 types.ts Provider.cacheEdits)
166
+ ...(entry.apiFormat === 'anthropic' &&
167
+ process.env.MINIMAL_AGENT_CACHE_EDITS === '1'
168
+ ? { cacheEdits: true }
169
+ : {}),
105
170
  };
106
171
  }
107
172
  function mergeRecord(base, patch) {
108
173
  const out = { ...(base ?? {}) };
109
174
  for (const [key, value] of Object.entries(patch)) {
110
175
  if (value && typeof value === 'object' && !Array.isArray(value)) {
111
- out[key] = mergeRecord(out[key] && typeof out[key] === 'object' && !Array.isArray(out[key]) ? out[key] : undefined, value);
176
+ out[key] = mergeRecord(out[key] && typeof out[key] === 'object' && !Array.isArray(out[key])
177
+ ? out[key]
178
+ : undefined, value);
112
179
  }
113
180
  else if (value !== undefined)
114
181
  out[key] = value;
@@ -118,6 +185,13 @@ function mergeRecord(base, patch) {
118
185
  function hasEntries(value) {
119
186
  return !!value && Object.keys(value).length > 0;
120
187
  }
188
+ /** Remove an optional config key while keeping the persisted object sparse. */
189
+ function omitKey(value, key) {
190
+ if (!value)
191
+ return value;
192
+ const { [key]: _removed, ...rest } = value;
193
+ return rest;
194
+ }
121
195
  function applyModelsPatch(models, ops) {
122
196
  let out = [...models];
123
197
  const now = Date.now();
@@ -137,9 +211,14 @@ function applyModelsPatch(models, ops) {
137
211
  baseURL,
138
212
  apiKey,
139
213
  model: modelId,
140
- contextWindow: m.contextWindow && m.contextWindow > 0 ? m.contextWindow : DEFAULT_CONTEXT_WINDOW,
214
+ contextWindow: m.contextWindow && m.contextWindow > 0
215
+ ? m.contextWindow
216
+ : DEFAULT_CONTEXT_WINDOW,
141
217
  ...(m.maxTokens ? { maxTokens: m.maxTokens } : {}),
142
218
  supportsVision: m.supportsVision !== false,
219
+ ...(m.supportsJsonSchema !== undefined
220
+ ? { supportsJsonSchema: m.supportsJsonSchema }
221
+ : {}),
143
222
  promptCache: m.promptCache ?? { mode: 'auto' },
144
223
  enabled: m.enabled ?? true,
145
224
  createdAt: now,
@@ -154,13 +233,26 @@ function applyModelsPatch(models, ops) {
154
233
  const patch = item.patch;
155
234
  const next = {
156
235
  ...existing,
157
- ...(patch.apiFormat ? { apiFormat: patch.apiFormat === 'anthropic' ? 'anthropic' : 'openai' } : {}),
158
- ...(patch.displayName !== undefined ? { displayName: patch.displayName.trim() || undefined } : {}),
236
+ ...(patch.apiFormat
237
+ ? {
238
+ apiFormat: patch.apiFormat === 'anthropic' ? 'anthropic' : 'openai',
239
+ }
240
+ : {}),
241
+ ...(patch.displayName !== undefined
242
+ ? { displayName: patch.displayName.trim() || undefined }
243
+ : {}),
159
244
  ...(patch.baseURL?.trim() ? { baseURL: patch.baseURL.trim() } : {}),
160
245
  ...(patch.model?.trim() ? { model: patch.model.trim() } : {}),
161
246
  ...(patch.contextWindow ? { contextWindow: patch.contextWindow } : {}),
162
- ...(patch.maxTokens !== undefined ? { maxTokens: patch.maxTokens || undefined } : {}),
163
- ...(patch.supportsVision !== undefined ? { supportsVision: patch.supportsVision !== false } : {}),
247
+ ...(patch.maxTokens !== undefined
248
+ ? { maxTokens: patch.maxTokens || undefined }
249
+ : {}),
250
+ ...(patch.supportsVision !== undefined
251
+ ? { supportsVision: patch.supportsVision !== false }
252
+ : {}),
253
+ ...(patch.supportsJsonSchema !== undefined
254
+ ? { supportsJsonSchema: patch.supportsJsonSchema }
255
+ : {}),
164
256
  ...(patch.promptCache ? { promptCache: patch.promptCache } : {}),
165
257
  ...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),
166
258
  updatedAt: now,
@@ -187,7 +279,8 @@ function applyConfigPatch(base, patch) {
187
279
  if (wasEmpty && baseModelId === null && models.length > 0)
188
280
  baseModelId = models[0].id;
189
281
  if (patch.baseModelId !== undefined) {
190
- if (patch.baseModelId !== null && !models.some((entry) => entry.id === patch.baseModelId)) {
282
+ if (patch.baseModelId !== null &&
283
+ !models.some((entry) => entry.id === patch.baseModelId)) {
191
284
  throw new Error('要设为基座的模型不存在');
192
285
  }
193
286
  baseModelId = patch.baseModelId;
@@ -200,6 +293,11 @@ function applyConfigPatch(base, patch) {
200
293
  if (baseEntry.enabled === false)
201
294
  throw new Error('不能禁用当前基座模型,请先设置其他模型为基座');
202
295
  }
296
+ // 团队服务器地址:不像 baseModelId 那样要交叉校验(不引用 models[]),一个裸字符串。
297
+ let teamServerUrl = base?.teamServerUrl ?? null;
298
+ if (patch.teamServerUrl !== undefined) {
299
+ teamServerUrl = patch.teamServerUrl?.trim() || null;
300
+ }
203
301
  let advisor = base?.advisor;
204
302
  if (patch.advisor) {
205
303
  if (patch.advisor.clear) {
@@ -207,85 +305,113 @@ function applyConfigPatch(base, patch) {
207
305
  }
208
306
  else {
209
307
  advisor = {
210
- enabled: patch.advisor.enabled ?? advisor?.enabled ?? true,
308
+ enabled: patch.advisor.enabled ?? advisor?.enabled ?? DEFAULT_ADVISOR_CONFIG.enabled,
211
309
  mode: patch.advisor.mode ?? advisor?.mode ?? 'auto',
212
- modelId: patch.advisor.modelId !== undefined ? patch.advisor.modelId : (advisor?.modelId ?? null),
310
+ modelId: patch.advisor.modelId !== undefined
311
+ ? patch.advisor.modelId
312
+ : (advisor?.modelId ?? null),
213
313
  contextPolicy: 'full-relevant',
214
314
  shareSensitive: patch.advisor.shareSensitive ?? advisor?.shareSensitive ?? false,
215
- inputTokenBudget: normalizeLimited(patch.advisor.inputTokenBudget ?? advisor?.inputTokenBudget, CONFIG_LIMITS.advisorInputTokenBudget, 128_000),
216
- timeoutMs: normalizeLimited(patch.advisor.timeoutMs ?? advisor?.timeoutMs, CONFIG_LIMITS.advisorTimeoutMs, 180_000),
315
+ inputTokenBudget: normalizeLimited(patch.advisor.inputTokenBudget ?? advisor?.inputTokenBudget, CONFIG_LIMITS.advisorInputTokenBudget, DEFAULT_ADVISOR_CONFIG.inputTokenBudget),
316
+ timeoutMs: normalizeLimited(patch.advisor.timeoutMs ?? advisor?.timeoutMs, CONFIG_LIMITS.advisorTimeoutMs, DEFAULT_ADVISOR_CONFIG.timeoutMs),
217
317
  };
218
318
  }
219
319
  }
220
320
  // 顾问引用的模型若已被删除或禁用,级联置空(软失联——解析层已把 null/悬空 id 当
221
321
  // 「未配置」优雅处理,不留死链接;这与基座模型的硬阻止是刻意的不对称:顾问本来就是
222
322
  // 可降级的第二意见,不像基座那样「没有就整个应用跑不起来」)。
223
- if (advisor?.modelId) {
323
+ if (advisor?.modelId && !advisor.modelId.startsWith('online:')) {
224
324
  const referenced = models.find((entry) => entry.id === advisor.modelId);
225
325
  if (!referenced || referenced.enabled === false)
226
326
  advisor = { ...advisor, modelId: null };
227
327
  }
328
+ const workflowModels = {
329
+ ...(base?.workflowModels ?? {}),
330
+ };
331
+ for (const [role, modelId] of Object.entries(patch.workflowModels ?? {})) {
332
+ if (modelId)
333
+ workflowModels[role] = modelId;
334
+ else
335
+ delete workflowModels[role];
336
+ }
337
+ for (const role of Object.keys(workflowModels)) {
338
+ const modelId = workflowModels[role];
339
+ const configured = models.find((entry) => entry.id === modelId);
340
+ if (!configured || configured.enabled === false)
341
+ delete workflowModels[role];
342
+ }
228
343
  // 比例类:保留 4 位小数(= 百分比 2 位),否则 UI 上下箭头按 0.01 步进会累加出
229
344
  // `0.8500000000000001` 这种浮点脏值直接写进 config.json。
230
345
  const compactRatio = patch.compactRatio !== undefined
231
- ? (patch.compactRatio > 0 && patch.compactRatio <= 1
346
+ ? patch.compactRatio > 0 && patch.compactRatio <= 1
232
347
  ? normalizeLimited(patch.compactRatio, CONFIG_LIMITS.compactRatio, CONFIG_LIMITS.compactRatio.max)
233
- : undefined)
348
+ : undefined
234
349
  : base?.compactRatio;
235
- const tools = { ...(base?.tools ?? {}) };
350
+ let tools = { ...(base?.tools ?? {}) };
236
351
  const drafts = structuredClone(base?.drafts ?? {});
237
352
  const toolPatch = patch.tools;
238
353
  if (toolPatch?.webSearch) {
239
354
  if (toolPatch.webSearch.clear) {
240
- delete tools.webSearch;
241
- delete drafts.tools?.webSearch;
355
+ tools = omitKey(tools, 'webSearch') ?? {};
356
+ if (drafts.tools)
357
+ drafts.tools = omitKey(drafts.tools, 'webSearch');
242
358
  }
243
359
  else
244
- tools.webSearch = mergeRecord(tools.webSearch, { provider: 'tavily', ...toolPatch.webSearch });
360
+ tools.webSearch = mergeRecord(tools.webSearch, {
361
+ provider: 'tavily',
362
+ ...toolPatch.webSearch,
363
+ });
245
364
  }
246
365
  if (toolPatch?.imageGeneration) {
247
366
  if (toolPatch.imageGeneration.clear) {
248
- delete tools.imageGeneration;
249
- delete drafts.tools?.imageGeneration;
367
+ tools = omitKey(tools, 'imageGeneration') ?? {};
368
+ if (drafts.tools)
369
+ drafts.tools = omitKey(drafts.tools, 'imageGeneration');
250
370
  }
251
371
  else {
252
372
  const next = mergeRecord(tools.imageGeneration, toolPatch.imageGeneration);
253
373
  if (toolPatch.imageGeneration.clearApiKey)
254
374
  next.apiKey = '';
255
- delete next.clear;
256
- delete next.clearApiKey;
257
- if (!next.baseURL || !next.apiKey || !next.model)
375
+ const cleanNext = omitKey(omitKey(next, 'clear'), 'clearApiKey');
376
+ if (!cleanNext.baseURL || !cleanNext.apiKey || !cleanNext.model)
258
377
  throw new Error('图片生成缺少 Base URL、API Key 或模型名称');
259
- tools.imageGeneration = next;
378
+ tools.imageGeneration = cleanNext;
260
379
  }
261
380
  }
262
381
  if (toolPatch?.openRouter) {
263
382
  if (toolPatch.openRouter.clear) {
264
- delete tools.openRouter;
265
- delete drafts.tools?.openRouter;
383
+ tools = omitKey(tools, 'openRouter') ?? {};
384
+ if (drafts.tools)
385
+ drafts.tools = omitKey(drafts.tools, 'openRouter');
266
386
  }
267
387
  else
268
388
  tools.openRouter = mergeRecord(tools.openRouter, toolPatch.openRouter);
269
389
  }
270
390
  if (toolPatch?.textToSpeech) {
271
391
  if (toolPatch.textToSpeech.clear) {
272
- delete tools.textToSpeech;
273
- delete drafts.tools?.textToSpeech;
392
+ tools = omitKey(tools, 'textToSpeech') ?? {};
393
+ if (drafts.tools)
394
+ drafts.tools = omitKey(drafts.tools, 'textToSpeech');
274
395
  }
275
396
  else {
276
- const next = mergeRecord(tools.textToSpeech, { provider: 'minimax', ...toolPatch.textToSpeech });
397
+ const next = mergeRecord(tools.textToSpeech, {
398
+ provider: 'minimax',
399
+ ...toolPatch.textToSpeech,
400
+ });
277
401
  if (toolPatch.textToSpeech.clearApiKey)
278
402
  next.apiKey = '';
279
- delete next.clear;
280
- delete next.clearApiKey;
281
- if (!next.apiKey || !next.groupId)
403
+ const cleanNext = omitKey(omitKey(next, 'clear'), 'clearApiKey');
404
+ if (!cleanNext.apiKey || !cleanNext.groupId)
282
405
  throw new Error('MiniMax 语音缺少 API Key 或 Group ID');
283
- tools.textToSpeech = next;
406
+ tools.textToSpeech = cleanNext;
284
407
  }
285
408
  }
286
409
  // 数字字段必须在**写入时**就按同一份边界规整——此前这里是裸 spread,读回时才被
287
410
  // parseSubagents 的边界收窄,于是「存进去 300、读出来 100」,UI 表现成静默变回原值。
288
- const mergedSubagents = { ...(base?.subagents ?? DEFAULT_SUBAGENTS_CONFIG), ...(patch.subagents ?? {}) };
411
+ const mergedSubagents = {
412
+ ...(base?.subagents ?? DEFAULT_SUBAGENTS_CONFIG),
413
+ ...(patch.subagents ?? {}),
414
+ };
289
415
  const subagents = {
290
416
  ...mergedSubagents,
291
417
  maxCallsPerTurn: normalizeLimited(mergedSubagents.maxCallsPerTurn, CONFIG_LIMITS.subagentMaxCallsPerTurn, DEFAULT_SUBAGENTS_CONFIG.maxCallsPerTurn),
@@ -294,7 +420,11 @@ function applyConfigPatch(base, patch) {
294
420
  exploreMaxTurns: normalizeLimited(mergedSubagents.exploreMaxTurns, CONFIG_LIMITS.subagentExploreMaxTurns, DEFAULT_SUBAGENTS_CONFIG.exploreMaxTurns),
295
421
  generalMaxTurns: normalizeLimited(mergedSubagents.generalMaxTurns, CONFIG_LIMITS.subagentGeneralMaxTurns, DEFAULT_SUBAGENTS_CONFIG.generalMaxTurns),
296
422
  };
297
- const browser = { ...(base?.browser ?? DEFAULT_BROWSER_CONFIG), ...(patch.browser ?? {}), profileId: 'default' };
423
+ const browser = {
424
+ ...(base?.browser ?? DEFAULT_BROWSER_CONFIG),
425
+ ...(patch.browser ?? {}),
426
+ profileId: 'default',
427
+ };
298
428
  const computerUse = {
299
429
  ...(base?.computerUse ?? DEFAULT_COMPUTER_USE_CONFIG),
300
430
  ...(patch.computerUse ?? {}),
@@ -302,12 +432,34 @@ function applyConfigPatch(base, patch) {
302
432
  computerUse.observationFrames = 1;
303
433
  computerUse.maxImagePixels = normalizeLimited(computerUse.maxImagePixels, CONFIG_LIMITS.computerUseMaxImagePixels, DEFAULT_COMPUTER_USE_CONFIG.maxImagePixels);
304
434
  if (!hasEntries(drafts.tools))
305
- delete drafts.tools;
306
- return { models, baseModelId, ...(compactRatio !== undefined ? { compactRatio } : {}), advisor, subagents, browser, computerUse, tools, ...(hasEntries(drafts) ? { drafts } : {}) };
435
+ drafts.tools = undefined;
436
+ return {
437
+ models,
438
+ baseModelId,
439
+ teamServerUrl,
440
+ ...(compactRatio !== undefined ? { compactRatio } : {}),
441
+ advisor,
442
+ // Preserve an explicit empty object through updateMinimalAgentConfig so
443
+ // removing the final role is distinguishable from an unrelated mutator
444
+ // that omitted this optional field.
445
+ workflowModels,
446
+ subagents,
447
+ browser,
448
+ computerUse,
449
+ tools,
450
+ ...(hasEntries(drafts) ? { drafts } : {}),
451
+ };
307
452
  }
308
453
  export class ConfigService {
309
- snapshot = { source: 'none', readOnly: false, config: null, revision: 0 };
310
- get revision() { return this.snapshot.revision; }
454
+ snapshot = {
455
+ source: 'none',
456
+ readOnly: false,
457
+ config: null,
458
+ revision: 0,
459
+ };
460
+ get revision() {
461
+ return this.snapshot.revision;
462
+ }
311
463
  async reload() {
312
464
  const envOnly = process.env.MINIMAL_AGENT_CONFIG_MODE === 'env';
313
465
  const json = envOnly ? null : await readMinimalAgentConfig();
@@ -317,11 +469,14 @@ export class ConfigService {
317
469
  readOnly: envOnly,
318
470
  config: json ?? env,
319
471
  };
320
- const changed = this.snapshot.revision === 0
321
- || this.snapshot.source !== next.source
322
- || this.snapshot.readOnly !== next.readOnly
323
- || JSON.stringify(this.snapshot.config) !== JSON.stringify(next.config);
324
- this.snapshot = { ...next, revision: changed ? this.snapshot.revision + 1 : this.snapshot.revision };
472
+ const changed = this.snapshot.revision === 0 ||
473
+ this.snapshot.source !== next.source ||
474
+ this.snapshot.readOnly !== next.readOnly ||
475
+ JSON.stringify(this.snapshot.config) !== JSON.stringify(next.config);
476
+ this.snapshot = {
477
+ ...next,
478
+ revision: changed ? this.snapshot.revision + 1 : this.snapshot.revision,
479
+ };
325
480
  return this.getSnapshot();
326
481
  }
327
482
  async getSnapshot() {
@@ -336,21 +491,149 @@ export class ConfigService {
336
491
  return null;
337
492
  return resolveProvider(entry, config?.compactRatio);
338
493
  }
494
+ /**
495
+ * 团队登录服务器的默认地址:env 优先于 config.json,跟随 minimal-desktop 的
496
+ * `resolve_social_server()`(`src-tauri/src/lib.rs`)已验证的同一优先级——这两个
497
+ * 项目共享 `KAKADEAI_SOCIAL_SERVER_URL` 这一个环境变量名,语义必须一致,不能
498
+ * minimal-agent 这边搞成 config 优先。
499
+ *
500
+ * ⚠️ 不能简单读 `getSnapshot().config?.teamServerUrl`:那个 snapshot 在存在
501
+ * config.json 时完全不看 env(`reload()` 里 `config: json ?? env`,env 只在
502
+ * **没有** config.json 时才整体生效),会让"config.json 存在但没配地址、同时设了
503
+ * env"这种常见场景里 env 被错误地忽略。这里必须独立读 `process.env`。
504
+ *
505
+ * 返回值带 `source`,供诊断和私有部署使用;正式用户不需要接触服务器地址。
506
+ */
507
+ async resolveTeamServerUrl() {
508
+ const rawEnvValue = process.env.KAKADEAI_SOCIAL_SERVER_URL;
509
+ if (rawEnvValue !== undefined)
510
+ return {
511
+ value: rawEnvValue.trim() || null,
512
+ source: 'env',
513
+ };
514
+ const { config } = await this.getSnapshot();
515
+ const configValue = config?.teamServerUrl ?? null;
516
+ return configValue
517
+ ? { value: configValue, source: 'config' }
518
+ : { value: 'https://kakadeai.com', source: 'default' };
519
+ }
339
520
  async providerForModel(modelId) {
340
521
  if (!modelId)
341
522
  return this.provider();
523
+ const ref = modelRefFromLegacy(modelId);
524
+ if (ref.source === 'gateway') {
525
+ const resolved = await this.providerForRef(ref);
526
+ return resolved;
527
+ }
342
528
  const { config } = await this.getSnapshot();
343
529
  const entry = config?.models.find((m) => m.id === modelId);
344
530
  if (!entry?.apiKey)
345
531
  return null;
346
532
  return resolveProvider(entry, config?.compactRatio);
347
533
  }
534
+ /** Resolve a portable workflow role from fresh cross-process config. */
535
+ async providerForWorkflowRole(role) {
536
+ const { config } = await this.reload();
537
+ const modelId = config?.workflowModels?.[role];
538
+ return modelId ? this.providerForModel(modelId) : null;
539
+ }
540
+ async providerForGatewayModel(modelId) {
541
+ // A remembered gateway model must not make standalone mode inspect the
542
+ // team credential file or attempt a network request. The configured
543
+ // server is the explicit opt-in boundary; credentials are read only after
544
+ // it is present.
545
+ const configured = await this.resolveTeamServerUrl();
546
+ if (!configured.value)
547
+ return null;
548
+ const resolved = await resolveOnlineModel(modelId, configured.value ?? undefined).catch(() => null);
549
+ if (!resolved)
550
+ return null;
551
+ const { credentials, model } = resolved;
552
+ if (model.availability && model.availability.state !== 'available')
553
+ return null;
554
+ return gatewayProviderFromModel(credentials, model);
555
+ }
556
+ /** Resolve the persisted source-aware identity without making callers encode
557
+ * gateway selections as the legacy `online:<id>` string. */
558
+ async providerForRef(ref) {
559
+ if (!ref)
560
+ return this.provider();
561
+ return ref.source === 'gateway'
562
+ ? this.providerForGatewayModel(ref.modelId)
563
+ : this.providerForModel(ref.modelId);
564
+ }
565
+ /**
566
+ * Resolve a persisted model reference and retain the reason when a gateway
567
+ * model cannot be used. The reason is intentionally kept at the local
568
+ * session boundary: it is UI/selection state, not a server-side session or
569
+ * prompt record.
570
+ */
571
+ async resolveModelRef(ref) {
572
+ if (!ref)
573
+ return {
574
+ provider: await this.providerForModel(null),
575
+ fallbackReason: null,
576
+ };
577
+ if (ref.source === 'local')
578
+ return {
579
+ provider: await this.providerForRef(ref),
580
+ fallbackReason: null,
581
+ };
582
+ const configured = await this.resolveTeamServerUrl();
583
+ if (!configured.value)
584
+ return { provider: null, fallbackReason: 'logged_out' };
585
+ const credentials = await loadTeamCredentials(configured.value);
586
+ if (!credentials)
587
+ return { provider: null, fallbackReason: 'logged_out' };
588
+ try {
589
+ const models = await fetchOnlineModels(credentials);
590
+ const model = models.find((item) => item.id === ref.modelId);
591
+ if (!model)
592
+ return { provider: null, fallbackReason: 'grant_revoked' };
593
+ if (model.availability?.state !== undefined &&
594
+ model.availability.state !== 'available')
595
+ return {
596
+ provider: null,
597
+ fallbackReason: gatewayFallbackReason(model),
598
+ };
599
+ return {
600
+ provider: gatewayProviderFromModel(credentials, model),
601
+ fallbackReason: null,
602
+ };
603
+ }
604
+ catch (error) {
605
+ return {
606
+ provider: null,
607
+ fallbackReason: gatewayFallbackReason(undefined, error),
608
+ };
609
+ }
610
+ }
611
+ /** Online defaults are server-owned and fetched only when team credentials
612
+ * exist. No standalone launch calls this path. */
613
+ async onlineDefaultProvider() {
614
+ const configured = await this.resolveTeamServerUrl();
615
+ if (!configured.value)
616
+ return null;
617
+ const credentials = await import('../team/auth.js')
618
+ .then((module) => module.loadTeamCredentials(configured.value ?? undefined))
619
+ .catch(() => null);
620
+ if (!credentials)
621
+ return null;
622
+ const models = await import('../team/auth.js')
623
+ .then((module) => module.fetchOnlineModels(credentials))
624
+ .catch(() => []);
625
+ const model = models.find((item) => item.isDefault &&
626
+ (!item.availability || item.availability.state === 'available'));
627
+ if (!model)
628
+ return null;
629
+ return gatewayProviderFromModel(credentials, model);
630
+ }
348
631
  /** 带 apiKey 的原始列表——仅服务端内部消费(桌面端 store.ts 的 readConfig() 会脱敏成 ModelView)。 */
349
632
  async models() {
350
633
  return (await this.getSnapshot()).config?.models ?? [];
351
634
  }
352
635
  async model(id) {
353
- return (await this.getSnapshot()).config?.models.find((entry) => entry.id === id) ?? null;
636
+ return ((await this.getSnapshot()).config?.models.find((entry) => entry.id === id) ?? null);
354
637
  }
355
638
  /**
356
639
  * 保留「未启用但已配置」和「完全未配置」两种返回值的区分——advisor.ts 的两条不同报错
@@ -368,10 +651,25 @@ export class ConfigService {
368
651
  const advisor = config?.advisor;
369
652
  if (!advisor?.modelId)
370
653
  return null;
654
+ const advisorRef = modelRefFromLegacy(advisor.modelId);
655
+ if (advisorRef.source === 'gateway') {
656
+ const provider = await this.providerForRef(advisorRef);
657
+ return provider
658
+ ? {
659
+ ...advisor,
660
+ provider,
661
+ supportsVision: provider.supportsVision !== false,
662
+ }
663
+ : null;
664
+ }
371
665
  const entry = config.models.find((m) => m.id === advisor.modelId);
372
666
  if (!entry?.apiKey)
373
667
  return null;
374
- return { ...advisor, provider: resolveProvider(entry), supportsVision: entry.supportsVision !== false };
668
+ return {
669
+ ...advisor,
670
+ provider: resolveProvider(entry),
671
+ supportsVision: entry.supportsVision !== false,
672
+ };
375
673
  }
376
674
  /**
377
675
  * 同步版 advisor 可用性探测——仅用于 resolveAvailability 这类工具列表探测场景。
@@ -387,6 +685,14 @@ export class ConfigService {
387
685
  const advisor = config?.advisor;
388
686
  if (!advisor?.modelId)
389
687
  return { enabled: false, mode: 'auto', modelId: null, configured: false };
688
+ if (modelRefFromLegacy(advisor.modelId).source === 'gateway') {
689
+ return {
690
+ enabled: advisor.enabled !== false,
691
+ mode: advisor.mode === 'manual' ? 'manual' : 'auto',
692
+ modelId: advisor.modelId,
693
+ configured: true,
694
+ };
695
+ }
390
696
  const entry = config?.models?.find((m) => m.id === advisor.modelId);
391
697
  if (!entry?.apiKey)
392
698
  return { enabled: false, mode: 'auto', modelId: null, configured: false };
@@ -404,7 +710,7 @@ export class ConfigService {
404
710
  return (await this.reload()).config?.browser ?? DEFAULT_BROWSER_CONFIG;
405
711
  }
406
712
  async computerUse() {
407
- return (await this.reload()).config?.computerUse ?? DEFAULT_COMPUTER_USE_CONFIG;
713
+ return ((await this.reload()).config?.computerUse ?? DEFAULT_COMPUTER_USE_CONFIG);
408
714
  }
409
715
  async tool(key) {
410
716
  return (await this.reload()).config?.tools[key];
@@ -412,10 +718,22 @@ export class ConfigService {
412
718
  async toolStatus() {
413
719
  const tools = (await this.reload()).config?.tools ?? {};
414
720
  return {
415
- webSearch: { state: tools.webSearch ? 'configured' : 'unconfigured', configured: !!tools.webSearch },
416
- imageGeneration: { state: tools.imageGeneration ? 'configured' : 'unconfigured', configured: !!tools.imageGeneration },
417
- openRouter: { state: tools.openRouter ? 'configured' : 'unconfigured', configured: !!tools.openRouter },
418
- textToSpeech: { state: tools.textToSpeech ? 'configured' : 'unconfigured', configured: !!tools.textToSpeech },
721
+ webSearch: {
722
+ state: tools.webSearch ? 'configured' : 'unconfigured',
723
+ configured: !!tools.webSearch,
724
+ },
725
+ imageGeneration: {
726
+ state: tools.imageGeneration ? 'configured' : 'unconfigured',
727
+ configured: !!tools.imageGeneration,
728
+ },
729
+ openRouter: {
730
+ state: tools.openRouter ? 'configured' : 'unconfigured',
731
+ configured: !!tools.openRouter,
732
+ },
733
+ textToSpeech: {
734
+ state: tools.textToSpeech ? 'configured' : 'unconfigured',
735
+ configured: !!tools.textToSpeech,
736
+ },
419
737
  };
420
738
  }
421
739
  async savePatch(patch) {
@@ -438,33 +756,55 @@ export class ConfigService {
438
756
  await updateMinimalAgentConfig((latest) => {
439
757
  let active = latest ?? current.config;
440
758
  if (patch.subagents)
441
- active = { version: 4, ...applyConfigPatch(active, { subagents: patch.subagents }), savedAt: active.savedAt };
759
+ active = {
760
+ version: 4,
761
+ ...applyConfigPatch(active, { subagents: patch.subagents }),
762
+ savedAt: active.savedAt,
763
+ };
442
764
  if (patch.computerUse)
443
- active = { version: 4, ...applyConfigPatch(active, { computerUse: patch.computerUse }), savedAt: active.savedAt };
765
+ active = {
766
+ version: 4,
767
+ ...applyConfigPatch(active, { computerUse: patch.computerUse }),
768
+ savedAt: active.savedAt,
769
+ };
444
770
  const drafts = structuredClone(active.drafts ?? {});
445
771
  for (const key of Object.keys(patch.tools ?? {})) {
446
772
  const rawPiece = patch.tools[key];
447
773
  if (!rawPiece)
448
774
  continue;
449
- const previous = (drafts.tools ?? {})[key];
775
+ const previous = drafts.tools?.[key];
450
776
  const merged = mergeRecord(previous, rawPiece);
451
777
  try {
452
- active = { version: 4, ...applyConfigPatch(active, { tools: { [key]: merged } }), savedAt: active.savedAt };
453
- delete drafts.tools?.[key];
778
+ active = {
779
+ version: 4,
780
+ ...applyConfigPatch(active, {
781
+ tools: { [key]: merged },
782
+ }),
783
+ savedAt: active.savedAt,
784
+ };
785
+ drafts.tools = omitKey(drafts.tools, key);
454
786
  }
455
787
  catch {
456
788
  state = 'draft';
457
789
  draftFields.push(key);
458
- (drafts.tools ??= {})[key] = merged;
790
+ const toolDrafts = drafts.tools ?? {};
791
+ toolDrafts[key] = merged;
792
+ drafts.tools = toolDrafts;
459
793
  }
460
794
  }
461
795
  if (!hasEntries(drafts.tools))
462
- delete drafts.tools;
796
+ drafts.tools = undefined;
463
797
  return {
464
- models: active.models, baseModelId: active.baseModelId,
465
- ...(active.compactRatio !== undefined ? { compactRatio: active.compactRatio } : {}),
466
- advisor: active.advisor, subagents: active.subagents, browser: active.browser,
467
- computerUse: active.computerUse, tools: active.tools,
798
+ models: active.models,
799
+ baseModelId: active.baseModelId,
800
+ ...(active.compactRatio !== undefined
801
+ ? { compactRatio: active.compactRatio }
802
+ : {}),
803
+ advisor: active.advisor,
804
+ subagents: active.subagents,
805
+ browser: active.browser,
806
+ computerUse: active.computerUse,
807
+ tools: active.tools,
468
808
  ...(hasEntries(drafts) ? { drafts } : {}),
469
809
  };
470
810
  });
@@ -473,14 +813,19 @@ export class ConfigService {
473
813
  }
474
814
  export const configService = new ConfigService();
475
815
  export const SENSITIVE_ENV_KEYS = new Set([
476
- 'MINIMAL_AGENT_API_KEY', 'TAVILY_API_KEY', 'OPENAI_IMAGE_API_KEY',
477
- 'OPENROUTER_API_KEY', 'MINIMAX_API_KEY', 'MINIMAX_GROUP_ID',
816
+ 'MINIMAL_AGENT_API_KEY',
817
+ 'TAVILY_API_KEY',
818
+ 'OPENAI_IMAGE_API_KEY',
819
+ 'OPENROUTER_API_KEY',
820
+ 'MINIMAX_API_KEY',
821
+ 'MINIMAX_GROUP_ID',
478
822
  ]);
479
823
  /** Child processes inherit normal runtime variables, never model or tool credentials. */
480
824
  export function sanitizeCredentialEnv(source = process.env) {
481
- const env = { ...source };
482
- for (const key of SENSITIVE_ENV_KEYS)
483
- delete env[key];
825
+ let env = { ...source };
826
+ for (const key of SENSITIVE_ENV_KEYS) {
827
+ env = omitKey(env, key) ?? {};
828
+ }
484
829
  return env;
485
830
  }
486
831
  export async function trustedToolEnv(kind, service = configService) {
@@ -506,7 +851,7 @@ export async function trustedToolEnv(kind, service = configService) {
506
851
  if (cfg.protocol && cfg.protocol !== 'auto')
507
852
  env.OPENAI_IMAGE_PROTOCOL = cfg.protocol;
508
853
  else
509
- delete env.OPENAI_IMAGE_PROTOCOL;
854
+ env.OPENAI_IMAGE_PROTOCOL = undefined;
510
855
  }
511
856
  }
512
857
  else if (kind === 'openRouter') {