blackriver-gateway 3.8.46

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 (2415) hide show
  1. package/.env.example +2070 -0
  2. package/@omniroute/opencode-plugin/LICENSE +21 -0
  3. package/@omniroute/opencode-plugin/README.md +296 -0
  4. package/@omniroute/opencode-plugin/package-lock.json +1930 -0
  5. package/@omniroute/opencode-plugin/package.json +73 -0
  6. package/@omniroute/opencode-plugin/src/index.ts +4685 -0
  7. package/@omniroute/opencode-plugin/src/logger.ts +74 -0
  8. package/@omniroute/opencode-plugin/src/naming.ts +301 -0
  9. package/@omniroute/opencode-plugin/tsconfig.json +20 -0
  10. package/@omniroute/opencode-plugin/tsup.config.ts +20 -0
  11. package/@omniroute/opencode-provider/LICENSE +21 -0
  12. package/@omniroute/opencode-provider/README.md +156 -0
  13. package/@omniroute/opencode-provider/package-lock.json +1514 -0
  14. package/@omniroute/opencode-provider/package.json +63 -0
  15. package/@omniroute/opencode-provider/src/index.ts +908 -0
  16. package/@omniroute/opencode-provider/tsconfig.json +20 -0
  17. package/@omniroute/opencode-provider/tsup.config.ts +18 -0
  18. package/LICENSE +22 -0
  19. package/README.md +1265 -0
  20. package/bin/_ops-common.sh +70 -0
  21. package/bin/cli/CONVENTIONS.md +224 -0
  22. package/bin/cli/README.md +146 -0
  23. package/bin/cli/api-commands/agent-skills.mjs +70 -0
  24. package/bin/cli/api-commands/agentbridge.mjs +155 -0
  25. package/bin/cli/api-commands/api-keys.mjs +42 -0
  26. package/bin/cli/api-commands/audio.mjs +40 -0
  27. package/bin/cli/api-commands/chat.mjs +58 -0
  28. package/bin/cli/api-commands/cli-tools.mjs +361 -0
  29. package/bin/cli/api-commands/cloud.mjs +81 -0
  30. package/bin/cli/api-commands/combos.mjs +69 -0
  31. package/bin/cli/api-commands/compression.mjs +128 -0
  32. package/bin/cli/api-commands/embedded-services.mjs +202 -0
  33. package/bin/cli/api-commands/embeddings.mjs +42 -0
  34. package/bin/cli/api-commands/fallback.mjs +49 -0
  35. package/bin/cli/api-commands/images.mjs +42 -0
  36. package/bin/cli/api-commands/memory.mjs +251 -0
  37. package/bin/cli/api-commands/messages.mjs +40 -0
  38. package/bin/cli/api-commands/models.mjs +89 -0
  39. package/bin/cli/api-commands/moderations.mjs +24 -0
  40. package/bin/cli/api-commands/oauth.mjs +114 -0
  41. package/bin/cli/api-commands/playground.mjs +83 -0
  42. package/bin/cli/api-commands/pricing.mjs +44 -0
  43. package/bin/cli/api-commands/provider-nodes.mjs +62 -0
  44. package/bin/cli/api-commands/providers.mjs +148 -0
  45. package/bin/cli/api-commands/quota.mjs +154 -0
  46. package/bin/cli/api-commands/registry.mjs +75 -0
  47. package/bin/cli/api-commands/rerank.mjs +24 -0
  48. package/bin/cli/api-commands/responses.mjs +24 -0
  49. package/bin/cli/api-commands/settings.mjs +228 -0
  50. package/bin/cli/api-commands/system.mjs +320 -0
  51. package/bin/cli/api-commands/telemetry.mjs +26 -0
  52. package/bin/cli/api-commands/traffic-inspector.mjs +307 -0
  53. package/bin/cli/api-commands/translator.mjs +65 -0
  54. package/bin/cli/api-commands/usage.mjs +117 -0
  55. package/bin/cli/api.mjs +269 -0
  56. package/bin/cli/commands/a2a.mjs +323 -0
  57. package/bin/cli/commands/audit.mjs +203 -0
  58. package/bin/cli/commands/autostart.mjs +57 -0
  59. package/bin/cli/commands/backup.mjs +469 -0
  60. package/bin/cli/commands/batches.mjs +235 -0
  61. package/bin/cli/commands/cache.mjs +102 -0
  62. package/bin/cli/commands/chat.mjs +162 -0
  63. package/bin/cli/commands/cloud.mjs +233 -0
  64. package/bin/cli/commands/combo.mjs +361 -0
  65. package/bin/cli/commands/completion.mjs +346 -0
  66. package/bin/cli/commands/compression.mjs +247 -0
  67. package/bin/cli/commands/config.mjs +351 -0
  68. package/bin/cli/commands/configure.mjs +180 -0
  69. package/bin/cli/commands/connect.mjs +132 -0
  70. package/bin/cli/commands/context-eng.mjs +182 -0
  71. package/bin/cli/commands/contexts.mjs +271 -0
  72. package/bin/cli/commands/cost.mjs +144 -0
  73. package/bin/cli/commands/dashboard.mjs +65 -0
  74. package/bin/cli/commands/doctor.mjs +527 -0
  75. package/bin/cli/commands/env.mjs +100 -0
  76. package/bin/cli/commands/eval.mjs +278 -0
  77. package/bin/cli/commands/files.mjs +144 -0
  78. package/bin/cli/commands/health.mjs +123 -0
  79. package/bin/cli/commands/keys.mjs +599 -0
  80. package/bin/cli/commands/launch-codex.mjs +201 -0
  81. package/bin/cli/commands/launch.mjs +155 -0
  82. package/bin/cli/commands/login.mjs +192 -0
  83. package/bin/cli/commands/logs.mjs +183 -0
  84. package/bin/cli/commands/mcp.mjs +273 -0
  85. package/bin/cli/commands/memory.mjs +244 -0
  86. package/bin/cli/commands/models.mjs +92 -0
  87. package/bin/cli/commands/nodes.mjs +177 -0
  88. package/bin/cli/commands/oauth.mjs +258 -0
  89. package/bin/cli/commands/oneproxy.mjs +120 -0
  90. package/bin/cli/commands/open.mjs +75 -0
  91. package/bin/cli/commands/openapi.mjs +168 -0
  92. package/bin/cli/commands/plugin.mjs +219 -0
  93. package/bin/cli/commands/policy.mjs +216 -0
  94. package/bin/cli/commands/pricing.mjs +123 -0
  95. package/bin/cli/commands/provider-cmd.mjs +18 -0
  96. package/bin/cli/commands/providers.mjs +706 -0
  97. package/bin/cli/commands/quota.mjs +100 -0
  98. package/bin/cli/commands/redis.mjs +294 -0
  99. package/bin/cli/commands/registry.mjs +162 -0
  100. package/bin/cli/commands/repl.mjs +19 -0
  101. package/bin/cli/commands/reset-encrypted-columns.mjs +88 -0
  102. package/bin/cli/commands/resilience.mjs +208 -0
  103. package/bin/cli/commands/restart.mjs +25 -0
  104. package/bin/cli/commands/runtime.mjs +98 -0
  105. package/bin/cli/commands/serve.mjs +426 -0
  106. package/bin/cli/commands/sessions.mjs +108 -0
  107. package/bin/cli/commands/setup-aider.mjs +146 -0
  108. package/bin/cli/commands/setup-claude.mjs +219 -0
  109. package/bin/cli/commands/setup-cline.mjs +160 -0
  110. package/bin/cli/commands/setup-codex.mjs +387 -0
  111. package/bin/cli/commands/setup-continue.mjs +173 -0
  112. package/bin/cli/commands/setup-crush.mjs +148 -0
  113. package/bin/cli/commands/setup-cursor.mjs +108 -0
  114. package/bin/cli/commands/setup-goose.mjs +150 -0
  115. package/bin/cli/commands/setup-kilo.mjs +178 -0
  116. package/bin/cli/commands/setup-open-code.mjs +398 -0
  117. package/bin/cli/commands/setup-opencode.mjs +129 -0
  118. package/bin/cli/commands/setup-qwen.mjs +156 -0
  119. package/bin/cli/commands/setup-roo.mjs +172 -0
  120. package/bin/cli/commands/setup.mjs +211 -0
  121. package/bin/cli/commands/simulate.mjs +125 -0
  122. package/bin/cli/commands/skills.mjs +373 -0
  123. package/bin/cli/commands/status.mjs +95 -0
  124. package/bin/cli/commands/stop.mjs +96 -0
  125. package/bin/cli/commands/stream.mjs +166 -0
  126. package/bin/cli/commands/sync.mjs +230 -0
  127. package/bin/cli/commands/tags.mjs +116 -0
  128. package/bin/cli/commands/telemetry.mjs +74 -0
  129. package/bin/cli/commands/test-provider.mjs +242 -0
  130. package/bin/cli/commands/tokens.mjs +118 -0
  131. package/bin/cli/commands/translator.mjs +131 -0
  132. package/bin/cli/commands/tray.mjs +36 -0
  133. package/bin/cli/commands/tunnel.mjs +347 -0
  134. package/bin/cli/commands/update.mjs +194 -0
  135. package/bin/cli/commands/usage.mjs +331 -0
  136. package/bin/cli/commands/webhooks.mjs +196 -0
  137. package/bin/cli/contexts.mjs +60 -0
  138. package/bin/cli/data-dir.mjs +59 -0
  139. package/bin/cli/encryption.mjs +67 -0
  140. package/bin/cli/i18n.mjs +106 -0
  141. package/bin/cli/io.mjs +83 -0
  142. package/bin/cli/locales/ar.json +32 -0
  143. package/bin/cli/locales/az.json +32 -0
  144. package/bin/cli/locales/bg.json +32 -0
  145. package/bin/cli/locales/bn.json +5 -0
  146. package/bin/cli/locales/cs.json +32 -0
  147. package/bin/cli/locales/da.json +32 -0
  148. package/bin/cli/locales/de.json +32 -0
  149. package/bin/cli/locales/en.json +1289 -0
  150. package/bin/cli/locales/es.json +32 -0
  151. package/bin/cli/locales/fa.json +32 -0
  152. package/bin/cli/locales/fi.json +32 -0
  153. package/bin/cli/locales/fr.json +32 -0
  154. package/bin/cli/locales/gu.json +5 -0
  155. package/bin/cli/locales/he.json +5 -0
  156. package/bin/cli/locales/hi.json +32 -0
  157. package/bin/cli/locales/hu.json +32 -0
  158. package/bin/cli/locales/id.json +32 -0
  159. package/bin/cli/locales/in.json +5 -0
  160. package/bin/cli/locales/it.json +32 -0
  161. package/bin/cli/locales/ja.json +32 -0
  162. package/bin/cli/locales/ko.json +32 -0
  163. package/bin/cli/locales/mr.json +5 -0
  164. package/bin/cli/locales/ms.json +5 -0
  165. package/bin/cli/locales/nl.json +32 -0
  166. package/bin/cli/locales/no.json +32 -0
  167. package/bin/cli/locales/phi.json +5 -0
  168. package/bin/cli/locales/pl.json +32 -0
  169. package/bin/cli/locales/pt-BR.json +1286 -0
  170. package/bin/cli/locales/pt.json +32 -0
  171. package/bin/cli/locales/ro.json +32 -0
  172. package/bin/cli/locales/ru.json +32 -0
  173. package/bin/cli/locales/sk.json +32 -0
  174. package/bin/cli/locales/sv.json +32 -0
  175. package/bin/cli/locales/sw.json +5 -0
  176. package/bin/cli/locales/ta.json +5 -0
  177. package/bin/cli/locales/te.json +5 -0
  178. package/bin/cli/locales/th.json +32 -0
  179. package/bin/cli/locales/tr.json +32 -0
  180. package/bin/cli/locales/uk-UA.json +32 -0
  181. package/bin/cli/locales/ur.json +5 -0
  182. package/bin/cli/locales/vi.json +32 -0
  183. package/bin/cli/locales/zh-CN.json +1262 -0
  184. package/bin/cli/output.mjs +200 -0
  185. package/bin/cli/plugins.mjs +90 -0
  186. package/bin/cli/program.mjs +40 -0
  187. package/bin/cli/provider-catalog.mjs +175 -0
  188. package/bin/cli/provider-store.mjs +312 -0
  189. package/bin/cli/provider-test.mjs +181 -0
  190. package/bin/cli/runtime/index.mjs +19 -0
  191. package/bin/cli/runtime/magicBytes.mjs +47 -0
  192. package/bin/cli/runtime/nativeDeps.mjs +137 -0
  193. package/bin/cli/runtime/processSupervisor.mjs +136 -0
  194. package/bin/cli/runtime/sqliteRuntime.mjs +129 -0
  195. package/bin/cli/runtime/supervisorPolicy.mjs +56 -0
  196. package/bin/cli/runtime/trayRuntime.ts +94 -0
  197. package/bin/cli/runtime.mjs +61 -0
  198. package/bin/cli/schemas/output-schemas.mjs +56 -0
  199. package/bin/cli/scripts/generate-locales.mjs +911 -0
  200. package/bin/cli/settings-store.mjs +45 -0
  201. package/bin/cli/spinner.mjs +30 -0
  202. package/bin/cli/sqlite.mjs +158 -0
  203. package/bin/cli/tray/autostart.mjs +410 -0
  204. package/bin/cli/tray/autostart.ts +18 -0
  205. package/bin/cli/tray/icon.png +0 -0
  206. package/bin/cli/tray/index.mjs +28 -0
  207. package/bin/cli/tray/tray.ps1 +99 -0
  208. package/bin/cli/tray/tray.ts +186 -0
  209. package/bin/cli/tray/traySystray.mjs +135 -0
  210. package/bin/cli/tray/trayWin.ts +91 -0
  211. package/bin/cli/tray/trayWindows.mjs +75 -0
  212. package/bin/cli/tui/Dashboard.jsx +70 -0
  213. package/bin/cli/tui/EvalWatch.jsx +171 -0
  214. package/bin/cli/tui/InterfaceMenu.jsx +55 -0
  215. package/bin/cli/tui/OAuthFlow.jsx +193 -0
  216. package/bin/cli/tui/ProvidersTestAll.jsx +190 -0
  217. package/bin/cli/tui/Repl.jsx +392 -0
  218. package/bin/cli/tui/session.mjs +54 -0
  219. package/bin/cli/tui/tabs/Combos.jsx +47 -0
  220. package/bin/cli/tui/tabs/Cost.jsx +52 -0
  221. package/bin/cli/tui/tabs/Health.jsx +53 -0
  222. package/bin/cli/tui/tabs/Keys.jsx +48 -0
  223. package/bin/cli/tui/tabs/Logs.jsx +60 -0
  224. package/bin/cli/tui/tabs/Overview.jsx +80 -0
  225. package/bin/cli/tui/tabs/Providers.jsx +48 -0
  226. package/bin/cli/tui-components/CodeBlock.jsx +15 -0
  227. package/bin/cli/tui-components/ConfirmDialog.jsx +40 -0
  228. package/bin/cli/tui-components/DataTable.jsx +50 -0
  229. package/bin/cli/tui-components/HeaderSwr.jsx +25 -0
  230. package/bin/cli/tui-components/KeyMaskedDisplay.jsx +12 -0
  231. package/bin/cli/tui-components/MarkdownView.jsx +13 -0
  232. package/bin/cli/tui-components/MenuSelect.jsx +38 -0
  233. package/bin/cli/tui-components/MultilineInput.jsx +18 -0
  234. package/bin/cli/tui-components/ProgressBar.jsx +15 -0
  235. package/bin/cli/tui-components/Sparkline.jsx +15 -0
  236. package/bin/cli/tui-components/StatusBadge.jsx +17 -0
  237. package/bin/cli/tui-components/TokenCounter.jsx +18 -0
  238. package/bin/cli/tui-components/theme.jsx +11 -0
  239. package/bin/cli/utils/cliToken.mjs +22 -0
  240. package/bin/cli/utils/clipboard.mjs +35 -0
  241. package/bin/cli/utils/environment.mjs +50 -0
  242. package/bin/cli/utils/pid.mjs +110 -0
  243. package/bin/cli/utils/storageKeyProvision.mjs +31 -0
  244. package/bin/cold-start-bench.sh +82 -0
  245. package/bin/mcp-server.mjs +71 -0
  246. package/bin/nodeRuntimeSupport.mjs +84 -0
  247. package/bin/omniroute.mjs +237 -0
  248. package/bin/reset-password.mjs +137 -0
  249. package/bin/restore-data.sh +64 -0
  250. package/bin/restore-policies.sh +77 -0
  251. package/bin/rollback.sh +102 -0
  252. package/bin/snapshot-data.sh +61 -0
  253. package/open-sse/config/agyModels.ts +157 -0
  254. package/open-sse/config/anthropicHeaders.ts +127 -0
  255. package/open-sse/config/antigravityModelAliases.ts +309 -0
  256. package/open-sse/config/antigravityUpstream.ts +20 -0
  257. package/open-sse/config/audioRegistry.ts +547 -0
  258. package/open-sse/config/azureAi.ts +49 -0
  259. package/open-sse/config/bedrock.ts +196 -0
  260. package/open-sse/config/cliFingerprints.ts +405 -0
  261. package/open-sse/config/codexClient.ts +49 -0
  262. package/open-sse/config/codexIdentity.ts +87 -0
  263. package/open-sse/config/codexInstructions.ts +122 -0
  264. package/open-sse/config/codexQuotaScopes.ts +87 -0
  265. package/open-sse/config/constants.ts +281 -0
  266. package/open-sse/config/contextEditing.ts +156 -0
  267. package/open-sse/config/credentialLoader.ts +123 -0
  268. package/open-sse/config/datarobot.ts +69 -0
  269. package/open-sse/config/defaultThinkingSignature.ts +8 -0
  270. package/open-sse/config/embeddingRegistry.ts +434 -0
  271. package/open-sse/config/errorConfig.ts +201 -0
  272. package/open-sse/config/freeModelCatalog.data.ts +467 -0
  273. package/open-sse/config/freeModelCatalog.ts +142 -0
  274. package/open-sse/config/freeTierCatalog.ts +101 -0
  275. package/open-sse/config/geminiRateLimits.json +34 -0
  276. package/open-sse/config/glmProvider.ts +488 -0
  277. package/open-sse/config/imageRegistry.ts +752 -0
  278. package/open-sse/config/maritalk.ts +18 -0
  279. package/open-sse/config/mediaServiceKinds.ts +70 -0
  280. package/open-sse/config/moderationRegistry.ts +89 -0
  281. package/open-sse/config/musicRegistry.ts +115 -0
  282. package/open-sse/config/oci.ts +44 -0
  283. package/open-sse/config/ocrRegistry.ts +82 -0
  284. package/open-sse/config/ollamaModels.ts +28 -0
  285. package/open-sse/config/providerErrorRules.ts +218 -0
  286. package/open-sse/config/providerFieldStrips.ts +42 -0
  287. package/open-sse/config/providerHeaderProfiles.ts +188 -0
  288. package/open-sse/config/providerModels.ts +199 -0
  289. package/open-sse/config/providerPluginManifest.ts +186 -0
  290. package/open-sse/config/providerPluginManifestRegistry.ts +31 -0
  291. package/open-sse/config/providerPluginManifestUrl.ts +26 -0
  292. package/open-sse/config/providerRegistry.ts +257 -0
  293. package/open-sse/config/providers/index.ts +377 -0
  294. package/open-sse/config/providers/registry/adapta-web/index.ts +20 -0
  295. package/open-sse/config/providers/registry/agentrouter/index.ts +24 -0
  296. package/open-sse/config/providers/registry/agy/index.ts +28 -0
  297. package/open-sse/config/providers/registry/ai21/index.ts +13 -0
  298. package/open-sse/config/providers/registry/aimlapi/index.ts +21 -0
  299. package/open-sse/config/providers/registry/alibaba/cn/index.ts +15 -0
  300. package/open-sse/config/providers/registry/alibaba/index.ts +15 -0
  301. package/open-sse/config/providers/registry/anthropic/index.ts +52 -0
  302. package/open-sse/config/providers/registry/antigravity/index.ts +28 -0
  303. package/open-sse/config/providers/registry/api-airforce/index.ts +57 -0
  304. package/open-sse/config/providers/registry/auggie/index.ts +38 -0
  305. package/open-sse/config/providers/registry/bai/index.ts +14 -0
  306. package/open-sse/config/providers/registry/baichuan/index.ts +20 -0
  307. package/open-sse/config/providers/registry/baidu/index.ts +31 -0
  308. package/open-sse/config/providers/registry/bailian-coding-plan/index.ts +27 -0
  309. package/open-sse/config/providers/registry/baseten/index.ts +13 -0
  310. package/open-sse/config/providers/registry/bazaarlink/index.ts +48 -0
  311. package/open-sse/config/providers/registry/bedrock/index.ts +49 -0
  312. package/open-sse/config/providers/registry/blackbox/index.ts +25 -0
  313. package/open-sse/config/providers/registry/blackbox/web/index.ts +19 -0
  314. package/open-sse/config/providers/registry/bluesminds/index.ts +39 -0
  315. package/open-sse/config/providers/registry/byteplus/index.ts +21 -0
  316. package/open-sse/config/providers/registry/bytez/index.ts +17 -0
  317. package/open-sse/config/providers/registry/cerebras/index.ts +16 -0
  318. package/open-sse/config/providers/registry/charm-hyper/index.ts +14 -0
  319. package/open-sse/config/providers/registry/chatgpt-web/index.ts +23 -0
  320. package/open-sse/config/providers/registry/chipotle/index.ts +14 -0
  321. package/open-sse/config/providers/registry/chutes/index.ts +12 -0
  322. package/open-sse/config/providers/registry/claude/index.ts +102 -0
  323. package/open-sse/config/providers/registry/claude/web/index.ts +16 -0
  324. package/open-sse/config/providers/registry/cline/index.ts +45 -0
  325. package/open-sse/config/providers/registry/clinepass/index.ts +47 -0
  326. package/open-sse/config/providers/registry/cloudflare-ai/index.ts +33 -0
  327. package/open-sse/config/providers/registry/codebuddy-cn/index.ts +151 -0
  328. package/open-sse/config/providers/registry/codestral/index.ts +13 -0
  329. package/open-sse/config/providers/registry/codex/index.ts +115 -0
  330. package/open-sse/config/providers/registry/cohere/index.ts +28 -0
  331. package/open-sse/config/providers/registry/command-code/index.ts +143 -0
  332. package/open-sse/config/providers/registry/copilot-m365-web/index.ts +12 -0
  333. package/open-sse/config/providers/registry/copilot-web/index.ts +16 -0
  334. package/open-sse/config/providers/registry/coze/index.ts +12 -0
  335. package/open-sse/config/providers/registry/crof/index.ts +38 -0
  336. package/open-sse/config/providers/registry/cursor/index.ts +111 -0
  337. package/open-sse/config/providers/registry/databricks/index.ts +13 -0
  338. package/open-sse/config/providers/registry/deepinfra/index.ts +13 -0
  339. package/open-sse/config/providers/registry/deepseek/index.ts +15 -0
  340. package/open-sse/config/providers/registry/deepseek/web/index.ts +35 -0
  341. package/open-sse/config/providers/registry/devin-cli/index.ts +68 -0
  342. package/open-sse/config/providers/registry/dgrid/index.ts +15 -0
  343. package/open-sse/config/providers/registry/dify/index.ts +12 -0
  344. package/open-sse/config/providers/registry/digitalocean/index.ts +11 -0
  345. package/open-sse/config/providers/registry/dit/index.ts +41 -0
  346. package/open-sse/config/providers/registry/doubao/index.ts +28 -0
  347. package/open-sse/config/providers/registry/doubao/web/index.ts +15 -0
  348. package/open-sse/config/providers/registry/duckduckgo-web/index.ts +19 -0
  349. package/open-sse/config/providers/registry/factory/index.ts +33 -0
  350. package/open-sse/config/providers/registry/featherless-ai/index.ts +13 -0
  351. package/open-sse/config/providers/registry/fireworks/index.ts +35 -0
  352. package/open-sse/config/providers/registry/freeaiapikey/index.ts +38 -0
  353. package/open-sse/config/providers/registry/freemodel-dev/index.ts +19 -0
  354. package/open-sse/config/providers/registry/friendliai/index.ts +16 -0
  355. package/open-sse/config/providers/registry/galadriel/index.ts +13 -0
  356. package/open-sse/config/providers/registry/gemini/index.ts +63 -0
  357. package/open-sse/config/providers/registry/gemini/web/index.ts +16 -0
  358. package/open-sse/config/providers/registry/gigachat/index.ts +13 -0
  359. package/open-sse/config/providers/registry/github/index.ts +161 -0
  360. package/open-sse/config/providers/registry/github/models/index.ts +38 -0
  361. package/open-sse/config/providers/registry/gitlab-duo/index.ts +29 -0
  362. package/open-sse/config/providers/registry/gitlawb/gmi/index.ts +19 -0
  363. package/open-sse/config/providers/registry/gitlawb/index.ts +18 -0
  364. package/open-sse/config/providers/registry/glhf/index.ts +12 -0
  365. package/open-sse/config/providers/registry/glm/cn/index.ts +17 -0
  366. package/open-sse/config/providers/registry/glm/index.ts +16 -0
  367. package/open-sse/config/providers/registry/glm/t/index.ts +16 -0
  368. package/open-sse/config/providers/registry/grok-cli/index.ts +32 -0
  369. package/open-sse/config/providers/registry/grok-web/index.ts +18 -0
  370. package/open-sse/config/providers/registry/groq/index.ts +25 -0
  371. package/open-sse/config/providers/registry/hackclub/index.ts +19 -0
  372. package/open-sse/config/providers/registry/haiper/index.ts +15 -0
  373. package/open-sse/config/providers/registry/hcnsec/index.ts +11 -0
  374. package/open-sse/config/providers/registry/heroku/index.ts +13 -0
  375. package/open-sse/config/providers/registry/huggingchat/index.ts +143 -0
  376. package/open-sse/config/providers/registry/huggingface/index.ts +20 -0
  377. package/open-sse/config/providers/registry/hyperbolic/index.ts +21 -0
  378. package/open-sse/config/providers/registry/ideogram/index.ts +15 -0
  379. package/open-sse/config/providers/registry/iflytek/index.ts +21 -0
  380. package/open-sse/config/providers/registry/inclusionai/index.ts +12 -0
  381. package/open-sse/config/providers/registry/inference-net/index.ts +13 -0
  382. package/open-sse/config/providers/registry/inner-ai/index.ts +43 -0
  383. package/open-sse/config/providers/registry/kenari/index.ts +14 -0
  384. package/open-sse/config/providers/registry/kie/index.ts +27 -0
  385. package/open-sse/config/providers/registry/kilo-gateway/index.ts +21 -0
  386. package/open-sse/config/providers/registry/kilocode/index.ts +43 -0
  387. package/open-sse/config/providers/registry/kimi/coding/index.ts +17 -0
  388. package/open-sse/config/providers/registry/kimi/coding-apikey/index.ts +9 -0
  389. package/open-sse/config/providers/registry/kimi/index.ts +17 -0
  390. package/open-sse/config/providers/registry/kimi/web/index.ts +27 -0
  391. package/open-sse/config/providers/registry/kiro/index.ts +50 -0
  392. package/open-sse/config/providers/registry/kluster/index.ts +12 -0
  393. package/open-sse/config/providers/registry/lambda-ai/index.ts +13 -0
  394. package/open-sse/config/providers/registry/leonardo/index.ts +15 -0
  395. package/open-sse/config/providers/registry/liquid/index.ts +12 -0
  396. package/open-sse/config/providers/registry/llamagate/index.ts +13 -0
  397. package/open-sse/config/providers/registry/llm7/index.ts +27 -0
  398. package/open-sse/config/providers/registry/longcat/index.ts +24 -0
  399. package/open-sse/config/providers/registry/maritalk/index.ts +13 -0
  400. package/open-sse/config/providers/registry/meta-llama/index.ts +13 -0
  401. package/open-sse/config/providers/registry/mimocode/index.ts +16 -0
  402. package/open-sse/config/providers/registry/minimax/cn/index.ts +24 -0
  403. package/open-sse/config/providers/registry/minimax/index.ts +24 -0
  404. package/open-sse/config/providers/registry/mistral/index.ts +18 -0
  405. package/open-sse/config/providers/registry/modal/index.ts +12 -0
  406. package/open-sse/config/providers/registry/modelscope/index.ts +24 -0
  407. package/open-sse/config/providers/registry/monsterapi/index.ts +17 -0
  408. package/open-sse/config/providers/registry/moonshot/index.ts +13 -0
  409. package/open-sse/config/providers/registry/morph/index.ts +13 -0
  410. package/open-sse/config/providers/registry/muse-spark-web/index.ts +24 -0
  411. package/open-sse/config/providers/registry/nanogpt/index.ts +13 -0
  412. package/open-sse/config/providers/registry/nebius/index.ts +9 -0
  413. package/open-sse/config/providers/registry/nlpcloud/index.ts +19 -0
  414. package/open-sse/config/providers/registry/nous-research/index.ts +15 -0
  415. package/open-sse/config/providers/registry/novita/index.ts +15 -0
  416. package/open-sse/config/providers/registry/nscale/index.ts +13 -0
  417. package/open-sse/config/providers/registry/nube/index.ts +17 -0
  418. package/open-sse/config/providers/registry/nvidia/index.ts +36 -0
  419. package/open-sse/config/providers/registry/ollama-cloud/index.ts +27 -0
  420. package/open-sse/config/providers/registry/openadapter/index.ts +25 -0
  421. package/open-sse/config/providers/registry/openai/index.ts +43 -0
  422. package/open-sse/config/providers/registry/opencode/go/index.ts +61 -0
  423. package/open-sse/config/providers/registry/opencode/index.ts +51 -0
  424. package/open-sse/config/providers/registry/opencode/zen/index.ts +98 -0
  425. package/open-sse/config/providers/registry/openrouter/index.ts +17 -0
  426. package/open-sse/config/providers/registry/orcarouter/index.ts +87 -0
  427. package/open-sse/config/providers/registry/ovhcloud/index.ts +13 -0
  428. package/open-sse/config/providers/registry/perplexity/index.ts +22 -0
  429. package/open-sse/config/providers/registry/perplexity/web/index.ts +23 -0
  430. package/open-sse/config/providers/registry/pioneer/index.ts +41 -0
  431. package/open-sse/config/providers/registry/pollinations/index.ts +51 -0
  432. package/open-sse/config/providers/registry/predibase/index.ts +13 -0
  433. package/open-sse/config/providers/registry/publicai/index.ts +13 -0
  434. package/open-sse/config/providers/registry/puter/index.ts +70 -0
  435. package/open-sse/config/providers/registry/qianfan/index.ts +18 -0
  436. package/open-sse/config/providers/registry/qiniu/index.ts +15 -0
  437. package/open-sse/config/providers/registry/qoder/index.ts +37 -0
  438. package/open-sse/config/providers/registry/qwen/index.ts +25 -0
  439. package/open-sse/config/providers/registry/qwen/web/index.ts +24 -0
  440. package/open-sse/config/providers/registry/reka/index.ts +18 -0
  441. package/open-sse/config/providers/registry/requesty/index.ts +11 -0
  442. package/open-sse/config/providers/registry/sambanova/index.ts +13 -0
  443. package/open-sse/config/providers/registry/scaleway/index.ts +20 -0
  444. package/open-sse/config/providers/registry/sensenova/index.ts +27 -0
  445. package/open-sse/config/providers/registry/siliconflow/index.ts +84 -0
  446. package/open-sse/config/providers/registry/snowflake/index.ts +13 -0
  447. package/open-sse/config/providers/registry/sparkdesk/index.ts +20 -0
  448. package/open-sse/config/providers/registry/stepfun/index.ts +20 -0
  449. package/open-sse/config/providers/registry/sumopod/index.ts +15 -0
  450. package/open-sse/config/providers/registry/suno/index.ts +18 -0
  451. package/open-sse/config/providers/registry/synthetic/index.ts +21 -0
  452. package/open-sse/config/providers/registry/t3-web/index.ts +45 -0
  453. package/open-sse/config/providers/registry/tencent/index.ts +25 -0
  454. package/open-sse/config/providers/registry/theoldllm/index.ts +51 -0
  455. package/open-sse/config/providers/registry/together/index.ts +20 -0
  456. package/open-sse/config/providers/registry/tokenrouter/index.ts +44 -0
  457. package/open-sse/config/providers/registry/trae/index.ts +24 -0
  458. package/open-sse/config/providers/registry/udio/index.ts +12 -0
  459. package/open-sse/config/providers/registry/uncloseai/index.ts +19 -0
  460. package/open-sse/config/providers/registry/upstage/index.ts +13 -0
  461. package/open-sse/config/providers/registry/v0-vercel/index.ts +13 -0
  462. package/open-sse/config/providers/registry/venice/index.ts +13 -0
  463. package/open-sse/config/providers/registry/veoaifree-web/index.ts +15 -0
  464. package/open-sse/config/providers/registry/vercel-ai-gateway/index.ts +13 -0
  465. package/open-sse/config/providers/registry/vertex/index.ts +33 -0
  466. package/open-sse/config/providers/registry/vertex/partner/index.ts +22 -0
  467. package/open-sse/config/providers/registry/volcengine/index.ts +13 -0
  468. package/open-sse/config/providers/registry/wafer/index.ts +19 -0
  469. package/open-sse/config/providers/registry/wandb/index.ts +13 -0
  470. package/open-sse/config/providers/registry/windsurf/index.ts +119 -0
  471. package/open-sse/config/providers/registry/x5lab/index.ts +15 -0
  472. package/open-sse/config/providers/registry/xai/index.ts +18 -0
  473. package/open-sse/config/providers/registry/xiaomi-mimo/index.ts +13 -0
  474. package/open-sse/config/providers/registry/yi/index.ts +12 -0
  475. package/open-sse/config/providers/registry/yuanbao-web/index.ts +37 -0
  476. package/open-sse/config/providers/registry/zai/index.ts +28 -0
  477. package/open-sse/config/providers/registry/zed-hosted/index.ts +35 -0
  478. package/open-sse/config/providers/registry/zenmux/index.ts +87 -0
  479. package/open-sse/config/providers/registry/zenmux-free/index.ts +40 -0
  480. package/open-sse/config/providers/shared.ts +766 -0
  481. package/open-sse/config/registryUtils.ts +134 -0
  482. package/open-sse/config/rerankRegistry.ts +196 -0
  483. package/open-sse/config/runway.ts +39 -0
  484. package/open-sse/config/sap.ts +58 -0
  485. package/open-sse/config/searchRegistry.ts +317 -0
  486. package/open-sse/config/toolCloaking.ts +253 -0
  487. package/open-sse/config/videoRegistry.ts +229 -0
  488. package/open-sse/config/watsonx.ts +43 -0
  489. package/open-sse/executors/adapta-web.ts +564 -0
  490. package/open-sse/executors/antigravity/sseCollect.ts +148 -0
  491. package/open-sse/executors/antigravity.ts +1716 -0
  492. package/open-sse/executors/antigravityUpstreamError.ts +25 -0
  493. package/open-sse/executors/auggie.ts +573 -0
  494. package/open-sse/executors/azure-openai.ts +48 -0
  495. package/open-sse/executors/base/headers.ts +93 -0
  496. package/open-sse/executors/base/reasoningEffort.ts +160 -0
  497. package/open-sse/executors/base.ts +1315 -0
  498. package/open-sse/executors/bedrock.ts +714 -0
  499. package/open-sse/executors/blackbox-web.ts +708 -0
  500. package/open-sse/executors/chatgpt-web/models.ts +133 -0
  501. package/open-sse/executors/chatgpt-web.ts +3107 -0
  502. package/open-sse/executors/chatgptWebErrors.ts +18 -0
  503. package/open-sse/executors/chatgptWebTools.ts +127 -0
  504. package/open-sse/executors/chipotle.ts +432 -0
  505. package/open-sse/executors/claude-web/payload.ts +230 -0
  506. package/open-sse/executors/claude-web-with-auto-refresh.ts +117 -0
  507. package/open-sse/executors/claude-web.ts +833 -0
  508. package/open-sse/executors/claudeIdentity.ts +445 -0
  509. package/open-sse/executors/cliproxyapi.ts +466 -0
  510. package/open-sse/executors/cloudflare-ai.ts +97 -0
  511. package/open-sse/executors/codebuddy-cn.ts +53 -0
  512. package/open-sse/executors/codex/quota.ts +114 -0
  513. package/open-sse/executors/codex/tools.ts +165 -0
  514. package/open-sse/executors/codex.ts +1270 -0
  515. package/open-sse/executors/commandCode.ts +716 -0
  516. package/open-sse/executors/copilot-m365-connection.ts +271 -0
  517. package/open-sse/executors/copilot-m365-frames.ts +279 -0
  518. package/open-sse/executors/copilot-m365-web.ts +341 -0
  519. package/open-sse/executors/copilot-web.ts +722 -0
  520. package/open-sse/executors/cursor/composer.ts +53 -0
  521. package/open-sse/executors/cursor/prompt.ts +75 -0
  522. package/open-sse/executors/cursor.ts +1465 -0
  523. package/open-sse/executors/deepseek-web/stream-format.ts +44 -0
  524. package/open-sse/executors/deepseek-web-with-auto-refresh.ts +184 -0
  525. package/open-sse/executors/deepseek-web.ts +1123 -0
  526. package/open-sse/executors/default/urlNormalizers.ts +64 -0
  527. package/open-sse/executors/default.ts +873 -0
  528. package/open-sse/executors/devin-cli.ts +470 -0
  529. package/open-sse/executors/doubao-web.ts +665 -0
  530. package/open-sse/executors/duckduckgo-web/challenge.ts +151 -0
  531. package/open-sse/executors/duckduckgo-web.ts +782 -0
  532. package/open-sse/executors/firecrawl-fetch.ts +177 -0
  533. package/open-sse/executors/forceResponsesUpstream.ts +60 -0
  534. package/open-sse/executors/gemini-business.ts +446 -0
  535. package/open-sse/executors/gemini-web.ts +413 -0
  536. package/open-sse/executors/github.ts +376 -0
  537. package/open-sse/executors/gitlab.ts +793 -0
  538. package/open-sse/executors/gitlabResponses.ts +191 -0
  539. package/open-sse/executors/glm.ts +520 -0
  540. package/open-sse/executors/grok-cli.ts +253 -0
  541. package/open-sse/executors/grok-web/native-tools.ts +182 -0
  542. package/open-sse/executors/grok-web/text-cleanup.ts +137 -0
  543. package/open-sse/executors/grok-web/tool-bridge.ts +666 -0
  544. package/open-sse/executors/grok-web/types.ts +47 -0
  545. package/open-sse/executors/grok-web.ts +883 -0
  546. package/open-sse/executors/huggingchat/jsonlStream.ts +221 -0
  547. package/open-sse/executors/huggingchat.ts +593 -0
  548. package/open-sse/executors/index.ts +232 -0
  549. package/open-sse/executors/inner-ai.ts +764 -0
  550. package/open-sse/executors/jina-reader-fetch.ts +119 -0
  551. package/open-sse/executors/kie.ts +109 -0
  552. package/open-sse/executors/kimi-web.ts +455 -0
  553. package/open-sse/executors/kimi.ts +133 -0
  554. package/open-sse/executors/kiro/eventstream.ts +192 -0
  555. package/open-sse/executors/kiro.ts +821 -0
  556. package/open-sse/executors/kiroThinking.ts +116 -0
  557. package/open-sse/executors/lmarena.ts +511 -0
  558. package/open-sse/executors/mimocode.ts +560 -0
  559. package/open-sse/executors/muse-spark-web/response-parser.ts +383 -0
  560. package/open-sse/executors/muse-spark-web.ts +928 -0
  561. package/open-sse/executors/ninerouter.ts +212 -0
  562. package/open-sse/executors/nlpcloud.ts +546 -0
  563. package/open-sse/executors/opencode.ts +336 -0
  564. package/open-sse/executors/perplexity-web/protocol.ts +503 -0
  565. package/open-sse/executors/perplexity-web.ts +545 -0
  566. package/open-sse/executors/poe-web.ts +158 -0
  567. package/open-sse/executors/pollinations.ts +119 -0
  568. package/open-sse/executors/puter.ts +59 -0
  569. package/open-sse/executors/qoder.ts +416 -0
  570. package/open-sse/executors/qwen-web.ts +474 -0
  571. package/open-sse/executors/t3-chat-web.ts +582 -0
  572. package/open-sse/executors/tavily-fetch.ts +103 -0
  573. package/open-sse/executors/theoldllm.ts +354 -0
  574. package/open-sse/executors/tinyfish-fetch.ts +131 -0
  575. package/open-sse/executors/trae.ts +481 -0
  576. package/open-sse/executors/v0-vercel-web.ts +164 -0
  577. package/open-sse/executors/venice-web.ts +165 -0
  578. package/open-sse/executors/veoaifree-web.ts +397 -0
  579. package/open-sse/executors/vertex.ts +208 -0
  580. package/open-sse/executors/vertexMedia.ts +341 -0
  581. package/open-sse/executors/windsurf.ts +706 -0
  582. package/open-sse/executors/xai.ts +94 -0
  583. package/open-sse/executors/yuanbao-web.ts +504 -0
  584. package/open-sse/executors/zed-hosted.ts +364 -0
  585. package/open-sse/executors/zenmux-free.ts +283 -0
  586. package/open-sse/handlers/audioSpeech.ts +1060 -0
  587. package/open-sse/handlers/audioTranscription.ts +554 -0
  588. package/open-sse/handlers/audioTranslation.ts +135 -0
  589. package/open-sse/handlers/chatCore/attemptLogging.ts +210 -0
  590. package/open-sse/handlers/chatCore/backgroundRedirect.ts +41 -0
  591. package/open-sse/handlers/chatCore/cacheUsageMeta.ts +65 -0
  592. package/open-sse/handlers/chatCore/cavemanOutputAnalytics.ts +47 -0
  593. package/open-sse/handlers/chatCore/claudeClassifierCompat.ts +99 -0
  594. package/open-sse/handlers/chatCore/claudeEffortVariant.ts +62 -0
  595. package/open-sse/handlers/chatCore/claudeMessageTypes.ts +15 -0
  596. package/open-sse/handlers/chatCore/claudeSystemRole.ts +48 -0
  597. package/open-sse/handlers/chatCore/claudeToolDefaults.ts +27 -0
  598. package/open-sse/handlers/chatCore/claudeUpstreamMessages.ts +143 -0
  599. package/open-sse/handlers/chatCore/clientUsageBuffer.ts +54 -0
  600. package/open-sse/handlers/chatCore/clineResponseEnvelope.ts +25 -0
  601. package/open-sse/handlers/chatCore/codexFailover.ts +41 -0
  602. package/open-sse/handlers/chatCore/codexQuota.ts +85 -0
  603. package/open-sse/handlers/chatCore/comboContextCache.ts +63 -0
  604. package/open-sse/handlers/chatCore/compressionAnalyticsWrite.ts +149 -0
  605. package/open-sse/handlers/chatCore/compressionCacheStats.ts +53 -0
  606. package/open-sse/handlers/chatCore/compressionComboPredicates.ts +41 -0
  607. package/open-sse/handlers/chatCore/compressionSettings.ts +35 -0
  608. package/open-sse/handlers/chatCore/compressionUsageReceipt.ts +27 -0
  609. package/open-sse/handlers/chatCore/contextEditingTelemetry.ts +40 -0
  610. package/open-sse/handlers/chatCore/cooldownClassification.ts +26 -0
  611. package/open-sse/handlers/chatCore/executionCredentials.ts +72 -0
  612. package/open-sse/handlers/chatCore/executorClientHeaders.ts +36 -0
  613. package/open-sse/handlers/chatCore/executorHelpers.ts +151 -0
  614. package/open-sse/handlers/chatCore/executorProxy.ts +117 -0
  615. package/open-sse/handlers/chatCore/failureUsage.ts +41 -0
  616. package/open-sse/handlers/chatCore/gamificationEvent.ts +28 -0
  617. package/open-sse/handlers/chatCore/headers.ts +65 -0
  618. package/open-sse/handlers/chatCore/idempotency.ts +65 -0
  619. package/open-sse/handlers/chatCore/jsonBodyToSse.ts +161 -0
  620. package/open-sse/handlers/chatCore/keyHealth.ts +113 -0
  621. package/open-sse/handlers/chatCore/logTruncation.ts +93 -0
  622. package/open-sse/handlers/chatCore/memoryExtraction.ts +131 -0
  623. package/open-sse/handlers/chatCore/memorySkillsInjection.ts +165 -0
  624. package/open-sse/handlers/chatCore/nonStreamingJsonResponse.ts +16 -0
  625. package/open-sse/handlers/chatCore/nonStreamingResponseBody.ts +155 -0
  626. package/open-sse/handlers/chatCore/nonStreamingResponseHeaders.ts +46 -0
  627. package/open-sse/handlers/chatCore/nonStreamingResponseParse.ts +135 -0
  628. package/open-sse/handlers/chatCore/nonStreamingSse.ts +171 -0
  629. package/open-sse/handlers/chatCore/nonStreamingUsageStats.ts +90 -0
  630. package/open-sse/handlers/chatCore/outputStyleTelemetry.ts +53 -0
  631. package/open-sse/handlers/chatCore/passthroughHelpers.ts +83 -0
  632. package/open-sse/handlers/chatCore/passthroughToolNames.ts +65 -0
  633. package/open-sse/handlers/chatCore/pluginOnRequest.ts +65 -0
  634. package/open-sse/handlers/chatCore/pluginOnResponse.ts +34 -0
  635. package/open-sse/handlers/chatCore/postCallGuardrailContext.ts +47 -0
  636. package/open-sse/handlers/chatCore/quotaShareConsumption.ts +41 -0
  637. package/open-sse/handlers/chatCore/requestFormat.ts +111 -0
  638. package/open-sse/handlers/chatCore/requestSetup.ts +51 -0
  639. package/open-sse/handlers/chatCore/responseHeaders.ts +138 -0
  640. package/open-sse/handlers/chatCore/sanitization.ts +63 -0
  641. package/open-sse/handlers/chatCore/semanticCache.ts +98 -0
  642. package/open-sse/handlers/chatCore/semanticCacheStore.ts +73 -0
  643. package/open-sse/handlers/chatCore/serviceTier.ts +70 -0
  644. package/open-sse/handlers/chatCore/skillsFormat.ts +33 -0
  645. package/open-sse/handlers/chatCore/stageTrace.ts +30 -0
  646. package/open-sse/handlers/chatCore/streamErrorResult.ts +58 -0
  647. package/open-sse/handlers/chatCore/streamFinalize.ts +48 -0
  648. package/open-sse/handlers/chatCore/streamingCost.ts +37 -0
  649. package/open-sse/handlers/chatCore/streamingPipeline.ts +99 -0
  650. package/open-sse/handlers/chatCore/streamingQuotaShare.ts +54 -0
  651. package/open-sse/handlers/chatCore/streamingResponseHeaders.ts +39 -0
  652. package/open-sse/handlers/chatCore/streamingSemanticCacheStore.ts +95 -0
  653. package/open-sse/handlers/chatCore/streamingUsageStats.ts +79 -0
  654. package/open-sse/handlers/chatCore/targetFormat.ts +34 -0
  655. package/open-sse/handlers/chatCore/telemetryHelpers.ts +78 -0
  656. package/open-sse/handlers/chatCore/upstreamBody.ts +168 -0
  657. package/open-sse/handlers/chatCore/upstreamExecuteHeaders.ts +71 -0
  658. package/open-sse/handlers/chatCore/upstreamTimeouts.ts +158 -0
  659. package/open-sse/handlers/chatCore.ts +4452 -0
  660. package/open-sse/handlers/embeddings.ts +378 -0
  661. package/open-sse/handlers/imageGeneration/providers/chatgptWeb.ts +187 -0
  662. package/open-sse/handlers/imageGeneration/providers/comfyUI.ts +116 -0
  663. package/open-sse/handlers/imageGeneration/providers/haiper.ts +120 -0
  664. package/open-sse/handlers/imageGeneration/providers/huggingface.ts +90 -0
  665. package/open-sse/handlers/imageGeneration/providers/hyperbolic.ts +100 -0
  666. package/open-sse/handlers/imageGeneration/providers/ideogram.ts +96 -0
  667. package/open-sse/handlers/imageGeneration/providers/imagen3.ts +136 -0
  668. package/open-sse/handlers/imageGeneration/providers/leonardo.ts +140 -0
  669. package/open-sse/handlers/imageGeneration/providers/nvidiaNim.ts +286 -0
  670. package/open-sse/handlers/imageGeneration/providers/sdWebUI.ts +94 -0
  671. package/open-sse/handlers/imageGeneration.ts +2880 -0
  672. package/open-sse/handlers/moderations.ts +82 -0
  673. package/open-sse/handlers/musicGeneration.ts +640 -0
  674. package/open-sse/handlers/ocr.ts +79 -0
  675. package/open-sse/handlers/rerank.ts +210 -0
  676. package/open-sse/handlers/responseSanitizer/reasoning.ts +149 -0
  677. package/open-sse/handlers/responseSanitizer.ts +1086 -0
  678. package/open-sse/handlers/responseTranslator.ts +640 -0
  679. package/open-sse/handlers/responsesHandler.ts +92 -0
  680. package/open-sse/handlers/search.ts +1545 -0
  681. package/open-sse/handlers/sseParser.ts +825 -0
  682. package/open-sse/handlers/usageExtractor.ts +93 -0
  683. package/open-sse/handlers/videoGeneration/googleFlow.ts +219 -0
  684. package/open-sse/handlers/videoGeneration/googleFlowHandler.ts +145 -0
  685. package/open-sse/handlers/videoGeneration.ts +1264 -0
  686. package/open-sse/handlers/webFetch.ts +130 -0
  687. package/open-sse/index.ts +170 -0
  688. package/open-sse/lib/deepseek-pow-solver.cjs +3 -0
  689. package/open-sse/lib/deepseek-pow.ts +189 -0
  690. package/open-sse/lib/sha3_wasm_bg.wasm +0 -0
  691. package/open-sse/mcp-server/README.md +611 -0
  692. package/open-sse/mcp-server/audit.ts +478 -0
  693. package/open-sse/mcp-server/catalog.ts +290 -0
  694. package/open-sse/mcp-server/descriptionCompressor.ts +243 -0
  695. package/open-sse/mcp-server/httpAuthContext.ts +42 -0
  696. package/open-sse/mcp-server/httpTransport.ts +306 -0
  697. package/open-sse/mcp-server/index.ts +19 -0
  698. package/open-sse/mcp-server/mcpCallerIdentity.ts +53 -0
  699. package/open-sse/mcp-server/runtimeHeartbeat.ts +162 -0
  700. package/open-sse/mcp-server/schemas/a2a.ts +203 -0
  701. package/open-sse/mcp-server/schemas/audit.ts +121 -0
  702. package/open-sse/mcp-server/schemas/index.ts +116 -0
  703. package/open-sse/mcp-server/schemas/pickFastestModel.ts +110 -0
  704. package/open-sse/mcp-server/schemas/toolDefinition.ts +31 -0
  705. package/open-sse/mcp-server/schemas/toolSearch.ts +37 -0
  706. package/open-sse/mcp-server/schemas/tools.ts +1481 -0
  707. package/open-sse/mcp-server/scopeEnforcement.ts +135 -0
  708. package/open-sse/mcp-server/server.ts +1370 -0
  709. package/open-sse/mcp-server/toolCardinality.ts +254 -0
  710. package/open-sse/mcp-server/toolSearch/catalog.ts +98 -0
  711. package/open-sse/mcp-server/toolSearch/handler.ts +18 -0
  712. package/open-sse/mcp-server/toolSearch/index.ts +5 -0
  713. package/open-sse/mcp-server/toolSearch/register.ts +36 -0
  714. package/open-sse/mcp-server/toolSearch/search.ts +96 -0
  715. package/open-sse/mcp-server/toolSearch/signature.ts +92 -0
  716. package/open-sse/mcp-server/tools/advancedTools.ts +1119 -0
  717. package/open-sse/mcp-server/tools/agentSkillTools.ts +83 -0
  718. package/open-sse/mcp-server/tools/compressionTools.ts +451 -0
  719. package/open-sse/mcp-server/tools/gamificationTools.ts +148 -0
  720. package/open-sse/mcp-server/tools/githubSkillTools.ts +141 -0
  721. package/open-sse/mcp-server/tools/memoryTools.ts +137 -0
  722. package/open-sse/mcp-server/tools/notionTools.ts +106 -0
  723. package/open-sse/mcp-server/tools/obsidianTools.ts +327 -0
  724. package/open-sse/mcp-server/tools/pickFastestModel.ts +293 -0
  725. package/open-sse/mcp-server/tools/pluginTools.ts +216 -0
  726. package/open-sse/mcp-server/tools/poolTools.ts +205 -0
  727. package/open-sse/mcp-server/tools/skillTools.ts +119 -0
  728. package/open-sse/package.json +17 -0
  729. package/open-sse/services/AGENTS.md +78 -0
  730. package/open-sse/services/accountFallback.ts +1863 -0
  731. package/open-sse/services/accountSelector.ts +80 -0
  732. package/open-sse/services/accountSemaphore.ts +367 -0
  733. package/open-sse/services/antigravity429Engine.ts +178 -0
  734. package/open-sse/services/antigravityClientProfile.ts +167 -0
  735. package/open-sse/services/antigravityCredits.ts +68 -0
  736. package/open-sse/services/antigravityHeaderScrub.ts +75 -0
  737. package/open-sse/services/antigravityHeaders.ts +121 -0
  738. package/open-sse/services/antigravityIdentity.ts +127 -0
  739. package/open-sse/services/antigravityObfuscation.ts +64 -0
  740. package/open-sse/services/antigravityProjectBootstrap.ts +145 -0
  741. package/open-sse/services/antigravityQuotaFamily.ts +56 -0
  742. package/open-sse/services/antigravityVersion.ts +163 -0
  743. package/open-sse/services/apiKeyRotator.ts +385 -0
  744. package/open-sse/services/autoCombo/autoPrefix.ts +61 -0
  745. package/open-sse/services/autoCombo/builtinCatalog.ts +126 -0
  746. package/open-sse/services/autoCombo/complexityRouter.ts +111 -0
  747. package/open-sse/services/autoCombo/engine.ts +314 -0
  748. package/open-sse/services/autoCombo/index.ts +18 -0
  749. package/open-sse/services/autoCombo/modePacks.ts +105 -0
  750. package/open-sse/services/autoCombo/modelFamily.ts +95 -0
  751. package/open-sse/services/autoCombo/paidModelFilter.ts +44 -0
  752. package/open-sse/services/autoCombo/persistence.ts +124 -0
  753. package/open-sse/services/autoCombo/pipelineRouter.ts +418 -0
  754. package/open-sse/services/autoCombo/providerDiversity.ts +170 -0
  755. package/open-sse/services/autoCombo/providerRegistryAccessor.ts +9 -0
  756. package/open-sse/services/autoCombo/requestControls.ts +80 -0
  757. package/open-sse/services/autoCombo/routerStrategy.ts +375 -0
  758. package/open-sse/services/autoCombo/scoring.ts +242 -0
  759. package/open-sse/services/autoCombo/selfHealing.ts +167 -0
  760. package/open-sse/services/autoCombo/speedRanking.ts +327 -0
  761. package/open-sse/services/autoCombo/suffixComposition.ts +147 -0
  762. package/open-sse/services/autoCombo/taskFitness.ts +407 -0
  763. package/open-sse/services/autoCombo/virtualFactory.ts +446 -0
  764. package/open-sse/services/autoRefreshDaemon.ts +206 -0
  765. package/open-sse/services/backgroundTaskDetector.ts +263 -0
  766. package/open-sse/services/bailianQuotaFetcher.ts +333 -0
  767. package/open-sse/services/batchProcessor.ts +914 -0
  768. package/open-sse/services/bedrock.ts +160 -0
  769. package/open-sse/services/browserBackedChat.ts +849 -0
  770. package/open-sse/services/browserPool.ts +501 -0
  771. package/open-sse/services/ccBridgeTransforms.ts +581 -0
  772. package/open-sse/services/ccWireImageBuiltins.ts +26 -0
  773. package/open-sse/services/chatgptImageCache.ts +143 -0
  774. package/open-sse/services/chatgptTlsClient.ts +628 -0
  775. package/open-sse/services/claudeAdaptiveThinking.ts +52 -0
  776. package/open-sse/services/claudeCodeCCH.ts +49 -0
  777. package/open-sse/services/claudeCodeCompatible.ts +1198 -0
  778. package/open-sse/services/claudeCodeCompatibleBeta.ts +23 -0
  779. package/open-sse/services/claudeCodeCompatibleThinkingDisplay.ts +34 -0
  780. package/open-sse/services/claudeCodeConstraints.ts +144 -0
  781. package/open-sse/services/claudeCodeExtraRemap.ts +18 -0
  782. package/open-sse/services/claudeCodeFingerprint.ts +46 -0
  783. package/open-sse/services/claudeCodeObfuscation.ts +116 -0
  784. package/open-sse/services/claudeCodeToolRemapper.ts +339 -0
  785. package/open-sse/services/claudeHaikuConstraints.ts +88 -0
  786. package/open-sse/services/claudeTlsClient.ts +590 -0
  787. package/open-sse/services/claudeTurnstileSolver.ts +206 -0
  788. package/open-sse/services/claudeUsageCooldown.ts +51 -0
  789. package/open-sse/services/claudeWebAutoRefresh.ts +224 -0
  790. package/open-sse/services/clinepassModels.ts +76 -0
  791. package/open-sse/services/cloudCodeHeaders.ts +41 -0
  792. package/open-sse/services/cloudCodeThinking.ts +71 -0
  793. package/open-sse/services/codeAssistSubscription.ts +83 -0
  794. package/open-sse/services/codexQuotaFetcher.ts +523 -0
  795. package/open-sse/services/codexUsageQuotas.ts +270 -0
  796. package/open-sse/services/codexVerbosity.ts +59 -0
  797. package/open-sse/services/combo/applyStrategyOrdering.ts +226 -0
  798. package/open-sse/services/combo/autoConfig.ts +62 -0
  799. package/open-sse/services/combo/autoStrategy.ts +475 -0
  800. package/open-sse/services/combo/comboCompatFallback.ts +82 -0
  801. package/open-sse/services/combo/comboCooldownRetry.ts +237 -0
  802. package/open-sse/services/combo/comboData.ts +24 -0
  803. package/open-sse/services/combo/comboPredicates.ts +211 -0
  804. package/open-sse/services/combo/comboSetup.ts +135 -0
  805. package/open-sse/services/combo/comboStructure.ts +766 -0
  806. package/open-sse/services/combo/concurrencyCaps.ts +76 -0
  807. package/open-sse/services/combo/context.ts +46 -0
  808. package/open-sse/services/combo/fingerprintExpansion.ts +105 -0
  809. package/open-sse/services/combo/headroomRanking.ts +91 -0
  810. package/open-sse/services/combo/providerWildcard.ts +253 -0
  811. package/open-sse/services/combo/quotaExhaustionCutoff.ts +140 -0
  812. package/open-sse/services/combo/quotaScoring.ts +311 -0
  813. package/open-sse/services/combo/quotaShareConcurrency.ts +74 -0
  814. package/open-sse/services/combo/quotaShareInflight.ts +133 -0
  815. package/open-sse/services/combo/quotaShareStrategy.ts +349 -0
  816. package/open-sse/services/combo/quotaStrategies.ts +647 -0
  817. package/open-sse/services/combo/resolveAutoStrategy.ts +334 -0
  818. package/open-sse/services/combo/responseValidation.ts +206 -0
  819. package/open-sse/services/combo/rrState.ts +98 -0
  820. package/open-sse/services/combo/runtimeUnits.ts +269 -0
  821. package/open-sse/services/combo/sessionStickiness.ts +301 -0
  822. package/open-sse/services/combo/shadowRouting.ts +179 -0
  823. package/open-sse/services/combo/targetExhaustion.ts +160 -0
  824. package/open-sse/services/combo/targetSorters.ts +174 -0
  825. package/open-sse/services/combo/targetTimeoutRunner.ts +91 -0
  826. package/open-sse/services/combo/types.ts +175 -0
  827. package/open-sse/services/combo/validateQuality.ts +445 -0
  828. package/open-sse/services/combo.ts +3085 -0
  829. package/open-sse/services/comboAgentMiddleware.ts +214 -0
  830. package/open-sse/services/comboConfig.ts +248 -0
  831. package/open-sse/services/comboManifestMetrics.ts +13 -0
  832. package/open-sse/services/comboMetrics.ts +480 -0
  833. package/open-sse/services/compression/adaptiveCompression/computeTarget.ts +31 -0
  834. package/open-sse/services/compression/adaptiveCompression/ladder.ts +59 -0
  835. package/open-sse/services/compression/adaptiveCompression/resolveAdaptivePlan.ts +104 -0
  836. package/open-sse/services/compression/adaptiveCompression/types.ts +61 -0
  837. package/open-sse/services/compression/aggressive.ts +204 -0
  838. package/open-sse/services/compression/bodyAdapter.ts +354 -0
  839. package/open-sse/services/compression/cacheAwareConfig.ts +60 -0
  840. package/open-sse/services/compression/cachingAware.ts +130 -0
  841. package/open-sse/services/compression/caveman.ts +602 -0
  842. package/open-sse/services/compression/cavemanRules.ts +432 -0
  843. package/open-sse/services/compression/deriveDefaultPlan.ts +59 -0
  844. package/open-sse/services/compression/diffHelper.ts +219 -0
  845. package/open-sse/services/compression/engineBreakdown.ts +29 -0
  846. package/open-sse/services/compression/engineCatalog.ts +91 -0
  847. package/open-sse/services/compression/engines/cavemanAdapter.ts +454 -0
  848. package/open-sse/services/compression/engines/ccr/ccrQuery.ts +110 -0
  849. package/open-sse/services/compression/engines/ccr/index.ts +460 -0
  850. package/open-sse/services/compression/engines/headroom/encoderComparison.ts +72 -0
  851. package/open-sse/services/compression/engines/headroom/gcf/decode_generic.ts +711 -0
  852. package/open-sse/services/compression/engines/headroom/gcf/generic.ts +332 -0
  853. package/open-sse/services/compression/engines/headroom/gcf/index.ts +9 -0
  854. package/open-sse/services/compression/engines/headroom/gcf/scalar.ts +336 -0
  855. package/open-sse/services/compression/engines/headroom/index.ts +286 -0
  856. package/open-sse/services/compression/engines/headroom/smartcrusher.ts +255 -0
  857. package/open-sse/services/compression/engines/headroom/tabular.ts +263 -0
  858. package/open-sse/services/compression/engines/headroom/toon.ts +43 -0
  859. package/open-sse/services/compression/engines/index.ts +42 -0
  860. package/open-sse/services/compression/engines/ionizer/index.ts +124 -0
  861. package/open-sse/services/compression/engines/ionizer/sample.ts +200 -0
  862. package/open-sse/services/compression/engines/llm/index.ts +346 -0
  863. package/open-sse/services/compression/engines/llmlingua/constants.ts +55 -0
  864. package/open-sse/services/compression/engines/llmlingua/index.ts +474 -0
  865. package/open-sse/services/compression/engines/llmlingua/modelStore.ts +67 -0
  866. package/open-sse/services/compression/engines/llmlingua/onnxWorker.ts +117 -0
  867. package/open-sse/services/compression/engines/llmlingua/ultraEntry.ts +109 -0
  868. package/open-sse/services/compression/engines/llmlingua/worker.ts +373 -0
  869. package/open-sse/services/compression/engines/mcpAccessibility/collapseRepeated.ts +121 -0
  870. package/open-sse/services/compression/engines/mcpAccessibility/constants.ts +63 -0
  871. package/open-sse/services/compression/engines/mcpAccessibility/index.ts +52 -0
  872. package/open-sse/services/compression/engines/readLifecycle/index.ts +299 -0
  873. package/open-sse/services/compression/engines/registry.ts +87 -0
  874. package/open-sse/services/compression/engines/relevance/configSchema.ts +63 -0
  875. package/open-sse/services/compression/engines/relevance/index.ts +185 -0
  876. package/open-sse/services/compression/engines/relevance/scorer.ts +85 -0
  877. package/open-sse/services/compression/engines/rtk/codeStripper.ts +145 -0
  878. package/open-sse/services/compression/engines/rtk/commandDetector.ts +482 -0
  879. package/open-sse/services/compression/engines/rtk/configSchema.ts +117 -0
  880. package/open-sse/services/compression/engines/rtk/deduplicator.ts +37 -0
  881. package/open-sse/services/compression/engines/rtk/discover.ts +150 -0
  882. package/open-sse/services/compression/engines/rtk/filterLoader.ts +245 -0
  883. package/open-sse/services/compression/engines/rtk/filterSchema.ts +207 -0
  884. package/open-sse/services/compression/engines/rtk/filters/aws.json +34 -0
  885. package/open-sse/services/compression/engines/rtk/filters/biome.json +35 -0
  886. package/open-sse/services/compression/engines/rtk/filters/build-eslint.json +37 -0
  887. package/open-sse/services/compression/engines/rtk/filters/build-typescript.json +33 -0
  888. package/open-sse/services/compression/engines/rtk/filters/build-vite.json +41 -0
  889. package/open-sse/services/compression/engines/rtk/filters/build-webpack.json +34 -0
  890. package/open-sse/services/compression/engines/rtk/filters/bundle-install.json +35 -0
  891. package/open-sse/services/compression/engines/rtk/filters/composer.json +81 -0
  892. package/open-sse/services/compression/engines/rtk/filters/curl.json +34 -0
  893. package/open-sse/services/compression/engines/rtk/filters/df.json +34 -0
  894. package/open-sse/services/compression/engines/rtk/filters/docker-build.json +78 -0
  895. package/open-sse/services/compression/engines/rtk/filters/docker-logs.json +42 -0
  896. package/open-sse/services/compression/engines/rtk/filters/docker-ps.json +33 -0
  897. package/open-sse/services/compression/engines/rtk/filters/dotnet.json +47 -0
  898. package/open-sse/services/compression/engines/rtk/filters/du.json +33 -0
  899. package/open-sse/services/compression/engines/rtk/filters/error-stacktrace.json +41 -0
  900. package/open-sse/services/compression/engines/rtk/filters/gcloud.json +34 -0
  901. package/open-sse/services/compression/engines/rtk/filters/generic-output.json +32 -0
  902. package/open-sse/services/compression/engines/rtk/filters/gh.json +98 -0
  903. package/open-sse/services/compression/engines/rtk/filters/git-branch.json +45 -0
  904. package/open-sse/services/compression/engines/rtk/filters/git-diff.json +33 -0
  905. package/open-sse/services/compression/engines/rtk/filters/git-log.json +33 -0
  906. package/open-sse/services/compression/engines/rtk/filters/git-status.json +40 -0
  907. package/open-sse/services/compression/engines/rtk/filters/golangci-lint.json +34 -0
  908. package/open-sse/services/compression/engines/rtk/filters/gradle.json +47 -0
  909. package/open-sse/services/compression/engines/rtk/filters/json-output.json +40 -0
  910. package/open-sse/services/compression/engines/rtk/filters/kubectl.json +99 -0
  911. package/open-sse/services/compression/engines/rtk/filters/make.json +38 -0
  912. package/open-sse/services/compression/engines/rtk/filters/mypy.json +34 -0
  913. package/open-sse/services/compression/engines/rtk/filters/npm-audit.json +43 -0
  914. package/open-sse/services/compression/engines/rtk/filters/npm-install.json +41 -0
  915. package/open-sse/services/compression/engines/rtk/filters/nx.json +34 -0
  916. package/open-sse/services/compression/engines/rtk/filters/pip.json +41 -0
  917. package/open-sse/services/compression/engines/rtk/filters/playwright.json +42 -0
  918. package/open-sse/services/compression/engines/rtk/filters/poetry-install.json +35 -0
  919. package/open-sse/services/compression/engines/rtk/filters/prettier.json +40 -0
  920. package/open-sse/services/compression/engines/rtk/filters/ps.json +34 -0
  921. package/open-sse/services/compression/engines/rtk/filters/rsync.json +33 -0
  922. package/open-sse/services/compression/engines/rtk/filters/rubocop.json +34 -0
  923. package/open-sse/services/compression/engines/rtk/filters/ruff.json +40 -0
  924. package/open-sse/services/compression/engines/rtk/filters/shell-find.json +33 -0
  925. package/open-sse/services/compression/engines/rtk/filters/shell-grep.json +37 -0
  926. package/open-sse/services/compression/engines/rtk/filters/shell-ls.json +33 -0
  927. package/open-sse/services/compression/engines/rtk/filters/ssh.json +43 -0
  928. package/open-sse/services/compression/engines/rtk/filters/systemctl-status.json +43 -0
  929. package/open-sse/services/compression/engines/rtk/filters/terraform-plan.json +34 -0
  930. package/open-sse/services/compression/engines/rtk/filters/test-cargo.json +42 -0
  931. package/open-sse/services/compression/engines/rtk/filters/test-go.json +41 -0
  932. package/open-sse/services/compression/engines/rtk/filters/test-jest.json +43 -0
  933. package/open-sse/services/compression/engines/rtk/filters/test-pytest.json +41 -0
  934. package/open-sse/services/compression/engines/rtk/filters/test-vitest.json +43 -0
  935. package/open-sse/services/compression/engines/rtk/filters/tofu-plan.json +34 -0
  936. package/open-sse/services/compression/engines/rtk/filters/turbo.json +34 -0
  937. package/open-sse/services/compression/engines/rtk/filters/uv-sync.json +35 -0
  938. package/open-sse/services/compression/engines/rtk/filters/wget.json +34 -0
  939. package/open-sse/services/compression/engines/rtk/grouper.ts +99 -0
  940. package/open-sse/services/compression/engines/rtk/index.ts +706 -0
  941. package/open-sse/services/compression/engines/rtk/learn.ts +290 -0
  942. package/open-sse/services/compression/engines/rtk/lineFilter.ts +178 -0
  943. package/open-sse/services/compression/engines/rtk/rawOutput.ts +208 -0
  944. package/open-sse/services/compression/engines/rtk/renderers/gitDiff.ts +39 -0
  945. package/open-sse/services/compression/engines/rtk/renderers/index.ts +50 -0
  946. package/open-sse/services/compression/engines/rtk/renderers/structuredTable.ts +96 -0
  947. package/open-sse/services/compression/engines/rtk/renderers/terraformPlan.ts +40 -0
  948. package/open-sse/services/compression/engines/rtk/renderers/testGreen.ts +70 -0
  949. package/open-sse/services/compression/engines/rtk/renderers/types.ts +13 -0
  950. package/open-sse/services/compression/engines/rtk/smartTruncate.ts +67 -0
  951. package/open-sse/services/compression/engines/rtk/splitCompositeCommand.ts +111 -0
  952. package/open-sse/services/compression/engines/rtk/verify.ts +107 -0
  953. package/open-sse/services/compression/engines/session-dedup/fuzzy.ts +153 -0
  954. package/open-sse/services/compression/engines/session-dedup/index.ts +435 -0
  955. package/open-sse/services/compression/engines/types.ts +77 -0
  956. package/open-sse/services/compression/entrypointWrap.ts +43 -0
  957. package/open-sse/services/compression/eval/aggregate.ts +62 -0
  958. package/open-sse/services/compression/eval/corpus.ts +45 -0
  959. package/open-sse/services/compression/eval/costMeter.ts +31 -0
  960. package/open-sse/services/compression/eval/executorModelClient.ts +44 -0
  961. package/open-sse/services/compression/eval/fidelityCheck.ts +61 -0
  962. package/open-sse/services/compression/eval/grader.ts +27 -0
  963. package/open-sse/services/compression/eval/judge.ts +68 -0
  964. package/open-sse/services/compression/eval/report.ts +44 -0
  965. package/open-sse/services/compression/eval/runner.ts +135 -0
  966. package/open-sse/services/compression/eval/savings.ts +30 -0
  967. package/open-sse/services/compression/eval/seedCorpus.ts +60 -0
  968. package/open-sse/services/compression/eval/types.ts +65 -0
  969. package/open-sse/services/compression/fidelityGate.ts +124 -0
  970. package/open-sse/services/compression/fidelityGateStep.ts +44 -0
  971. package/open-sse/services/compression/hardBudget.ts +196 -0
  972. package/open-sse/services/compression/harness/benchmark.ts +318 -0
  973. package/open-sse/services/compression/harness/budgetGate.ts +62 -0
  974. package/open-sse/services/compression/harness/index.ts +52 -0
  975. package/open-sse/services/compression/harness/measure.ts +98 -0
  976. package/open-sse/services/compression/harness/replay.ts +72 -0
  977. package/open-sse/services/compression/harness/runner.ts +58 -0
  978. package/open-sse/services/compression/index.ts +165 -0
  979. package/open-sse/services/compression/languageDetector.ts +51 -0
  980. package/open-sse/services/compression/lite.ts +241 -0
  981. package/open-sse/services/compression/messageContent.ts +89 -0
  982. package/open-sse/services/compression/outputMode.ts +175 -0
  983. package/open-sse/services/compression/outputStyles/apply.ts +135 -0
  984. package/open-sse/services/compression/outputStyles/backCompat.ts +29 -0
  985. package/open-sse/services/compression/outputStyles/catalog.ts +76 -0
  986. package/open-sse/services/compression/outputStyles/telemetry.ts +50 -0
  987. package/open-sse/services/compression/pipelineEngineBreaker.ts +139 -0
  988. package/open-sse/services/compression/pipelineGuards.ts +45 -0
  989. package/open-sse/services/compression/planResolution.ts +128 -0
  990. package/open-sse/services/compression/prefixFreeze.ts +124 -0
  991. package/open-sse/services/compression/preservation.ts +0 -0
  992. package/open-sse/services/compression/preserveSystemPromptMode.ts +72 -0
  993. package/open-sse/services/compression/progressiveAging.ts +145 -0
  994. package/open-sse/services/compression/quantumLock/index.ts +17 -0
  995. package/open-sse/services/compression/quantumLock/quantumLock.ts +58 -0
  996. package/open-sse/services/compression/quantumLock/quantumLockStep.ts +72 -0
  997. package/open-sse/services/compression/quantumLock/quantumPatterns.ts +80 -0
  998. package/open-sse/services/compression/quantumLock/strategyWrap.ts +72 -0
  999. package/open-sse/services/compression/resolveCompressionPlan.ts +28 -0
  1000. package/open-sse/services/compression/resultMemo.ts +83 -0
  1001. package/open-sse/services/compression/riskGate/index.ts +3 -0
  1002. package/open-sse/services/compression/riskGate/riskGate.ts +136 -0
  1003. package/open-sse/services/compression/riskGate/riskGateStep.ts +115 -0
  1004. package/open-sse/services/compression/riskGate/riskPatterns.ts +61 -0
  1005. package/open-sse/services/compression/riskGate/strategyWrap.ts +44 -0
  1006. package/open-sse/services/compression/ruleLoader.ts +273 -0
  1007. package/open-sse/services/compression/rules/_schema.json +31 -0
  1008. package/open-sse/services/compression/rules/de/context.json +38 -0
  1009. package/open-sse/services/compression/rules/de/dedup.json +38 -0
  1010. package/open-sse/services/compression/rules/de/filler.json +70 -0
  1011. package/open-sse/services/compression/rules/de/structural.json +30 -0
  1012. package/open-sse/services/compression/rules/de/ultra.json +107 -0
  1013. package/open-sse/services/compression/rules/en/context.json +88 -0
  1014. package/open-sse/services/compression/rules/en/dedup.json +38 -0
  1015. package/open-sse/services/compression/rules/en/filler.json +129 -0
  1016. package/open-sse/services/compression/rules/en/structural.json +102 -0
  1017. package/open-sse/services/compression/rules/en/ultra.json +107 -0
  1018. package/open-sse/services/compression/rules/es/context.json +87 -0
  1019. package/open-sse/services/compression/rules/es/dedup.json +38 -0
  1020. package/open-sse/services/compression/rules/es/filler.json +110 -0
  1021. package/open-sse/services/compression/rules/es/structural.json +105 -0
  1022. package/open-sse/services/compression/rules/es/ultra.json +107 -0
  1023. package/open-sse/services/compression/rules/fr/context.json +38 -0
  1024. package/open-sse/services/compression/rules/fr/dedup.json +38 -0
  1025. package/open-sse/services/compression/rules/fr/filler.json +70 -0
  1026. package/open-sse/services/compression/rules/fr/structural.json +30 -0
  1027. package/open-sse/services/compression/rules/fr/ultra.json +107 -0
  1028. package/open-sse/services/compression/rules/id/context.json +113 -0
  1029. package/open-sse/services/compression/rules/id/dedup.json +38 -0
  1030. package/open-sse/services/compression/rules/id/filler.json +138 -0
  1031. package/open-sse/services/compression/rules/id/structural.json +111 -0
  1032. package/open-sse/services/compression/rules/id/ultra.json +252 -0
  1033. package/open-sse/services/compression/rules/ja/context.json +38 -0
  1034. package/open-sse/services/compression/rules/ja/dedup.json +38 -0
  1035. package/open-sse/services/compression/rules/ja/filler.json +70 -0
  1036. package/open-sse/services/compression/rules/ja/structural.json +30 -0
  1037. package/open-sse/services/compression/rules/ja/ultra.json +86 -0
  1038. package/open-sse/services/compression/rules/pt-BR/context.json +69 -0
  1039. package/open-sse/services/compression/rules/pt-BR/dedup.json +51 -0
  1040. package/open-sse/services/compression/rules/pt-BR/filler.json +151 -0
  1041. package/open-sse/services/compression/rules/pt-BR/structural.json +78 -0
  1042. package/open-sse/services/compression/rules/pt-BR/ultra.json +192 -0
  1043. package/open-sse/services/compression/rules/zh/dedup.json +38 -0
  1044. package/open-sse/services/compression/rules/zh/filler.json +54 -0
  1045. package/open-sse/services/compression/rules/zh/ultra.json +55 -0
  1046. package/open-sse/services/compression/stackedStepCore.ts +87 -0
  1047. package/open-sse/services/compression/stats.ts +59 -0
  1048. package/open-sse/services/compression/strategySelector.ts +1007 -0
  1049. package/open-sse/services/compression/summarizer.ts +244 -0
  1050. package/open-sse/services/compression/toolResultCompressor.ts +283 -0
  1051. package/open-sse/services/compression/types.ts +479 -0
  1052. package/open-sse/services/compression/ultra.ts +321 -0
  1053. package/open-sse/services/compression/ultraHeuristic.ts +157 -0
  1054. package/open-sse/services/compression/validation.ts +432 -0
  1055. package/open-sse/services/contextHandoff.ts +770 -0
  1056. package/open-sse/services/contextManager.ts +617 -0
  1057. package/open-sse/services/credentialGate.ts +84 -0
  1058. package/open-sse/services/crofUsageFetcher.ts +182 -0
  1059. package/open-sse/services/cursorSessionManager.ts +208 -0
  1060. package/open-sse/services/deepseekQuotaFetcher.ts +244 -0
  1061. package/open-sse/services/deviceTracker.ts +307 -0
  1062. package/open-sse/services/emergencyFallback.ts +162 -0
  1063. package/open-sse/services/errorClassifier.ts +198 -0
  1064. package/open-sse/services/evalRouting.ts +276 -0
  1065. package/open-sse/services/freeWebSearch.ts +154 -0
  1066. package/open-sse/services/fusion.ts +337 -0
  1067. package/open-sse/services/geminiRateLimitTracker.ts +145 -0
  1068. package/open-sse/services/geminiThoughtSignatureStore.ts +329 -0
  1069. package/open-sse/services/genericQuotaFetcher.ts +215 -0
  1070. package/open-sse/services/gigachatAuth.ts +113 -0
  1071. package/open-sse/services/githubCopilotModels.ts +162 -0
  1072. package/open-sse/services/gpt5SamplingGuard.ts +81 -0
  1073. package/open-sse/services/grokTlsClient.ts +607 -0
  1074. package/open-sse/services/hfModelSuggestions.ts +63 -0
  1075. package/open-sse/services/inAppLoginService.ts +256 -0
  1076. package/open-sse/services/intentClassifier.ts +665 -0
  1077. package/open-sse/services/ipFilter.ts +340 -0
  1078. package/open-sse/services/keyGroupAuth.ts +84 -0
  1079. package/open-sse/services/kiroModels.ts +195 -0
  1080. package/open-sse/services/manifestAdapter.ts +134 -0
  1081. package/open-sse/services/mimoThinking.ts +54 -0
  1082. package/open-sse/services/model.ts +738 -0
  1083. package/open-sse/services/modelCapabilities.ts +5 -0
  1084. package/open-sse/services/modelDeprecation.ts +173 -0
  1085. package/open-sse/services/modelFamilyFallback.ts +240 -0
  1086. package/open-sse/services/modelStrip.ts +60 -0
  1087. package/open-sse/services/modelscopePolicy.ts +97 -0
  1088. package/open-sse/services/opencodeOllamaUsage.ts +562 -0
  1089. package/open-sse/services/opencodeQuotaFetcher.ts +351 -0
  1090. package/open-sse/services/payloadRules.ts +474 -0
  1091. package/open-sse/services/perplexityTlsClient.ts +593 -0
  1092. package/open-sse/services/pipeline.ts +189 -0
  1093. package/open-sse/services/provider.ts +460 -0
  1094. package/open-sse/services/providerCooldownTracker.ts +198 -0
  1095. package/open-sse/services/providerCostData.ts +52 -0
  1096. package/open-sse/services/providerDefaultRateLimit.ts +94 -0
  1097. package/open-sse/services/providerRequestDefaults.ts +88 -0
  1098. package/open-sse/services/proxyAutoSelector.ts +58 -0
  1099. package/open-sse/services/qoderCli.ts +987 -0
  1100. package/open-sse/services/qoderCliResolve.ts +111 -0
  1101. package/open-sse/services/quotaFetchThrottle.ts +118 -0
  1102. package/open-sse/services/quotaMonitor.ts +377 -0
  1103. package/open-sse/services/quotaPreflight.ts +349 -0
  1104. package/open-sse/services/qwenThinking.ts +44 -0
  1105. package/open-sse/services/rateLimitManager/headers.ts +94 -0
  1106. package/open-sse/services/rateLimitManager.ts +945 -0
  1107. package/open-sse/services/rateLimitSemaphore.ts +231 -0
  1108. package/open-sse/services/reasoningCache.ts +514 -0
  1109. package/open-sse/services/reasoningTokenBuffer.ts +50 -0
  1110. package/open-sse/services/refreshSerializer.ts +131 -0
  1111. package/open-sse/services/requestDedup.ts +127 -0
  1112. package/open-sse/services/responseModelEcho.ts +79 -0
  1113. package/open-sse/services/responsesInputSanitizer.ts +145 -0
  1114. package/open-sse/services/retryAfterJson.ts +44 -0
  1115. package/open-sse/services/roleNormalizer.ts +283 -0
  1116. package/open-sse/services/searchCache.ts +150 -0
  1117. package/open-sse/services/sessionManager.ts +380 -0
  1118. package/open-sse/services/sessionPool/fingerprintRotator.ts +126 -0
  1119. package/open-sse/services/sessionPool/index.ts +28 -0
  1120. package/open-sse/services/sessionPool/poolRegistry.ts +93 -0
  1121. package/open-sse/services/sessionPool/session.ts +119 -0
  1122. package/open-sse/services/sessionPool/sessionFactory.ts +57 -0
  1123. package/open-sse/services/sessionPool/sessionPool.ts +326 -0
  1124. package/open-sse/services/sessionPool/types.ts +100 -0
  1125. package/open-sse/services/sessionPool/webExecutorWrapper.ts +132 -0
  1126. package/open-sse/services/signatureCache.ts +189 -0
  1127. package/open-sse/services/slidingWindowLimiter.ts +84 -0
  1128. package/open-sse/services/specificityDetector.ts +89 -0
  1129. package/open-sse/services/specificityRules.ts +257 -0
  1130. package/open-sse/services/specificityTypes.ts +43 -0
  1131. package/open-sse/services/streamRecovery.ts +545 -0
  1132. package/open-sse/services/systemPrompt.ts +187 -0
  1133. package/open-sse/services/systemTransforms.ts +532 -0
  1134. package/open-sse/services/taskAwareRouter.ts +326 -0
  1135. package/open-sse/services/taskAwareRouting.ts +553 -0
  1136. package/open-sse/services/thinkingBudget.ts +391 -0
  1137. package/open-sse/services/tierConfig.ts +124 -0
  1138. package/open-sse/services/tierDefaults.json +26 -0
  1139. package/open-sse/services/tierResolver.ts +144 -0
  1140. package/open-sse/services/tierTypes.ts +40 -0
  1141. package/open-sse/services/tlsClientProxy.ts +30 -0
  1142. package/open-sse/services/tokenExtractionConfig.ts +398 -0
  1143. package/open-sse/services/tokenLimitCounter.ts +342 -0
  1144. package/open-sse/services/tokenRefresh.ts +2180 -0
  1145. package/open-sse/services/toolLatencyTracker.ts +89 -0
  1146. package/open-sse/services/toolLimitDetector.ts +87 -0
  1147. package/open-sse/services/toolSchemaSanitizer.ts +165 -0
  1148. package/open-sse/services/usage/antigravity.ts +794 -0
  1149. package/open-sse/services/usage/claude.ts +216 -0
  1150. package/open-sse/services/usage/codebuddy-cn.ts +199 -0
  1151. package/open-sse/services/usage/codex.ts +75 -0
  1152. package/open-sse/services/usage/cursor.ts +161 -0
  1153. package/open-sse/services/usage/glm.ts +220 -0
  1154. package/open-sse/services/usage/kimi.ts +209 -0
  1155. package/open-sse/services/usage/kiro.ts +243 -0
  1156. package/open-sse/services/usage/minimax.ts +346 -0
  1157. package/open-sse/services/usage/quota.ts +85 -0
  1158. package/open-sse/services/usage/scalars.ts +75 -0
  1159. package/open-sse/services/usage.ts +1058 -0
  1160. package/open-sse/services/volumeDetector.ts +224 -0
  1161. package/open-sse/services/webSearchFallback.ts +246 -0
  1162. package/open-sse/services/webSearchRouting.ts +68 -0
  1163. package/open-sse/services/webSessionPoolHealth.ts +287 -0
  1164. package/open-sse/services/wildcardRouter.ts +136 -0
  1165. package/open-sse/services/workflowFSM.ts +340 -0
  1166. package/open-sse/shared/zedAuth.ts +535 -0
  1167. package/open-sse/transformer/responsesTransformer.ts +667 -0
  1168. package/open-sse/translator/bootstrap.ts +27 -0
  1169. package/open-sse/translator/deepseekWebTools.ts +486 -0
  1170. package/open-sse/translator/formats.ts +12 -0
  1171. package/open-sse/translator/helpers/claudeHelper.ts +563 -0
  1172. package/open-sse/translator/helpers/geminiHelper.ts +657 -0
  1173. package/open-sse/translator/helpers/geminiToolsSanitizer.ts +255 -0
  1174. package/open-sse/translator/helpers/jsonUtil.ts +18 -0
  1175. package/open-sse/translator/helpers/maxTokensHelper.ts +21 -0
  1176. package/open-sse/translator/helpers/openaiHelper.ts +244 -0
  1177. package/open-sse/translator/helpers/responsesApiHelper.ts +9 -0
  1178. package/open-sse/translator/helpers/schemaCoercion.ts +408 -0
  1179. package/open-sse/translator/helpers/toolCallHelper.ts +224 -0
  1180. package/open-sse/translator/helpers/toolCallShim.ts +113 -0
  1181. package/open-sse/translator/image/sizeMapper.ts +22 -0
  1182. package/open-sse/translator/index.ts +614 -0
  1183. package/open-sse/translator/paramSupport.ts +70 -0
  1184. package/open-sse/translator/registry.ts +41 -0
  1185. package/open-sse/translator/request/antigravity-to-openai.ts +357 -0
  1186. package/open-sse/translator/request/claude-to-gemini.ts +236 -0
  1187. package/open-sse/translator/request/claude-to-openai.ts +534 -0
  1188. package/open-sse/translator/request/gemini-to-openai.ts +193 -0
  1189. package/open-sse/translator/request/openai-responses/helpers.ts +69 -0
  1190. package/open-sse/translator/request/openai-responses/toResponses.ts +357 -0
  1191. package/open-sse/translator/request/openai-responses.ts +533 -0
  1192. package/open-sse/translator/request/openai-to-claude/thinkingBudget.ts +89 -0
  1193. package/open-sse/translator/request/openai-to-claude/toolResultAdjacency.ts +106 -0
  1194. package/open-sse/translator/request/openai-to-claude.ts +747 -0
  1195. package/open-sse/translator/request/openai-to-cursor.ts +226 -0
  1196. package/open-sse/translator/request/openai-to-gemini/helpers.ts +142 -0
  1197. package/open-sse/translator/request/openai-to-gemini.ts +753 -0
  1198. package/open-sse/translator/request/openai-to-kiro/messageHelpers.ts +109 -0
  1199. package/open-sse/translator/request/openai-to-kiro.ts +889 -0
  1200. package/open-sse/translator/response/claude-to-openai.ts +327 -0
  1201. package/open-sse/translator/response/cursor-to-openai.ts +30 -0
  1202. package/open-sse/translator/response/gemini-to-claude.ts +199 -0
  1203. package/open-sse/translator/response/gemini-to-openai.ts +765 -0
  1204. package/open-sse/translator/response/kiro-to-openai.ts +211 -0
  1205. package/open-sse/translator/response/openai-responses/pureHelpers.ts +92 -0
  1206. package/open-sse/translator/response/openai-responses.ts +1011 -0
  1207. package/open-sse/translator/response/openai-to-antigravity.ts +145 -0
  1208. package/open-sse/translator/response/openai-to-claude.ts +289 -0
  1209. package/open-sse/translator/response/openai-to-gemini-sse.ts +431 -0
  1210. package/open-sse/translator/webTools.ts +531 -0
  1211. package/open-sse/tsconfig.json +25 -0
  1212. package/open-sse/types.d.ts +139 -0
  1213. package/open-sse/utils/agentGoalPolicy.ts +112 -0
  1214. package/open-sse/utils/aiSdkCompat.ts +179 -0
  1215. package/open-sse/utils/anthropicHost.ts +25 -0
  1216. package/open-sse/utils/awsSigV4.ts +139 -0
  1217. package/open-sse/utils/bypassHandler.ts +300 -0
  1218. package/open-sse/utils/cacheControlPolicy.ts +374 -0
  1219. package/open-sse/utils/claudeCodeMetaRequests.ts +87 -0
  1220. package/open-sse/utils/clinepassEnvelope.ts +59 -0
  1221. package/open-sse/utils/comfyuiClient.ts +126 -0
  1222. package/open-sse/utils/composerToolCalls.ts +307 -0
  1223. package/open-sse/utils/cors.ts +13 -0
  1224. package/open-sse/utils/cursorAgentProtobuf/wire.ts +143 -0
  1225. package/open-sse/utils/cursorAgentProtobuf.ts +1400 -0
  1226. package/open-sse/utils/cursorChecksum.ts +139 -0
  1227. package/open-sse/utils/cursorImages.ts +354 -0
  1228. package/open-sse/utils/cursorVersionDetector.ts +74 -0
  1229. package/open-sse/utils/diagnostics.ts +288 -0
  1230. package/open-sse/utils/earlyStreamKeepalive.ts +228 -0
  1231. package/open-sse/utils/error.ts +515 -0
  1232. package/open-sse/utils/estimateSize.ts +35 -0
  1233. package/open-sse/utils/finishReason.ts +36 -0
  1234. package/open-sse/utils/flattenToolHistory.ts +116 -0
  1235. package/open-sse/utils/headers.ts +61 -0
  1236. package/open-sse/utils/heapPressure.ts +81 -0
  1237. package/open-sse/utils/jsonToSse.ts +127 -0
  1238. package/open-sse/utils/keepaliveThreshold.ts +62 -0
  1239. package/open-sse/utils/kieTask.ts +127 -0
  1240. package/open-sse/utils/kiroSanitizer.ts +127 -0
  1241. package/open-sse/utils/logger.ts +190 -0
  1242. package/open-sse/utils/networkProxy.ts +75 -0
  1243. package/open-sse/utils/noThinkingAlias.ts +153 -0
  1244. package/open-sse/utils/number.ts +4 -0
  1245. package/open-sse/utils/ollamaTransform.ts +122 -0
  1246. package/open-sse/utils/opencodeHeaders.ts +98 -0
  1247. package/open-sse/utils/passthroughTailProcessor.ts +299 -0
  1248. package/open-sse/utils/progressTracker.ts +112 -0
  1249. package/open-sse/utils/providerRequestLogging.ts +272 -0
  1250. package/open-sse/utils/proxyDispatcher.ts +507 -0
  1251. package/open-sse/utils/proxyDispatcherCache.ts +124 -0
  1252. package/open-sse/utils/proxyFallback.ts +418 -0
  1253. package/open-sse/utils/proxyFamily.ts +24 -0
  1254. package/open-sse/utils/proxyFamilyResolve.ts +39 -0
  1255. package/open-sse/utils/proxyFetch.ts +666 -0
  1256. package/open-sse/utils/publicCreds.ts +215 -0
  1257. package/open-sse/utils/reasoningContentInjector.ts +73 -0
  1258. package/open-sse/utils/reasoningFields.ts +72 -0
  1259. package/open-sse/utils/requestLogger.ts +386 -0
  1260. package/open-sse/utils/responsesInputNormalization.ts +94 -0
  1261. package/open-sse/utils/responsesStatePolicy.ts +75 -0
  1262. package/open-sse/utils/responsesStreamHelpers.ts +166 -0
  1263. package/open-sse/utils/setupPolyfill.ts +33 -0
  1264. package/open-sse/utils/sha3-512.ts +164 -0
  1265. package/open-sse/utils/sleep.ts +9 -0
  1266. package/open-sse/utils/socksConnectorWithFamily.ts +89 -0
  1267. package/open-sse/utils/sseHeartbeat.ts +119 -0
  1268. package/open-sse/utils/stream.ts +2791 -0
  1269. package/open-sse/utils/streamFailureFinalization.ts +174 -0
  1270. package/open-sse/utils/streamHandler.ts +680 -0
  1271. package/open-sse/utils/streamHelpers.ts +460 -0
  1272. package/open-sse/utils/streamPayloadCollector.ts +700 -0
  1273. package/open-sse/utils/streamReadiness.ts +385 -0
  1274. package/open-sse/utils/streamReadinessPolicy.ts +132 -0
  1275. package/open-sse/utils/textualToolCall.ts +112 -0
  1276. package/open-sse/utils/thinkCloseMarker.ts +77 -0
  1277. package/open-sse/utils/thinkTagParser.ts +146 -0
  1278. package/open-sse/utils/tlsClient.ts +243 -0
  1279. package/open-sse/utils/toolCallArguments.ts +32 -0
  1280. package/open-sse/utils/toolSources.ts +69 -0
  1281. package/open-sse/utils/upstreamResponseHeaders.ts +47 -0
  1282. package/open-sse/utils/urlSanitize.ts +24 -0
  1283. package/open-sse/utils/usageTracking.ts +596 -0
  1284. package/package.json +393 -0
  1285. package/scripts/build/build-next-isolated.mjs +322 -0
  1286. package/scripts/build/colocateOptionals.mjs +144 -0
  1287. package/scripts/build/native-binary-compat.mjs +167 -0
  1288. package/scripts/build/postinstall.mjs +357 -0
  1289. package/scripts/build/postinstallSupport.mjs +45 -0
  1290. package/scripts/build/runtime-env.mjs +140 -0
  1291. package/scripts/build/sync-env.mjs +3 -0
  1292. package/scripts/check/check-supported-node-runtime.ts +20 -0
  1293. package/scripts/dev/responses-ws-proxy.mjs +907 -0
  1294. package/scripts/dev/sync-env.mjs +362 -0
  1295. package/scripts/dev/tls-options.mjs +92 -0
  1296. package/scripts/postinstall.mjs +27 -0
  1297. package/src/domain/assessment/assessor.ts +206 -0
  1298. package/src/domain/assessment/categorizer.ts +118 -0
  1299. package/src/domain/assessment/index.ts +24 -0
  1300. package/src/domain/assessment/migration.ts +111 -0
  1301. package/src/domain/assessment/selfHealer.ts +261 -0
  1302. package/src/domain/assessment/types.ts +361 -0
  1303. package/src/domain/comboResolver.ts +106 -0
  1304. package/src/domain/configAudit.ts +285 -0
  1305. package/src/domain/connectionModelRules.ts +82 -0
  1306. package/src/domain/costRules.ts +631 -0
  1307. package/src/domain/degradation.ts +253 -0
  1308. package/src/domain/fallbackPolicy.ts +160 -0
  1309. package/src/domain/lockoutPolicy.ts +208 -0
  1310. package/src/domain/modelAvailability.ts +41 -0
  1311. package/src/domain/omnirouteResponseMeta.ts +202 -0
  1312. package/src/domain/pipeline.ts +307 -0
  1313. package/src/domain/policyEngine.ts +195 -0
  1314. package/src/domain/prompts.ts +103 -0
  1315. package/src/domain/providerExpiration.ts +255 -0
  1316. package/src/domain/quotaCache.ts +553 -0
  1317. package/src/domain/responses.ts +139 -0
  1318. package/src/domain/tagRouter.ts +64 -0
  1319. package/src/domain/types.ts +123 -0
  1320. package/src/lib/a2a/README.md +748 -0
  1321. package/src/lib/a2a/routingLogger.ts +67 -0
  1322. package/src/lib/a2a/skills/costAnalysis.ts +162 -0
  1323. package/src/lib/a2a/skills/healthReport.ts +155 -0
  1324. package/src/lib/a2a/skills/listCapabilities.ts +72 -0
  1325. package/src/lib/a2a/skills/providerDiscovery.ts +202 -0
  1326. package/src/lib/a2a/skills/quotaManagement.ts +121 -0
  1327. package/src/lib/a2a/skills/smartRouting.ts +89 -0
  1328. package/src/lib/a2a/streaming.ts +149 -0
  1329. package/src/lib/a2a/taskExecution.ts +64 -0
  1330. package/src/lib/a2a/taskManager.ts +240 -0
  1331. package/src/lib/accessTokens/scopes.ts +51 -0
  1332. package/src/lib/acp/index.ts +11 -0
  1333. package/src/lib/acp/manager.ts +202 -0
  1334. package/src/lib/acp/registry.ts +384 -0
  1335. package/src/lib/agentSkills/catalog.ts +256 -0
  1336. package/src/lib/agentSkills/cliRegistryParser.ts +242 -0
  1337. package/src/lib/agentSkills/generator.ts +367 -0
  1338. package/src/lib/agentSkills/openapiParser.ts +201 -0
  1339. package/src/lib/agentSkills/schemas.ts +36 -0
  1340. package/src/lib/agentSkills/types.ts +101 -0
  1341. package/src/lib/api/comboErrorResponse.ts +80 -0
  1342. package/src/lib/api/errorResponse.ts +54 -0
  1343. package/src/lib/api/modelTestRunner.ts +390 -0
  1344. package/src/lib/api/proxyRegistryRouteHandlers.ts +142 -0
  1345. package/src/lib/api/requireCliToolsAuth.ts +5 -0
  1346. package/src/lib/api/requireManagementAuth.ts +118 -0
  1347. package/src/lib/api/serverErrorMessage.ts +36 -0
  1348. package/src/lib/apiBridgeServer.ts +233 -0
  1349. package/src/lib/apiKeyExposure.ts +19 -0
  1350. package/src/lib/arenaEloSync.ts +564 -0
  1351. package/src/lib/audit/activityIcons.ts +69 -0
  1352. package/src/lib/audit/highLevelActions.ts +57 -0
  1353. package/src/lib/audit/timeline.ts +132 -0
  1354. package/src/lib/auth/managementPassword.ts +117 -0
  1355. package/src/lib/batches/costEstimator.ts +130 -0
  1356. package/src/lib/batches/csvToJsonl.ts +248 -0
  1357. package/src/lib/batches/dispatch.ts +53 -0
  1358. package/src/lib/batches/retryFailed.ts +77 -0
  1359. package/src/lib/batches/schemas.ts +38 -0
  1360. package/src/lib/batches/types.ts +78 -0
  1361. package/src/lib/batches/validateJsonl.ts +154 -0
  1362. package/src/lib/benchmarks.ts +33 -0
  1363. package/src/lib/build-profile/featureDisabled.ts +23 -0
  1364. package/src/lib/cacheControlSettings.ts +25 -0
  1365. package/src/lib/cacheLayer.ts +220 -0
  1366. package/src/lib/catalog/openrouterCatalog.ts +177 -0
  1367. package/src/lib/cli-helper/claudeProfileAutoSync.ts +92 -0
  1368. package/src/lib/cli-helper/codexProfileAutoSync.ts +80 -0
  1369. package/src/lib/cli-helper/config-generator/claude.ts +25 -0
  1370. package/src/lib/cli-helper/config-generator/cline.ts +23 -0
  1371. package/src/lib/cli-helper/config-generator/codex.ts +34 -0
  1372. package/src/lib/cli-helper/config-generator/continue.ts +37 -0
  1373. package/src/lib/cli-helper/config-generator/hermes-agent.ts +210 -0
  1374. package/src/lib/cli-helper/config-generator/hermes.ts +47 -0
  1375. package/src/lib/cli-helper/config-generator/hermesHome.ts +40 -0
  1376. package/src/lib/cli-helper/config-generator/index.ts +124 -0
  1377. package/src/lib/cli-helper/config-generator/kilocode.ts +23 -0
  1378. package/src/lib/cli-helper/config-generator/opencode.ts +443 -0
  1379. package/src/lib/cli-helper/doctor/checks.ts +41 -0
  1380. package/src/lib/cli-helper/log-streamer.ts +78 -0
  1381. package/src/lib/cli-helper/tool-detector.ts +165 -0
  1382. package/src/lib/cliTools/batchStatusCache.ts +47 -0
  1383. package/src/lib/cliTools/checkToolConfigStatus.ts +112 -0
  1384. package/src/lib/cloudAgent/agents/codex.ts +148 -0
  1385. package/src/lib/cloudAgent/agents/cursor.ts +205 -0
  1386. package/src/lib/cloudAgent/agents/devin.ts +137 -0
  1387. package/src/lib/cloudAgent/agents/jules.ts +354 -0
  1388. package/src/lib/cloudAgent/api.ts +86 -0
  1389. package/src/lib/cloudAgent/baseAgent.ts +98 -0
  1390. package/src/lib/cloudAgent/credentials.ts +89 -0
  1391. package/src/lib/cloudAgent/db.ts +145 -0
  1392. package/src/lib/cloudAgent/index.ts +8 -0
  1393. package/src/lib/cloudAgent/julesApi.ts +7 -0
  1394. package/src/lib/cloudAgent/registry.ts +29 -0
  1395. package/src/lib/cloudAgent/types.ts +90 -0
  1396. package/src/lib/cloudSync.stub.ts +31 -0
  1397. package/src/lib/cloudSync.ts +210 -0
  1398. package/src/lib/cloudflaredTunnel.ts +933 -0
  1399. package/src/lib/combos/autoPromote.ts +92 -0
  1400. package/src/lib/combos/builderDraft.ts +242 -0
  1401. package/src/lib/combos/builderOptions.ts +681 -0
  1402. package/src/lib/combos/compositeTiers.ts +200 -0
  1403. package/src/lib/combos/controlCenter.ts +271 -0
  1404. package/src/lib/combos/intelligentRouting.ts +192 -0
  1405. package/src/lib/combos/steps.ts +322 -0
  1406. package/src/lib/combos/testHealth.ts +190 -0
  1407. package/src/lib/compliance/index.ts +637 -0
  1408. package/src/lib/compliance/noLog.ts +86 -0
  1409. package/src/lib/compliance/providerAudit.ts +98 -0
  1410. package/src/lib/compression/judgeModelClient.ts +43 -0
  1411. package/src/lib/config/hotReload.ts +115 -0
  1412. package/src/lib/config/runtimeSettings.ts +551 -0
  1413. package/src/lib/consoleInterceptor.ts +136 -0
  1414. package/src/lib/container.ts +122 -0
  1415. package/src/lib/contextWindowResolver.ts +147 -0
  1416. package/src/lib/copilot/codegraphKnowledge.ts +229 -0
  1417. package/src/lib/copilot/engine.ts +372 -0
  1418. package/src/lib/copilot/systemPrompt.ts +189 -0
  1419. package/src/lib/copilot/tools.ts +415 -0
  1420. package/src/lib/credentialHealth/cache.ts +206 -0
  1421. package/src/lib/credentialHealth/scheduler.ts +328 -0
  1422. package/src/lib/dataPaths.ts +122 -0
  1423. package/src/lib/db/AGENTS.md +70 -0
  1424. package/src/lib/db/_rowTypes.ts +45 -0
  1425. package/src/lib/db/accessTokens.ts +183 -0
  1426. package/src/lib/db/adapters/betterSqliteAdapter.ts +58 -0
  1427. package/src/lib/db/adapters/driverFactory.ts +98 -0
  1428. package/src/lib/db/adapters/nodeSqliteAdapter.ts +60 -0
  1429. package/src/lib/db/adapters/nodeSqliteShared.ts +148 -0
  1430. package/src/lib/db/adapters/sqljsAdapter.ts +232 -0
  1431. package/src/lib/db/adapters/types.ts +34 -0
  1432. package/src/lib/db/agentBridgeBypass.ts +81 -0
  1433. package/src/lib/db/agentBridgeMappings.ts +47 -0
  1434. package/src/lib/db/agentBridgeState.ts +115 -0
  1435. package/src/lib/db/apiKeyColumnFallbacks.ts +47 -0
  1436. package/src/lib/db/apiKeyContextSources.ts +107 -0
  1437. package/src/lib/db/apiKeyGroups.ts +318 -0
  1438. package/src/lib/db/apiKeyUsageLimitFields.ts +65 -0
  1439. package/src/lib/db/apiKeys/modelPermissions.ts +122 -0
  1440. package/src/lib/db/apiKeys/rowParsers.ts +161 -0
  1441. package/src/lib/db/apiKeys/types.ts +21 -0
  1442. package/src/lib/db/apiKeys.ts +1492 -0
  1443. package/src/lib/db/backup.ts +708 -0
  1444. package/src/lib/db/batches.ts +450 -0
  1445. package/src/lib/db/callLogStats.ts +235 -0
  1446. package/src/lib/db/caseMapping.ts +80 -0
  1447. package/src/lib/db/cleanup.ts +584 -0
  1448. package/src/lib/db/cliToolState.ts +159 -0
  1449. package/src/lib/db/comboForecast.ts +119 -0
  1450. package/src/lib/db/combos.ts +339 -0
  1451. package/src/lib/db/commandCodeAuth.ts +209 -0
  1452. package/src/lib/db/compression.ts +780 -0
  1453. package/src/lib/db/compressionAnalytics.ts +661 -0
  1454. package/src/lib/db/compressionCacheStats.ts +112 -0
  1455. package/src/lib/db/compressionCombos.ts +491 -0
  1456. package/src/lib/db/compressionRunTelemetry.ts +126 -0
  1457. package/src/lib/db/contextHandoffs.ts +233 -0
  1458. package/src/lib/db/core.ts +1520 -0
  1459. package/src/lib/db/creditBalance.ts +92 -0
  1460. package/src/lib/db/databaseSettings.ts +309 -0
  1461. package/src/lib/db/detailedLogs.ts +170 -0
  1462. package/src/lib/db/discovery.ts +97 -0
  1463. package/src/lib/db/discoveryResults.ts +176 -0
  1464. package/src/lib/db/domainState.ts +630 -0
  1465. package/src/lib/db/encryption.ts +327 -0
  1466. package/src/lib/db/evals.ts +786 -0
  1467. package/src/lib/db/featureFlags.ts +82 -0
  1468. package/src/lib/db/files.ts +170 -0
  1469. package/src/lib/db/freeProxies.ts +360 -0
  1470. package/src/lib/db/gamification.ts +613 -0
  1471. package/src/lib/db/healthCheck.ts +565 -0
  1472. package/src/lib/db/inspectorCustomHosts.ts +88 -0
  1473. package/src/lib/db/inspectorSessions.ts +161 -0
  1474. package/src/lib/db/jsonMigration.ts +321 -0
  1475. package/src/lib/db/memoryVec.ts +138 -0
  1476. package/src/lib/db/middleware.ts +239 -0
  1477. package/src/lib/db/migrationRunner/constants.ts +118 -0
  1478. package/src/lib/db/migrationRunner.ts +1069 -0
  1479. package/src/lib/db/migrations/001_initial_schema.sql +226 -0
  1480. package/src/lib/db/migrations/002_mcp_a2a_tables.sql +95 -0
  1481. package/src/lib/db/migrations/003_provider_node_custom_paths.sql +5 -0
  1482. package/src/lib/db/migrations/004_proxy_registry.sql +31 -0
  1483. package/src/lib/db/migrations/005_combo_agent_fields.sql +19 -0
  1484. package/src/lib/db/migrations/006_detailed_request_logs.sql +42 -0
  1485. package/src/lib/db/migrations/007_search_request_type.sql +4 -0
  1486. package/src/lib/db/migrations/008_registered_keys.sql +65 -0
  1487. package/src/lib/db/migrations/009_requested_model.sql +9 -0
  1488. package/src/lib/db/migrations/010_model_combo_mappings.sql +19 -0
  1489. package/src/lib/db/migrations/011_webhooks.sql +15 -0
  1490. package/src/lib/db/migrations/012_fix_token_input_cache_tokens.sql +15 -0
  1491. package/src/lib/db/migrations/013_quota_snapshots.sql +19 -0
  1492. package/src/lib/db/migrations/014_unified_log_artifacts.sql +15 -0
  1493. package/src/lib/db/migrations/015_create_memories.sql +22 -0
  1494. package/src/lib/db/migrations/016_create_skills.sql +37 -0
  1495. package/src/lib/db/migrations/017_version_manager_upstream_proxy.sql +56 -0
  1496. package/src/lib/db/migrations/018_call_logs_detailed_tokens.sql +6 -0
  1497. package/src/lib/db/migrations/019_context_handoffs.sql +28 -0
  1498. package/src/lib/db/migrations/020_combo_sort_order.sql +16 -0
  1499. package/src/lib/db/migrations/021_combo_call_log_targets.sql +5 -0
  1500. package/src/lib/db/migrations/022_add_memory_fts5.sql +33 -0
  1501. package/src/lib/db/migrations/023_fix_memory_fts_uuid.sql +55 -0
  1502. package/src/lib/db/migrations/024_create_sync_tokens.sql +15 -0
  1503. package/src/lib/db/migrations/025_call_logs_summary_storage.sql +145 -0
  1504. package/src/lib/db/migrations/027_skill_mode_and_metadata.sql +10 -0
  1505. package/src/lib/db/migrations/028_create_files_and_batches.sql +51 -0
  1506. package/src/lib/db/migrations/029_provider_connection_max_concurrent.sql +10 -0
  1507. package/src/lib/db/migrations/030_create_eval_runs.sql +28 -0
  1508. package/src/lib/db/migrations/031_create_eval_suites.sql +27 -0
  1509. package/src/lib/db/migrations/032_apikey_lifecycle.sql +24 -0
  1510. package/src/lib/db/migrations/033_create_reasoning_cache.sql +27 -0
  1511. package/src/lib/db/migrations/034_compression_settings.sql +10 -0
  1512. package/src/lib/db/migrations/035_standard_compression_config.sql +9 -0
  1513. package/src/lib/db/migrations/036_aggressive_compression.sql +4 -0
  1514. package/src/lib/db/migrations/037_ultra_compression.sql +6 -0
  1515. package/src/lib/db/migrations/038_compression_analytics.sql +13 -0
  1516. package/src/lib/db/migrations/039_compression_cache_stats.sql +15 -0
  1517. package/src/lib/db/migrations/040_oneproxy_proxy_fields.sql +24 -0
  1518. package/src/lib/db/migrations/041_compression_receipts.sql +18 -0
  1519. package/src/lib/db/migrations/042_compression_combos.sql +43 -0
  1520. package/src/lib/db/migrations/043_default_compression_combo_pipeline.sql +12 -0
  1521. package/src/lib/db/migrations/044_usage_history_api_key_backfill.sql +27 -0
  1522. package/src/lib/db/migrations/045_compression_tokens.sql +4 -0
  1523. package/src/lib/db/migrations/046_database_settings.sql +44 -0
  1524. package/src/lib/db/migrations/047_aggregation_tables.sql +44 -0
  1525. package/src/lib/db/migrations/048_summary_indexes.sql +29 -0
  1526. package/src/lib/db/migrations/049_compression_analytics_indexes.sql +10 -0
  1527. package/src/lib/db/migrations/050_session_account_affinity.sql +11 -0
  1528. package/src/lib/db/migrations/051_hot_path_db_indexes.sql +10 -0
  1529. package/src/lib/db/migrations/052_api_key_combo_throttle.sql +4 -0
  1530. package/src/lib/db/migrations/053_remove_status_from_files.sql +2 -0
  1531. package/src/lib/db/migrations/054_usage_history_service_tier.sql +4 -0
  1532. package/src/lib/db/migrations/056_mcp_accessibility_compression.sql +8 -0
  1533. package/src/lib/db/migrations/057_provider_connection_quota_window_thresholds.sql +14 -0
  1534. package/src/lib/db/migrations/058_command_code_auth_sessions.sql +19 -0
  1535. package/src/lib/db/migrations/059_manifest_routing.sql +21 -0
  1536. package/src/lib/db/migrations/060_create_gamification.sql +94 -0
  1537. package/src/lib/db/migrations/061_cloud_agent_credentials.sql +9 -0
  1538. package/src/lib/db/migrations/062_usage_history_combo_strategy.sql +4 -0
  1539. package/src/lib/db/migrations/063_add_last_model_to_handoffs.sql +7 -0
  1540. package/src/lib/db/migrations/064_create_session_model_history.sql +19 -0
  1541. package/src/lib/db/migrations/065_middleware_hooks.sql +45 -0
  1542. package/src/lib/db/migrations/066_api_key_groups.sql +47 -0
  1543. package/src/lib/db/migrations/067_relay_proxies.sql +56 -0
  1544. package/src/lib/db/migrations/068_free_proxies.sql +52 -0
  1545. package/src/lib/db/migrations/069_webhook_deliveries.sql +15 -0
  1546. package/src/lib/db/migrations/070_webhooks_kind_metadata.sql +3 -0
  1547. package/src/lib/db/migrations/071_services.sql +19 -0
  1548. package/src/lib/db/migrations/072_free_proxies_fk.sql +27 -0
  1549. package/src/lib/db/migrations/073_per_model_token_limits.sql +61 -0
  1550. package/src/lib/db/migrations/074_discovery_results.sql +20 -0
  1551. package/src/lib/db/migrations/075_api_key_self_service_usage_scopes.sql +51 -0
  1552. package/src/lib/db/migrations/076_create_plugins.sql +31 -0
  1553. package/src/lib/db/migrations/077_api_key_stream_default_mode.sql +3 -0
  1554. package/src/lib/db/migrations/078_quota_consumption.sql +24 -0
  1555. package/src/lib/db/migrations/079_provider_plans.sql +19 -0
  1556. package/src/lib/db/migrations/080_agent_bridge.sql +24 -0
  1557. package/src/lib/db/migrations/081_inspector_custom_hosts.sql +11 -0
  1558. package/src/lib/db/migrations/082_inspector_sessions.sql +18 -0
  1559. package/src/lib/db/migrations/083_memory_vec.sql +26 -0
  1560. package/src/lib/db/migrations/084_playground_presets.sql +15 -0
  1561. package/src/lib/db/migrations/085_quota_pools.sql +39 -0
  1562. package/src/lib/db/migrations/086_api_key_allowed_quotas.sql +8 -0
  1563. package/src/lib/db/migrations/087_quota_pool_connections.sql +21 -0
  1564. package/src/lib/db/migrations/088_quota_groups.sql +28 -0
  1565. package/src/lib/db/migrations/089_add_disable_non_public_to_api_keys.sql +3 -0
  1566. package/src/lib/db/migrations/090_plugin_metrics.sql +9 -0
  1567. package/src/lib/db/migrations/091_plugin_analytics.sql +23 -0
  1568. package/src/lib/db/migrations/092_api_key_context_sources.sql +13 -0
  1569. package/src/lib/db/migrations/093_proxy_enable_toggles.sql +17 -0
  1570. package/src/lib/db/migrations/094_per_key_proxy_toggles.sql +12 -0
  1571. package/src/lib/db/migrations/095_provider_node_custom_headers.sql +5 -0
  1572. package/src/lib/db/migrations/096_sync_context_cache_protection.sql +9 -0
  1573. package/src/lib/db/migrations/097_model_intelligence.sql +25 -0
  1574. package/src/lib/db/migrations/098_clear_semantic_cache_for_key_isolation.sql +4 -0
  1575. package/src/lib/db/migrations/099_proxy_family.sql +5 -0
  1576. package/src/lib/db/migrations/100_cli_access_tokens.sql +18 -0
  1577. package/src/lib/db/migrations/101_api_key_usage_limits.sql +4 -0
  1578. package/src/lib/db/migrations/102_compression_engines_map.sql +5 -0
  1579. package/src/lib/db/migrations/103_strip_legacy_combo_config_keys.sql +54 -0
  1580. package/src/lib/db/migrations/104_normalize_database_cache_size.sql +10 -0
  1581. package/src/lib/db/migrations/105_usage_history_endpoint.sql +6 -0
  1582. package/src/lib/db/migrations/106_quota_allocation_model_caps.sql +32 -0
  1583. package/src/lib/db/migrations/107_quota_combos_quota_share_strategy.sql +25 -0
  1584. package/src/lib/db/migrations/108_provider_quota_reset_events.sql +26 -0
  1585. package/src/lib/db/migrations/109_call_logs_correlation_id.sql +2 -0
  1586. package/src/lib/db/migrations/110_model_context_overrides.sql +17 -0
  1587. package/src/lib/db/migrations/111_memory_typed_decay.sql +10 -0
  1588. package/src/lib/db/migrations/112_batch_item_checkpoints.sql +18 -0
  1589. package/src/lib/db/migrations/113_provider_node_icon_url.sql +5 -0
  1590. package/src/lib/db/migrations/114_mux_service_seed.sql +12 -0
  1591. package/src/lib/db/migrations/115_bifrost_service.sql +9 -0
  1592. package/src/lib/db/migrations/116_call_logs_reasoning_source.sql +13 -0
  1593. package/src/lib/db/migrations/117_proxy_pool_rotation.sql +53 -0
  1594. package/src/lib/db/modelComboMappings.ts +255 -0
  1595. package/src/lib/db/modelContextOverrides.ts +133 -0
  1596. package/src/lib/db/modelIntelligence.ts +232 -0
  1597. package/src/lib/db/models/aliases.ts +61 -0
  1598. package/src/lib/db/models/compat.ts +249 -0
  1599. package/src/lib/db/models/mitmAlias.ts +32 -0
  1600. package/src/lib/db/models/shared.ts +19 -0
  1601. package/src/lib/db/models.ts +936 -0
  1602. package/src/lib/db/notion.ts +48 -0
  1603. package/src/lib/db/obsidian.ts +283 -0
  1604. package/src/lib/db/oneproxy.ts +293 -0
  1605. package/src/lib/db/optimizationSettings.ts +284 -0
  1606. package/src/lib/db/playgroundPresets.ts +167 -0
  1607. package/src/lib/db/pluginMetrics.ts +88 -0
  1608. package/src/lib/db/plugins.ts +280 -0
  1609. package/src/lib/db/prompts.ts +302 -0
  1610. package/src/lib/db/providerLimits.ts +131 -0
  1611. package/src/lib/db/providerNodeSelect.ts +48 -0
  1612. package/src/lib/db/providerPlans.ts +149 -0
  1613. package/src/lib/db/providerStats.ts +68 -0
  1614. package/src/lib/db/providers/columns.ts +116 -0
  1615. package/src/lib/db/providers/nodes.ts +169 -0
  1616. package/src/lib/db/providers/rateLimit.ts +198 -0
  1617. package/src/lib/db/providers.ts +803 -0
  1618. package/src/lib/db/proxies/mappers.ts +181 -0
  1619. package/src/lib/db/proxies/types.ts +78 -0
  1620. package/src/lib/db/proxies.ts +1176 -0
  1621. package/src/lib/db/proxyLogs.ts +35 -0
  1622. package/src/lib/db/quotaConsumption.ts +274 -0
  1623. package/src/lib/db/quotaGroups.ts +147 -0
  1624. package/src/lib/db/quotaModelCaps.ts +128 -0
  1625. package/src/lib/db/quotaPools.ts +548 -0
  1626. package/src/lib/db/quotaResetEvents.ts +334 -0
  1627. package/src/lib/db/quotaSnapshots.ts +209 -0
  1628. package/src/lib/db/readCache.ts +202 -0
  1629. package/src/lib/db/reasoningCache.ts +276 -0
  1630. package/src/lib/db/recovery.ts +33 -0
  1631. package/src/lib/db/registeredKeys.ts +532 -0
  1632. package/src/lib/db/relayProxies.ts +364 -0
  1633. package/src/lib/db/schemaColumns.ts +226 -0
  1634. package/src/lib/db/secrets.ts +28 -0
  1635. package/src/lib/db/semanticCache.ts +117 -0
  1636. package/src/lib/db/serviceModels.ts +79 -0
  1637. package/src/lib/db/sessionAccountAffinity.ts +212 -0
  1638. package/src/lib/db/settings/cacheMetrics.ts +235 -0
  1639. package/src/lib/db/settings/lkgp.ts +49 -0
  1640. package/src/lib/db/settings/pricing.ts +254 -0
  1641. package/src/lib/db/settings/shared.ts +9 -0
  1642. package/src/lib/db/settings.ts +661 -0
  1643. package/src/lib/db/skills.ts +62 -0
  1644. package/src/lib/db/stateReset.ts +30 -0
  1645. package/src/lib/db/stats.ts +71 -0
  1646. package/src/lib/db/syncTokens.ts +163 -0
  1647. package/src/lib/db/tierConfig.ts +88 -0
  1648. package/src/lib/db/tokenLimits.ts +295 -0
  1649. package/src/lib/db/upstreamProxy.ts +247 -0
  1650. package/src/lib/db/usageAnalytics/sources.ts +208 -0
  1651. package/src/lib/db/usageAnalytics.ts +723 -0
  1652. package/src/lib/db/usageLogs.ts +94 -0
  1653. package/src/lib/db/usageSummary.ts +18 -0
  1654. package/src/lib/db/vacuumScheduler.ts +326 -0
  1655. package/src/lib/db/versionManager.ts +377 -0
  1656. package/src/lib/db/webSessionDedup.ts +57 -0
  1657. package/src/lib/db/webhookDeliveries.ts +77 -0
  1658. package/src/lib/db/webhooks.ts +178 -0
  1659. package/src/lib/discovery/index.ts +137 -0
  1660. package/src/lib/display/names.ts +73 -0
  1661. package/src/lib/display/useProviderNodeMap.ts +68 -0
  1662. package/src/lib/docsI18nPath.ts +33 -0
  1663. package/src/lib/docsSanitizer.ts +42 -0
  1664. package/src/lib/embeddings/familyGuard.ts +24 -0
  1665. package/src/lib/embeddings/service.ts +288 -0
  1666. package/src/lib/env/runtimeEnv.ts +166 -0
  1667. package/src/lib/evals/evalRunner/builtinSuites.ts +676 -0
  1668. package/src/lib/evals/evalRunner.ts +301 -0
  1669. package/src/lib/evals/runtime.ts +311 -0
  1670. package/src/lib/events/eventBus.ts +148 -0
  1671. package/src/lib/events/types.ts +181 -0
  1672. package/src/lib/freeProviderRankings.ts +340 -0
  1673. package/src/lib/freeProxyProviders/index.ts +24 -0
  1674. package/src/lib/freeProxyProviders/iplocate.ts +107 -0
  1675. package/src/lib/freeProxyProviders/oneproxy.ts +127 -0
  1676. package/src/lib/freeProxyProviders/proxifly.ts +143 -0
  1677. package/src/lib/freeProxyProviders/types.ts +33 -0
  1678. package/src/lib/freeProxyProviders/webshare.ts +148 -0
  1679. package/src/lib/gamification/antiCheat.ts +160 -0
  1680. package/src/lib/gamification/badges.ts +542 -0
  1681. package/src/lib/gamification/events.ts +187 -0
  1682. package/src/lib/gamification/index.ts +37 -0
  1683. package/src/lib/gamification/invites.ts +127 -0
  1684. package/src/lib/gamification/leaderboard.ts +64 -0
  1685. package/src/lib/gamification/notifications.ts +118 -0
  1686. package/src/lib/gamification/servers.ts +179 -0
  1687. package/src/lib/gamification/sharing.ts +56 -0
  1688. package/src/lib/gamification/streaks.ts +164 -0
  1689. package/src/lib/gamification/xp.ts +152 -0
  1690. package/src/lib/gracefulShutdown.ts +151 -0
  1691. package/src/lib/guardrails/base.ts +65 -0
  1692. package/src/lib/guardrails/index.ts +4 -0
  1693. package/src/lib/guardrails/piiMasker.ts +208 -0
  1694. package/src/lib/guardrails/promptInjection.ts +285 -0
  1695. package/src/lib/guardrails/registry.ts +282 -0
  1696. package/src/lib/guardrails/visionBridge.ts +237 -0
  1697. package/src/lib/guardrails/visionBridgeHelpers.ts +499 -0
  1698. package/src/lib/guardrails/visionBridgeRouter.ts +271 -0
  1699. package/src/lib/headroom/detect.ts +214 -0
  1700. package/src/lib/headroom/process.ts +177 -0
  1701. package/src/lib/idempotencyLayer.ts +105 -0
  1702. package/src/lib/images/imageRouteModel.ts +168 -0
  1703. package/src/lib/initCloudSync.ts +52 -0
  1704. package/src/lib/inspector/agentBridgeMaintenanceApi.ts +70 -0
  1705. package/src/lib/inspector/captureState.ts +90 -0
  1706. package/src/lib/inspector/configPortability.ts +86 -0
  1707. package/src/lib/inspector/harExport.ts +188 -0
  1708. package/src/lib/inspector/matchesTrafficFilter.ts +37 -0
  1709. package/src/lib/inspector/secretMask.ts +6 -0
  1710. package/src/lib/inspector/tproxyCaptureApi.ts +60 -0
  1711. package/src/lib/ipUtils.ts +94 -0
  1712. package/src/lib/jobs/budgetResetJob.ts +40 -0
  1713. package/src/lib/jobs/reasoningCacheCleanupJob.ts +40 -0
  1714. package/src/lib/localDb.ts +797 -0
  1715. package/src/lib/localHealthCheck.ts +267 -0
  1716. package/src/lib/logEnv.ts +164 -0
  1717. package/src/lib/logPayloads.ts +110 -0
  1718. package/src/lib/logRotation.ts +206 -0
  1719. package/src/lib/machineToken.ts +53 -0
  1720. package/src/lib/memory/cache.ts +76 -0
  1721. package/src/lib/memory/embedding/cache.ts +77 -0
  1722. package/src/lib/memory/embedding/index.ts +281 -0
  1723. package/src/lib/memory/embedding/remote.ts +95 -0
  1724. package/src/lib/memory/embedding/staticPotion.ts +253 -0
  1725. package/src/lib/memory/embedding/transformersLocal.ts +153 -0
  1726. package/src/lib/memory/embedding/types.ts +40 -0
  1727. package/src/lib/memory/extraction.ts +195 -0
  1728. package/src/lib/memory/injection.ts +211 -0
  1729. package/src/lib/memory/qdrant.ts +521 -0
  1730. package/src/lib/memory/reindex.ts +102 -0
  1731. package/src/lib/memory/retrieval/scoring.ts +104 -0
  1732. package/src/lib/memory/retrieval.ts +1072 -0
  1733. package/src/lib/memory/schemas.ts +39 -0
  1734. package/src/lib/memory/settings.ts +184 -0
  1735. package/src/lib/memory/store.ts +621 -0
  1736. package/src/lib/memory/summarization.ts +202 -0
  1737. package/src/lib/memory/typedDecay.ts +245 -0
  1738. package/src/lib/memory/types.ts +45 -0
  1739. package/src/lib/memory/vectorStore.ts +425 -0
  1740. package/src/lib/memory/verify.ts +56 -0
  1741. package/src/lib/middleware/cliTokenAuth.ts +91 -0
  1742. package/src/lib/middleware/registry.ts +432 -0
  1743. package/src/lib/middleware/types.ts +129 -0
  1744. package/src/lib/modelAliasSeed.ts +82 -0
  1745. package/src/lib/modelCapabilities.ts +481 -0
  1746. package/src/lib/modelMetadataRegistry.ts +574 -0
  1747. package/src/lib/modelsDevSync/transform.ts +279 -0
  1748. package/src/lib/modelsDevSync.ts +677 -0
  1749. package/src/lib/monitoring/comboHealthAutopilot.ts +494 -0
  1750. package/src/lib/monitoring/observability.ts +336 -0
  1751. package/src/lib/monitoring/providerHealthAutopilot.ts +743 -0
  1752. package/src/lib/monitoring/providerHealthMatrix.ts +621 -0
  1753. package/src/lib/ngrokTunnel.ts +142 -0
  1754. package/src/lib/notion/api.ts +247 -0
  1755. package/src/lib/oauth/codexDeviceFlow.ts +316 -0
  1756. package/src/lib/oauth/config/index.ts +31 -0
  1757. package/src/lib/oauth/connectionPersistence.ts +114 -0
  1758. package/src/lib/oauth/constants/oauth.ts +494 -0
  1759. package/src/lib/oauth/credentialBlob.ts +105 -0
  1760. package/src/lib/oauth/deviceFlowTickets.ts +110 -0
  1761. package/src/lib/oauth/gitlab.ts +103 -0
  1762. package/src/lib/oauth/pasteCredentials.ts +51 -0
  1763. package/src/lib/oauth/providers/agy.ts +15 -0
  1764. package/src/lib/oauth/providers/antigravity.ts +159 -0
  1765. package/src/lib/oauth/providers/claude.ts +170 -0
  1766. package/src/lib/oauth/providers/cline.ts +91 -0
  1767. package/src/lib/oauth/providers/codebuddy-cn.ts +123 -0
  1768. package/src/lib/oauth/providers/codex.ts +214 -0
  1769. package/src/lib/oauth/providers/cursor.ts +15 -0
  1770. package/src/lib/oauth/providers/github.ts +89 -0
  1771. package/src/lib/oauth/providers/gitlab-duo.ts +124 -0
  1772. package/src/lib/oauth/providers/grok-cli.ts +155 -0
  1773. package/src/lib/oauth/providers/index.ts +59 -0
  1774. package/src/lib/oauth/providers/kilocode.ts +77 -0
  1775. package/src/lib/oauth/providers/kimi-coding.ts +135 -0
  1776. package/src/lib/oauth/providers/kiro.ts +185 -0
  1777. package/src/lib/oauth/providers/qoder.ts +81 -0
  1778. package/src/lib/oauth/providers/qwen.ts +82 -0
  1779. package/src/lib/oauth/providers/trae.ts +78 -0
  1780. package/src/lib/oauth/providers/windsurf.ts +64 -0
  1781. package/src/lib/oauth/providers/zed-hosted.ts +89 -0
  1782. package/src/lib/oauth/providers/zed.ts +35 -0
  1783. package/src/lib/oauth/providers.ts +278 -0
  1784. package/src/lib/oauth/services/codexImport.ts +222 -0
  1785. package/src/lib/oauth/services/cursor.ts +219 -0
  1786. package/src/lib/oauth/services/kiro.ts +441 -0
  1787. package/src/lib/oauth/utils/agyAuthImport.ts +259 -0
  1788. package/src/lib/oauth/utils/banner.ts +62 -0
  1789. package/src/lib/oauth/utils/claudeAuthFile.ts +334 -0
  1790. package/src/lib/oauth/utils/claudeAuthImport.ts +259 -0
  1791. package/src/lib/oauth/utils/claudeAuthZipExtract.ts +5 -0
  1792. package/src/lib/oauth/utils/cliProxyAuthImport.ts +142 -0
  1793. package/src/lib/oauth/utils/codexAuthFile.ts +352 -0
  1794. package/src/lib/oauth/utils/codexAuthImport.ts +294 -0
  1795. package/src/lib/oauth/utils/codexAuthZipExtract.ts +5 -0
  1796. package/src/lib/oauth/utils/jsonZipExtract.ts +89 -0
  1797. package/src/lib/oauth/utils/pkce.ts +37 -0
  1798. package/src/lib/oauth/utils/server.ts +122 -0
  1799. package/src/lib/oauth/utils/ui.ts +47 -0
  1800. package/src/lib/obsidian/api.ts +390 -0
  1801. package/src/lib/obsidianSync.ts +110 -0
  1802. package/src/lib/oneproxyRotator.ts +19 -0
  1803. package/src/lib/oneproxySync.ts +182 -0
  1804. package/src/lib/piiSanitizer.ts +416 -0
  1805. package/src/lib/playground/codeExport.ts +408 -0
  1806. package/src/lib/playground/promptImprover.ts +147 -0
  1807. package/src/lib/playground/streamMetrics.ts +61 -0
  1808. package/src/lib/playground/types.ts +114 -0
  1809. package/src/lib/plugins/devMode.ts +65 -0
  1810. package/src/lib/plugins/doctor.ts +138 -0
  1811. package/src/lib/plugins/errors.ts +38 -0
  1812. package/src/lib/plugins/hooks.ts +322 -0
  1813. package/src/lib/plugins/index.ts +72 -0
  1814. package/src/lib/plugins/loader.ts +326 -0
  1815. package/src/lib/plugins/logger.ts +50 -0
  1816. package/src/lib/plugins/manager.ts +579 -0
  1817. package/src/lib/plugins/manifest.ts +213 -0
  1818. package/src/lib/plugins/marketplace.ts +202 -0
  1819. package/src/lib/plugins/pluginWorker.ts +246 -0
  1820. package/src/lib/plugins/sandbox.ts +29 -0
  1821. package/src/lib/plugins/scanner.ts +110 -0
  1822. package/src/lib/plugins/sdk.ts +88 -0
  1823. package/src/lib/plugins/signing.ts +34 -0
  1824. package/src/lib/plugins/testRunner.ts +95 -0
  1825. package/src/lib/plugins/watcher.ts +90 -0
  1826. package/src/lib/pricingSync.ts +456 -0
  1827. package/src/lib/promptCache/index.ts +1 -0
  1828. package/src/lib/promptCache/prefixAnalyzer.ts +81 -0
  1829. package/src/lib/providerModels/cursorAgent.ts +166 -0
  1830. package/src/lib/providerModels/geminiModelsParser.ts +91 -0
  1831. package/src/lib/providerModels/managedAvailableModels.ts +165 -0
  1832. package/src/lib/providerModels/managedModelImport.ts +349 -0
  1833. package/src/lib/providerModels/modelDiscovery.ts +151 -0
  1834. package/src/lib/providers/catalog.ts +246 -0
  1835. package/src/lib/providers/claudeExtraUsage.ts +160 -0
  1836. package/src/lib/providers/claudeFastMode.ts +75 -0
  1837. package/src/lib/providers/codexConnectionDefaults.ts +85 -0
  1838. package/src/lib/providers/codexFastTier.ts +210 -0
  1839. package/src/lib/providers/imageValidation.ts +160 -0
  1840. package/src/lib/providers/managedAvailableModels.ts +21 -0
  1841. package/src/lib/providers/modelListingCapability.ts +26 -0
  1842. package/src/lib/providers/nvidiaValidationModel.ts +24 -0
  1843. package/src/lib/providers/requestDefaults.ts +318 -0
  1844. package/src/lib/providers/serviceKindIndex.ts +0 -0
  1845. package/src/lib/providers/staticModels.ts +170 -0
  1846. package/src/lib/providers/validation/anthropicFormat.ts +319 -0
  1847. package/src/lib/providers/validation/audioMiscProviders.ts +582 -0
  1848. package/src/lib/providers/validation/cloudProviders.ts +669 -0
  1849. package/src/lib/providers/validation/cozeError.ts +56 -0
  1850. package/src/lib/providers/validation/directChatProbe.ts +47 -0
  1851. package/src/lib/providers/validation/embeddingProviders.ts +143 -0
  1852. package/src/lib/providers/validation/headers.ts +122 -0
  1853. package/src/lib/providers/validation/metaAi.ts +117 -0
  1854. package/src/lib/providers/validation/openaiFormat.ts +500 -0
  1855. package/src/lib/providers/validation/searchProviders.ts +199 -0
  1856. package/src/lib/providers/validation/transport.ts +109 -0
  1857. package/src/lib/providers/validation/urlHelpers.ts +114 -0
  1858. package/src/lib/providers/validation/webProvidersA.ts +808 -0
  1859. package/src/lib/providers/validation/webProvidersB.ts +536 -0
  1860. package/src/lib/providers/validation.ts +772 -0
  1861. package/src/lib/providers/webCookieAuth.ts +157 -0
  1862. package/src/lib/providers/xai/thinking.ts +127 -0
  1863. package/src/lib/providers/xai/translators/claude.ts +368 -0
  1864. package/src/lib/providers/xai/translators/gemini.ts +371 -0
  1865. package/src/lib/providers/xai/translators/openai-chat.ts +310 -0
  1866. package/src/lib/providers/xai/translators/openai-responses.ts +77 -0
  1867. package/src/lib/proxyEgress.ts +388 -0
  1868. package/src/lib/proxyHealth/decision.ts +77 -0
  1869. package/src/lib/proxyHealth/scheduler.ts +207 -0
  1870. package/src/lib/proxyHealth/statusPolicy.ts +41 -0
  1871. package/src/lib/proxyHealth.ts +173 -0
  1872. package/src/lib/proxyLogger.ts +240 -0
  1873. package/src/lib/proxyRelay/cloudflareWorkerScript.ts +107 -0
  1874. package/src/lib/quota/QuotaStore.ts +23 -0
  1875. package/src/lib/quota/accountBuckets.ts +225 -0
  1876. package/src/lib/quota/burnRate.ts +111 -0
  1877. package/src/lib/quota/connectionProvider.ts +32 -0
  1878. package/src/lib/quota/connectionRecovery.ts +303 -0
  1879. package/src/lib/quota/dimensions.ts +61 -0
  1880. package/src/lib/quota/enforce.ts +401 -0
  1881. package/src/lib/quota/fairShare.ts +186 -0
  1882. package/src/lib/quota/planRegistry.ts +107 -0
  1883. package/src/lib/quota/planResolver.ts +78 -0
  1884. package/src/lib/quota/quotaCombos.ts +414 -0
  1885. package/src/lib/quota/quotaKey.ts +202 -0
  1886. package/src/lib/quota/quotaModelNaming.ts +84 -0
  1887. package/src/lib/quota/redisQuotaStore.ts +352 -0
  1888. package/src/lib/quota/saturationSignals.ts +559 -0
  1889. package/src/lib/quota/spendRecorder.ts +131 -0
  1890. package/src/lib/quota/sqliteQuotaStore.ts +282 -0
  1891. package/src/lib/quota/storeFactory.ts +124 -0
  1892. package/src/lib/quota/types.ts +94 -0
  1893. package/src/lib/resilience/modelLockoutSettings.ts +95 -0
  1894. package/src/lib/resilience/settings/normalize.ts +359 -0
  1895. package/src/lib/resilience/settings/types.ts +182 -0
  1896. package/src/lib/resilience/settings.ts +386 -0
  1897. package/src/lib/runtime/ports.ts +32 -0
  1898. package/src/lib/search/executeWebSearch.ts +270 -0
  1899. package/src/lib/security/localEndpoints.ts +82 -0
  1900. package/src/lib/semanticCache.ts +377 -0
  1901. package/src/lib/services/ServiceSupervisor.ts +243 -0
  1902. package/src/lib/services/apiKey.ts +40 -0
  1903. package/src/lib/services/bootstrap.ts +133 -0
  1904. package/src/lib/services/embedPath.ts +19 -0
  1905. package/src/lib/services/embedWsProxy.ts +285 -0
  1906. package/src/lib/services/healthCheck.ts +79 -0
  1907. package/src/lib/services/htmlRewriter.ts +185 -0
  1908. package/src/lib/services/installers/bifrost.ts +145 -0
  1909. package/src/lib/services/installers/cliproxy.ts +116 -0
  1910. package/src/lib/services/installers/mux.ts +178 -0
  1911. package/src/lib/services/installers/ninerouter.stub.ts +17 -0
  1912. package/src/lib/services/installers/ninerouter.ts +157 -0
  1913. package/src/lib/services/installers/utils.ts +167 -0
  1914. package/src/lib/services/modelSync.ts +105 -0
  1915. package/src/lib/services/portProbe.ts +104 -0
  1916. package/src/lib/services/registry.ts +42 -0
  1917. package/src/lib/services/reverseProxy.ts +180 -0
  1918. package/src/lib/services/ringBuffer.ts +91 -0
  1919. package/src/lib/services/types.ts +50 -0
  1920. package/src/lib/settingsCache.ts +62 -0
  1921. package/src/lib/skills/a2a.ts +34 -0
  1922. package/src/lib/skills/builtin/browser.ts +22 -0
  1923. package/src/lib/skills/builtins.ts +493 -0
  1924. package/src/lib/skills/custom.ts +41 -0
  1925. package/src/lib/skills/executor.ts +196 -0
  1926. package/src/lib/skills/githubCollector.ts +426 -0
  1927. package/src/lib/skills/hybrid.ts +67 -0
  1928. package/src/lib/skills/injection.ts +307 -0
  1929. package/src/lib/skills/interception.ts +343 -0
  1930. package/src/lib/skills/providerSettings.ts +14 -0
  1931. package/src/lib/skills/registry.ts +398 -0
  1932. package/src/lib/skills/sandbox.ts +178 -0
  1933. package/src/lib/skills/schemas.ts +43 -0
  1934. package/src/lib/skills/skillssh.ts +73 -0
  1935. package/src/lib/skills/types.ts +61 -0
  1936. package/src/lib/source.ts +7 -0
  1937. package/src/lib/spend/batchWriter.ts +208 -0
  1938. package/src/lib/sseTextTransform.ts +346 -0
  1939. package/src/lib/streamingPiiTransform.ts +350 -0
  1940. package/src/lib/sync/bundle.ts +208 -0
  1941. package/src/lib/sync/tokens.ts +107 -0
  1942. package/src/lib/system/autoUpdate.ts +400 -0
  1943. package/src/lib/system/globalPackagePath.ts +49 -0
  1944. package/src/lib/system/versionCheck.ts +163 -0
  1945. package/src/lib/tailscaleTunnel.ts +1201 -0
  1946. package/src/lib/tokenHealthCheck.ts +829 -0
  1947. package/src/lib/toolPolicy.ts +150 -0
  1948. package/src/lib/translator/streamTransform.ts +27 -0
  1949. package/src/lib/translatorEvents.ts +40 -0
  1950. package/src/lib/usage/aggregateHistory.ts +212 -0
  1951. package/src/lib/usage/apiKeySelfService.ts +420 -0
  1952. package/src/lib/usage/apiKeyUsageLimits.ts +578 -0
  1953. package/src/lib/usage/callLogArtifacts.ts +337 -0
  1954. package/src/lib/usage/callLogs/format.ts +129 -0
  1955. package/src/lib/usage/callLogs.ts +928 -0
  1956. package/src/lib/usage/callLogsBoundedQueries.ts +42 -0
  1957. package/src/lib/usage/codexResetCredits.ts +355 -0
  1958. package/src/lib/usage/comboForecast.ts +441 -0
  1959. package/src/lib/usage/comboHealth.ts +545 -0
  1960. package/src/lib/usage/comboHealthDashboard.ts +109 -0
  1961. package/src/lib/usage/comboScoringInspector.ts +416 -0
  1962. package/src/lib/usage/completedRequestDetails.ts +103 -0
  1963. package/src/lib/usage/costCalculator.ts +279 -0
  1964. package/src/lib/usage/fetcher.ts +483 -0
  1965. package/src/lib/usage/flatRateProviders.ts +59 -0
  1966. package/src/lib/usage/internalUsageCommand.ts +788 -0
  1967. package/src/lib/usage/migrations.ts +471 -0
  1968. package/src/lib/usage/pendingRequestScope.ts +26 -0
  1969. package/src/lib/usage/providerLimits/quotaNormalize.ts +72 -0
  1970. package/src/lib/usage/providerLimits.ts +997 -0
  1971. package/src/lib/usage/providerWindowCosts.ts +571 -0
  1972. package/src/lib/usage/resilienceExplain.ts +468 -0
  1973. package/src/lib/usage/routeExplain.ts +747 -0
  1974. package/src/lib/usage/tokenAccounting.ts +212 -0
  1975. package/src/lib/usage/usageEvents.ts +91 -0
  1976. package/src/lib/usage/usageHistory/helpers.ts +85 -0
  1977. package/src/lib/usage/usageHistory.ts +916 -0
  1978. package/src/lib/usage/usageStats.ts +581 -0
  1979. package/src/lib/usageAnalytics.ts +372 -0
  1980. package/src/lib/usageDb.ts +38 -0
  1981. package/src/lib/versionManager/binaryManager.ts +240 -0
  1982. package/src/lib/versionManager/healthMonitor.ts +71 -0
  1983. package/src/lib/versionManager/index.ts +155 -0
  1984. package/src/lib/versionManager/processManager.ts +155 -0
  1985. package/src/lib/versionManager/releaseChecker.ts +98 -0
  1986. package/src/lib/vscode/familyFirstModelIds.ts +92 -0
  1987. package/src/lib/vscode/modelPresentation.ts +132 -0
  1988. package/src/lib/vscode/reasoningMetadata.ts +183 -0
  1989. package/src/lib/vscode/serviceTierVariants.ts +202 -0
  1990. package/src/lib/vscode/tokenizedRequest.ts +79 -0
  1991. package/src/lib/webhookDispatcher.ts +221 -0
  1992. package/src/lib/webhooks/eventDescriptions.ts +76 -0
  1993. package/src/lib/webhooks/integrations/discord.ts +49 -0
  1994. package/src/lib/webhooks/integrations/slack.ts +45 -0
  1995. package/src/lib/webhooks/integrations/telegram.ts +67 -0
  1996. package/src/lib/ws/handshake.ts +129 -0
  1997. package/src/lib/zed-oauth/confirmedAccounts.ts +38 -0
  1998. package/src/lib/zed-oauth/credentialFingerprint.ts +23 -0
  1999. package/src/lib/zed-oauth/dockerDetect.ts +38 -0
  2000. package/src/lib/zed-oauth/importUtils.ts +46 -0
  2001. package/src/lib/zed-oauth/keychain-reader.stub.ts +28 -0
  2002. package/src/lib/zed-oauth/keychain-reader.ts +231 -0
  2003. package/src/mitm/_internal/bypass.cjs +170 -0
  2004. package/src/mitm/_internal/forwardTarget.cjs +55 -0
  2005. package/src/mitm/_internal/ingest.cjs +82 -0
  2006. package/src/mitm/cert/generate.ts +41 -0
  2007. package/src/mitm/cert/install.stub.ts +23 -0
  2008. package/src/mitm/cert/install.ts +440 -0
  2009. package/src/mitm/dataDir.ts +41 -0
  2010. package/src/mitm/detection/antigravity.ts +33 -0
  2011. package/src/mitm/detection/claudeCode.ts +25 -0
  2012. package/src/mitm/detection/codex.ts +25 -0
  2013. package/src/mitm/detection/copilot.ts +39 -0
  2014. package/src/mitm/detection/cursor.ts +31 -0
  2015. package/src/mitm/detection/index.ts +53 -0
  2016. package/src/mitm/detection/kiro.ts +30 -0
  2017. package/src/mitm/detection/openCode.ts +32 -0
  2018. package/src/mitm/detection/zed.ts +26 -0
  2019. package/src/mitm/dns/dnsConfig.ts +242 -0
  2020. package/src/mitm/dns/provision.ts +92 -0
  2021. package/src/mitm/handlers/antigravity.ts +192 -0
  2022. package/src/mitm/handlers/base.ts +333 -0
  2023. package/src/mitm/handlers/claudeCode.ts +56 -0
  2024. package/src/mitm/handlers/codex.ts +55 -0
  2025. package/src/mitm/handlers/copilot.ts +55 -0
  2026. package/src/mitm/handlers/cursor.ts +55 -0
  2027. package/src/mitm/handlers/kiro.ts +58 -0
  2028. package/src/mitm/handlers/openCode.ts +55 -0
  2029. package/src/mitm/handlers/trae.ts +24 -0
  2030. package/src/mitm/handlers/zed.ts +55 -0
  2031. package/src/mitm/inspector/agentBridgeHook.ts +137 -0
  2032. package/src/mitm/inspector/buffer.ts +201 -0
  2033. package/src/mitm/inspector/contextKey.ts +98 -0
  2034. package/src/mitm/inspector/conversationNormalizer.ts +393 -0
  2035. package/src/mitm/inspector/diagnostics.ts +67 -0
  2036. package/src/mitm/inspector/httpProxyServer.ts +272 -0
  2037. package/src/mitm/inspector/kindDetector.ts +87 -0
  2038. package/src/mitm/inspector/llmMetadataExtractor.ts +183 -0
  2039. package/src/mitm/inspector/pricing.ts +57 -0
  2040. package/src/mitm/inspector/processAttribution.ts +107 -0
  2041. package/src/mitm/inspector/sseMerger.ts +316 -0
  2042. package/src/mitm/inspector/systemProxyConfig.ts +316 -0
  2043. package/src/mitm/inspector/types.ts +112 -0
  2044. package/src/mitm/manager.runtime.ts +5 -0
  2045. package/src/mitm/manager.stub.ts +44 -0
  2046. package/src/mitm/manager.ts +762 -0
  2047. package/src/mitm/maskSecrets.ts +31 -0
  2048. package/src/mitm/passthrough.ts +76 -0
  2049. package/src/mitm/sanitizeHeaders.ts +61 -0
  2050. package/src/mitm/server.cjs +786 -0
  2051. package/src/mitm/socketTimeouts.ts +24 -0
  2052. package/src/mitm/systemCommands.ts +280 -0
  2053. package/src/mitm/targets/antigravity.ts +85 -0
  2054. package/src/mitm/targets/claudeCode.ts +37 -0
  2055. package/src/mitm/targets/codex.ts +30 -0
  2056. package/src/mitm/targets/copilot.ts +32 -0
  2057. package/src/mitm/targets/cursor.ts +33 -0
  2058. package/src/mitm/targets/index.ts +75 -0
  2059. package/src/mitm/targets/kiro.ts +64 -0
  2060. package/src/mitm/targets/openCode.ts +34 -0
  2061. package/src/mitm/targets/trae.ts +32 -0
  2062. package/src/mitm/targets/zed.ts +32 -0
  2063. package/src/mitm/tproxy/caTrust.ts +120 -0
  2064. package/src/mitm/tproxy/captureManager.ts +118 -0
  2065. package/src/mitm/tproxy/captureMode.ts +226 -0
  2066. package/src/mitm/tproxy/commands.ts +122 -0
  2067. package/src/mitm/tproxy/dynamicCert.ts +119 -0
  2068. package/src/mitm/tproxy/native/README.md +55 -0
  2069. package/src/mitm/tproxy/native/binding.gyp +9 -0
  2070. package/src/mitm/tproxy/native/transparent.c +147 -0
  2071. package/src/mitm/tproxy/setup.ts +68 -0
  2072. package/src/mitm/tproxy/tlsCapture.ts +368 -0
  2073. package/src/mitm/tproxy/transparentSocket.ts +131 -0
  2074. package/src/mitm/types.ts +75 -0
  2075. package/src/mitm/upstreamTrust.ts +40 -0
  2076. package/src/models/index.ts +29 -0
  2077. package/src/server/auth/loginGuard.ts +130 -0
  2078. package/src/server/authz/accessScopes.ts +62 -0
  2079. package/src/server/authz/accessTokenAuth.ts +67 -0
  2080. package/src/server/authz/assertAuth.ts +88 -0
  2081. package/src/server/authz/classify.ts +135 -0
  2082. package/src/server/authz/context.ts +44 -0
  2083. package/src/server/authz/csrf.ts +85 -0
  2084. package/src/server/authz/headers.ts +76 -0
  2085. package/src/server/authz/peerStamp.ts +99 -0
  2086. package/src/server/authz/pipeline.ts +370 -0
  2087. package/src/server/authz/policies/clientApi.ts +72 -0
  2088. package/src/server/authz/policies/management.ts +298 -0
  2089. package/src/server/authz/policies/public.ts +9 -0
  2090. package/src/server/authz/routeGuard.ts +233 -0
  2091. package/src/server/authz/types.ts +77 -0
  2092. package/src/server/cors/origins.ts +172 -0
  2093. package/src/server/origin/publicOrigin.ts +270 -0
  2094. package/src/server/ws/liveServer.ts +630 -0
  2095. package/src/server/ws/liveServerAllowList.ts +106 -0
  2096. package/src/server/ws/types.ts +57 -0
  2097. package/src/shared/components/Avatar.tsx +81 -0
  2098. package/src/shared/components/Badge.tsx +68 -0
  2099. package/src/shared/components/Breadcrumbs.tsx +103 -0
  2100. package/src/shared/components/Button.tsx +85 -0
  2101. package/src/shared/components/Card.tsx +141 -0
  2102. package/src/shared/components/Checkbox.tsx +38 -0
  2103. package/src/shared/components/CloudSyncStatus.tsx +104 -0
  2104. package/src/shared/components/Collapsible.tsx +93 -0
  2105. package/src/shared/components/CollapsibleSection.tsx +66 -0
  2106. package/src/shared/components/ColumnToggle.tsx +100 -0
  2107. package/src/shared/components/CommandPalette.tsx +375 -0
  2108. package/src/shared/components/ConsoleLogViewer.tsx +326 -0
  2109. package/src/shared/components/CursorAuthModal.tsx +198 -0
  2110. package/src/shared/components/DataTable.tsx +195 -0
  2111. package/src/shared/components/DegradationBadge.tsx +41 -0
  2112. package/src/shared/components/DistributeProxiesButton.tsx +74 -0
  2113. package/src/shared/components/EmptyState.tsx +121 -0
  2114. package/src/shared/components/ErrorPageScaffold.tsx +91 -0
  2115. package/src/shared/components/FilterBar.tsx +197 -0
  2116. package/src/shared/components/Footer.tsx +169 -0
  2117. package/src/shared/components/Header.tsx +284 -0
  2118. package/src/shared/components/InfoTooltip.tsx +34 -0
  2119. package/src/shared/components/Input.tsx +155 -0
  2120. package/src/shared/components/KiroAuthModal.tsx +425 -0
  2121. package/src/shared/components/KiroOAuthWrapper.tsx +116 -0
  2122. package/src/shared/components/KiroSocialOAuthModal.tsx +202 -0
  2123. package/src/shared/components/LanguageSelector.tsx +106 -0
  2124. package/src/shared/components/LinkifiedText.tsx +30 -0
  2125. package/src/shared/components/Loading.tsx +128 -0
  2126. package/src/shared/components/LocaleAutoDetect.tsx +43 -0
  2127. package/src/shared/components/MaintenanceBanner.tsx +87 -0
  2128. package/src/shared/components/ManualConfigModal.tsx +51 -0
  2129. package/src/shared/components/Modal.tsx +240 -0
  2130. package/src/shared/components/ModelRoutingSection.tsx +323 -0
  2131. package/src/shared/components/ModelSelectModal.tsx +618 -0
  2132. package/src/shared/components/MonacoEditor.tsx +23 -0
  2133. package/src/shared/components/NavigationProgress.tsx +105 -0
  2134. package/src/shared/components/NoAuthAccountCard.tsx +539 -0
  2135. package/src/shared/components/NoAuthProviderCard.tsx +40 -0
  2136. package/src/shared/components/NoAuthProviderToggle.tsx +36 -0
  2137. package/src/shared/components/NotificationToast.tsx +206 -0
  2138. package/src/shared/components/OAuthModal.tsx +992 -0
  2139. package/src/shared/components/OmniRouteLogo.tsx +86 -0
  2140. package/src/shared/components/PresetSlider.tsx +64 -0
  2141. package/src/shared/components/PricingModal.tsx +211 -0
  2142. package/src/shared/components/ProviderIcon.tsx +263 -0
  2143. package/src/shared/components/ProviderTestSlideOver.tsx +560 -0
  2144. package/src/shared/components/ProxyConfigModal.tsx +781 -0
  2145. package/src/shared/components/ProxyLogDetail.tsx +192 -0
  2146. package/src/shared/components/ProxyLogger.tsx +573 -0
  2147. package/src/shared/components/PwaRegister.tsx +22 -0
  2148. package/src/shared/components/RequestLoggerDetail.tsx +797 -0
  2149. package/src/shared/components/RequestLoggerV2.tsx +1628 -0
  2150. package/src/shared/components/RiskNoticeModal.tsx +81 -0
  2151. package/src/shared/components/SegmentedControl.tsx +69 -0
  2152. package/src/shared/components/Select.tsx +110 -0
  2153. package/src/shared/components/Sidebar.tsx +726 -0
  2154. package/src/shared/components/SkillsConceptCard.tsx +84 -0
  2155. package/src/shared/components/SystemMonitor.tsx +179 -0
  2156. package/src/shared/components/Textarea.tsx +29 -0
  2157. package/src/shared/components/ThemeProvider.tsx +14 -0
  2158. package/src/shared/components/ThemeToggle.tsx +52 -0
  2159. package/src/shared/components/Toggle.tsx +102 -0
  2160. package/src/shared/components/TokenHealthBadge.tsx +113 -0
  2161. package/src/shared/components/Tooltip.tsx +193 -0
  2162. package/src/shared/components/TraeAuthModal.tsx +334 -0
  2163. package/src/shared/components/UsageAnalytics.tsx +414 -0
  2164. package/src/shared/components/UsageStats.tsx +693 -0
  2165. package/src/shared/components/analytics/ApiKeyFilterDropdown.tsx +205 -0
  2166. package/src/shared/components/analytics/CustomRangePicker.tsx +195 -0
  2167. package/src/shared/components/analytics/TimeRangeSelector.tsx +49 -0
  2168. package/src/shared/components/analytics/chartColors.ts +12 -0
  2169. package/src/shared/components/analytics/charts.tsx +1023 -0
  2170. package/src/shared/components/analytics/index.tsx +28 -0
  2171. package/src/shared/components/analytics/rechartsCore.tsx +85 -0
  2172. package/src/shared/components/analytics/rechartsDonuts.tsx +195 -0
  2173. package/src/shared/components/analytics/rechartsUsageCharts.tsx +312 -0
  2174. package/src/shared/components/cli/CliComparisonCard.tsx +82 -0
  2175. package/src/shared/components/cli/CliConceptCard.tsx +58 -0
  2176. package/src/shared/components/cli/CliToolCard.tsx +152 -0
  2177. package/src/shared/components/cli/index.ts +8 -0
  2178. package/src/shared/components/compression/CompressionPipelineEditor.tsx +175 -0
  2179. package/src/shared/components/compression/EngineConfigForm.tsx +78 -0
  2180. package/src/shared/components/compression/EngineConfigPage.tsx +411 -0
  2181. package/src/shared/components/compression/compressionPipelineModel.ts +78 -0
  2182. package/src/shared/components/docs/APIReference.stories.tsx +35 -0
  2183. package/src/shared/components/docs/APIReference.tsx +83 -0
  2184. package/src/shared/components/docs/Callout.stories.tsx +40 -0
  2185. package/src/shared/components/docs/Callout.tsx +38 -0
  2186. package/src/shared/components/docs/CodeBlock.stories.tsx +25 -0
  2187. package/src/shared/components/docs/CodeBlock.tsx +52 -0
  2188. package/src/shared/components/docs/DocsBreadcrumbs.stories.tsx +20 -0
  2189. package/src/shared/components/docs/DocsBreadcrumbs.tsx +46 -0
  2190. package/src/shared/components/docs/DocsSidebar.stories.tsx +31 -0
  2191. package/src/shared/components/docs/DocsSidebar.tsx +77 -0
  2192. package/src/shared/components/docs/DocsThemeProvider.tsx +21 -0
  2193. package/src/shared/components/docs/Tabs.stories.tsx +26 -0
  2194. package/src/shared/components/docs/Tabs.tsx +50 -0
  2195. package/src/shared/components/docs/tokens.ts +38 -0
  2196. package/src/shared/components/flow/FlowCanvas.tsx +151 -0
  2197. package/src/shared/components/flow/StatusDot.tsx +36 -0
  2198. package/src/shared/components/flow/edgeStyles.ts +32 -0
  2199. package/src/shared/components/index.tsx +49 -0
  2200. package/src/shared/components/layouts/AuthLayout.tsx +28 -0
  2201. package/src/shared/components/layouts/DashboardLayout.tsx +131 -0
  2202. package/src/shared/components/layouts/index.tsx +3 -0
  2203. package/src/shared/components/lobeProviderIcons.ts +488 -0
  2204. package/src/shared/components/logTableStyles.ts +7 -0
  2205. package/src/shared/components/modelSelectModalHelpers.ts +75 -0
  2206. package/src/shared/components/oauthBlobSubmit.ts +42 -0
  2207. package/src/shared/components/proxyAssignment.ts +40 -0
  2208. package/src/shared/components/requestLoggerPreferences.ts +44 -0
  2209. package/src/shared/components/requestLoggerSignature.ts +56 -0
  2210. package/src/shared/constants/agentSkills.ts +457 -0
  2211. package/src/shared/constants/antigravityClientProfile.ts +29 -0
  2212. package/src/shared/constants/apiKeyPolicyScopes.ts +5 -0
  2213. package/src/shared/constants/appConfig.ts +12 -0
  2214. package/src/shared/constants/batch.ts +1 -0
  2215. package/src/shared/constants/batchEndpoints.ts +11 -0
  2216. package/src/shared/constants/bodySize.ts +39 -0
  2217. package/src/shared/constants/cliCompatProviders.ts +88 -0
  2218. package/src/shared/constants/cliTools.ts +862 -0
  2219. package/src/shared/constants/clientIdentityProfiles.ts +89 -0
  2220. package/src/shared/constants/colors.ts +147 -0
  2221. package/src/shared/constants/comboConfigMode.ts +9 -0
  2222. package/src/shared/constants/config.ts +44 -0
  2223. package/src/shared/constants/dashboardCsrf.ts +1 -0
  2224. package/src/shared/constants/endpointCategories.ts +133 -0
  2225. package/src/shared/constants/errorCodes.ts +245 -0
  2226. package/src/shared/constants/featureFlagDefinitions.ts +495 -0
  2227. package/src/shared/constants/headers.ts +16 -0
  2228. package/src/shared/constants/homeWidgets.ts +5 -0
  2229. package/src/shared/constants/index.ts +4 -0
  2230. package/src/shared/constants/managementScopes.ts +31 -0
  2231. package/src/shared/constants/mcpScopes.ts +78 -0
  2232. package/src/shared/constants/mitmToolHosts.ts +31 -0
  2233. package/src/shared/constants/modal.ts +5 -0
  2234. package/src/shared/constants/modelCompat.ts +9 -0
  2235. package/src/shared/constants/modelSpecs.ts +607 -0
  2236. package/src/shared/constants/models.ts +40 -0
  2237. package/src/shared/constants/openRouterPreset.ts +11 -0
  2238. package/src/shared/constants/pricing/default-pricing.ts +16 -0
  2239. package/src/shared/constants/pricing/frontier-labs.ts +386 -0
  2240. package/src/shared/constants/pricing/inference-hosts.ts +208 -0
  2241. package/src/shared/constants/pricing/oauth-subscriptions.ts +599 -0
  2242. package/src/shared/constants/pricing/regional.ts +168 -0
  2243. package/src/shared/constants/pricing/shared-tiers.ts +162 -0
  2244. package/src/shared/constants/pricing.ts +40 -0
  2245. package/src/shared/constants/providers/apikey/enterprise-cloud.ts +214 -0
  2246. package/src/shared/constants/providers/apikey/frontier-labs.ts +253 -0
  2247. package/src/shared/constants/providers/apikey/gateways.ts +662 -0
  2248. package/src/shared/constants/providers/apikey/index.ts +21 -0
  2249. package/src/shared/constants/providers/apikey/inference-hosts.ts +328 -0
  2250. package/src/shared/constants/providers/apikey/regional.ts +372 -0
  2251. package/src/shared/constants/providers/apikey/specialty-media.ts +266 -0
  2252. package/src/shared/constants/providers/audio.ts +71 -0
  2253. package/src/shared/constants/providers/cloud-agent.ts +36 -0
  2254. package/src/shared/constants/providers/local.ts +162 -0
  2255. package/src/shared/constants/providers/noauth.ts +123 -0
  2256. package/src/shared/constants/providers/oauth.ts +231 -0
  2257. package/src/shared/constants/providers/search.ts +125 -0
  2258. package/src/shared/constants/providers/system.ts +16 -0
  2259. package/src/shared/constants/providers/upstream-proxy.ts +36 -0
  2260. package/src/shared/constants/providers/web-cookie.ts +364 -0
  2261. package/src/shared/constants/providers.ts +449 -0
  2262. package/src/shared/constants/publicApiRoutes.ts +62 -0
  2263. package/src/shared/constants/responsesPreviousResponseId.ts +5 -0
  2264. package/src/shared/constants/routingStrategies.ts +216 -0
  2265. package/src/shared/constants/selfServiceScopes.ts +20 -0
  2266. package/src/shared/constants/serviceKinds.ts +34 -0
  2267. package/src/shared/constants/sidebarGroupVisibility.ts +31 -0
  2268. package/src/shared/constants/sidebarVisibility/sections.ts +769 -0
  2269. package/src/shared/constants/sidebarVisibility/types.ts +161 -0
  2270. package/src/shared/constants/sidebarVisibility.ts +291 -0
  2271. package/src/shared/constants/spawnCapablePrefixes.ts +35 -0
  2272. package/src/shared/constants/statusColors.ts +17 -0
  2273. package/src/shared/constants/upstreamHeaders.ts +42 -0
  2274. package/src/shared/constants/visionBridgeDefaults.ts +88 -0
  2275. package/src/shared/constants/visionModels.ts +68 -0
  2276. package/src/shared/contracts/quota.ts +138 -0
  2277. package/src/shared/hooks/cli/useToolBatchStatuses.ts +54 -0
  2278. package/src/shared/hooks/index.ts +3 -0
  2279. package/src/shared/hooks/useCopyToClipboard.ts +38 -0
  2280. package/src/shared/hooks/useDisplayBaseUrl.ts +49 -0
  2281. package/src/shared/hooks/useElectron.ts +197 -0
  2282. package/src/shared/hooks/useTheme.ts +59 -0
  2283. package/src/shared/http/apiErrorMessage.ts +19 -0
  2284. package/src/shared/lib/persistLocale.ts +19 -0
  2285. package/src/shared/middleware/bodySizeGuard.ts +97 -0
  2286. package/src/shared/middleware/chatBodyAdmission.ts +161 -0
  2287. package/src/shared/middleware/correlationId.ts +43 -0
  2288. package/src/shared/network/outboundUrlGuard.ts +276 -0
  2289. package/src/shared/network/remoteImageFetch.ts +182 -0
  2290. package/src/shared/network/safeOutboundFetch.ts +372 -0
  2291. package/src/shared/providers/webSessionCredentials.ts +308 -0
  2292. package/src/shared/reasoning/effortStandardization.ts +124 -0
  2293. package/src/shared/schemas/agentBridge.ts +37 -0
  2294. package/src/shared/schemas/cliCatalog.ts +66 -0
  2295. package/src/shared/schemas/inspector.ts +47 -0
  2296. package/src/shared/schemas/memory.ts +142 -0
  2297. package/src/shared/schemas/playground.ts +67 -0
  2298. package/src/shared/schemas/qdrant.ts +39 -0
  2299. package/src/shared/schemas/quota.ts +61 -0
  2300. package/src/shared/schemas/searchTools.ts +39 -0
  2301. package/src/shared/schemas/validation.ts +154 -0
  2302. package/src/shared/services/apiKeyResolver.ts +44 -0
  2303. package/src/shared/services/backupService.ts +233 -0
  2304. package/src/shared/services/claudeCliConfig.ts +17 -0
  2305. package/src/shared/services/cliRuntime.ts +1099 -0
  2306. package/src/shared/services/cloudSyncScheduler.ts +135 -0
  2307. package/src/shared/services/droidCustomModels.ts +118 -0
  2308. package/src/shared/services/initializeCloudSync.ts +31 -0
  2309. package/src/shared/services/loginShellPath.ts +87 -0
  2310. package/src/shared/services/modelSyncScheduler.ts +225 -0
  2311. package/src/shared/services/opencodeConfig.ts +140 -0
  2312. package/src/shared/services/providerLimitsSyncScheduler.ts +72 -0
  2313. package/src/shared/types/cliBatchStatus.ts +18 -0
  2314. package/src/shared/types/index.ts +3 -0
  2315. package/src/shared/types/pagination.ts +61 -0
  2316. package/src/shared/types/utilization.ts +405 -0
  2317. package/src/shared/utils/a11yAudit.ts +140 -0
  2318. package/src/shared/utils/api.ts +112 -0
  2319. package/src/shared/utils/apiAuth.ts +354 -0
  2320. package/src/shared/utils/apiKey.ts +92 -0
  2321. package/src/shared/utils/apiKeyPolicy.ts +680 -0
  2322. package/src/shared/utils/apiResponse.ts +79 -0
  2323. package/src/shared/utils/bulkApiKeyParser.ts +113 -0
  2324. package/src/shared/utils/circuitBreaker.ts +611 -0
  2325. package/src/shared/utils/classify429.ts +253 -0
  2326. package/src/shared/utils/cliCompat.ts +5 -0
  2327. package/src/shared/utils/clineAuth.ts +62 -0
  2328. package/src/shared/utils/clipboard.ts +49 -0
  2329. package/src/shared/utils/cloud.ts +41 -0
  2330. package/src/shared/utils/cn.ts +12 -0
  2331. package/src/shared/utils/codexBaseUrl.ts +32 -0
  2332. package/src/shared/utils/codexConfig.ts +30 -0
  2333. package/src/shared/utils/compressionHeaderEcho.ts +59 -0
  2334. package/src/shared/utils/cors.ts +24 -0
  2335. package/src/shared/utils/costEstimator.ts +126 -0
  2336. package/src/shared/utils/dashboardCsrf.ts +196 -0
  2337. package/src/shared/utils/featureFlags.ts +113 -0
  2338. package/src/shared/utils/fetchError.ts +26 -0
  2339. package/src/shared/utils/fetchTimeout.ts +78 -0
  2340. package/src/shared/utils/formatting.ts +183 -0
  2341. package/src/shared/utils/freeModels.ts +112 -0
  2342. package/src/shared/utils/index.ts +39 -0
  2343. package/src/shared/utils/inputSanitizer.ts +339 -0
  2344. package/src/shared/utils/linkify.ts +54 -0
  2345. package/src/shared/utils/logRedaction.ts +108 -0
  2346. package/src/shared/utils/logger.ts +173 -0
  2347. package/src/shared/utils/machine.ts +5 -0
  2348. package/src/shared/utils/machineId.ts +167 -0
  2349. package/src/shared/utils/maskEmail.ts +77 -0
  2350. package/src/shared/utils/modelCatalogSearch.ts +84 -0
  2351. package/src/shared/utils/noAuthProviders.ts +79 -0
  2352. package/src/shared/utils/nodeRuntimeSupport.ts +112 -0
  2353. package/src/shared/utils/parseApiKeys.ts +41 -0
  2354. package/src/shared/utils/providerDisplayLabel.ts +41 -0
  2355. package/src/shared/utils/providerHints.ts +73 -0
  2356. package/src/shared/utils/providerModelAliases.ts +68 -0
  2357. package/src/shared/utils/rateLimiter.ts +243 -0
  2358. package/src/shared/utils/releaseNotes.ts +53 -0
  2359. package/src/shared/utils/requestId.ts +102 -0
  2360. package/src/shared/utils/requestTelemetry.ts +189 -0
  2361. package/src/shared/utils/requestTimeout.ts +64 -0
  2362. package/src/shared/utils/resolveOmniRouteBaseUrl.ts +24 -0
  2363. package/src/shared/utils/runtimeTimeouts.ts +257 -0
  2364. package/src/shared/utils/secretsValidator.ts +135 -0
  2365. package/src/shared/utils/secureRandom.ts +66 -0
  2366. package/src/shared/utils/serviceTierLabels.ts +42 -0
  2367. package/src/shared/utils/shuffleDeck.ts +147 -0
  2368. package/src/shared/utils/sidebarRouteMatch.ts +43 -0
  2369. package/src/shared/utils/streamTracker.ts +187 -0
  2370. package/src/shared/utils/structuredLogger.ts +219 -0
  2371. package/src/shared/utils/tiktokenCounter.ts +21 -0
  2372. package/src/shared/utils/turkishText.ts +66 -0
  2373. package/src/shared/utils/upstreamError.ts +112 -0
  2374. package/src/shared/validation/compressionConfigSchemas.ts +234 -0
  2375. package/src/shared/validation/freeProxySchemas.ts +111 -0
  2376. package/src/shared/validation/helpers.ts +117 -0
  2377. package/src/shared/validation/oneproxySchemas.ts +14 -0
  2378. package/src/shared/validation/providerSchema.ts +51 -0
  2379. package/src/shared/validation/providerSpecificData.ts +354 -0
  2380. package/src/shared/validation/schemas/apiV1.ts +297 -0
  2381. package/src/shared/validation/schemas/auth.ts +200 -0
  2382. package/src/shared/validation/schemas/cli.ts +86 -0
  2383. package/src/shared/validation/schemas/cloud.ts +53 -0
  2384. package/src/shared/validation/schemas/combo.ts +373 -0
  2385. package/src/shared/validation/schemas/evals.ts +86 -0
  2386. package/src/shared/validation/schemas/gemini.ts +59 -0
  2387. package/src/shared/validation/schemas/keys.ts +144 -0
  2388. package/src/shared/validation/schemas/misc.ts +203 -0
  2389. package/src/shared/validation/schemas/payloadRules.ts +64 -0
  2390. package/src/shared/validation/schemas/pricing.ts +40 -0
  2391. package/src/shared/validation/schemas/provider.ts +430 -0
  2392. package/src/shared/validation/schemas/proxy.ts +243 -0
  2393. package/src/shared/validation/schemas/routing.ts +88 -0
  2394. package/src/shared/validation/schemas/settings.ts +267 -0
  2395. package/src/shared/validation/schemas/translator.ts +44 -0
  2396. package/src/shared/validation/schemas.ts +18 -0
  2397. package/src/shared/validation/settingsSchemas.ts +396 -0
  2398. package/src/sse/handlers/chat.ts +1750 -0
  2399. package/src/sse/handlers/chatHelpers.ts +859 -0
  2400. package/src/sse/handlers/requestBody.ts +24 -0
  2401. package/src/sse/handlers/resolveRoutingModel.ts +17 -0
  2402. package/src/sse/services/auth.ts +2446 -0
  2403. package/src/sse/services/cooldownAwareRetry.ts +162 -0
  2404. package/src/sse/services/model.ts +254 -0
  2405. package/src/sse/services/noAuthProviderSettings.ts +18 -0
  2406. package/src/sse/services/noAuthProxyResolution.ts +111 -0
  2407. package/src/sse/services/sessionAffinityPin.ts +247 -0
  2408. package/src/sse/services/streamState.ts +218 -0
  2409. package/src/sse/services/tokenRefresh.ts +275 -0
  2410. package/src/sse/utils/logger.ts +37 -0
  2411. package/src/types/databaseSettings.ts +124 -0
  2412. package/src/types/global.d.ts +122 -0
  2413. package/src/types/index.ts +10 -0
  2414. package/src/types/provider.ts +9 -0
  2415. package/src/types/sqljs.d.ts +32 -0
@@ -0,0 +1,3085 @@
1
+ /**
2
+ * Shared combo (model combo) handling with fallback support
3
+ * Supports: priority, weighted, round-robin, random, least-used, cost-optimized,
4
+ * reset-aware, reset-window, strict-random, auto, fill-first, p2c, lkgp,
5
+ * context-optimized, context-relay, and fusion strategies
6
+ */
7
+
8
+ import {
9
+ checkFallbackError,
10
+ classifyLockoutReason,
11
+ decayModelFailureCount,
12
+ formatRetryAfter,
13
+ getModelLockoutInfo,
14
+ getRuntimeProviderProfile,
15
+ hasPerModelQuota,
16
+ isModelLocked,
17
+ recordModelLockoutFailure,
18
+ recordProviderFailure,
19
+ selectLockoutCooldownMs,
20
+ } from "./accountFallback.ts";
21
+ import { errorResponse, unavailableResponse } from "../utils/error.ts";
22
+ import { buildTargetTimeoutRunner } from "./combo/targetTimeoutRunner.ts";
23
+ import { recordComboRequest, recordComboShadowRequest, getComboMetrics } from "./comboMetrics.ts";
24
+ import {
25
+ resolveComboConfig,
26
+ getDefaultComboConfig,
27
+ resolveComboQueueDepth,
28
+ } from "./comboConfig.ts";
29
+ import {
30
+ maybeGenerateHandoff,
31
+ maybeGenerateUniversalHandoff,
32
+ injectUniversalHandoffBody,
33
+ SKIP_UNIVERSAL_HANDOFF_FLAG,
34
+ type MessageLike,
35
+ } from "./contextHandoff.ts";
36
+ import {
37
+ recordSessionModelUsage,
38
+ getLastSessionModel,
39
+ getHandoff,
40
+ } from "../../src/lib/db/contextHandoffs.ts";
41
+ import { extractSessionAffinityKey } from "@/sse/services/auth";
42
+ import { getHiddenModelsByProvider } from "@/models";
43
+ import { resolveModelLockoutSettings } from "../../src/lib/resilience/modelLockoutSettings";
44
+ import { fetchCodexQuota } from "./codexQuotaFetcher.ts";
45
+ import { evaluateQuotaCutoff, getQuotaFetcher, type QuotaInfo } from "./quotaPreflight.ts";
46
+ import * as semaphore from "./rateLimitSemaphore.ts";
47
+ import { getCircuitBreaker } from "../../src/shared/utils/circuitBreaker";
48
+ import { fisherYatesShuffle, getNextFromDeck } from "../../src/shared/utils/shuffleDeck";
49
+ import { parseModel } from "./model.ts";
50
+ import { createComboContext } from "./combo/context.ts";
51
+ import { phaseComboSetup } from "./combo/comboSetup.ts";
52
+ import { checkCredentialGate, logCredentialSkip } from "./credentialGate.ts";
53
+ import { emit } from "../../src/lib/events/eventBus";
54
+ import { notifyWebhookEvent } from "../../src/lib/webhookDispatcher";
55
+ import { parseAutoPrefix } from "./autoCombo/autoPrefix.ts";
56
+ import { resolveAutoStrategyOrder } from "./combo/resolveAutoStrategy.ts";
57
+ import { applyStrategyOrdering } from "./combo/applyStrategyOrdering.ts";
58
+ import { handlePipelineCombo, buildPipelineResponse } from "./autoCombo/pipelineRouter.ts";
59
+ import { type ProviderCandidate } from "./autoCombo/scoring.ts";
60
+ import { estimateTokens } from "./contextManager.ts";
61
+ import { getSessionConnection } from "./sessionManager.ts";
62
+ import {
63
+ applySessionStickiness,
64
+ recordStickyBinding,
65
+ resolveDisableSessionStickiness,
66
+ } from "./combo/sessionStickiness.ts";
67
+ import { selectQuotaShareTarget } from "./combo/quotaShareStrategy.ts";
68
+ import { makeConnectionConcurrencyResolver, lookupPositiveCap } from "./combo/concurrencyCaps.ts";
69
+ import { acquireQuotaShareConcurrencySlot } from "./combo/quotaShareConcurrency.ts";
70
+ import { orderTargetsByEvalScores } from "./evalRouting.ts";
71
+ import type { CompressionMode } from "./compression/types.ts";
72
+ import { getProviderConnections } from "../../src/lib/db/providers";
73
+ import {
74
+ isProviderInCooldown,
75
+ recordProviderCooldown,
76
+ recordProviderSuccess,
77
+ } from "./providerCooldownTracker.ts";
78
+ import {
79
+ resolveResilienceSettings,
80
+ type ResilienceSettings,
81
+ } from "../../src/lib/resilience/settings";
82
+ import { resolveReasoningBufferedMaxTokens, toPositiveInteger } from "./reasoningTokenBuffer.ts";
83
+ import { RESET_WINDOW_NAMES } from "./combo/types.ts";
84
+ import type {
85
+ ComboLike,
86
+ ComboRetryAfter,
87
+ ComboErrorBody,
88
+ SingleModelTarget,
89
+ HandleComboChatOptions,
90
+ HandleRoundRobinOptions,
91
+ NestedComboMode,
92
+ ResolvedComboTarget,
93
+ ResolvedComboUnit,
94
+ AutoProviderCandidate,
95
+ ComboRuntimeStep,
96
+ HistoricalLatencyStatsEntry,
97
+ } from "./combo/types.ts";
98
+
99
+ import {
100
+ MAX_RR_COUNTERS,
101
+ rrCounters,
102
+ rrStickyTargets,
103
+ weightedStickyTargets,
104
+ clampStickyRoundRobinTargetLimit,
105
+ clampStickyWeightedTargetLimit,
106
+ getStickyRoundRobinStartIndex,
107
+ recordStickyRoundRobinSuccess,
108
+ getStickyWeightedExecutionKey,
109
+ recordStickyWeightedSuccess,
110
+ } from "./combo/rrState.ts";
111
+ import {
112
+ validateResponseQuality,
113
+ releaseQualityClone,
114
+ toRetryAfterDisplayValue,
115
+ } from "./combo/validateQuality.ts";
116
+ import { resolveComboCooldownWaitDecision } from "./combo/comboCooldownRetry.ts";
117
+ import {
118
+ computeClosestRetryAfter,
119
+ waitForCooldownAwareRetry,
120
+ } from "../../src/sse/services/cooldownAwareRetry.ts";
121
+ import { handleFusionChat, type FusionTuning } from "./fusion.ts";
122
+ import { handlePipelineChat, type PipelineStep } from "./pipeline.ts";
123
+ import {
124
+ TRANSIENT_FOR_SEMAPHORE,
125
+ MAX_FALLBACK_WAIT_MS,
126
+ MAX_GLOBAL_ATTEMPTS,
127
+ isAllAccountsRateLimitedResponse,
128
+ clampComboDepth,
129
+ shouldSkipForPredictedTtft,
130
+ shouldRecordProviderBreakerFailure,
131
+ resolveDelayMs,
132
+ comboModelNotFoundResponse,
133
+ isStreamReadinessFailureErrorBody,
134
+ isTokenLimitBreachErrorBody,
135
+ toRecordedTarget,
136
+ getExhaustedTargetSkipReason,
137
+ } from "./combo/comboPredicates.ts";
138
+ import { applyComboTargetExhaustion } from "./combo/targetExhaustion.ts";
139
+ import { executeRuntimeUnitCombo } from "./combo/runtimeUnits.ts";
140
+ import { isRecord } from "./combo/comboData.ts";
141
+ import {
142
+ expandProviderWildcardsInCombo,
143
+ expandProviderWildcardsInCollection,
144
+ } from "./combo/providerWildcard.ts";
145
+ import { resolveShadowTargets, scheduleShadowRouting } from "./combo/shadowRouting.ts";
146
+ import { attemptCompatRejectedFallback } from "./combo/comboCompatFallback.ts";
147
+ import {
148
+ filterTargetsByRequestCompatibility,
149
+ resolveComboRuntimeUnits,
150
+ resolveComboTargets,
151
+ resolveWeightedTargets,
152
+ resolveWeightedStepGroups,
153
+ } from "./combo/comboStructure.ts";
154
+ import {
155
+ QUOTA_SOFT_DEPRIORITIZE_FACTOR,
156
+ setCandidateQuotaSoftPenalty,
157
+ _registerExecutionCandidates,
158
+ _unregisterExecutionCandidates,
159
+ applyRequestTagRouting,
160
+ scoreAutoTargets,
161
+ expandAutoComboCandidatePool,
162
+ } from "./combo/autoStrategy.ts";
163
+ import {
164
+ resolveResetWindowConfig,
165
+ calculateResetWindowAffinity,
166
+ type ResetWindowConfig,
167
+ } from "./combo/quotaScoring.ts";
168
+ import {
169
+ fetchResetAwareQuotaWithCache,
170
+ preScreenTargets,
171
+ type PreScreenResult,
172
+ } from "./combo/quotaStrategies.ts";
173
+ import {
174
+ buildAutoQuotaThresholds,
175
+ resolveQuotaExhaustionCutoffForTarget,
176
+ } from "./combo/quotaExhaustionCutoff.ts";
177
+ import {
178
+ classifyTask,
179
+ getConversationCacheKey,
180
+ isTaskRoutingStrategy,
181
+ reorderByTaskWeight,
182
+ } from "./taskAwareRouting.ts";
183
+ import { expandTargetsByFingerprints } from "./combo/fingerprintExpansion.ts";
184
+
185
+ export { RESET_WINDOW_NAMES };
186
+ export { QUOTA_SOFT_DEPRIORITIZE_FACTOR, setCandidateQuotaSoftPenalty };
187
+ export { scoreAutoTargets, expandAutoComboCandidatePool };
188
+ export type { SingleModelTarget, ResolvedComboTarget };
189
+ export { validateResponseQuality };
190
+ export { clampComboDepth, shouldSkipForPredictedTtft, shouldRecordProviderBreakerFailure };
191
+ export { resolveShadowTargets, scheduleShadowRouting };
192
+ export { preScreenTargets };
193
+ export { resolveComboRuntimeUnits, resolveComboTargets, filterTargetsByRequestCompatibility };
194
+ export {
195
+ getComboFromData,
196
+ getComboModelsFromData,
197
+ resolveNestedComboModels,
198
+ resolveNestedComboTargets,
199
+ validateComboDAG,
200
+ } from "./combo/comboStructure.ts";
201
+
202
+ const DEFAULT_MODEL_P95_MS: Record<string, number> = {
203
+ "grok-4-fast-non-reasoning": 1143,
204
+ "grok-4-1-fast-non-reasoning": 1244,
205
+ "gemini-2.5-flash": 1238,
206
+ "kimi-k2.5": 1646,
207
+ "gpt-4o-mini": 2764,
208
+ "claude-sonnet-4.6": 4000,
209
+ "claude-opus-4.6": 6000,
210
+ "deepseek-chat": 2000,
211
+ };
212
+ const MIN_HISTORY_SAMPLES = 10;
213
+ const OUTPUT_TOKEN_RATIO = 0.4;
214
+
215
+ function normalizeNestedComboMode(value: unknown): NestedComboMode {
216
+ return value === "execute" ? "execute" : "flatten";
217
+ }
218
+
219
+ function calculateTargetContextAffinity(
220
+ target: ResolvedComboTarget,
221
+ sessionId: string | null | undefined
222
+ ): number {
223
+ const sessionConnectionId = getSessionConnection(sessionId || null);
224
+ if (!sessionConnectionId) return 0.5;
225
+ if (target.connectionId === sessionConnectionId) return 1;
226
+ if (!target.connectionId) return 0.5;
227
+ return 0.1;
228
+ }
229
+
230
+ function getBootstrapLatencyMs(modelId: string): number {
231
+ const normalized = String(modelId || "").toLowerCase();
232
+ return DEFAULT_MODEL_P95_MS[normalized] ?? 1500;
233
+ }
234
+
235
+ function clampPercent(value: number): number {
236
+ if (!Number.isFinite(value)) return 100;
237
+ return Math.max(0, Math.min(100, value));
238
+ }
239
+
240
+ function quotaRemainingPercentFromQuota(quota: unknown): number {
241
+ if (!quota || typeof quota !== "object") return 100;
242
+ const record = quota as Record<string, unknown>;
243
+ if (record.limitReached === true) return 0;
244
+
245
+ const windows = record.windows;
246
+ if (windows && typeof windows === "object" && !Array.isArray(windows)) {
247
+ let minRemaining: number | null = null;
248
+ for (const windowInfo of Object.values(windows as Record<string, unknown>)) {
249
+ if (!windowInfo || typeof windowInfo !== "object") continue;
250
+ const percentUsed = Number((windowInfo as Record<string, unknown>).percentUsed);
251
+ if (!Number.isFinite(percentUsed)) continue;
252
+ const remaining = clampPercent((1 - percentUsed) * 100);
253
+ minRemaining = minRemaining === null ? remaining : Math.min(minRemaining, remaining);
254
+ }
255
+ if (minRemaining !== null) return minRemaining;
256
+ }
257
+
258
+ const percentUsed = Number(record.percentUsed);
259
+ if (Number.isFinite(percentUsed)) return clampPercent((1 - percentUsed) * 100);
260
+ return 100;
261
+ }
262
+
263
+ const QUOTA_BLOCKING_CONNECTION_STATUSES = new Set([
264
+ "banned",
265
+ "credits_exhausted",
266
+ "deactivated",
267
+ "expired",
268
+ "rate_limited",
269
+ ]);
270
+
271
+ function normalizeConnectionStatus(value: unknown): string {
272
+ return typeof value === "string" ? value.trim().toLowerCase() : "";
273
+ }
274
+
275
+ function hasFutureRateLimitUntil(value: unknown): boolean {
276
+ if (value == null || value === "") return false;
277
+ const time = new Date(String(value)).getTime();
278
+ return Number.isFinite(time) && time > Date.now();
279
+ }
280
+
281
+ export function getConnectionStatusQuotaCutoffReason(
282
+ connection: Record<string, unknown> | undefined
283
+ ): string | undefined {
284
+ if (!connection) return undefined;
285
+ const status = normalizeConnectionStatus(connection.testStatus);
286
+ if (QUOTA_BLOCKING_CONNECTION_STATUSES.has(status)) return status;
287
+ if (status === "unavailable" && hasFutureRateLimitUntil(connection.rateLimitedUntil)) {
288
+ return "rate_limited";
289
+ }
290
+ return undefined;
291
+ }
292
+
293
+ export async function buildAutoCandidates(
294
+ targets: ResolvedComboTarget[],
295
+ comboName: string,
296
+ sessionId: string | null | undefined = null,
297
+ resetWindowConfig: ResetWindowConfig = resolveResetWindowConfig(null),
298
+ resilienceSettings: ResilienceSettings | null = null
299
+ ): Promise<AutoProviderCandidate[]> {
300
+ const hiddenModelsMap = getHiddenModelsByProvider();
301
+ const metrics = getComboMetrics(comboName);
302
+ // Opt-in hard quota cutoff (default OFF). When disabled, candidates are never
303
+ // dropped for low quota here — the soft quota penalty + connection cooldown still
304
+ // apply, so auto-routing behavior is unchanged.
305
+ const quotaCutoffEnabled =
306
+ (resilienceSettings ?? resolveResilienceSettings(null))?.quotaPreflight?.enabled === true;
307
+ const { getPricingForModel } = await import("../../src/lib/localDb");
308
+ const quotaPromises = new Map<string, Promise<unknown>>();
309
+ let historicalLatencyStats: Record<string, HistoricalLatencyStatsEntry> = {};
310
+ try {
311
+ const { getModelLatencyStats } = await import("../../src/lib/usageDb");
312
+ historicalLatencyStats = await getModelLatencyStats({
313
+ windowHours: 24,
314
+ minSamples: 3,
315
+ maxRows: 10000,
316
+ });
317
+ } catch {
318
+ // keep empty stats — auto-combo will use runtime + bootstrap signals
319
+ }
320
+
321
+ const uniqueProviders = Array.from(
322
+ new Set(
323
+ targets.map((target) => target.provider || parseModel(target.modelStr).provider || "unknown")
324
+ )
325
+ );
326
+ const connectionPoolCounts = new Map<string, number>();
327
+ const connectionsByProvider = new Map<string, Array<Record<string, unknown>>>();
328
+ const connectionById = new Map<string, Record<string, unknown>>();
329
+ await Promise.all(
330
+ uniqueProviders.map(async (provider) => {
331
+ try {
332
+ const connections = await getProviderConnections({ provider, isActive: true });
333
+ const active = Array.isArray(connections) ? connections : [];
334
+ connectionPoolCounts.set(provider, active.length);
335
+ connectionsByProvider.set(provider, active);
336
+ for (const connection of active) {
337
+ if (connection && typeof connection === "object" && typeof connection.id === "string") {
338
+ connectionById.set(connection.id, connection as Record<string, unknown>);
339
+ }
340
+ }
341
+ } catch {
342
+ connectionPoolCounts.set(provider, 0);
343
+ connectionsByProvider.set(provider, []);
344
+ }
345
+ })
346
+ );
347
+
348
+ const expandedTargets: ResolvedComboTarget[] = [];
349
+ for (const target of targets) {
350
+ const provider = target.provider || parseModel(target.modelStr).provider || "unknown";
351
+ const providerConnections = connectionsByProvider.get(provider) || [];
352
+ if (target.connectionId) {
353
+ expandedTargets.push(target);
354
+ continue;
355
+ }
356
+ const connectionIds = providerConnections
357
+ .map((c) => (c && typeof c === "object" && typeof c.id === "string" ? c.id : null))
358
+ .filter((id): id is string => id !== null);
359
+ const allowedConnectionIds = Array.isArray(target.allowedConnectionIds)
360
+ ? new Set(
361
+ target.allowedConnectionIds.filter(
362
+ (connectionId): connectionId is string =>
363
+ typeof connectionId === "string" && connectionId.trim().length > 0
364
+ )
365
+ )
366
+ : null;
367
+ const scopedConnectionIds = allowedConnectionIds
368
+ ? connectionIds.filter((connectionId) => allowedConnectionIds.has(connectionId))
369
+ : connectionIds;
370
+ if (scopedConnectionIds.length === 0) {
371
+ expandedTargets.push(target);
372
+ continue;
373
+ }
374
+ for (const connectionId of scopedConnectionIds) {
375
+ expandedTargets.push({
376
+ ...target,
377
+ connectionId,
378
+ executionKey: `${target.executionKey}@${connectionId}`,
379
+ });
380
+ }
381
+ }
382
+
383
+ // #5521: Expand fingerprint-based providers (mimocode, mcode, opencode) so each
384
+ // fingerprint gets its own combo slot instead of being bundled into one connection.
385
+ const fingerprintExpandedTargets = expandTargetsByFingerprints(
386
+ expandedTargets,
387
+ connectionById,
388
+ (t) => {
389
+ const parsed = parseModel(t.modelStr);
390
+ return t.provider || parsed.provider || parsed.providerAlias || "unknown";
391
+ }
392
+ );
393
+
394
+ const candidates = await Promise.all(
395
+ fingerprintExpandedTargets.map(async (target) => {
396
+ const modelStr = target.modelStr;
397
+ const parsed = parseModel(modelStr);
398
+ const provider = target.provider || parsed.provider || parsed.providerAlias || "unknown";
399
+ const model = parsed.model || modelStr;
400
+ const historicalKey = `${provider}/${model}`;
401
+ const historicalModelMetric = historicalLatencyStats[historicalKey] || null;
402
+ const historicalTotal = Number(historicalModelMetric?.totalRequests);
403
+ const hasHistoricalSignal =
404
+ Number.isFinite(historicalTotal) && historicalTotal >= MIN_HISTORY_SAMPLES;
405
+
406
+ let costPer1MTokens = 1;
407
+ try {
408
+ const pricing = await getPricingForModel(provider, model);
409
+ const inputPrice = Number(pricing?.input);
410
+ const outputPrice = Number(pricing?.output);
411
+ if (Number.isFinite(inputPrice) && inputPrice >= 0) {
412
+ if (Number.isFinite(outputPrice) && outputPrice >= 0) {
413
+ costPer1MTokens =
414
+ inputPrice * (1 - OUTPUT_TOKEN_RATIO) + outputPrice * OUTPUT_TOKEN_RATIO;
415
+ } else {
416
+ costPer1MTokens = inputPrice;
417
+ }
418
+ }
419
+ } catch {
420
+ // keep default cost
421
+ }
422
+
423
+ const modelMetric = metrics?.byModel?.[modelStr] || null;
424
+ const avgLatency = Number(modelMetric?.avgLatencyMs);
425
+ const successRate = Number(modelMetric?.successRate);
426
+ const historicalP95Latency = Number(historicalModelMetric?.p95LatencyMs);
427
+ const historicalStdDev = Number(historicalModelMetric?.latencyStdDev);
428
+ const historicalSuccessRate = Number(historicalModelMetric?.successRate); // 0..1
429
+
430
+ const p95LatencyMs = hasHistoricalSignal
431
+ ? Number.isFinite(historicalP95Latency) && historicalP95Latency > 0
432
+ ? historicalP95Latency
433
+ : getBootstrapLatencyMs(model)
434
+ : Number.isFinite(avgLatency) && avgLatency > 0
435
+ ? avgLatency
436
+ : getBootstrapLatencyMs(model);
437
+
438
+ const errorRate = hasHistoricalSignal
439
+ ? Number.isFinite(historicalSuccessRate) &&
440
+ historicalSuccessRate >= 0 &&
441
+ historicalSuccessRate <= 1
442
+ ? 1 - historicalSuccessRate
443
+ : 0.05
444
+ : Number.isFinite(successRate) && successRate >= 0 && successRate <= 100
445
+ ? 1 - successRate / 100
446
+ : 0.05;
447
+ const latencyStdDev =
448
+ hasHistoricalSignal && Number.isFinite(historicalStdDev) && historicalStdDev > 0
449
+ ? Math.max(10, historicalStdDev)
450
+ : Math.max(10, p95LatencyMs * 0.1);
451
+
452
+ const breakerStateRaw = getCircuitBreaker(provider)?.getStatus?.()?.state;
453
+ const circuitBreakerState: ProviderCandidate["circuitBreakerState"] =
454
+ breakerStateRaw === "OPEN" || breakerStateRaw === "HALF_OPEN" ? breakerStateRaw : "CLOSED";
455
+ const contextAffinity = calculateTargetContextAffinity(target, sessionId);
456
+ let resetWindowAffinity = 0.5;
457
+ let quotaRemaining = 100;
458
+ let quotaCutoffBlocked = false;
459
+ let quotaCutoffReason: string | undefined;
460
+ const fetcher = getQuotaFetcher(provider);
461
+ const connection = target.connectionId ? connectionById.get(target.connectionId) : undefined;
462
+ // Gate the terminal-status cutoff behind the same opt-in as the quota-percent
463
+ // cutoff (#4483): when quota cutoff is disabled, a connection in a terminal
464
+ // testStatus must still fall through to normal connection-cooldown / model-lockout
465
+ // handling instead of being hard-blocked here (which would surface a misleading
466
+ // "below quota cutoff" 429 when every candidate is transiently unavailable).
467
+ // The connection's terminal/transient status (credits_exhausted / rate_limited /
468
+ // banned / expired / future-dated unavailable) is classified unconditionally.
469
+ const connectionStatusReason = getConnectionStatusQuotaCutoffReason(connection);
470
+ const statusCutoffReason = quotaCutoffEnabled ? connectionStatusReason : undefined;
471
+ // #4540: when the HARD cutoff is OFF (default), a status-flagged connection is NOT
472
+ // hard-blocked (that would surface a misleading "below quota cutoff" 429), but it
473
+ // also must not score identically to a healthy provider. A no-fetcher exhausted
474
+ // connection keeps quotaRemaining=100, so we tag a SOFT penalty applied at scoring
475
+ // time (scoreAutoTargets → STATUS_SOFT_DEPRIORITIZE_FACTOR) instead.
476
+ let statusPenalty = false;
477
+ let statusPenaltyReason: string | undefined;
478
+ if (statusCutoffReason) {
479
+ quotaCutoffBlocked = true;
480
+ quotaCutoffReason = statusCutoffReason;
481
+ quotaRemaining = 0;
482
+ } else if (connectionStatusReason) {
483
+ statusPenalty = true;
484
+ statusPenaltyReason = connectionStatusReason;
485
+ }
486
+ if (fetcher && target.connectionId) {
487
+ const quotaKey = `${provider}:${target.connectionId}`;
488
+ if (!quotaPromises.has(quotaKey)) {
489
+ quotaPromises.set(
490
+ quotaKey,
491
+ fetchResetAwareQuotaWithCache({
492
+ provider,
493
+ connectionId: target.connectionId,
494
+ connection,
495
+ fetcher,
496
+ config: resetWindowConfig,
497
+ log: {},
498
+ comboName,
499
+ })
500
+ );
501
+ }
502
+ const quota = await quotaPromises.get(quotaKey)!;
503
+ resetWindowAffinity = calculateResetWindowAffinity(quota, resetWindowConfig);
504
+ if (!quotaCutoffBlocked) {
505
+ quotaRemaining = quotaRemainingPercentFromQuota(quota);
506
+ }
507
+ if (!quotaCutoffBlocked && quotaCutoffEnabled) {
508
+ const cutoffDecision = evaluateQuotaCutoff(
509
+ quota as QuotaInfo | null,
510
+ buildAutoQuotaThresholds(provider, connection, resilienceSettings)
511
+ );
512
+ if (!cutoffDecision.proceed) {
513
+ quotaCutoffBlocked = true;
514
+ quotaCutoffReason = cutoffDecision.reason || "quota_exhausted";
515
+ }
516
+ }
517
+ }
518
+
519
+ return {
520
+ stepId: target.stepId,
521
+ executionKey: target.executionKey,
522
+ modelStr,
523
+ provider,
524
+ model,
525
+ quotaRemaining,
526
+ quotaTotal: 100,
527
+ circuitBreakerState,
528
+ costPer1MTokens,
529
+ p95LatencyMs,
530
+ latencyStdDev,
531
+ errorRate,
532
+ accountTier: "standard" as const,
533
+ quotaResetIntervalSecs: 86400,
534
+ contextAffinity,
535
+ resetWindowAffinity,
536
+ quotaCutoffBlocked,
537
+ quotaCutoffReason,
538
+ statusPenalty,
539
+ statusPenaltyReason,
540
+ connectionPoolSize: connectionPoolCounts.get(provider) ?? 1,
541
+ connectionId: target.connectionId ?? undefined,
542
+ };
543
+ })
544
+ );
545
+
546
+ // Filter out candidates whose model is hidden by the user in the dashboard
547
+ return candidates.filter((c) => {
548
+ const hiddenModels = hiddenModelsMap.get(c.provider);
549
+ return !hiddenModels?.has(c.model);
550
+ });
551
+ }
552
+
553
+ const TERMINAL_PIN_STATUSES = new Set(["credits_exhausted", "banned", "expired"]);
554
+
555
+ /**
556
+ * Pure decision: should a context-cache pin be DROPPED because its provider has
557
+ * DURABLY fallen? A ccp pin keeps the prompt cache warm by bypassing the combo
558
+ * strategy — but if the pinned provider is dead (credits exhausted / banned /
559
+ * expired, circuit-open, repeated failures, or a long rate-limit) honoring the
560
+ * pin pounds a dead account forever with no failover (laila throttle + credits
561
+ * incidents, 2026-06-22). A brief transient cooldown is tolerated (pin kept) so
562
+ * an unstable provider does not churn the pin every turn. Connection-level
563
+ * `backoffLevel` already resets on success, so `backoffLevel >= K` ≈ K
564
+ * consecutive failures — no per-session counter needed.
565
+ *
566
+ * Returns true ⇒ drop the pin and use the strategy. Pure + unit-testable.
567
+ */
568
+ export function pinIsDurablyUnhealthy(
569
+ circuitState: string | undefined,
570
+ connections: Array<{
571
+ testStatus?: string | null;
572
+ backoffLevel?: number | null;
573
+ rateLimitedUntil?: string | null;
574
+ }>,
575
+ now: number,
576
+ opts: { backoffLevel?: number; graceMs?: number } = {}
577
+ ): boolean {
578
+ if (circuitState === "OPEN") return true;
579
+ if (!Array.isArray(connections) || connections.length === 0) return true;
580
+ const backoffThreshold = opts.backoffLevel ?? Number(process.env.PIN_DROP_BACKOFF_LEVEL || "2");
581
+ const graceMs = opts.graceMs ?? Number(process.env.PIN_DROP_GRACE_MS || "20000");
582
+ // The pin survives as long as AT LEAST ONE connection is healthy or only
583
+ // briefly cooling down — failover only when every connection is durably down.
584
+ const anyUsable = connections.some((c) => {
585
+ const status = typeof c.testStatus === "string" ? c.testStatus : "";
586
+ if (TERMINAL_PIN_STATUSES.has(status)) return false;
587
+ if (Number(c.backoffLevel ?? 0) >= backoffThreshold) return false;
588
+ const rl = c.rateLimitedUntil ? new Date(String(c.rateLimitedUntil)).getTime() : 0;
589
+ if (Number.isFinite(rl) && rl - now > graceMs) return false;
590
+ return true;
591
+ });
592
+ return !anyUsable;
593
+ }
594
+
595
+ /**
596
+ * Async wrapper: resolve the pinned model's provider, read its circuit state and
597
+ * active connections, and decide via {@link pinIsDurablyUnhealthy}. Fail-open
598
+ * (return false) on any error so a lookup bug never drops a healthy pin.
599
+ */
600
+ async function isPinnedModelDurablyUnhealthy(pinnedModel: string): Promise<boolean> {
601
+ try {
602
+ const provider = parseModel(pinnedModel).provider;
603
+ if (!provider) return false;
604
+ const circuitState = getCircuitBreaker(provider)?.getStatus?.()?.state;
605
+ const connections = (await getProviderConnections({
606
+ provider,
607
+ isActive: true,
608
+ })) as Array<{
609
+ testStatus?: string | null;
610
+ backoffLevel?: number | null;
611
+ rateLimitedUntil?: string | null;
612
+ }>;
613
+ return pinIsDurablyUnhealthy(circuitState, connections || [], Date.now());
614
+ } catch {
615
+ return false;
616
+ }
617
+ }
618
+
619
+ /**
620
+ * Handle combo chat with fallback.
621
+ * @param {Object} options
622
+ * @param {Object} options.body - Request body
623
+ * @param {Object} options.combo - Full combo object { name, models, strategy, config }
624
+ * @param {Function} options.handleSingleModel - Function: (body, modelStr) => Promise<Response>
625
+ * @param {Function} [options.isModelAvailable] - Optional pre-check: (modelStr) => Promise<boolean>
626
+ * @param {Object} options.log - Logger object
627
+ * @returns {Promise<Response>}
628
+ */
629
+ // #2101 guard helpers: a 400 caused by context overflow or parameter validation
630
+ // is NOT body-specific — different combo targets have different context windows /
631
+ // output limits, so the request should fall through to the next target instead of
632
+ // being short-circuited. Exported as pure predicates so the guard is unit-testable.
633
+ /** @param {string} errorText */
634
+ export function isContextOverflow400(errorText) {
635
+ return (
636
+ /\bcontext.*(?:length_exceeded|too long|overflow|exceeded|window|limit)\b/i.test(errorText) ||
637
+ /exceeds.*context/i.test(errorText) ||
638
+ /your input exceeds/i.test(errorText)
639
+ );
640
+ }
641
+ /** @param {string} errorText */
642
+ export function isParamValidation400(errorText) {
643
+ return (
644
+ /\bmax_tokens\b.*(?:illegal|must|range|invalid)/i.test(errorText) ||
645
+ /\bparameter is illegal\b/i.test(errorText) ||
646
+ /\bis illegal.*range\b/i.test(errorText)
647
+ );
648
+ }
649
+
650
+ /** @param {object} options */
651
+ export async function handleComboChat({
652
+ body,
653
+ combo,
654
+ handleSingleModel,
655
+ isModelAvailable,
656
+ log,
657
+ settings,
658
+ allCombos,
659
+ relayOptions,
660
+ signal,
661
+ apiKeyAllowedConnections = null,
662
+ nesting = null,
663
+ }: HandleComboChatOptions): Promise<Response> {
664
+ const comboCtx = createComboContext({ body, combo, settings, relayOptions, log });
665
+ const {
666
+ strategy,
667
+ relayConfig,
668
+ resilienceSettings,
669
+ universalHandoffConfig,
670
+ effectiveSessionId,
671
+ pinnedModel,
672
+ clientRequestedStream,
673
+ config,
674
+ comboTargetTimeoutMs,
675
+ reasoningTokenBufferEnabled,
676
+ } = phaseComboSetup(comboCtx);
677
+ body = comboCtx.body;
678
+
679
+ const handleSingleModelWithTimeout = buildTargetTimeoutRunner({
680
+ handleSingleModel,
681
+ comboTargetTimeoutMs,
682
+ log,
683
+ });
684
+
685
+ // Route to pinned model if context caching specifies one (Fix #679)
686
+ if (pinnedModel) {
687
+ // The pin is read from session_model_history (a PRIOR turn) and may name a
688
+ // model that has since been removed from this combo, or a provider whose
689
+ // credentials are gone. Without this guard a stale pin bypasses the strategy
690
+ // and routes to a dead model forever — incident 2026-06-21: cli-claude-heavy
691
+ // pinned to a deepseek connection with no active credentials → instant fail,
692
+ // never falling through to the live targets; and combos re-pointed Opus→Sonnet
693
+ // kept serving the old model. Validate the pin is still reachable in THIS
694
+ // combo's resolved targets (refs flattened) before honoring it. Only validate
695
+ // when allCombos is authoritative (non-empty) so we can resolve combo-refs;
696
+ // the auto-combo redirect path passes an empty list and keeps prior behavior.
697
+ const haveFullCombos = Array.isArray(allCombos) ? allCombos.length > 0 : !!allCombos;
698
+ const pinInCombo =
699
+ !haveFullCombos ||
700
+ resolveComboTargets(combo, allCombos, clampComboDepth(config.maxComboDepth)).some(
701
+ (t) => t.modelStr === pinnedModel
702
+ );
703
+ // Honor the pin only if it is still a combo target AND its provider is not
704
+ // DURABLY down. Without the health gate a pin keeps routing a session to a
705
+ // dead/credits-exhausted/throttled account forever (strategy bypassed, no
706
+ // failover) — incident 2026-06-22: laila stuck on a throttled claude account
707
+ // and credits_exhausted accounts never failing over. A transient cooldown is
708
+ // tolerated (pin kept) so an unstable provider does not churn the pin.
709
+ const pinDurablyDown = pinInCombo ? await isPinnedModelDurablyUnhealthy(pinnedModel) : false;
710
+ if (pinInCombo && !pinDurablyDown) {
711
+ log.info(
712
+ "COMBO",
713
+ `Bypassing strategy — routing directly to pinned context model: ${pinnedModel}`
714
+ );
715
+ let pinnedResult: Response | null = null;
716
+ try {
717
+ pinnedResult = await handleSingleModelWithTimeout(body, pinnedModel, {
718
+ modelPinned: true,
719
+ } as SingleModelTarget);
720
+ } catch (pinErr) {
721
+ log.warn(
722
+ "COMBO",
723
+ `Pinned model ${pinnedModel} threw error: ${pinErr instanceof Error ? pinErr.message : String(pinErr)}, falling through to combo retry/fallback`
724
+ );
725
+ }
726
+ if (pinnedResult) {
727
+ if (pinnedResult.ok) {
728
+ let pinnedClone: Response;
729
+ try {
730
+ pinnedClone = pinnedResult.clone();
731
+ } catch {
732
+ pinnedClone = pinnedResult;
733
+ }
734
+ const pinnedQuality = await validateResponseQuality(
735
+ pinnedClone,
736
+ clientRequestedStream,
737
+ log,
738
+ config.responseValidation
739
+ );
740
+ releaseQualityClone(pinnedClone, pinnedResult, pinnedQuality);
741
+ if (pinnedQuality.valid) return pinnedResult;
742
+ log.warn(
743
+ "COMBO",
744
+ `Pinned model ${pinnedModel} returned 200 but failed quality check: ${pinnedQuality.reason}, falling through to combo retry/fallback`
745
+ );
746
+ } else {
747
+ const pinnedStatus = pinnedResult.status || 500;
748
+ if (![408, 429, 500, 502, 503, 504].includes(pinnedStatus)) {
749
+ return pinnedResult;
750
+ }
751
+ log.warn(
752
+ "COMBO",
753
+ `Pinned model ${pinnedModel} failed (${pinnedStatus}), falling through to combo retry/fallback`
754
+ );
755
+ }
756
+ }
757
+ // Fall through to the target iteration loop below — retries and sibling
758
+ // models will be tried via the normal combo machinery.
759
+ }
760
+ log.warn(
761
+ "COMBO",
762
+ pinInCombo
763
+ ? `Context-cache pin "${pinnedModel}" provider durably unhealthy — dropping pin, using strategy`
764
+ : `Stale context-cache pin "${pinnedModel}" not in combo "${combo.name}" targets — dropping pin, using strategy`
765
+ );
766
+ // Fall through to the normal target iteration loop below — the pin is
767
+ // dropped, so the combo strategy picks the best available target.
768
+ }
769
+
770
+ // Fusion strategy: parallel panel + judge synthesis. Handled in a separate module
771
+ // because it neither iterates targets in order nor needs the failover/retry/credential
772
+ // gate machinery that follows — it fans out, then synthesizes once.
773
+ if (strategy === "fusion") {
774
+ const fusionModels = (combo.models || [])
775
+ .map((m) => {
776
+ if (typeof m === "string") return m;
777
+ if (m && typeof m === "object") {
778
+ const obj = m as Record<string, unknown>;
779
+ if (typeof obj.model === "string") return obj.model;
780
+ }
781
+ return null;
782
+ })
783
+ .filter((m): m is string => Boolean(m));
784
+ const cfg = config as Record<string, unknown>;
785
+ const judgeModel = typeof cfg.judgeModel === "string" ? cfg.judgeModel : undefined;
786
+ const tuning =
787
+ cfg.fusionTuning && typeof cfg.fusionTuning === "object"
788
+ ? (cfg.fusionTuning as FusionTuning)
789
+ : undefined;
790
+ return handleFusionChat({
791
+ body,
792
+ models: fusionModels,
793
+ handleSingleModel: handleSingleModelWithTimeout,
794
+ log,
795
+ comboName: combo.name,
796
+ judgeModel,
797
+ tuning,
798
+ });
799
+ }
800
+
801
+ // Pipeline strategy: sequential chain — each step's output feeds the next step's
802
+ // input, only the final step's response is returned. Handled in a separate module
803
+ // because it neither iterates targets as fallbacks nor needs the failover/retry
804
+ // machinery below — it runs targets in order, threading output → input. The step
805
+ // list is `combo.models` (in order); an optional per-step `prompt` is read off the
806
+ // target object (comboModelStepInputSchema.prompt).
807
+ if (strategy === "pipeline") {
808
+ const pipelineSteps = (combo.models || [])
809
+ .map((m): PipelineStep | null => {
810
+ if (typeof m === "string") return { model: m };
811
+ if (m && typeof m === "object") {
812
+ const obj = m as Record<string, unknown>;
813
+ if (typeof obj.model === "string") {
814
+ return {
815
+ model: obj.model,
816
+ prompt: typeof obj.prompt === "string" ? obj.prompt : undefined,
817
+ };
818
+ }
819
+ }
820
+ return null;
821
+ })
822
+ .filter((s): s is PipelineStep => Boolean(s));
823
+ return handlePipelineChat({
824
+ body,
825
+ steps: pipelineSteps,
826
+ handleSingleModel: handleSingleModelWithTimeout,
827
+ log,
828
+ comboName: combo.name,
829
+ });
830
+ }
831
+
832
+ const nestingContext = nesting || {
833
+ depth: 0,
834
+ maxDepth: clampComboDepth(config.maxComboDepth),
835
+ visitedComboNames: [combo.name],
836
+ rootComboName: combo.name,
837
+ attemptBudget: { count: 0, limit: MAX_GLOBAL_ATTEMPTS },
838
+ };
839
+ const nestedComboMode = normalizeNestedComboMode(config.nestedComboMode);
840
+
841
+ const executeModeUnits =
842
+ nestedComboMode === "execute" && allCombos
843
+ ? resolveComboRuntimeUnits(combo, allCombos, "execute", nestingContext.maxDepth)
844
+ : [];
845
+ const hasExecutableComboRef = executeModeUnits.some((unit) => unit.kind === "combo-ref");
846
+ const simpleExecuteStrategies = new Set([
847
+ "priority",
848
+ "round-robin",
849
+ "random",
850
+ "strict-random",
851
+ "weighted",
852
+ "fill-first",
853
+ ]);
854
+
855
+ if (hasExecutableComboRef && simpleExecuteStrategies.has(strategy)) {
856
+ let runtimeUnits = executeModeUnits;
857
+ let unitExecutionStrategy = strategy;
858
+ if (strategy === "weighted") {
859
+ const stickyLimit = clampStickyWeightedTargetLimit(
860
+ (config as Record<string, unknown>).stickyWeightedLimit
861
+ );
862
+ const stickyKey = getStickyWeightedExecutionKey(combo.name, stickyLimit);
863
+ const stickyUnit = stickyKey
864
+ ? runtimeUnits.find((unit) => unit.executionKey === stickyKey)
865
+ : null;
866
+ if (stickyUnit) {
867
+ runtimeUnits = [
868
+ stickyUnit,
869
+ ...runtimeUnits.filter((unit) => unit.executionKey !== stickyUnit.executionKey),
870
+ ];
871
+ unitExecutionStrategy = "priority";
872
+ }
873
+ }
874
+ if (strategy === "random") runtimeUnits = fisherYatesShuffle([...runtimeUnits]);
875
+ if (strategy === "strict-random") {
876
+ const key = await getNextFromDeck(
877
+ `combo:${combo.name}`,
878
+ runtimeUnits.map((unit) => unit.executionKey)
879
+ );
880
+ const selected = runtimeUnits.find((unit) => unit.executionKey === key) || runtimeUnits[0];
881
+ runtimeUnits = [
882
+ selected,
883
+ ...runtimeUnits.filter((unit) => unit.executionKey !== selected.executionKey),
884
+ ];
885
+ }
886
+ let runtimeStickyLimit: number | null = null;
887
+ let runtimeStickyTargets: ResolvedComboUnit[] = runtimeUnits;
888
+ if (strategy === "round-robin") {
889
+ const perComboStickyLimit = (config as Record<string, unknown>).stickyRoundRobinLimit;
890
+ runtimeStickyLimit = clampStickyRoundRobinTargetLimit(
891
+ perComboStickyLimit !== undefined && perComboStickyLimit !== null
892
+ ? perComboStickyLimit
893
+ : (settings as Record<string, unknown> | null)?.stickyRoundRobinLimit
894
+ );
895
+ const { startIndex, counter } = getStickyRoundRobinStartIndex(
896
+ combo.name,
897
+ runtimeUnits,
898
+ runtimeStickyLimit
899
+ );
900
+ if (runtimeStickyLimit <= 1) rrCounters.set(combo.name, counter + 1);
901
+ runtimeUnits = runtimeUnits.map(
902
+ (_, offset) => runtimeUnits[(startIndex + offset) % runtimeUnits.length]
903
+ );
904
+ runtimeStickyTargets = executeModeUnits;
905
+ }
906
+ const execution = await executeRuntimeUnitCombo({
907
+ body,
908
+ combo,
909
+ strategy: unitExecutionStrategy,
910
+ effectiveComboStrategy: strategy,
911
+ units: runtimeUnits,
912
+ handleSingleModel: handleSingleModelWithTimeout,
913
+ isModelAvailable,
914
+ log,
915
+ config,
916
+ settings,
917
+ allCombos,
918
+ signal,
919
+ nesting: nestingContext,
920
+ baseOptions: {
921
+ body,
922
+ combo,
923
+ handleSingleModel,
924
+ isModelAvailable,
925
+ log,
926
+ settings,
927
+ allCombos,
928
+ relayOptions,
929
+ signal,
930
+ apiKeyAllowedConnections,
931
+ },
932
+ runCombo: handleComboChat,
933
+ });
934
+ if (strategy === "weighted" && execution.response.ok && execution.unit) {
935
+ const stickyLimit = clampStickyWeightedTargetLimit(
936
+ (config as Record<string, unknown>).stickyWeightedLimit
937
+ );
938
+ if (stickyLimit > 1)
939
+ recordStickyWeightedSuccess(combo.name, execution.unit.executionKey, stickyLimit);
940
+ }
941
+ if (
942
+ strategy === "round-robin" &&
943
+ execution.response.ok &&
944
+ execution.unit &&
945
+ runtimeStickyLimit &&
946
+ runtimeStickyLimit > 1
947
+ ) {
948
+ recordStickyRoundRobinSuccess(
949
+ combo.name,
950
+ execution.unit,
951
+ runtimeStickyLimit,
952
+ runtimeStickyTargets
953
+ );
954
+ }
955
+ return execution.response;
956
+ }
957
+
958
+ // Route to round-robin handler if strategy matches
959
+ if (strategy === "round-robin") {
960
+ return handleRoundRobinCombo({
961
+ body,
962
+ combo,
963
+ handleSingleModel: handleSingleModelWithTimeout,
964
+ isModelAvailable,
965
+ log,
966
+ settings,
967
+ allCombos,
968
+ signal,
969
+ });
970
+ }
971
+
972
+ const maxRetries = config.maxRetries ?? 1;
973
+ const retryDelayMs = resolveDelayMs(config.retryDelayMs, 2000);
974
+ const fallbackDelayMs = resolveDelayMs(config.fallbackDelayMs, 0);
975
+ const maxSetRetries = config.maxSetRetries ?? 0;
976
+ const setRetryDelayMs = resolveDelayMs(config.setRetryDelayMs, 2000);
977
+
978
+ const isTargetSelectableForWeighted = async (target: ResolvedComboTarget): Promise<boolean> => {
979
+ const rawModel = parseModel(target.modelStr).model || target.modelStr;
980
+ if (target.provider && getCircuitBreaker(target.provider).getStatus().state === "OPEN")
981
+ return false;
982
+ if (
983
+ resilienceSettings.providerCooldown.enabled &&
984
+ Boolean(target.provider && target.provider !== "unknown") &&
985
+ isProviderInCooldown(target.provider, target.connectionId ?? undefined, resilienceSettings)
986
+ ) {
987
+ return false;
988
+ }
989
+ if (
990
+ target.provider &&
991
+ rawModel &&
992
+ isModelLocked(target.provider, target.connectionId || "", rawModel)
993
+ ) {
994
+ return false;
995
+ }
996
+ return isModelAvailable ? await isModelAvailable(target.modelStr, target) : true;
997
+ };
998
+
999
+ // #2562: Expand provider-wildcard steps (e.g. `fta/*`, `openai/gpt-4*`) into
1000
+ // concrete model entries sourced from the live synced-models catalog + registry.
1001
+ // Must run before any step-group / target resolution so that wildcard-originated
1002
+ // steps are treated identically to hand-authored entries by all downstream logic
1003
+ // (including the sticky-weighted eligibility pass below).
1004
+ const expandedCombo = await expandProviderWildcardsInCombo(combo);
1005
+ const expandedAllCombos = allCombos
1006
+ ? Array.isArray(allCombos)
1007
+ ? await expandProviderWildcardsInCollection(allCombos as ComboLike[])
1008
+ : {
1009
+ ...allCombos,
1010
+ combos: await expandProviderWildcardsInCollection(
1011
+ ((allCombos as { combos?: ComboLike[] }).combos || []) as ComboLike[]
1012
+ ),
1013
+ }
1014
+ : allCombos;
1015
+
1016
+ const stickyWeightedLimit = clampStickyWeightedTargetLimit(
1017
+ (config as Record<string, unknown>).stickyWeightedLimit
1018
+ );
1019
+ if (
1020
+ strategy === "weighted" &&
1021
+ !weightedStickyTargets.has(combo.name) &&
1022
+ weightedStickyTargets.size >= MAX_RR_COUNTERS
1023
+ ) {
1024
+ const oldest = weightedStickyTargets.keys().next().value;
1025
+ if (oldest !== undefined) weightedStickyTargets.delete(oldest);
1026
+ }
1027
+ let stepGroups: Array<{ step: ComboRuntimeStep; targets: ResolvedComboTarget[] }> | undefined;
1028
+ const weightedEligibleKeys = new Set<string>();
1029
+ if (strategy === "weighted") {
1030
+ stepGroups = resolveWeightedStepGroups(expandedCombo, expandedAllCombos);
1031
+ for (const group of stepGroups) {
1032
+ const availability = await Promise.all(group.targets.map(isTargetSelectableForWeighted));
1033
+ if (availability.some(Boolean)) weightedEligibleKeys.add(group.step.executionKey);
1034
+ }
1035
+ }
1036
+ const rawStickyWeightedKey =
1037
+ strategy === "weighted" ? getStickyWeightedExecutionKey(combo.name, stickyWeightedLimit) : null;
1038
+ const stickyWeightedKey =
1039
+ rawStickyWeightedKey && weightedEligibleKeys.has(rawStickyWeightedKey)
1040
+ ? rawStickyWeightedKey
1041
+ : null;
1042
+ if (strategy !== "weighted" || stickyWeightedLimit <= 1) {
1043
+ weightedStickyTargets.delete(combo.name);
1044
+ } else if (rawStickyWeightedKey && !stickyWeightedKey) {
1045
+ weightedStickyTargets.delete(combo.name);
1046
+ }
1047
+ const weightedResolution =
1048
+ strategy === "weighted"
1049
+ ? resolveWeightedTargets(
1050
+ expandedCombo,
1051
+ expandedAllCombos,
1052
+ stickyWeightedKey,
1053
+ weightedEligibleKeys,
1054
+ stepGroups
1055
+ )
1056
+ : null;
1057
+ const getWeightedStepKeyForTarget = (target: ResolvedComboTarget): string | null => {
1058
+ if (!weightedResolution?.orderedSteps) return null;
1059
+ const step = weightedResolution.orderedSteps.find(
1060
+ (entry) =>
1061
+ target.executionKey === entry.executionKey ||
1062
+ target.executionKey.startsWith(entry.executionKey + ">")
1063
+ );
1064
+ return step?.executionKey || null;
1065
+ };
1066
+ let orderedTargets =
1067
+ strategy === "weighted"
1068
+ ? weightedResolution?.orderedTargets || []
1069
+ : resolveComboTargets(
1070
+ expandedCombo,
1071
+ expandedAllCombos,
1072
+ clampComboDepth(config.maxComboDepth)
1073
+ );
1074
+
1075
+ orderedTargets = await applyRequestTagRouting(orderedTargets, body, log);
1076
+
1077
+ if (strategy === "weighted") {
1078
+ log.info(
1079
+ "COMBO",
1080
+ `Weighted selection${stickyWeightedKey ? " (sticky)" : ""}${allCombos ? " with nested resolution" : ""}: ${orderedTargets.length} total targets`
1081
+ );
1082
+ } else if (allCombos) {
1083
+ log.info("COMBO", `${strategy} with nested resolution: ${orderedTargets.length} total targets`);
1084
+ }
1085
+
1086
+ // Pipeline dispatch: route smart/pipeline-enabled combos through the multi-stage pipeline
1087
+ if (strategy === "auto") {
1088
+ const autoParsed = parseAutoPrefix(combo.name);
1089
+ const autoVariant = autoParsed.valid ? autoParsed.variant : undefined;
1090
+ if (autoVariant === "smart" || config.pipeline_enabled) {
1091
+ try {
1092
+ const pipelineRaw = await handlePipelineCombo({
1093
+ body,
1094
+ combo,
1095
+ handleChatCore: handleSingleModelWithTimeout,
1096
+ log: {
1097
+ info: log.info,
1098
+ warn: log.warn,
1099
+ error: log.error ?? log.warn,
1100
+ },
1101
+ settings: settings ?? {},
1102
+ signal: signal ?? undefined,
1103
+ });
1104
+ // handlePipelineCombo resolves to a PipelineResult (buffered text) or,
1105
+ // in the streaming-final-stage case, a Response. Callers downstream
1106
+ // (chat.ts → withSessionHeader) require a Response, so adapt the
1107
+ // PipelineResult here instead of leaking the raw object.
1108
+ return pipelineRaw instanceof Response
1109
+ ? pipelineRaw
1110
+ : buildPipelineResponse(pipelineRaw, body);
1111
+ } catch (pipelineErr) {
1112
+ const pipelineMsg = pipelineErr instanceof Error ? pipelineErr.message : "";
1113
+ if (pipelineMsg === "PIPELINE_DISABLED") {
1114
+ log.info("COMBO", "Pipeline disabled, falling through to standard auto routing");
1115
+ } else if (pipelineMsg === "PIPELINE_TOKEN_THRESHOLD") {
1116
+ log.info(
1117
+ "COMBO",
1118
+ "Pipeline skipped (prompt below token threshold), falling through to standard auto routing"
1119
+ );
1120
+ } else {
1121
+ log.warn("COMBO", "Pipeline dispatch failed, falling through to standard auto routing", {
1122
+ err: pipelineErr,
1123
+ });
1124
+ }
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ // #4945 regression guard: when an "auto" combo uses an EXPLICIT router
1130
+ // (routingStrategy lkgp/cost/etc, not the default "rules" scorer), that router
1131
+ // pins orderedTargets[0]. The task-aware reordering below must then refine only
1132
+ // the fallback order, never override the router's primary choice.
1133
+ let autoUsedExplicitRouter = false;
1134
+ if (strategy === "auto") {
1135
+ const autoResult = await resolveAutoStrategyOrder({
1136
+ orderedTargets,
1137
+ body,
1138
+ combo,
1139
+ settings,
1140
+ config,
1141
+ relayOptions,
1142
+ resilienceSettings,
1143
+ log,
1144
+ buildAutoCandidates,
1145
+ });
1146
+ if ("earlyResponse" in autoResult) return autoResult.earlyResponse;
1147
+ orderedTargets = autoResult.orderedTargets;
1148
+ autoUsedExplicitRouter = autoResult.autoUsedExplicitRouter;
1149
+ } else {
1150
+ orderedTargets = await applyStrategyOrdering(strategy, orderedTargets, {
1151
+ combo,
1152
+ config,
1153
+ body,
1154
+ log,
1155
+ apiKeyAllowedConnections,
1156
+ });
1157
+ }
1158
+ // #6168: session stickiness opt-out. Per-combo `config.disableSessionStickiness`
1159
+ // overrides the global `settings.disableSessionStickiness` fallback (default false,
1160
+ // preserving the #3825 prompt-cache/504 fix). When disabled, skip the reorder and
1161
+ // treat the result as a no-op so the recordStickyBinding write-back below is skipped.
1162
+ const disableSessionStickiness = resolveDisableSessionStickiness(
1163
+ config as Record<string, unknown> | null | undefined,
1164
+ settings as Record<string, unknown> | null | undefined
1165
+ );
1166
+ const _sticky = disableSessionStickiness
1167
+ ? ({ targets: orderedTargets, messageHash: null, stuck: false } as const)
1168
+ : await applySessionStickiness(
1169
+ orderedTargets,
1170
+ body.messages as Array<{ role?: string; content?: unknown }>
1171
+ );
1172
+ orderedTargets = _sticky.targets;
1173
+ orderedTargets = orderTargetsByEvalScores(orderedTargets, config.evalRouting, log);
1174
+ orderedTargets = filterTargetsByRequestCompatibility(orderedTargets, body, log);
1175
+
1176
+ // Task-aware reordering: only active for strategies ["smart","task","task-aware","task_aware","auto"].
1177
+ // Additive — does not affect any of the other 15 strategies.
1178
+ if (isTaskRoutingStrategy(strategy)) {
1179
+ const task = classifyTask(body);
1180
+ const conversationCacheKey = getConversationCacheKey(body);
1181
+ const taskReordered = reorderByTaskWeight(orderedTargets, task);
1182
+ // #4945 regression guard: when an explicit auto router (lkgp/cost/…) pinned
1183
+ // orderedTargets[0], keep that primary choice and let task-aware refine only
1184
+ // the fallback tail — otherwise task weighting silently defeats the operator's
1185
+ // chosen LKGP/cost selection. reorderByTaskWeight returns the same target
1186
+ // objects (no clone), so identity filtering is safe.
1187
+ const pinnedFirst = autoUsedExplicitRouter ? orderedTargets[0] : undefined;
1188
+ const nextOrder = pinnedFirst
1189
+ ? [pinnedFirst, ...taskReordered.filter((t) => t !== pinnedFirst)]
1190
+ : taskReordered;
1191
+ if (nextOrder[0]?.modelStr !== orderedTargets[0]?.modelStr) {
1192
+ const reasons =
1193
+ Array.isArray(task.reasons) && task.reasons.length > 0
1194
+ ? ` (${task.reasons.join(",")})`
1195
+ : "";
1196
+ log.info(
1197
+ "COMBO",
1198
+ `task-route task=${task.level}${reasons} cacheKey=${conversationCacheKey ?? "none"} → ${nextOrder[0]?.modelStr}`
1199
+ );
1200
+ }
1201
+ orderedTargets = nextOrder;
1202
+ }
1203
+
1204
+ // Parallel pre-screen: check provider profiles and model availability for all targets
1205
+ // Only runs for priority strategy where sequential checking causes latency
1206
+ const preScreenMap =
1207
+ strategy === "priority"
1208
+ ? await preScreenTargets(orderedTargets, isModelAvailable).catch(
1209
+ () => new Map<string, PreScreenResult>()
1210
+ )
1211
+ : new Map<string, PreScreenResult>();
1212
+
1213
+ // #5923 (Finding #4) — reset-window config for the shared per-target quota-
1214
+ // exhaustion cutoff below. The "auto" strategy already applies its own cutoff
1215
+ // via buildAutoCandidates/routableCandidates, so this only affects the other
1216
+ // 16 strategies (priority, weighted, etc.) that funnel through executeTarget.
1217
+ const quotaCutoffResetWindowConfig = resolveResetWindowConfig(config as Record<string, unknown>);
1218
+
1219
+ if (orderedTargets.length === 0) {
1220
+ return comboModelNotFoundResponse("Combo has no executable targets");
1221
+ }
1222
+
1223
+ scheduleShadowRouting(
1224
+ combo,
1225
+ config,
1226
+ body,
1227
+ resolveShadowTargets(combo, config, allCombos),
1228
+ handleSingleModel,
1229
+ isModelAvailable,
1230
+ strategy,
1231
+ log
1232
+ );
1233
+
1234
+ // G2: Collect execution keys registered by _registerExecutionCandidates above (auto strategy).
1235
+ // We snapshot them now so cleanup can happen after the attempt loop finishes.
1236
+ const _registeredExecutionKeys = orderedTargets.map((t) => t.executionKey).filter(Boolean);
1237
+
1238
+ let globalAttempts = 0;
1239
+
1240
+ // Quota-share cooldown-aware retry (Variante A). Only quota-share (qtSd/)
1241
+ // combos opt in: when the set loop would crystallize a 429 model_cooldown
1242
+ // because the target hit a SHORT transient cooldown, we wait it out and
1243
+ // re-run the whole set loop instead of propagating the 429. `globalAttempts`
1244
+ // persists across these waits so MAX_GLOBAL_ATTEMPTS still bounds total work.
1245
+ // The wait happens at the crystallization point. The only semaphore slot the
1246
+ // quota-share path may hold is the FASE 2.1 per-connection concurrency slot
1247
+ // (acquired once around dispatchWithCooldownRetry below); it is intentionally
1248
+ // kept across the wait so the account stays "busy", and is released by the
1249
+ // outer finally — not here.
1250
+ //
1251
+ // The set loop is wrapped in a small recursive closure rather than an extra
1252
+ // labelled `while (true)` so the loop body keeps its original indentation; a
1253
+ // wait+redispatch is a tail `return dispatchWithCooldownRetry()`, which
1254
+ // re-runs ONLY the set loop (selection / shadow routing / setup above stay
1255
+ // untouched), preserving the pre-existing `continue`-to-top-of-set-loop
1256
+ // semantics exactly.
1257
+ const comboCooldownWaitEnabled =
1258
+ strategy === "quota-share" && resilienceSettings.comboCooldownWait.enabled;
1259
+ let comboCooldownAttempt = 0;
1260
+ let comboCooldownBudgetLeftMs = resilienceSettings.comboCooldownWait.budgetMs;
1261
+
1262
+ // FASE 2.1: per-connection concurrency limit for quota-share. The gating in
1263
+ // selectQuotaShareTarget is fail-open and cannot hard-limit a single-connection
1264
+ // pool, so we serialize concurrent requests to the selected account through a
1265
+ // per-connection semaphore. Enabled only for quota-share combos (the cap is the
1266
+ // account's) and gated by the kill-switch; the slot wraps the whole dispatch.
1267
+ const quotaShareConcurrencyEnabled =
1268
+ strategy === "quota-share" && resilienceSettings.quotaShareConcurrencyLimit.enabled;
1269
+
1270
+ const dispatchWithCooldownRetry = async (): Promise<Response> => {
1271
+ for (let setTry = 0; setTry <= maxSetRetries; setTry++) {
1272
+ // #1731: Per-set-iteration set of providers whose quota is fully exhausted.
1273
+ // Reset each retry so providers excluded in a previous attempt get another chance.
1274
+ const exhaustedProviders = new Set<string>();
1275
+ const exhaustedConnections = new Set<string>();
1276
+ const transientRateLimitedProviders = new Set<string>();
1277
+ if (setTry > 0) {
1278
+ log.info("COMBO", `All targets failed — retrying set (${setTry}/${maxSetRetries})`);
1279
+ await new Promise((resolve) => {
1280
+ const timer = setTimeout(resolve, setRetryDelayMs);
1281
+ signal?.addEventListener(
1282
+ "abort",
1283
+ () => {
1284
+ clearTimeout(timer);
1285
+ resolve(undefined);
1286
+ },
1287
+ { once: true }
1288
+ );
1289
+ });
1290
+ if (signal?.aborted) {
1291
+ log.info("COMBO", "Client disconnected during set retry delay — aborting");
1292
+ return errorResponse(499, "Client disconnected");
1293
+ }
1294
+ }
1295
+
1296
+ let lastError: string | null = null;
1297
+ let earliestRetryAfter: ComboRetryAfter | null = null;
1298
+ let lastStatus: number | null = null;
1299
+ const startTime = Date.now();
1300
+ let fallbackCount = 0;
1301
+ let recordedAttempts = 0;
1302
+
1303
+ let globalResolve: ((res: Response) => void) | null = null;
1304
+ const globalPromise = new Promise<Response>((res) => {
1305
+ globalResolve = res;
1306
+ });
1307
+ const runningTasks = new Set<Promise<void>>();
1308
+ let anySuccess = false;
1309
+ const abortControllers = new Map<number, AbortController>();
1310
+ const zeroLatencyOptimizationsEnabled = config.zeroLatencyOptimizationsEnabled === true;
1311
+
1312
+ const executeTarget = async (
1313
+ i: number
1314
+ ): Promise<{ ok: boolean; response?: Response } | null> => {
1315
+ const target = orderedTargets[i];
1316
+ const modelStr = target.modelStr;
1317
+ const rawModel = parseModel(modelStr).model || modelStr;
1318
+ const provider = target.provider;
1319
+
1320
+ const cb = getCircuitBreaker(provider);
1321
+ if (cb.getStatus().state === "OPEN") {
1322
+ log.info("COMBO", `Skipping ${modelStr} — circuit breaker OPEN for ${provider}`);
1323
+ if (i > 0) fallbackCount++;
1324
+ return null;
1325
+ }
1326
+
1327
+ if (
1328
+ resilienceSettings.providerCooldown.enabled &&
1329
+ Boolean(provider && provider !== "unknown") &&
1330
+ isProviderInCooldown(provider, target.connectionId ?? undefined, resilienceSettings)
1331
+ ) {
1332
+ log.info("COMBO", `Skipping ${modelStr} — provider ${provider} in global cooldown`);
1333
+ if (i > 0) fallbackCount++;
1334
+ return null;
1335
+ }
1336
+
1337
+ // Use pre-screened profile if available, otherwise fetch on demand
1338
+ const preScreenEntry = preScreenMap.get(target.executionKey);
1339
+ const profile = preScreenEntry?.profile ?? (await getRuntimeProviderProfile(provider));
1340
+
1341
+ const allowRateLimitedConnection =
1342
+ Boolean(provider && provider !== "unknown") &&
1343
+ transientRateLimitedProviders.has(provider);
1344
+ const targetForAttempt = allowRateLimitedConnection
1345
+ ? {
1346
+ ...target,
1347
+ allowRateLimitedConnection: true,
1348
+ modelAbortSignal: abortControllers.get(i)!.signal,
1349
+ }
1350
+ : { ...target, modelAbortSignal: abortControllers.get(i)!.signal };
1351
+
1352
+ // #1731 / #1731v2: skip targets already known-exhausted this request (shared predicate).
1353
+ const exhaustedSkip = getExhaustedTargetSkipReason(
1354
+ target,
1355
+ exhaustedProviders,
1356
+ exhaustedConnections
1357
+ );
1358
+ if (exhaustedSkip) {
1359
+ log.info("COMBO", exhaustedSkip);
1360
+ if (i > 0) fallbackCount++;
1361
+ return null;
1362
+ }
1363
+
1364
+ // Pre-check: skip models locked by the resilience system (model-level lockout)
1365
+ if (provider && rawModel && isModelLocked(provider, target.connectionId || "", rawModel)) {
1366
+ log.info("COMBO", `Skipping ${modelStr} — model locked by resilience (cooldown active)`);
1367
+ if (i > 0) fallbackCount++;
1368
+ return null;
1369
+ }
1370
+
1371
+ // #5923 (Finding #4) — honor the same opt-in quota-exhaustion cutoff the
1372
+ // "auto" strategy already applies (buildAutoCandidates), for every other
1373
+ // strategy (priority, weighted, etc.). Strictly scoped per (provider,
1374
+ // connectionId): a 0%-remaining connection is skipped here, but sibling
1375
+ // connections/models on the same provider are untouched — the provider
1376
+ // circuit breaker is never touched by this check. The "auto" strategy is
1377
+ // excluded to avoid a redundant duplicate fetch — it already filtered its
1378
+ // candidate pool via `routableCandidates` before reaching this loop.
1379
+ if (strategy !== "auto" && provider && target.connectionId) {
1380
+ const quotaCutoff = await resolveQuotaExhaustionCutoffForTarget(
1381
+ provider,
1382
+ target.connectionId,
1383
+ resilienceSettings,
1384
+ quotaCutoffResetWindowConfig,
1385
+ combo.name,
1386
+ log
1387
+ );
1388
+ if (quotaCutoff.blocked) {
1389
+ log.info(
1390
+ "COMBO",
1391
+ `Skipping ${modelStr} — quota exhaustion cutoff (${quotaCutoff.reason || "quota_exhausted"})`
1392
+ );
1393
+ if (i > 0) fallbackCount++;
1394
+ return null;
1395
+ }
1396
+ }
1397
+
1398
+ // Pre-screen snapshot is NOT used as a permanent skip — availability
1399
+ // is always re-checked via isModelAvailable below because connection
1400
+ // cooldowns can expire between setTry retries, making a previously
1401
+ // unavailable target available again. Circuit-breaker-OPEN providers
1402
+ // are already caught by the dedicated breaker check above.
1403
+ if (isModelAvailable) {
1404
+ const available = await isModelAvailable(modelStr, targetForAttempt);
1405
+ if (!available) {
1406
+ log.debug?.(
1407
+ "COMBO",
1408
+ `Skipping ${modelStr} — no credentials available or model excluded`
1409
+ );
1410
+ if (i > 0) fallbackCount++;
1411
+ return null;
1412
+ }
1413
+ }
1414
+
1415
+ // Credential gate: skip targets with known-bad credentials (fail-fast)
1416
+ const connectionId = target.connectionId as string | undefined;
1417
+ if (connectionId) {
1418
+ const gateResult = checkCredentialGate(connectionId, provider, modelStr);
1419
+ if (gateResult.allowed === false) {
1420
+ logCredentialSkip(log, modelStr, gateResult.reason || "Credential gate blocked");
1421
+ if (i > 0) fallbackCount++;
1422
+ return null;
1423
+ }
1424
+ }
1425
+
1426
+ // Retry loop for transient errors
1427
+ for (let retry = 0; retry <= maxRetries; retry++) {
1428
+ // Fix #1681: Bail out immediately if the client has disconnected
1429
+ if (signal?.aborted) {
1430
+ log.info("COMBO", `Client disconnected — aborting combo loop before model ${modelStr}`);
1431
+ return { ok: false, response: errorResponse(499, "Client disconnected") };
1432
+ }
1433
+ globalAttempts++;
1434
+ if (globalAttempts > MAX_GLOBAL_ATTEMPTS) {
1435
+ log.warn(
1436
+ "COMBO",
1437
+ `Maximum combo attempts (${MAX_GLOBAL_ATTEMPTS}) exceeded across all targets and fallbacks. Terminating loop to prevent runaway background requests.`
1438
+ );
1439
+ return { ok: false, response: errorResponse(503, "Maximum combo retry limit reached") };
1440
+ }
1441
+
1442
+ // Predictive TTFT Circuit Breaker (skip slow models)
1443
+ if (
1444
+ zeroLatencyOptimizationsEnabled &&
1445
+ config.predictiveTtftMs &&
1446
+ config.predictiveTtftMs > 0 &&
1447
+ retry === 0
1448
+ ) {
1449
+ const cMetrics = getComboMetrics(combo.name);
1450
+ if (cMetrics) {
1451
+ const targetKey = orderedTargets[i].executionKey || modelStr;
1452
+ const m = cMetrics.byTarget[targetKey] || cMetrics.byModel[modelStr];
1453
+ if (shouldSkipForPredictedTtft(m, config.predictiveTtftMs)) {
1454
+ log.warn(
1455
+ "COMBO",
1456
+ `Predictive TTFT Circuit Breaker: skipping ${modelStr} (avg ${m.avgLatencyMs}ms > max ${config.predictiveTtftMs}ms)`
1457
+ );
1458
+ return null;
1459
+ }
1460
+ }
1461
+ }
1462
+
1463
+ if (retry > 0) {
1464
+ log.info(
1465
+ "COMBO",
1466
+ `Retrying ${modelStr} in ${retryDelayMs}ms (attempt ${retry + 1}/${maxRetries + 1})`
1467
+ );
1468
+ await new Promise((resolve) => {
1469
+ const timer = setTimeout(resolve, retryDelayMs);
1470
+ signal?.addEventListener(
1471
+ "abort",
1472
+ () => {
1473
+ clearTimeout(timer);
1474
+ resolve(undefined);
1475
+ },
1476
+ { once: true }
1477
+ );
1478
+ });
1479
+ if (signal?.aborted) {
1480
+ log.info("COMBO", `Client disconnected during retry delay — aborting`);
1481
+ return { ok: false, response: errorResponse(499, "Client disconnected") };
1482
+ }
1483
+ }
1484
+
1485
+ log.info(
1486
+ "COMBO",
1487
+ `Trying model ${i + 1}/${orderedTargets.length}: ${modelStr}${retry > 0 ? ` (retry ${retry})` : ""}`
1488
+ );
1489
+ emit("combo.target.attempt", {
1490
+ comboName: combo.name,
1491
+ targetIndex: i,
1492
+ provider,
1493
+ model: modelStr,
1494
+ timestamp: Date.now(),
1495
+ strategy,
1496
+ });
1497
+
1498
+ // Deep clone the body to ensure context preservation and prevent mutations
1499
+ // from affecting other targets in the combo. structuredClone avoids the
1500
+ // full intermediate JSON string that JSON.parse(JSON.stringify(...)) builds
1501
+ // (a second multi-hundred-KB allocation per target on large agent payloads),
1502
+ // halving the per-target transient heap on the hot path (#5152).
1503
+ let attemptBody = structuredClone(body);
1504
+
1505
+ // Proactive Context Compression for fallbacks (Zero-Latency optimization)
1506
+ if (
1507
+ zeroLatencyOptimizationsEnabled &&
1508
+ i > 0 &&
1509
+ config.fallbackCompressionMode &&
1510
+ config.fallbackCompressionMode !== "off"
1511
+ ) {
1512
+ const { estimateTokens } = await import("./contextManager.ts");
1513
+ const estimatedTokens = estimateTokens(JSON.stringify(attemptBody));
1514
+ if (estimatedTokens > (config.fallbackCompressionThreshold ?? 1000)) {
1515
+ const { applyCompression } = await import("./compression/strategySelector.ts");
1516
+ const compressionResult = applyCompression(
1517
+ attemptBody,
1518
+ config.fallbackCompressionMode as CompressionMode,
1519
+ // Opt into the TV1 bail-out so a throwing fallback engine is SKIPPED rather than
1520
+ // propagating out of executeTarget and being swallowed as a "Speculative task
1521
+ // error" (which silently drops this combo target). minGainPercent:0 keeps the
1522
+ // advance behavior identical to the default path — this only adds skip-on-throw.
1523
+ { model: modelStr, bailout: { enabled: true, minGainPercent: 0 } }
1524
+ );
1525
+ if (compressionResult.compressed) {
1526
+ log.info(
1527
+ "COMBO",
1528
+ `Proactive fallback compression applied (${config.fallbackCompressionMode}): ${estimatedTokens} -> ${compressionResult.stats?.compressedTokens} tokens`
1529
+ );
1530
+ attemptBody = compressionResult.body;
1531
+ }
1532
+ }
1533
+ }
1534
+
1535
+ // Universal handoff: inject existing handoff if model changed
1536
+ if (
1537
+ universalHandoffConfig.enabled &&
1538
+ relayOptions?.sessionId &&
1539
+ !(body as Record<string, unknown>)?.[SKIP_UNIVERSAL_HANDOFF_FLAG]
1540
+ ) {
1541
+ const lastModel = getLastSessionModel(relayOptions.sessionId, combo.name);
1542
+ if (lastModel && lastModel !== modelStr) {
1543
+ const existingHandoff = getHandoff(relayOptions.sessionId, combo.name);
1544
+ attemptBody = injectUniversalHandoffBody(
1545
+ attemptBody, // Use the cloned body to maintain isolation
1546
+ lastModel,
1547
+ modelStr,
1548
+ `Model routing: ${lastModel} → ${modelStr}`,
1549
+ existingHandoff
1550
+ );
1551
+ }
1552
+ }
1553
+
1554
+ // Issue #3587: Reasoning models can spend the whole output budget on
1555
+ // reasoning. Only add headroom when the complete buffer fits inside the
1556
+ // model's known output cap; otherwise preserve the client's explicit limit.
1557
+ {
1558
+ const bodyRecord = attemptBody as Record<string, unknown>;
1559
+ const currentMaxTokens = toPositiveInteger(bodyRecord.max_tokens);
1560
+ const bufferedMaxTokens = resolveReasoningBufferedMaxTokens(
1561
+ modelStr,
1562
+ bodyRecord.max_tokens,
1563
+ { enabled: reasoningTokenBufferEnabled }
1564
+ );
1565
+ if (currentMaxTokens !== null && bufferedMaxTokens !== null) {
1566
+ bodyRecord.max_tokens = bufferedMaxTokens;
1567
+ if (bufferedMaxTokens !== currentMaxTokens) {
1568
+ log.info(
1569
+ "COMBO",
1570
+ `Reasoning model ${modelStr}: adjusted max_tokens ${currentMaxTokens} -> ${bufferedMaxTokens}`
1571
+ );
1572
+ }
1573
+ }
1574
+ }
1575
+ const result = await handleSingleModelWithTimeout(attemptBody, modelStr, {
1576
+ ...targetForAttempt,
1577
+ effectiveComboStrategy: strategy,
1578
+ failoverBeforeRetry: config.failoverBeforeRetry,
1579
+ });
1580
+
1581
+ // Success — validate response quality before returning
1582
+ if (result.ok) {
1583
+ const selectedConnectionId =
1584
+ result.headers?.get("X-OmniRoute-Selected-Connection-Id") ||
1585
+ result.headers?.get("x-omniroute-selected-connection-id") ||
1586
+ undefined;
1587
+ const effectiveConnectionId = selectedConnectionId || target.connectionId || "";
1588
+
1589
+ // Clone BEFORE quality check — validateResponseQuality reads the body
1590
+ // via getReader() which locks the stream. The clone's body is consumed
1591
+ // by the quality check; the original stays unlocked for piping.
1592
+ let qualityClone: Response;
1593
+ try {
1594
+ qualityClone = result.clone();
1595
+ } catch {
1596
+ qualityClone = result;
1597
+ }
1598
+ const quality = await validateResponseQuality(
1599
+ qualityClone,
1600
+ clientRequestedStream,
1601
+ log,
1602
+ config.responseValidation
1603
+ );
1604
+ releaseQualityClone(qualityClone, result, quality);
1605
+ if (!quality.valid) {
1606
+ log.warn(
1607
+ "COMBO",
1608
+ `Model ${modelStr} returned 200 but failed quality check: ${quality.reason}`
1609
+ );
1610
+ recordComboRequest(combo.name, modelStr, {
1611
+ success: false,
1612
+ latencyMs: Date.now() - startTime,
1613
+ fallbackCount,
1614
+ strategy,
1615
+ target: toRecordedTarget(target),
1616
+ });
1617
+ recordedAttempts++;
1618
+ // Fix #1707: Set terminal state so the fallback doesn't emit
1619
+ // misleading ALL_ACCOUNTS_INACTIVE when the real issue is quality.
1620
+ lastError = `Upstream response failed quality validation: ${quality.reason}`;
1621
+ if (!lastStatus) lastStatus = 502;
1622
+ if (i > 0) fallbackCount++;
1623
+ if (provider && rawModel) {
1624
+ const mlSettings = resolveModelLockoutSettings(settings);
1625
+ if (mlSettings.enabled && mlSettings.errorCodes.includes(502)) {
1626
+ recordModelLockoutFailure(
1627
+ provider,
1628
+ target.connectionId || "",
1629
+ rawModel,
1630
+ "quality_failure",
1631
+ 502,
1632
+ mlSettings.baseCooldownMs,
1633
+ profile,
1634
+ {
1635
+ exactCooldownMs: mlSettings.useExponentialBackoff
1636
+ ? 0
1637
+ : mlSettings.baseCooldownMs,
1638
+ maxCooldownMs: mlSettings.maxCooldownMs,
1639
+ }
1640
+ );
1641
+ }
1642
+ }
1643
+ emit("combo.target.failed", {
1644
+ comboName: combo.name,
1645
+ targetIndex: i,
1646
+ provider,
1647
+ model: modelStr,
1648
+ error: `Quality: ${quality.reason}`,
1649
+ latencyMs: Date.now() - startTime,
1650
+ });
1651
+ return null;
1652
+ }
1653
+
1654
+ // Success decay: a healthy response walks the model's lockout failure
1655
+ // count back down (and eventually clears an expired lockout entirely).
1656
+ if (provider && rawModel) {
1657
+ const dcResult = decayModelFailureCount(provider, effectiveConnectionId, rawModel);
1658
+ if (dcResult.cleared) {
1659
+ log.info("COMBO", `Model ${modelStr} fully recovered — lockout cleared`);
1660
+ } else if (dcResult.newFailureCount > 0) {
1661
+ log.debug(
1662
+ "COMBO",
1663
+ `Model ${modelStr} decayed to failureCount=${dcResult.newFailureCount}`
1664
+ );
1665
+ }
1666
+ }
1667
+
1668
+ const latencyMs = Date.now() - startTime;
1669
+ emit("combo.target.succeeded", {
1670
+ comboName: combo.name,
1671
+ targetIndex: i,
1672
+ provider,
1673
+ model: modelStr,
1674
+ latencyMs,
1675
+ });
1676
+ log.info(
1677
+ "COMBO",
1678
+ `Model ${modelStr} succeeded (${latencyMs}ms, ${fallbackCount} fallbacks)`
1679
+ );
1680
+ recordComboRequest(combo.name, modelStr, {
1681
+ success: true,
1682
+ latencyMs,
1683
+ fallbackCount,
1684
+ strategy,
1685
+ target: toRecordedTarget(target),
1686
+ });
1687
+ recordedAttempts++;
1688
+
1689
+ // Reset cooldown on success
1690
+ if (provider && provider !== "unknown") {
1691
+ recordProviderSuccess(provider, effectiveConnectionId || undefined);
1692
+ }
1693
+ if (strategy === "weighted" && stickyWeightedLimit > 1) {
1694
+ const stickySuccessKey = getWeightedStepKeyForTarget(target);
1695
+ if (stickySuccessKey) {
1696
+ recordStickyWeightedSuccess(combo.name, stickySuccessKey, stickyWeightedLimit);
1697
+ }
1698
+ }
1699
+ // Webhook fan-out: best-effort, never blocks the response stream.
1700
+ notifyWebhookEvent("request.completed", {
1701
+ combo: combo.name,
1702
+ provider,
1703
+ model: modelStr,
1704
+ account:
1705
+ typeof target.label === "string" && target.label.trim().length > 0
1706
+ ? target.label.trim()
1707
+ : "",
1708
+ accountId: effectiveConnectionId ?? "",
1709
+ latencyMs,
1710
+ fallbackCount,
1711
+ });
1712
+
1713
+ // Context cache pinning: record model usage for session-based pinning
1714
+ // (independent of universal handoff — always fires when context_cache_protection is on)
1715
+ // #3825: write under the SAME effectiveSessionId used by the read site so a
1716
+ // sessionless conversation re-pins to this model on its next turn.
1717
+ if (
1718
+ combo.context_cache_protection &&
1719
+ effectiveSessionId &&
1720
+ !(body as Record<string, unknown>)?.[SKIP_UNIVERSAL_HANDOFF_FLAG]
1721
+ ) {
1722
+ recordSessionModelUsage(
1723
+ effectiveSessionId,
1724
+ combo.name,
1725
+ modelStr,
1726
+ provider,
1727
+ target.connectionId ?? undefined
1728
+ );
1729
+ }
1730
+
1731
+ // Universal handoff: record model usage for session
1732
+ if (
1733
+ universalHandoffConfig.enabled &&
1734
+ relayOptions?.sessionId &&
1735
+ !(body as Record<string, unknown>)?.[SKIP_UNIVERSAL_HANDOFF_FLAG]
1736
+ ) {
1737
+ const prevModel = getLastSessionModel(relayOptions.sessionId, combo.name);
1738
+ recordSessionModelUsage(
1739
+ relayOptions.sessionId,
1740
+ combo.name,
1741
+ modelStr,
1742
+ provider,
1743
+ target.connectionId ?? undefined
1744
+ );
1745
+ if (prevModel && prevModel !== modelStr) {
1746
+ const handoffSourceMessages =
1747
+ Array.isArray(body?.messages) && body.messages.length > 0
1748
+ ? body.messages
1749
+ : Array.isArray(body?.input)
1750
+ ? body.input
1751
+ : [];
1752
+
1753
+ maybeGenerateUniversalHandoff({
1754
+ sessionId: relayOptions.sessionId,
1755
+ comboName: combo.name,
1756
+ messages: handoffSourceMessages as MessageLike[],
1757
+ prevModel,
1758
+ currModel: modelStr,
1759
+ universalConfig: universalHandoffConfig,
1760
+ handleSingleModel: handleSingleModelWithTimeout,
1761
+ });
1762
+ }
1763
+
1764
+ recordSessionModelUsage(
1765
+ relayOptions.sessionId,
1766
+ combo.name,
1767
+ modelStr,
1768
+ provider,
1769
+ target.connectionId ?? undefined
1770
+ );
1771
+ }
1772
+ // Context-relay intentionally splits responsibilities:
1773
+ // combo.ts decides whether a successful turn should generate a handoff,
1774
+ // while chat.ts injects the handoff after the real connectionId is resolved.
1775
+ if (
1776
+ strategy === "context-relay" &&
1777
+ relayOptions?.sessionId &&
1778
+ relayConfig &&
1779
+ relayConfig.handoffProviders.includes(provider) &&
1780
+ provider === "codex"
1781
+ ) {
1782
+ const connectionId = getSessionConnection(relayOptions.sessionId);
1783
+ if (connectionId) {
1784
+ const quotaInfo = await fetchCodexQuota(connectionId).catch(() => null);
1785
+ if (quotaInfo) {
1786
+ const resetCandidates = [
1787
+ quotaInfo.windows?.session?.resetAt,
1788
+ quotaInfo.windows?.weekly?.resetAt,
1789
+ quotaInfo.resetAt,
1790
+ ]
1791
+ .filter(
1792
+ (value): value is string => typeof value === "string" && value.length > 0
1793
+ )
1794
+ .sort((a, b) => a.localeCompare(b));
1795
+ const handoffSourceMessages =
1796
+ Array.isArray(body?.messages) && body.messages.length > 0
1797
+ ? body.messages
1798
+ : Array.isArray(body?.input)
1799
+ ? body.input
1800
+ : [];
1801
+
1802
+ maybeGenerateHandoff({
1803
+ sessionId: relayOptions.sessionId,
1804
+ comboName: combo.name,
1805
+ connectionId,
1806
+ percentUsed: quotaInfo.percentUsed,
1807
+ messages: handoffSourceMessages,
1808
+ model: modelStr,
1809
+ expiresAt: resetCandidates[0] || null,
1810
+ config: relayConfig,
1811
+ handleSingleModel: handleSingleModelWithTimeout,
1812
+ });
1813
+ }
1814
+ }
1815
+ }
1816
+ if (_sticky.messageHash && target.connectionId)
1817
+ recordStickyBinding(_sticky.messageHash, target.connectionId); // LKGP (#919):
1818
+ if (provider) {
1819
+ const connId = effectiveConnectionId || undefined;
1820
+ void (async () => {
1821
+ try {
1822
+ const { setLKGP } = await import("../../src/lib/localDb");
1823
+ await Promise.all([
1824
+ setLKGP(combo.name, target.executionKey, provider, connId),
1825
+ setLKGP(combo.name, combo.id || combo.name, provider, connId),
1826
+ ]);
1827
+ } catch (err) {
1828
+ log.warn(
1829
+ "COMBO",
1830
+ "Failed to record Last Known Good Provider. This is non-fatal.",
1831
+ {
1832
+ err,
1833
+ }
1834
+ );
1835
+ }
1836
+ })();
1837
+ }
1838
+
1839
+ return { ok: true, response: result };
1840
+ }
1841
+
1842
+ // Extract error info from response
1843
+ let errorText = result.statusText || "";
1844
+ let errorBody: ComboErrorBody = null;
1845
+ let retryAfter: ComboRetryAfter | null = null;
1846
+ try {
1847
+ const cloned = result.clone();
1848
+ try {
1849
+ const text = await cloned.text();
1850
+ if (text) {
1851
+ errorText = text.substring(0, 500);
1852
+ errorBody = JSON.parse(text);
1853
+ const parsedError = errorBody?.error;
1854
+ errorText =
1855
+ (typeof parsedError === "object" && parsedError?.message) ||
1856
+ (typeof parsedError === "string" ? parsedError : null) ||
1857
+ errorBody?.message ||
1858
+ errorText;
1859
+ retryAfter = errorBody?.retryAfter || null;
1860
+ }
1861
+ } catch {
1862
+ /* Clone parse failed */
1863
+ }
1864
+ } catch {
1865
+ /* Clone failed */
1866
+ }
1867
+
1868
+ // Track earliest retryAfter
1869
+ if (
1870
+ retryAfter &&
1871
+ (!earliestRetryAfter || new Date(retryAfter) < new Date(earliestRetryAfter))
1872
+ ) {
1873
+ earliestRetryAfter = retryAfter;
1874
+ }
1875
+
1876
+ // Normalize error text
1877
+ if (typeof errorText !== "string") {
1878
+ try {
1879
+ errorText = JSON.stringify(errorText);
1880
+ } catch {
1881
+ errorText = String(errorText);
1882
+ }
1883
+ }
1884
+
1885
+ const isStreamReadinessFailure =
1886
+ (result.status === 502 || result.status === 504) &&
1887
+ isStreamReadinessFailureErrorBody(errorBody);
1888
+
1889
+ // FIX 5: a local per-API-key token-limit 429 must not cool shared accounts.
1890
+ const isTokenLimitBreach =
1891
+ result.status === 429 && isTokenLimitBreachErrorBody(errorBody);
1892
+
1893
+ // Fix #1681: Status 499 means client disconnected — stop combo loop immediately.
1894
+ // There is no point trying fallback models when nobody is listening.
1895
+ if (result.status === 499) {
1896
+ log.info("COMBO", `Client disconnected (499) during ${modelStr} — stopping combo loop`);
1897
+ recordComboRequest(combo.name, modelStr, {
1898
+ success: false,
1899
+ latencyMs: Date.now() - startTime,
1900
+ fallbackCount,
1901
+ strategy,
1902
+ target: toRecordedTarget(target),
1903
+ });
1904
+ recordedAttempts++;
1905
+ // executeTarget must return the {ok,response} contract — a raw Response
1906
+ // here makes the speculative loop's res.ok/res.response checks both miss,
1907
+ // so the combo would wrongly fall through to the next model after a 499.
1908
+ return { ok: false, response: result };
1909
+ }
1910
+
1911
+ // Combo fallback is target-level orchestration: a non-ok target response is
1912
+ // treated as local to that target and the combo continues to the next target.
1913
+ // Error classification is retained only for retry/cooldown pacing; it must
1914
+ // not decide whether fallback happens, including for generic 400 responses.
1915
+ const rawError = errorBody?.error;
1916
+ const structuredError =
1917
+ rawError && typeof rawError === "object"
1918
+ ? {
1919
+ // Upstream JSON may carry a numeric `code`/`type` (e.g. {"code":40001}).
1920
+ // Coerce to string if present instead of discarding, so downstream string
1921
+ // ops (.toLowerCase, .startsWith) can run safely without type crashes.
1922
+ code:
1923
+ (rawError as Record<string, unknown>).code !== undefined &&
1924
+ (rawError as Record<string, unknown>).code !== null
1925
+ ? String((rawError as Record<string, unknown>).code)
1926
+ : undefined,
1927
+ type:
1928
+ (rawError as Record<string, unknown>).type !== undefined &&
1929
+ (rawError as Record<string, unknown>).type !== null
1930
+ ? String((rawError as Record<string, unknown>).type)
1931
+ : undefined,
1932
+ }
1933
+ : undefined;
1934
+ const fallbackResult = checkFallbackError(
1935
+ result.status,
1936
+ errorText,
1937
+ 0,
1938
+ null,
1939
+ provider,
1940
+ result.headers,
1941
+ profile,
1942
+ structuredError
1943
+ );
1944
+ const { cooldownMs } = fallbackResult;
1945
+ const selectedConnectionId =
1946
+ result.headers?.get("X-OmniRoute-Selected-Connection-Id") ||
1947
+ result.headers?.get("x-omniroute-selected-connection-id") ||
1948
+ undefined;
1949
+ const targetWithConnection = selectedConnectionId
1950
+ ? { ...target, connectionId: selectedConnectionId }
1951
+ : target;
1952
+
1953
+ // #1731 / #1731v2: classify the upstream error and update the exhaustion sets
1954
+ // (shared with handleRoundRobinCombo). Returns whether the provider is fully exhausted.
1955
+ const providerExhausted = applyComboTargetExhaustion(targetWithConnection, {
1956
+ result,
1957
+ fallbackResult,
1958
+ errorText,
1959
+ rawModel,
1960
+ isTokenLimitBreach,
1961
+ allAccountsRateLimited: false,
1962
+ sets: { exhaustedProviders, exhaustedConnections, transientRateLimitedProviders },
1963
+ log,
1964
+ tag: "COMBO",
1965
+ exhaustedLogLevel: "info",
1966
+ structuredError,
1967
+ });
1968
+
1969
+ // #2101: Prevent infinite fallback loops with 400 Bad Request errors that are genuinely
1970
+ // body-specific (malformed JSON, bad format, missing required fields).
1971
+ // Context overflow and parameter validation errors are NOT body-specific:
1972
+ // - Context overflow: different models have different context windows
1973
+ // - Max_tokens / param errors: different models have different output limits
1974
+ // - Model access denied: different providers serve different model sets
1975
+ // These should fall through so the next combo target can try.
1976
+ if (
1977
+ result.status === 400 &&
1978
+ fallbackResult.shouldFallback &&
1979
+ !isContextOverflow400(errorText) &&
1980
+ !isParamValidation400(errorText) &&
1981
+ (errorText.toLowerCase().includes("context") ||
1982
+ errorText.toLowerCase().includes("prompt") ||
1983
+ errorText.toLowerCase().includes("token") ||
1984
+ errorText.toLowerCase().includes("malformed") ||
1985
+ errorText.toLowerCase().includes("invalid") ||
1986
+ errorText.toLowerCase().includes("bad request"))
1987
+ ) {
1988
+ log.warn(
1989
+ "COMBO",
1990
+ `400 Bad Request with body-specific error detected on ${modelStr} — skipping fallback to other targets to prevent infinite loop`
1991
+ );
1992
+ // Record the failure and break to avoid trying other targets with the same bad request
1993
+ recordComboRequest(combo.name, modelStr, {
1994
+ success: false,
1995
+ latencyMs: Date.now() - startTime,
1996
+ fallbackCount,
1997
+ strategy,
1998
+ target: toRecordedTarget(target),
1999
+ });
2000
+ recordedAttempts++;
2001
+ lastError = errorText || String(result.status);
2002
+ if (!lastStatus) lastStatus = result.status;
2003
+ if (i > 0) fallbackCount++;
2004
+ log.warn("COMBO", `Model ${modelStr} failed with body-specific error, stopping combo`);
2005
+ // #4279: surface the 400 via the {ok,response} contract so the OUTER
2006
+ // target loop resolves the combo and stops. A bare `break` here only
2007
+ // exits the inner retry loop; executeTarget then returns null, which
2008
+ // the outer loop treats as "this target produced nothing" and advances
2009
+ // to the next model — so the guard failed to stop fallback and a combo
2010
+ // of N body-rejecting targets tried all N. Mirrors the 499 path above.
2011
+ return { ok: false, response: result };
2012
+ }
2013
+
2014
+ // Trigger shared provider circuit breaker for 5xx errors and connection failures.
2015
+ // If the next target in the combo is on the same provider, don't mark the provider
2016
+ // as failed — different models on the same provider may still succeed.
2017
+ // G-02: when fallbackResult.skipProviderBreaker is set (embedded service supervisor
2018
+ // outage signalled via X-Omni-Fallback-Hint: connection_cooldown) apply connection
2019
+ // cooldown only — do NOT trip the whole-provider breaker.
2020
+ const nextTarget = orderedTargets[i + 1];
2021
+ const sameProviderNext =
2022
+ typeof nextTarget?.provider === "string" && nextTarget.provider === provider;
2023
+ if (
2024
+ shouldRecordProviderBreakerFailure({
2025
+ isStreamReadinessFailure,
2026
+ status: result.status,
2027
+ sameProviderNext,
2028
+ skipProviderBreaker: fallbackResult.skipProviderBreaker,
2029
+ })
2030
+ ) {
2031
+ recordProviderFailure(provider, log, targetWithConnection.connectionId, profile);
2032
+ }
2033
+
2034
+ // Check if this is a transient error worth retrying on same model.
2035
+ // A token-limit 429 is terminal for the client — never retry it.
2036
+ const isTransient =
2037
+ !isStreamReadinessFailure &&
2038
+ !isTokenLimitBreach &&
2039
+ [408, 429, 500, 502, 503, 504].includes(result.status);
2040
+ if (retry < maxRetries && isTransient && !providerExhausted) {
2041
+ if (
2042
+ provider &&
2043
+ rawModel &&
2044
+ isModelLocked(provider, targetWithConnection.connectionId || "", rawModel)
2045
+ ) {
2046
+ log.info("COMBO", `Skipping retry for ${modelStr} — model lockout active`);
2047
+ if (i > 0) fallbackCount++;
2048
+ return null;
2049
+ }
2050
+ // Record model lockout immediately on the first transient failure —
2051
+ // once the model is cooling down, retrying it would waste an upstream
2052
+ // call and extend the cooldown via exponential backoff.
2053
+ let lockoutRecorded = false;
2054
+ if (provider && rawModel && retry === 0) {
2055
+ const mlSettings = resolveModelLockoutSettings(settings);
2056
+ if (mlSettings.enabled && mlSettings.errorCodes.includes(result.status)) {
2057
+ recordModelLockoutFailure(
2058
+ provider,
2059
+ targetWithConnection.connectionId || "",
2060
+ rawModel,
2061
+ classifyLockoutReason(result.status),
2062
+ result.status,
2063
+ mlSettings.baseCooldownMs,
2064
+ profile,
2065
+ {
2066
+ // #1308: honor a long upstream reset (e.g. "Resets in 160h") over
2067
+ // the short base cooldown / exponential backoff when present.
2068
+ exactCooldownMs: selectLockoutCooldownMs(cooldownMs, mlSettings),
2069
+ maxCooldownMs: mlSettings.maxCooldownMs,
2070
+ }
2071
+ );
2072
+ lockoutRecorded = true;
2073
+ }
2074
+ }
2075
+ if (lockoutRecorded) {
2076
+ log.info("COMBO", `Skipping retry for ${modelStr} — model lockout active`);
2077
+ if (i > 0) fallbackCount++;
2078
+ return null;
2079
+ }
2080
+ continue; // Retry same model (transient error, no lockout recorded)
2081
+ }
2082
+
2083
+ // Done retrying this model
2084
+ recordComboRequest(combo.name, modelStr, {
2085
+ success: false,
2086
+ latencyMs: Date.now() - startTime,
2087
+ fallbackCount,
2088
+ strategy,
2089
+ target: toRecordedTarget(target),
2090
+ });
2091
+ recordedAttempts++;
2092
+ lastError = errorText || String(result.status);
2093
+ if (!lastStatus) lastStatus = result.status;
2094
+ if (i > 0) fallbackCount++;
2095
+ // Wire combo failures into the resilience dashboard (model-level lockout)
2096
+ // alongside the provider-level cooldown below — they govern different scopes.
2097
+ if (provider && rawModel) {
2098
+ const mlSettings = resolveModelLockoutSettings(settings);
2099
+ if (mlSettings.enabled && mlSettings.errorCodes.includes(result.status)) {
2100
+ recordModelLockoutFailure(
2101
+ provider,
2102
+ targetWithConnection.connectionId || "",
2103
+ rawModel,
2104
+ classifyLockoutReason(result.status),
2105
+ result.status,
2106
+ mlSettings.baseCooldownMs,
2107
+ profile,
2108
+ {
2109
+ // #1308: honor a long upstream reset over base/exponential cooldown.
2110
+ exactCooldownMs: selectLockoutCooldownMs(cooldownMs, mlSettings),
2111
+ maxCooldownMs: mlSettings.maxCooldownMs,
2112
+ }
2113
+ );
2114
+ }
2115
+ }
2116
+ log.warn("COMBO", `Model ${modelStr} failed, trying next`, { status: result.status });
2117
+
2118
+ // #5976: per-model-quota providers (Gemini, GitHub, etc.) multiplex models
2119
+ // behind one connection. A model-level 500 must NOT cool down the entire
2120
+ // provider — sibling models may still succeed. Skip cooldown recording for
2121
+ // these providers on 500 errors so the next target can try.
2122
+ if (
2123
+ resilienceSettings.providerCooldown.enabled &&
2124
+ provider &&
2125
+ provider !== "unknown" &&
2126
+ !(result.status === 500 && hasPerModelQuota(provider, rawModel))
2127
+ ) {
2128
+ recordProviderCooldown(
2129
+ provider,
2130
+ targetWithConnection.connectionId ?? undefined,
2131
+ resilienceSettings
2132
+ );
2133
+ }
2134
+
2135
+ const fallbackWaitMs =
2136
+ fallbackDelayMs > 0 && cooldownMs > 0 && cooldownMs <= MAX_FALLBACK_WAIT_MS
2137
+ ? Math.min(cooldownMs, fallbackDelayMs)
2138
+ : 0;
2139
+ if ([502, 503, 504].includes(result.status) && fallbackWaitMs > 0) {
2140
+ log.debug?.("COMBO", `Waiting ${fallbackWaitMs}ms before fallback to next model`);
2141
+ await new Promise((resolve) => {
2142
+ const timer = setTimeout(resolve, fallbackWaitMs);
2143
+ signal?.addEventListener(
2144
+ "abort",
2145
+ () => {
2146
+ clearTimeout(timer);
2147
+ resolve(undefined);
2148
+ },
2149
+ { once: true }
2150
+ );
2151
+ });
2152
+ if (signal?.aborted) {
2153
+ log.info("COMBO", `Client disconnected during fallback wait — aborting`);
2154
+ return { ok: false, response: errorResponse(499, "Client disconnected") };
2155
+ }
2156
+ }
2157
+
2158
+ return null;
2159
+ }
2160
+ return null;
2161
+ };
2162
+
2163
+ for (let i = 0; i < orderedTargets.length; i++) {
2164
+ if (anySuccess) break;
2165
+
2166
+ const abortController = new AbortController();
2167
+ abortControllers.set(i, abortController);
2168
+ const onClientAbort = () => abortController.abort();
2169
+ signal?.addEventListener("abort", onClientAbort);
2170
+
2171
+ const task = (async () => {
2172
+ try {
2173
+ const res = await executeTarget(i);
2174
+ if (res && !anySuccess) {
2175
+ if (res.ok) {
2176
+ anySuccess = true;
2177
+ globalResolve!(res.response!);
2178
+ for (const [idx, ac] of abortControllers.entries()) {
2179
+ if (idx !== i) ac.abort();
2180
+ }
2181
+ } else if (res.response) {
2182
+ // Fatal error, abort combo
2183
+ anySuccess = true;
2184
+ globalResolve!(res.response);
2185
+ }
2186
+ }
2187
+ } finally {
2188
+ signal?.removeEventListener("abort", onClientAbort);
2189
+ }
2190
+ })().catch((err) => {
2191
+ const logError = log.error ?? log.warn;
2192
+ logError("COMBO", `Speculative task error for target ${i}`, err);
2193
+ });
2194
+
2195
+ runningTasks.add(task);
2196
+ task.finally(() => runningTasks.delete(task));
2197
+
2198
+ if (zeroLatencyOptimizationsEnabled && config.hedging && i + 1 < orderedTargets.length) {
2199
+ const hedgeDelay = resolveDelayMs(config.hedgeDelayMs, 500);
2200
+ let timeoutResolve: () => void;
2201
+ const timeoutPromise = new Promise<void>((r) => {
2202
+ timeoutResolve = r;
2203
+ setTimeout(r, hedgeDelay);
2204
+ });
2205
+ await Promise.race([task, globalPromise, timeoutPromise]);
2206
+ } else {
2207
+ await Promise.race([task, globalPromise]);
2208
+ }
2209
+ }
2210
+
2211
+ if (!anySuccess && runningTasks.size > 0) {
2212
+ await Promise.race([globalPromise, Promise.all([...runningTasks])]);
2213
+ }
2214
+
2215
+ if (anySuccess) {
2216
+ return await globalPromise;
2217
+ }
2218
+
2219
+ // All models failed in this set try
2220
+ const latencyMs = Date.now() - startTime;
2221
+ if (recordedAttempts === 0) {
2222
+ recordComboRequest(combo.name, null, {
2223
+ success: false,
2224
+ latencyMs,
2225
+ fallbackCount,
2226
+ strategy,
2227
+ });
2228
+ }
2229
+
2230
+ // Retry the entire set if more attempts remain
2231
+ if (setTry < maxSetRetries) continue;
2232
+
2233
+ // All set retries exhausted — return the final error
2234
+ if (!lastStatus) {
2235
+ notifyWebhookEvent("request.failed", {
2236
+ combo: combo.name,
2237
+ reason: "ALL_ACCOUNTS_INACTIVE",
2238
+ latencyMs,
2239
+ fallbackCount,
2240
+ });
2241
+ return new Response(
2242
+ JSON.stringify({
2243
+ error: {
2244
+ message: "Service temporarily unavailable: all upstream accounts are inactive",
2245
+ type: "service_unavailable",
2246
+ code: "ALL_ACCOUNTS_INACTIVE",
2247
+ },
2248
+ }),
2249
+ { status: 503, headers: { "Content-Type": "application/json" } }
2250
+ );
2251
+ }
2252
+
2253
+ const status = lastStatus;
2254
+ const msg = lastError || "All combo models unavailable";
2255
+
2256
+ if (earliestRetryAfter) {
2257
+ // Quota-share cooldown-aware retry: instead of crystallizing the 429,
2258
+ // wait out a SHORT transient cooldown and re-run the whole set loop.
2259
+ // Guarded by the helper (quota_exhausted/auth/not-found excluded,
2260
+ // ceiling, attempts, budget). MAX_GLOBAL_ATTEMPTS still bounds total
2261
+ // dispatches.
2262
+ if (comboCooldownWaitEnabled && status === 429) {
2263
+ const decision = resolveComboCooldownWaitDecision({
2264
+ targets: orderedTargets,
2265
+ earliestRetryAfter,
2266
+ attempt: comboCooldownAttempt,
2267
+ budgetLeftMs: comboCooldownBudgetLeftMs,
2268
+ settings: resilienceSettings.comboCooldownWait,
2269
+ lookupLock: (provider, connectionId) => {
2270
+ const rawModel = parseModel(orderedTargets[0]?.modelStr ?? "").model || "";
2271
+ return getModelLockoutInfo(provider, connectionId, rawModel);
2272
+ },
2273
+ computeWaitMs: (retryAfter) => computeClosestRetryAfter(retryAfter).waitMs,
2274
+ });
2275
+ if (decision.wait) {
2276
+ log.info(
2277
+ "COMBO",
2278
+ `Quota-share cooldown wait: ${msg} — waiting ${Math.ceil(
2279
+ decision.waitMs / 1000
2280
+ )}s (reason=${decision.reason ?? "?"}) then retrying (attempt ${
2281
+ comboCooldownAttempt + 1
2282
+ }/${resilienceSettings.comboCooldownWait.maxAttempts})`
2283
+ );
2284
+ const completed = await waitForCooldownAwareRetry(decision.waitMs, signal);
2285
+ if (!completed) {
2286
+ log.info("COMBO", "Quota-share cooldown wait aborted by client disconnect");
2287
+ return errorResponse(499, "Request aborted");
2288
+ }
2289
+ comboCooldownAttempt += 1;
2290
+ comboCooldownBudgetLeftMs = Math.max(0, comboCooldownBudgetLeftMs - decision.waitMs);
2291
+ return dispatchWithCooldownRetry();
2292
+ }
2293
+ }
2294
+ const retryHuman = formatRetryAfter(toRetryAfterDisplayValue(earliestRetryAfter));
2295
+ log.warn("COMBO", `All models failed | ${msg} (${retryHuman})`);
2296
+ return unavailableResponse(status, msg, earliestRetryAfter, retryHuman);
2297
+ }
2298
+
2299
+ log.warn("COMBO", `All models failed | ${msg}`);
2300
+ return new Response(JSON.stringify({ error: { message: msg } }), {
2301
+ status,
2302
+ headers: { "Content-Type": "application/json" },
2303
+ });
2304
+ }
2305
+
2306
+ return errorResponse(503, "Combo routing completed without an upstream response");
2307
+ };
2308
+
2309
+ // FASE 2.1: acquire the per-connection concurrency slot for the selected
2310
+ // quota-share target once, around the whole dispatch (including any
2311
+ // cooldown-aware re-dispatch), so concurrent requests to one subscription
2312
+ // account are serialized through the connection's max_concurrent ceiling. The
2313
+ // cap is read fresh from the selected connection; a null cap (no limit) or a
2314
+ // saturated queue is a no-op (fail-open). Released in the finally below.
2315
+ let quotaShareConcurrencyRelease: (() => void) | null = null;
2316
+ const qsConnectionId = orderedTargets[0]?.connectionId;
2317
+ if (quotaShareConcurrencyEnabled && qsConnectionId) {
2318
+ const qsCap = await lookupPositiveCap(qsConnectionId);
2319
+ quotaShareConcurrencyRelease = await acquireQuotaShareConcurrencySlot(
2320
+ orderedTargets[0],
2321
+ qsCap,
2322
+ {
2323
+ queueTimeoutMs: config.queueTimeoutMs ?? 30000,
2324
+ maxQueueSize: resolveComboQueueDepth(config),
2325
+ },
2326
+ log
2327
+ );
2328
+ }
2329
+
2330
+ try {
2331
+ return await dispatchWithCooldownRetry();
2332
+ } finally {
2333
+ quotaShareConcurrencyRelease?.();
2334
+ // G2: Clean up candidate registry to prevent unbounded memory growth.
2335
+ _unregisterExecutionCandidates(_registeredExecutionKeys);
2336
+ }
2337
+ }
2338
+
2339
+ /**
2340
+ * Handle round-robin combo: each request goes to the next model in circular order.
2341
+ * Uses semaphore-based concurrency control with queue + rate-limit awareness.
2342
+ *
2343
+ * Flow:
2344
+ * 1. Pick target model via atomic counter (counter % models.length)
2345
+ * 2. Acquire semaphore slot (may queue if at max concurrency)
2346
+ * 3. Send request to target model
2347
+ * 4. On 429 → mark model rate-limited, try next model in rotation
2348
+ * 5. On semaphore timeout → fallback to next available model
2349
+ */
2350
+ async function handleRoundRobinCombo({
2351
+ body,
2352
+ combo,
2353
+ handleSingleModel,
2354
+ isModelAvailable,
2355
+ log,
2356
+ settings,
2357
+ allCombos,
2358
+ signal,
2359
+ }: HandleRoundRobinOptions): Promise<Response> {
2360
+ const config = settings
2361
+ ? resolveComboConfig(combo, settings)
2362
+ : { ...getDefaultComboConfig(), ...(combo.config || {}) };
2363
+ const concurrency = config.concurrencyPerModel ?? 3;
2364
+ // Honor each target connection's own maxConcurrent ceiling (cached per dispatch)
2365
+ // so a low-concurrency subscription account is not flooded; falls back to the
2366
+ // combo-level concurrency when the connection has no positive cap.
2367
+ const resolveTargetConcurrency = makeConnectionConcurrencyResolver(concurrency);
2368
+ const queueTimeout = config.queueTimeoutMs ?? 30000;
2369
+ // #3872: pre-cascade queue depth — lower values fail over to the next combo member
2370
+ // sooner under concurrency saturation (0 = never queue). Default 20 (backward-compat).
2371
+ const queueDepth = resolveComboQueueDepth(config);
2372
+ const maxRetries = config.maxRetries ?? 1;
2373
+ const retryDelayMs = resolveDelayMs(config.retryDelayMs, 2000);
2374
+ const fallbackDelayMs = resolveDelayMs(config.fallbackDelayMs, 0);
2375
+ const reasoningTokenBufferEnabled = config.reasoningTokenBufferEnabled !== false;
2376
+
2377
+ const resilienceSettings: ResilienceSettings = settings
2378
+ ? resolveResilienceSettings(settings)
2379
+ : resolveResilienceSettings(null);
2380
+
2381
+ // #2562: Expand provider-wildcard steps before resolving targets.
2382
+ const rrExpandedCombo = await expandProviderWildcardsInCombo(combo);
2383
+ const rrExpandedAllCombos = allCombos
2384
+ ? Array.isArray(allCombos)
2385
+ ? await expandProviderWildcardsInCollection(allCombos as ComboLike[])
2386
+ : {
2387
+ ...allCombos,
2388
+ combos: await expandProviderWildcardsInCollection(
2389
+ ((allCombos as { combos?: ComboLike[] }).combos || []) as ComboLike[]
2390
+ ),
2391
+ }
2392
+ : allCombos;
2393
+
2394
+ const orderedTargets = resolveComboTargets(
2395
+ rrExpandedCombo,
2396
+ rrExpandedAllCombos,
2397
+ clampComboDepth(config.maxComboDepth)
2398
+ );
2399
+ const tagFilteredTargets = await applyRequestTagRouting(orderedTargets, body, log);
2400
+ const evalRankedTargets = orderTargetsByEvalScores(tagFilteredTargets, config.evalRouting, log);
2401
+ const filteredTargets = filterTargetsByRequestCompatibility(
2402
+ evalRankedTargets,
2403
+ body,
2404
+ log,
2405
+ "Context-aware round-robin fallback"
2406
+ );
2407
+ // #6238: keep the targets the compat pre-filter rejected so they can serve as a
2408
+ // last-resort fallback tier. The pre-filter drops request-incompatible targets
2409
+ // BEFORE availability is known; if every compat-kept target then turns out to be
2410
+ // runtime-unavailable, we must reconsider these before returning 503, instead of
2411
+ // permanently dropping a compat-rejected-but-healthy provider.
2412
+ const compatKeptSet = new Set(filteredTargets);
2413
+ const compatRejectedTargets = evalRankedTargets.filter(
2414
+ (target) => !compatKeptSet.has(target)
2415
+ );
2416
+ const modelCount = filteredTargets.length;
2417
+ if (modelCount === 0) {
2418
+ return comboModelNotFoundResponse("Round-robin combo has no executable targets");
2419
+ }
2420
+
2421
+ scheduleShadowRouting(
2422
+ combo,
2423
+ config,
2424
+ body,
2425
+ resolveShadowTargets(combo, config, allCombos),
2426
+ handleSingleModel,
2427
+ isModelAvailable,
2428
+ "round-robin",
2429
+ log
2430
+ );
2431
+
2432
+ // Sticky batch size at the combo level. A per-combo `stickyRoundRobinLimit` (in
2433
+ // combo.config, resolved through the cascade) overrides the global setting so one
2434
+ // combo can batch differently from the default. When the per-combo value is unset,
2435
+ // fall back to the global `stickyRoundRobinLimit` so the existing knob still controls
2436
+ // sticky batching for both account fallback and combo targets. Values <= 1 preserve
2437
+ // the historical one-request-per-target rotation.
2438
+ const perComboStickyLimit = (config as Record<string, unknown>).stickyRoundRobinLimit;
2439
+ const stickyLimit = clampStickyRoundRobinTargetLimit(
2440
+ perComboStickyLimit !== undefined && perComboStickyLimit !== null
2441
+ ? perComboStickyLimit
2442
+ : (settings as Record<string, unknown> | null)?.stickyRoundRobinLimit
2443
+ );
2444
+ const stickyRoundRobinEnabled = stickyLimit > 1;
2445
+ // Exhaustion-aware sticky: if the currently sticky target is no longer
2446
+ // available (circuit breaker OPEN, provider cooldown, model lockout, or
2447
+ // isModelAvailable returns false), clear the sticky record so the rotation
2448
+ // starts at the counter position instead of probing a dead target.
2449
+ if (stickyRoundRobinEnabled) {
2450
+ const sticky = rrStickyTargets.get(combo.name);
2451
+ if (sticky) {
2452
+ const stickyTarget = filteredTargets.find(
2453
+ (target) => target.executionKey === sticky.executionKey
2454
+ );
2455
+ if (stickyTarget) {
2456
+ const rawModel = parseModel(stickyTarget.modelStr).model || stickyTarget.modelStr;
2457
+ const stickyAvailable =
2458
+ (!stickyTarget.provider ||
2459
+ getCircuitBreaker(stickyTarget.provider).getStatus().state !== "OPEN") &&
2460
+ !(
2461
+ resilienceSettings.providerCooldown.enabled &&
2462
+ Boolean(stickyTarget.provider && stickyTarget.provider !== "unknown") &&
2463
+ isProviderInCooldown(
2464
+ stickyTarget.provider,
2465
+ stickyTarget.connectionId ?? undefined,
2466
+ resilienceSettings
2467
+ )
2468
+ ) &&
2469
+ !(
2470
+ stickyTarget.provider &&
2471
+ rawModel &&
2472
+ isModelLocked(stickyTarget.provider, stickyTarget.connectionId || "", rawModel)
2473
+ ) &&
2474
+ (isModelAvailable ? await isModelAvailable(stickyTarget.modelStr, stickyTarget) : true);
2475
+ if (!stickyAvailable) {
2476
+ log.info(
2477
+ "COMBO-RR",
2478
+ `Clearing stale sticky target ${stickyTarget.modelStr} — unavailable`
2479
+ );
2480
+ rrStickyTargets.delete(combo.name);
2481
+ }
2482
+ }
2483
+ }
2484
+ }
2485
+ if (
2486
+ !rrCounters.has(combo.name) &&
2487
+ !rrStickyTargets.has(combo.name) &&
2488
+ rrCounters.size >= MAX_RR_COUNTERS
2489
+ ) {
2490
+ const oldest = rrCounters.keys().next().value;
2491
+ if (oldest !== undefined) {
2492
+ rrCounters.delete(oldest);
2493
+ rrStickyTargets.delete(oldest);
2494
+ }
2495
+ }
2496
+ // Ensure rrCounters has an entry for this combo so the eviction logic above
2497
+ // applies to both maps even when sticky round-robin is enabled (in which
2498
+ // case rrCounters isn't incremented per request).
2499
+ if (!rrCounters.has(combo.name)) {
2500
+ rrCounters.set(combo.name, 0);
2501
+ }
2502
+ const { startIndex, counter } = getStickyRoundRobinStartIndex(
2503
+ combo.name,
2504
+ filteredTargets,
2505
+ stickyLimit
2506
+ );
2507
+ if (!stickyRoundRobinEnabled) {
2508
+ rrCounters.set(combo.name, counter + 1);
2509
+ }
2510
+
2511
+ // #3825: per-conversation session stickiness for round-robin. weighted/priority honor a
2512
+ // sticky connection via applySessionStickiness, but this RR handler returns before that
2513
+ // call — so sessionless RR combos rotated every turn, busting the upstream prompt-cache.
2514
+ // Reuse the SAME mechanism: start the rotation at the conversation's sticky connection
2515
+ // (the loop still falls through to the other targets on failure → failover preserved).
2516
+ // #6168: honor the session-stickiness opt-out here too, otherwise round-robin would
2517
+ // still pin the conversation even when the flag is set. Per-combo `config` overrides
2518
+ // the global `settings.disableSessionStickiness` fallback (default false).
2519
+ const disableSessionStickiness = resolveDisableSessionStickiness(
2520
+ config as Record<string, unknown> | null | undefined,
2521
+ settings as Record<string, unknown> | null | undefined
2522
+ );
2523
+ const _rrSessionSticky = disableSessionStickiness
2524
+ ? ({ targets: filteredTargets, messageHash: null, stuck: false } as const)
2525
+ : await applySessionStickiness(
2526
+ filteredTargets,
2527
+ body?.messages as Array<{ role?: string; content?: unknown }>
2528
+ );
2529
+ let rrStartIndex = startIndex;
2530
+ if (_rrSessionSticky.stuck) {
2531
+ const stickyIdx = filteredTargets.findIndex(
2532
+ (t) => t.connectionId === _rrSessionSticky.targets[0]?.connectionId
2533
+ );
2534
+ if (stickyIdx >= 0) rrStartIndex = stickyIdx;
2535
+ }
2536
+
2537
+ const clientRequestedStream = body?.stream === true;
2538
+ const startTime = Date.now();
2539
+ let lastError: string | null = null;
2540
+ let lastStatus: number | null = null;
2541
+ let earliestRetryAfter: ComboRetryAfter | null = null;
2542
+ let globalAttempts = 0;
2543
+ let fallbackCount = 0;
2544
+ let recordedAttempts = 0;
2545
+
2546
+ // #1731: Per-request in-memory set of providers whose quota is fully exhausted.
2547
+ // When a target returns a quota-exhausted 429, remaining targets from the same
2548
+ // provider are skipped to avoid the cascade through N same-provider targets.
2549
+ const exhaustedProviders = new Set<string>();
2550
+ const exhaustedConnections = new Set<string>();
2551
+ const transientRateLimitedProviders = new Set<string>();
2552
+
2553
+ // Try each model starting from the round-robin target
2554
+ for (let offset = 0; offset < modelCount; offset++) {
2555
+ const modelIndex = (rrStartIndex + offset) % modelCount;
2556
+ const target = filteredTargets[modelIndex];
2557
+ const modelStr = target.modelStr;
2558
+ const provider = target.provider;
2559
+ const profile = await getRuntimeProviderProfile(provider);
2560
+ const semaphoreKey = `combo:${combo.name}:${target.executionKey}`;
2561
+ const allowRateLimitedConnection =
2562
+ Boolean(provider && provider !== "unknown") && transientRateLimitedProviders.has(provider);
2563
+ const targetForAttempt = allowRateLimitedConnection
2564
+ ? { ...target, allowRateLimitedConnection: true }
2565
+ : target;
2566
+
2567
+ // Pre-check availability
2568
+ if (isModelAvailable) {
2569
+ const available = await isModelAvailable(modelStr, targetForAttempt);
2570
+ if (!available) {
2571
+ log.debug?.(
2572
+ "COMBO-RR",
2573
+ `Skipping ${modelStr} — no credentials available or model excluded`
2574
+ );
2575
+ if (offset > 0) fallbackCount++;
2576
+ continue;
2577
+ }
2578
+ }
2579
+
2580
+ if (
2581
+ resilienceSettings.providerCooldown.enabled &&
2582
+ Boolean(provider && provider !== "unknown") &&
2583
+ isProviderInCooldown(provider, target.connectionId as string | undefined, resilienceSettings)
2584
+ ) {
2585
+ log.info("COMBO-RR", `Skipping ${modelStr} — provider ${provider} in global cooldown`);
2586
+ if (offset > 0) fallbackCount++;
2587
+ continue;
2588
+ }
2589
+
2590
+ // #1731 / #1731v2: skip targets already known-exhausted this request (shared predicate).
2591
+ const exhaustedSkip = getExhaustedTargetSkipReason(
2592
+ target,
2593
+ exhaustedProviders,
2594
+ exhaustedConnections
2595
+ );
2596
+ if (exhaustedSkip) {
2597
+ log.info("COMBO-RR", exhaustedSkip);
2598
+ if (offset > 0) fallbackCount++;
2599
+ continue;
2600
+ }
2601
+
2602
+ // Acquire semaphore slot (may wait in queue). Honor the connection's own
2603
+ // maxConcurrent cap when set; else fall back to the combo-level concurrency.
2604
+ const targetConcurrency = await resolveTargetConcurrency(target.connectionId);
2605
+ let release: () => void;
2606
+ try {
2607
+ release = await semaphore.acquire(semaphoreKey, {
2608
+ maxConcurrency: targetConcurrency,
2609
+ timeoutMs: queueTimeout,
2610
+ maxQueueSize: queueDepth,
2611
+ });
2612
+ } catch (err) {
2613
+ const errCode = isRecord(err) && typeof err.code === "string" ? err.code : null;
2614
+ if (errCode === "SEMAPHORE_TIMEOUT" || errCode === "SEMAPHORE_QUEUE_FULL") {
2615
+ log.warn(
2616
+ "COMBO-RR",
2617
+ `Semaphore ${errCode === "SEMAPHORE_QUEUE_FULL" ? "queue full" : "timeout"} for ${modelStr}, trying next model`
2618
+ );
2619
+ if (offset > 0) fallbackCount++;
2620
+ continue;
2621
+ }
2622
+ throw err;
2623
+ }
2624
+
2625
+ // Retry loop within this model
2626
+ try {
2627
+ for (let retry = 0; retry <= maxRetries; retry++) {
2628
+ globalAttempts++;
2629
+ if (globalAttempts > MAX_GLOBAL_ATTEMPTS) {
2630
+ log.warn(
2631
+ "COMBO-RR",
2632
+ `Maximum combo attempts (${MAX_GLOBAL_ATTEMPTS}) exceeded. Terminating loop to prevent runaway requests.`
2633
+ );
2634
+ return errorResponse(503, "Maximum combo retry limit reached");
2635
+ }
2636
+ if (retry > 0) {
2637
+ log.info(
2638
+ "COMBO-RR",
2639
+ `Retrying ${modelStr} in ${retryDelayMs}ms (attempt ${retry + 1}/${maxRetries + 1})`
2640
+ );
2641
+ await new Promise((r) => setTimeout(r, retryDelayMs));
2642
+ }
2643
+
2644
+ log.info(
2645
+ "COMBO-RR",
2646
+ `[RR #${counter}] → ${modelStr}${offset > 0 ? ` (fallback +${offset})` : ""}${retry > 0 ? ` (retry ${retry})` : ""}`
2647
+ );
2648
+
2649
+ // Issue #3587: Reasoning models can spend the whole output budget on
2650
+ // reasoning. Apply any safe buffer to a per-attempt copy so round-robin
2651
+ // retries never compound across models.
2652
+ let attemptBody = body;
2653
+ {
2654
+ const bodyRecord = body as Record<string, unknown>;
2655
+ const currentMaxTokens = toPositiveInteger(bodyRecord.max_tokens);
2656
+ const bufferedMaxTokens = resolveReasoningBufferedMaxTokens(
2657
+ modelStr,
2658
+ bodyRecord.max_tokens,
2659
+ { enabled: reasoningTokenBufferEnabled }
2660
+ );
2661
+ if (
2662
+ currentMaxTokens !== null &&
2663
+ bufferedMaxTokens !== null &&
2664
+ bufferedMaxTokens !== currentMaxTokens
2665
+ ) {
2666
+ attemptBody = {
2667
+ ...bodyRecord,
2668
+ max_tokens: bufferedMaxTokens,
2669
+ } as typeof body;
2670
+ log.info(
2671
+ "COMBO-RR",
2672
+ `Reasoning model ${modelStr}: adjusted max_tokens ${currentMaxTokens} -> ${bufferedMaxTokens}`
2673
+ );
2674
+ }
2675
+ }
2676
+
2677
+ const result = await handleSingleModel(attemptBody, modelStr, {
2678
+ ...targetForAttempt,
2679
+ effectiveComboStrategy: "round-robin",
2680
+ failoverBeforeRetry: config.failoverBeforeRetry,
2681
+ });
2682
+
2683
+ // Success — validate response quality before returning
2684
+ if (result.ok) {
2685
+ let rrClone: Response;
2686
+ try {
2687
+ rrClone = result.clone();
2688
+ } catch {
2689
+ rrClone = result;
2690
+ }
2691
+ const quality = await validateResponseQuality(
2692
+ rrClone,
2693
+ clientRequestedStream,
2694
+ log,
2695
+ config.responseValidation
2696
+ );
2697
+ releaseQualityClone(rrClone, result, quality);
2698
+ if (!quality.valid) {
2699
+ log.warn(
2700
+ "COMBO-RR",
2701
+ `${modelStr} returned 200 but failed quality check: ${quality.reason}`
2702
+ );
2703
+ recordComboRequest(combo.name, modelStr, {
2704
+ success: false,
2705
+ latencyMs: Date.now() - startTime,
2706
+ fallbackCount,
2707
+ strategy: "round-robin",
2708
+ target: toRecordedTarget(target),
2709
+ });
2710
+ recordedAttempts++;
2711
+ // Fix #1707: Set terminal state so the fallback doesn't emit
2712
+ // misleading ALL_ACCOUNTS_INACTIVE when the real issue is quality.
2713
+ lastError = `Upstream response failed quality validation: ${quality.reason}`;
2714
+ if (!lastStatus) lastStatus = 502;
2715
+ if (offset > 0) fallbackCount++;
2716
+ break; // move to next model
2717
+ }
2718
+ const latencyMs = Date.now() - startTime;
2719
+ log.info(
2720
+ "COMBO-RR",
2721
+ `${modelStr} succeeded (${latencyMs}ms, ${fallbackCount} fallbacks)`
2722
+ );
2723
+ recordComboRequest(combo.name, modelStr, {
2724
+ success: true,
2725
+ latencyMs,
2726
+ fallbackCount,
2727
+ strategy: "round-robin",
2728
+ target: toRecordedTarget(target),
2729
+ });
2730
+ recordedAttempts++;
2731
+
2732
+ const selectedConnectionId =
2733
+ result.headers?.get("X-OmniRoute-Selected-Connection-Id") ||
2734
+ result.headers?.get("x-omniroute-selected-connection-id") ||
2735
+ undefined;
2736
+ const effectiveConnectionId = selectedConnectionId || target.connectionId || "";
2737
+
2738
+ const rawModel = parseModel(modelStr).model || modelStr;
2739
+ if (provider && rawModel) {
2740
+ const dcResult = decayModelFailureCount(provider, effectiveConnectionId, rawModel);
2741
+ if (dcResult.cleared) {
2742
+ log.info("COMBO-RR", `Model ${modelStr} fully recovered — lockout cleared`);
2743
+ } else if (dcResult.newFailureCount > 0) {
2744
+ log.debug?.(
2745
+ "COMBO-RR",
2746
+ `Model ${modelStr} decayed to failureCount=${dcResult.newFailureCount}`
2747
+ );
2748
+ }
2749
+ }
2750
+
2751
+ if (provider && provider !== "unknown") {
2752
+ recordProviderSuccess(provider, effectiveConnectionId || undefined);
2753
+ }
2754
+
2755
+ if (stickyRoundRobinEnabled) {
2756
+ recordStickyRoundRobinSuccess(combo.name, target, stickyLimit, filteredTargets);
2757
+ } else {
2758
+ // #948: true round-robin (stickyLimit <= 1). The counter was advanced
2759
+ // eagerly (+1 from the scheduled start index) before this loop ran, so
2760
+ // when the scheduled model failed and a *different* model served via
2761
+ // fallback, the next request reused the fallback-served model. Advance
2762
+ // the pointer past the model that ACTUALLY served (modelIndex) instead,
2763
+ // mirroring recordStickyRoundRobinSuccess's served-index logic. Read
2764
+ // side applies `% modelCount`, so storing modelIndex + 1 is correct.
2765
+ rrCounters.set(combo.name, modelIndex + 1);
2766
+ }
2767
+
2768
+ // #3825: (re)record the sticky binding so the next turn re-pins (prompt-cache).
2769
+ if (_rrSessionSticky.messageHash) {
2770
+ const stickyConn = effectiveConnectionId || target.connectionId;
2771
+ if (stickyConn) recordStickyBinding(_rrSessionSticky.messageHash, stickyConn);
2772
+ }
2773
+
2774
+ if (provider) {
2775
+ const connId = effectiveConnectionId || undefined;
2776
+ void (async () => {
2777
+ try {
2778
+ const { setLKGP } = await import("../../src/lib/localDb");
2779
+ await Promise.all([
2780
+ setLKGP(combo.name, target.executionKey, provider, connId),
2781
+ setLKGP(combo.name, combo.id || combo.name, provider, connId),
2782
+ ]);
2783
+ } catch (err) {
2784
+ log.warn(
2785
+ "COMBO-RR",
2786
+ "Failed to record Last Known Good Provider. This is non-fatal.",
2787
+ {
2788
+ err,
2789
+ }
2790
+ );
2791
+ }
2792
+ })();
2793
+ }
2794
+ // Clone is consumed by quality check; original stays unlocked.
2795
+ return result;
2796
+ }
2797
+
2798
+ // Extract error info
2799
+ let errorText = result.statusText || "";
2800
+ let retryAfter: ComboRetryAfter | null = null;
2801
+ let errorBody: ComboErrorBody = null;
2802
+ try {
2803
+ const cloned = result.clone();
2804
+ try {
2805
+ const text = await cloned.text();
2806
+ if (text) {
2807
+ errorText = text.substring(0, 500);
2808
+ errorBody = JSON.parse(text);
2809
+ const parsedError = errorBody?.error;
2810
+ errorText =
2811
+ (typeof parsedError === "object" && parsedError?.message) ||
2812
+ (typeof parsedError === "string" ? parsedError : null) ||
2813
+ errorBody?.message ||
2814
+ errorText;
2815
+ retryAfter = errorBody?.retryAfter || null;
2816
+ }
2817
+ } catch {
2818
+ /* Clone parse failed */
2819
+ }
2820
+ } catch {
2821
+ /* Clone failed */
2822
+ }
2823
+
2824
+ if (result.status === 499) {
2825
+ log.info(
2826
+ "COMBO-RR",
2827
+ `Client disconnected (499) during ${modelStr} — stopping combo loop`
2828
+ );
2829
+ recordComboRequest(combo.name, modelStr, {
2830
+ success: false,
2831
+ latencyMs: Date.now() - startTime,
2832
+ fallbackCount,
2833
+ strategy: "round-robin",
2834
+ target: toRecordedTarget(target),
2835
+ });
2836
+ recordedAttempts++;
2837
+ return result;
2838
+ }
2839
+
2840
+ if (
2841
+ retryAfter &&
2842
+ (!earliestRetryAfter || new Date(retryAfter) < new Date(earliestRetryAfter))
2843
+ ) {
2844
+ earliestRetryAfter = retryAfter;
2845
+ }
2846
+
2847
+ if (typeof errorText !== "string") {
2848
+ try {
2849
+ errorText = JSON.stringify(errorText);
2850
+ } catch {
2851
+ errorText = String(errorText);
2852
+ }
2853
+ }
2854
+
2855
+ const isStreamReadinessFailure =
2856
+ (result.status === 502 || result.status === 504) &&
2857
+ isStreamReadinessFailureErrorBody(errorBody);
2858
+
2859
+ // FIX 5: a local per-API-key token-limit 429 must not cool shared accounts.
2860
+ const isTokenLimitBreach = result.status === 429 && isTokenLimitBreachErrorBody(errorBody);
2861
+
2862
+ // Round-robin uses the same target-level fallback rule as other combo
2863
+ // strategies: non-ok target responses fall through to the next target.
2864
+ // Classification stays here only to support cooldown/semaphore pacing,
2865
+ // not to decide whether fallback is allowed.
2866
+ const rawError = errorBody?.error;
2867
+ const structuredError =
2868
+ rawError && typeof rawError === "object"
2869
+ ? {
2870
+ // Upstream JSON may carry a numeric `code`/`type` (e.g. {"code":40001}).
2871
+ // Coerce to string if present instead of discarding, so downstream string
2872
+ // ops (.toLowerCase, .startsWith) can run safely without type crashes.
2873
+ code:
2874
+ (rawError as Record<string, unknown>).code !== undefined &&
2875
+ (rawError as Record<string, unknown>).code !== null
2876
+ ? String((rawError as Record<string, unknown>).code)
2877
+ : undefined,
2878
+ type:
2879
+ (rawError as Record<string, unknown>).type !== undefined &&
2880
+ (rawError as Record<string, unknown>).type !== null
2881
+ ? String((rawError as Record<string, unknown>).type)
2882
+ : undefined,
2883
+ }
2884
+ : undefined;
2885
+ const fallbackResult = checkFallbackError(
2886
+ result.status,
2887
+ errorText,
2888
+ 0,
2889
+ null,
2890
+ provider,
2891
+ result.headers,
2892
+ profile,
2893
+ structuredError
2894
+ );
2895
+ const { cooldownMs } = fallbackResult;
2896
+ const selectedConnectionId =
2897
+ result.headers?.get("X-OmniRoute-Selected-Connection-Id") ||
2898
+ result.headers?.get("x-omniroute-selected-connection-id") ||
2899
+ undefined;
2900
+ const targetWithConnection = selectedConnectionId
2901
+ ? { ...target, connectionId: selectedConnectionId }
2902
+ : target;
2903
+
2904
+ const isAllAccountsRateLimited = isAllAccountsRateLimitedResponse(
2905
+ result.status,
2906
+ result.headers?.get("content-type") ?? null,
2907
+ errorText
2908
+ );
2909
+
2910
+ // #1731: If the entire provider quota is exhausted, mark it so subsequent
2911
+ // same-provider targets are skipped immediately. API-key 429s still use
2912
+ // the short resilience cooldown, but explicit quota text should stop the
2913
+ // combo from trying another target for the same provider in this request.
2914
+ // #1731 / #1731v2: classify the upstream error and update the exhaustion sets
2915
+ // (shared with handleComboChat). Returns whether the provider is fully exhausted.
2916
+ const providerExhausted = applyComboTargetExhaustion(targetWithConnection, {
2917
+ result,
2918
+ fallbackResult,
2919
+ errorText,
2920
+ rawModel: parseModel(modelStr).model || modelStr,
2921
+ isTokenLimitBreach,
2922
+ allAccountsRateLimited: isAllAccountsRateLimited,
2923
+ sets: { exhaustedProviders, exhaustedConnections, transientRateLimitedProviders },
2924
+ log,
2925
+ tag: "COMBO-RR",
2926
+ exhaustedLogLevel: "debug",
2927
+ structuredError,
2928
+ });
2929
+
2930
+ // Transient errors → mark in semaphore so round-robin stops stampeding this target.
2931
+ if (
2932
+ !isStreamReadinessFailure &&
2933
+ !isTokenLimitBreach &&
2934
+ TRANSIENT_FOR_SEMAPHORE.includes(result.status) &&
2935
+ cooldownMs > 0
2936
+ ) {
2937
+ semaphore.markRateLimited(semaphoreKey, cooldownMs);
2938
+ log.warn("COMBO-RR", `${modelStr} error ${result.status}, cooldown ${cooldownMs}ms`);
2939
+ }
2940
+
2941
+ if (isAllAccountsRateLimited) {
2942
+ log.info(
2943
+ "COMBO-RR",
2944
+ `All accounts rate-limited for ${modelStr}, falling back to next model`
2945
+ );
2946
+ }
2947
+
2948
+ // Transient error → retry same model.
2949
+ // A token-limit 429 is terminal for the client — never retry it.
2950
+ const isTransient =
2951
+ !isStreamReadinessFailure &&
2952
+ !isTokenLimitBreach &&
2953
+ [408, 429, 500, 502, 503, 504].includes(result.status);
2954
+ if (retry < maxRetries && isTransient && !providerExhausted) {
2955
+ continue;
2956
+ }
2957
+
2958
+ // Done with this model
2959
+ recordComboRequest(combo.name, modelStr, {
2960
+ success: false,
2961
+ latencyMs: Date.now() - startTime,
2962
+ fallbackCount,
2963
+ strategy: "round-robin",
2964
+ target: toRecordedTarget(target),
2965
+ });
2966
+ recordedAttempts++;
2967
+ lastError = errorText || String(result.status);
2968
+ if (!lastStatus) lastStatus = result.status;
2969
+ if (offset > 0) fallbackCount++;
2970
+ log.warn("COMBO-RR", `${modelStr} failed, trying next model`, { status: result.status });
2971
+
2972
+ if (
2973
+ resilienceSettings.providerCooldown.enabled &&
2974
+ provider &&
2975
+ provider !== "unknown" &&
2976
+ !(result.status === 500 && hasPerModelQuota(provider, parseModel(modelStr).model || modelStr))
2977
+ ) {
2978
+ recordProviderCooldown(
2979
+ provider,
2980
+ targetWithConnection.connectionId ?? undefined,
2981
+ resilienceSettings
2982
+ );
2983
+ }
2984
+
2985
+ const fallbackWaitMs =
2986
+ fallbackDelayMs > 0 && cooldownMs > 0 && cooldownMs <= MAX_FALLBACK_WAIT_MS
2987
+ ? Math.min(cooldownMs, fallbackDelayMs)
2988
+ : 0;
2989
+ if ([502, 503, 504].includes(result.status) && fallbackWaitMs > 0) {
2990
+ log.debug?.("COMBO-RR", `Waiting ${fallbackWaitMs}ms before fallback to next model`);
2991
+ await new Promise((resolve) => {
2992
+ const timer = setTimeout(resolve, fallbackWaitMs);
2993
+ signal?.addEventListener(
2994
+ "abort",
2995
+ () => {
2996
+ clearTimeout(timer);
2997
+ resolve(undefined);
2998
+ },
2999
+ { once: true }
3000
+ );
3001
+ });
3002
+ if (signal?.aborted) {
3003
+ log.info("COMBO-RR", `Client disconnected during fallback wait — aborting`);
3004
+ return errorResponse(499, "Client disconnected");
3005
+ }
3006
+ }
3007
+
3008
+ break;
3009
+ }
3010
+ } finally {
3011
+ // ALWAYS release semaphore slot
3012
+ release();
3013
+ }
3014
+ }
3015
+
3016
+ // All models exhausted
3017
+ const latencyMs = Date.now() - startTime;
3018
+
3019
+ // #6238: every compat-kept target was skipped as unavailable and NONE was ever
3020
+ // attempted (recordedAttempts === 0). Before crystallizing 503, probe the targets
3021
+ // the compat pre-filter rejected — a compat-rejected-but-healthy provider is a
3022
+ // valid last-resort fallback tier, not a permanently dropped target.
3023
+ if (recordedAttempts === 0 && compatRejectedTargets.length > 0) {
3024
+ const compatFallbackResult = await attemptCompatRejectedFallback(compatRejectedTargets, body, {
3025
+ handleSingleModel,
3026
+ isModelAvailable,
3027
+ isProviderInCooldown: (target) =>
3028
+ resilienceSettings.providerCooldown.enabled &&
3029
+ Boolean(target.provider && target.provider !== "unknown") &&
3030
+ isProviderInCooldown(
3031
+ target.provider as string,
3032
+ target.connectionId as string | undefined,
3033
+ resilienceSettings
3034
+ ),
3035
+ log,
3036
+ strategy: "round-robin",
3037
+ });
3038
+ if (compatFallbackResult) {
3039
+ recordComboRequest(combo.name, null, {
3040
+ success: true,
3041
+ latencyMs: Date.now() - startTime,
3042
+ fallbackCount,
3043
+ strategy: "round-robin",
3044
+ });
3045
+ return compatFallbackResult;
3046
+ }
3047
+ }
3048
+
3049
+ if (recordedAttempts === 0) {
3050
+ recordComboRequest(combo.name, null, {
3051
+ success: false,
3052
+ latencyMs,
3053
+ fallbackCount,
3054
+ strategy: "round-robin",
3055
+ });
3056
+ }
3057
+
3058
+ if (!lastStatus) {
3059
+ return new Response(
3060
+ JSON.stringify({
3061
+ error: {
3062
+ message: "Service temporarily unavailable: all upstream accounts are inactive",
3063
+ type: "service_unavailable",
3064
+ code: "ALL_ACCOUNTS_INACTIVE",
3065
+ },
3066
+ }),
3067
+ { status: 503, headers: { "Content-Type": "application/json" } }
3068
+ );
3069
+ }
3070
+
3071
+ const status = lastStatus;
3072
+ const msg = lastError || "All round-robin combo models unavailable";
3073
+
3074
+ if (earliestRetryAfter) {
3075
+ const retryHuman = formatRetryAfter(toRetryAfterDisplayValue(earliestRetryAfter));
3076
+ log.warn("COMBO-RR", `All models failed | ${msg} (${retryHuman})`);
3077
+ return unavailableResponse(status, msg, earliestRetryAfter, retryHuman);
3078
+ }
3079
+
3080
+ log.warn("COMBO-RR", `All models failed | ${msg}`);
3081
+ return new Response(JSON.stringify({ error: { message: msg } }), {
3082
+ status,
3083
+ headers: { "Content-Type": "application/json" },
3084
+ });
3085
+ }