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.
- package/.env.example +2070 -0
- package/@omniroute/opencode-plugin/LICENSE +21 -0
- package/@omniroute/opencode-plugin/README.md +296 -0
- package/@omniroute/opencode-plugin/package-lock.json +1930 -0
- package/@omniroute/opencode-plugin/package.json +73 -0
- package/@omniroute/opencode-plugin/src/index.ts +4685 -0
- package/@omniroute/opencode-plugin/src/logger.ts +74 -0
- package/@omniroute/opencode-plugin/src/naming.ts +301 -0
- package/@omniroute/opencode-plugin/tsconfig.json +20 -0
- package/@omniroute/opencode-plugin/tsup.config.ts +20 -0
- package/@omniroute/opencode-provider/LICENSE +21 -0
- package/@omniroute/opencode-provider/README.md +156 -0
- package/@omniroute/opencode-provider/package-lock.json +1514 -0
- package/@omniroute/opencode-provider/package.json +63 -0
- package/@omniroute/opencode-provider/src/index.ts +908 -0
- package/@omniroute/opencode-provider/tsconfig.json +20 -0
- package/@omniroute/opencode-provider/tsup.config.ts +18 -0
- package/LICENSE +22 -0
- package/README.md +1265 -0
- package/bin/_ops-common.sh +70 -0
- package/bin/cli/CONVENTIONS.md +224 -0
- package/bin/cli/README.md +146 -0
- package/bin/cli/api-commands/agent-skills.mjs +70 -0
- package/bin/cli/api-commands/agentbridge.mjs +155 -0
- package/bin/cli/api-commands/api-keys.mjs +42 -0
- package/bin/cli/api-commands/audio.mjs +40 -0
- package/bin/cli/api-commands/chat.mjs +58 -0
- package/bin/cli/api-commands/cli-tools.mjs +361 -0
- package/bin/cli/api-commands/cloud.mjs +81 -0
- package/bin/cli/api-commands/combos.mjs +69 -0
- package/bin/cli/api-commands/compression.mjs +128 -0
- package/bin/cli/api-commands/embedded-services.mjs +202 -0
- package/bin/cli/api-commands/embeddings.mjs +42 -0
- package/bin/cli/api-commands/fallback.mjs +49 -0
- package/bin/cli/api-commands/images.mjs +42 -0
- package/bin/cli/api-commands/memory.mjs +251 -0
- package/bin/cli/api-commands/messages.mjs +40 -0
- package/bin/cli/api-commands/models.mjs +89 -0
- package/bin/cli/api-commands/moderations.mjs +24 -0
- package/bin/cli/api-commands/oauth.mjs +114 -0
- package/bin/cli/api-commands/playground.mjs +83 -0
- package/bin/cli/api-commands/pricing.mjs +44 -0
- package/bin/cli/api-commands/provider-nodes.mjs +62 -0
- package/bin/cli/api-commands/providers.mjs +148 -0
- package/bin/cli/api-commands/quota.mjs +154 -0
- package/bin/cli/api-commands/registry.mjs +75 -0
- package/bin/cli/api-commands/rerank.mjs +24 -0
- package/bin/cli/api-commands/responses.mjs +24 -0
- package/bin/cli/api-commands/settings.mjs +228 -0
- package/bin/cli/api-commands/system.mjs +320 -0
- package/bin/cli/api-commands/telemetry.mjs +26 -0
- package/bin/cli/api-commands/traffic-inspector.mjs +307 -0
- package/bin/cli/api-commands/translator.mjs +65 -0
- package/bin/cli/api-commands/usage.mjs +117 -0
- package/bin/cli/api.mjs +269 -0
- package/bin/cli/commands/a2a.mjs +323 -0
- package/bin/cli/commands/audit.mjs +203 -0
- package/bin/cli/commands/autostart.mjs +57 -0
- package/bin/cli/commands/backup.mjs +469 -0
- package/bin/cli/commands/batches.mjs +235 -0
- package/bin/cli/commands/cache.mjs +102 -0
- package/bin/cli/commands/chat.mjs +162 -0
- package/bin/cli/commands/cloud.mjs +233 -0
- package/bin/cli/commands/combo.mjs +361 -0
- package/bin/cli/commands/completion.mjs +346 -0
- package/bin/cli/commands/compression.mjs +247 -0
- package/bin/cli/commands/config.mjs +351 -0
- package/bin/cli/commands/configure.mjs +180 -0
- package/bin/cli/commands/connect.mjs +132 -0
- package/bin/cli/commands/context-eng.mjs +182 -0
- package/bin/cli/commands/contexts.mjs +271 -0
- package/bin/cli/commands/cost.mjs +144 -0
- package/bin/cli/commands/dashboard.mjs +65 -0
- package/bin/cli/commands/doctor.mjs +527 -0
- package/bin/cli/commands/env.mjs +100 -0
- package/bin/cli/commands/eval.mjs +278 -0
- package/bin/cli/commands/files.mjs +144 -0
- package/bin/cli/commands/health.mjs +123 -0
- package/bin/cli/commands/keys.mjs +599 -0
- package/bin/cli/commands/launch-codex.mjs +201 -0
- package/bin/cli/commands/launch.mjs +155 -0
- package/bin/cli/commands/login.mjs +192 -0
- package/bin/cli/commands/logs.mjs +183 -0
- package/bin/cli/commands/mcp.mjs +273 -0
- package/bin/cli/commands/memory.mjs +244 -0
- package/bin/cli/commands/models.mjs +92 -0
- package/bin/cli/commands/nodes.mjs +177 -0
- package/bin/cli/commands/oauth.mjs +258 -0
- package/bin/cli/commands/oneproxy.mjs +120 -0
- package/bin/cli/commands/open.mjs +75 -0
- package/bin/cli/commands/openapi.mjs +168 -0
- package/bin/cli/commands/plugin.mjs +219 -0
- package/bin/cli/commands/policy.mjs +216 -0
- package/bin/cli/commands/pricing.mjs +123 -0
- package/bin/cli/commands/provider-cmd.mjs +18 -0
- package/bin/cli/commands/providers.mjs +706 -0
- package/bin/cli/commands/quota.mjs +100 -0
- package/bin/cli/commands/redis.mjs +294 -0
- package/bin/cli/commands/registry.mjs +162 -0
- package/bin/cli/commands/repl.mjs +19 -0
- package/bin/cli/commands/reset-encrypted-columns.mjs +88 -0
- package/bin/cli/commands/resilience.mjs +208 -0
- package/bin/cli/commands/restart.mjs +25 -0
- package/bin/cli/commands/runtime.mjs +98 -0
- package/bin/cli/commands/serve.mjs +426 -0
- package/bin/cli/commands/sessions.mjs +108 -0
- package/bin/cli/commands/setup-aider.mjs +146 -0
- package/bin/cli/commands/setup-claude.mjs +219 -0
- package/bin/cli/commands/setup-cline.mjs +160 -0
- package/bin/cli/commands/setup-codex.mjs +387 -0
- package/bin/cli/commands/setup-continue.mjs +173 -0
- package/bin/cli/commands/setup-crush.mjs +148 -0
- package/bin/cli/commands/setup-cursor.mjs +108 -0
- package/bin/cli/commands/setup-goose.mjs +150 -0
- package/bin/cli/commands/setup-kilo.mjs +178 -0
- package/bin/cli/commands/setup-open-code.mjs +398 -0
- package/bin/cli/commands/setup-opencode.mjs +129 -0
- package/bin/cli/commands/setup-qwen.mjs +156 -0
- package/bin/cli/commands/setup-roo.mjs +172 -0
- package/bin/cli/commands/setup.mjs +211 -0
- package/bin/cli/commands/simulate.mjs +125 -0
- package/bin/cli/commands/skills.mjs +373 -0
- package/bin/cli/commands/status.mjs +95 -0
- package/bin/cli/commands/stop.mjs +96 -0
- package/bin/cli/commands/stream.mjs +166 -0
- package/bin/cli/commands/sync.mjs +230 -0
- package/bin/cli/commands/tags.mjs +116 -0
- package/bin/cli/commands/telemetry.mjs +74 -0
- package/bin/cli/commands/test-provider.mjs +242 -0
- package/bin/cli/commands/tokens.mjs +118 -0
- package/bin/cli/commands/translator.mjs +131 -0
- package/bin/cli/commands/tray.mjs +36 -0
- package/bin/cli/commands/tunnel.mjs +347 -0
- package/bin/cli/commands/update.mjs +194 -0
- package/bin/cli/commands/usage.mjs +331 -0
- package/bin/cli/commands/webhooks.mjs +196 -0
- package/bin/cli/contexts.mjs +60 -0
- package/bin/cli/data-dir.mjs +59 -0
- package/bin/cli/encryption.mjs +67 -0
- package/bin/cli/i18n.mjs +106 -0
- package/bin/cli/io.mjs +83 -0
- package/bin/cli/locales/ar.json +32 -0
- package/bin/cli/locales/az.json +32 -0
- package/bin/cli/locales/bg.json +32 -0
- package/bin/cli/locales/bn.json +5 -0
- package/bin/cli/locales/cs.json +32 -0
- package/bin/cli/locales/da.json +32 -0
- package/bin/cli/locales/de.json +32 -0
- package/bin/cli/locales/en.json +1289 -0
- package/bin/cli/locales/es.json +32 -0
- package/bin/cli/locales/fa.json +32 -0
- package/bin/cli/locales/fi.json +32 -0
- package/bin/cli/locales/fr.json +32 -0
- package/bin/cli/locales/gu.json +5 -0
- package/bin/cli/locales/he.json +5 -0
- package/bin/cli/locales/hi.json +32 -0
- package/bin/cli/locales/hu.json +32 -0
- package/bin/cli/locales/id.json +32 -0
- package/bin/cli/locales/in.json +5 -0
- package/bin/cli/locales/it.json +32 -0
- package/bin/cli/locales/ja.json +32 -0
- package/bin/cli/locales/ko.json +32 -0
- package/bin/cli/locales/mr.json +5 -0
- package/bin/cli/locales/ms.json +5 -0
- package/bin/cli/locales/nl.json +32 -0
- package/bin/cli/locales/no.json +32 -0
- package/bin/cli/locales/phi.json +5 -0
- package/bin/cli/locales/pl.json +32 -0
- package/bin/cli/locales/pt-BR.json +1286 -0
- package/bin/cli/locales/pt.json +32 -0
- package/bin/cli/locales/ro.json +32 -0
- package/bin/cli/locales/ru.json +32 -0
- package/bin/cli/locales/sk.json +32 -0
- package/bin/cli/locales/sv.json +32 -0
- package/bin/cli/locales/sw.json +5 -0
- package/bin/cli/locales/ta.json +5 -0
- package/bin/cli/locales/te.json +5 -0
- package/bin/cli/locales/th.json +32 -0
- package/bin/cli/locales/tr.json +32 -0
- package/bin/cli/locales/uk-UA.json +32 -0
- package/bin/cli/locales/ur.json +5 -0
- package/bin/cli/locales/vi.json +32 -0
- package/bin/cli/locales/zh-CN.json +1262 -0
- package/bin/cli/output.mjs +200 -0
- package/bin/cli/plugins.mjs +90 -0
- package/bin/cli/program.mjs +40 -0
- package/bin/cli/provider-catalog.mjs +175 -0
- package/bin/cli/provider-store.mjs +312 -0
- package/bin/cli/provider-test.mjs +181 -0
- package/bin/cli/runtime/index.mjs +19 -0
- package/bin/cli/runtime/magicBytes.mjs +47 -0
- package/bin/cli/runtime/nativeDeps.mjs +137 -0
- package/bin/cli/runtime/processSupervisor.mjs +136 -0
- package/bin/cli/runtime/sqliteRuntime.mjs +129 -0
- package/bin/cli/runtime/supervisorPolicy.mjs +56 -0
- package/bin/cli/runtime/trayRuntime.ts +94 -0
- package/bin/cli/runtime.mjs +61 -0
- package/bin/cli/schemas/output-schemas.mjs +56 -0
- package/bin/cli/scripts/generate-locales.mjs +911 -0
- package/bin/cli/settings-store.mjs +45 -0
- package/bin/cli/spinner.mjs +30 -0
- package/bin/cli/sqlite.mjs +158 -0
- package/bin/cli/tray/autostart.mjs +410 -0
- package/bin/cli/tray/autostart.ts +18 -0
- package/bin/cli/tray/icon.png +0 -0
- package/bin/cli/tray/index.mjs +28 -0
- package/bin/cli/tray/tray.ps1 +99 -0
- package/bin/cli/tray/tray.ts +186 -0
- package/bin/cli/tray/traySystray.mjs +135 -0
- package/bin/cli/tray/trayWin.ts +91 -0
- package/bin/cli/tray/trayWindows.mjs +75 -0
- package/bin/cli/tui/Dashboard.jsx +70 -0
- package/bin/cli/tui/EvalWatch.jsx +171 -0
- package/bin/cli/tui/InterfaceMenu.jsx +55 -0
- package/bin/cli/tui/OAuthFlow.jsx +193 -0
- package/bin/cli/tui/ProvidersTestAll.jsx +190 -0
- package/bin/cli/tui/Repl.jsx +392 -0
- package/bin/cli/tui/session.mjs +54 -0
- package/bin/cli/tui/tabs/Combos.jsx +47 -0
- package/bin/cli/tui/tabs/Cost.jsx +52 -0
- package/bin/cli/tui/tabs/Health.jsx +53 -0
- package/bin/cli/tui/tabs/Keys.jsx +48 -0
- package/bin/cli/tui/tabs/Logs.jsx +60 -0
- package/bin/cli/tui/tabs/Overview.jsx +80 -0
- package/bin/cli/tui/tabs/Providers.jsx +48 -0
- package/bin/cli/tui-components/CodeBlock.jsx +15 -0
- package/bin/cli/tui-components/ConfirmDialog.jsx +40 -0
- package/bin/cli/tui-components/DataTable.jsx +50 -0
- package/bin/cli/tui-components/HeaderSwr.jsx +25 -0
- package/bin/cli/tui-components/KeyMaskedDisplay.jsx +12 -0
- package/bin/cli/tui-components/MarkdownView.jsx +13 -0
- package/bin/cli/tui-components/MenuSelect.jsx +38 -0
- package/bin/cli/tui-components/MultilineInput.jsx +18 -0
- package/bin/cli/tui-components/ProgressBar.jsx +15 -0
- package/bin/cli/tui-components/Sparkline.jsx +15 -0
- package/bin/cli/tui-components/StatusBadge.jsx +17 -0
- package/bin/cli/tui-components/TokenCounter.jsx +18 -0
- package/bin/cli/tui-components/theme.jsx +11 -0
- package/bin/cli/utils/cliToken.mjs +22 -0
- package/bin/cli/utils/clipboard.mjs +35 -0
- package/bin/cli/utils/environment.mjs +50 -0
- package/bin/cli/utils/pid.mjs +110 -0
- package/bin/cli/utils/storageKeyProvision.mjs +31 -0
- package/bin/cold-start-bench.sh +82 -0
- package/bin/mcp-server.mjs +71 -0
- package/bin/nodeRuntimeSupport.mjs +84 -0
- package/bin/omniroute.mjs +237 -0
- package/bin/reset-password.mjs +137 -0
- package/bin/restore-data.sh +64 -0
- package/bin/restore-policies.sh +77 -0
- package/bin/rollback.sh +102 -0
- package/bin/snapshot-data.sh +61 -0
- package/open-sse/config/agyModels.ts +157 -0
- package/open-sse/config/anthropicHeaders.ts +127 -0
- package/open-sse/config/antigravityModelAliases.ts +309 -0
- package/open-sse/config/antigravityUpstream.ts +20 -0
- package/open-sse/config/audioRegistry.ts +547 -0
- package/open-sse/config/azureAi.ts +49 -0
- package/open-sse/config/bedrock.ts +196 -0
- package/open-sse/config/cliFingerprints.ts +405 -0
- package/open-sse/config/codexClient.ts +49 -0
- package/open-sse/config/codexIdentity.ts +87 -0
- package/open-sse/config/codexInstructions.ts +122 -0
- package/open-sse/config/codexQuotaScopes.ts +87 -0
- package/open-sse/config/constants.ts +281 -0
- package/open-sse/config/contextEditing.ts +156 -0
- package/open-sse/config/credentialLoader.ts +123 -0
- package/open-sse/config/datarobot.ts +69 -0
- package/open-sse/config/defaultThinkingSignature.ts +8 -0
- package/open-sse/config/embeddingRegistry.ts +434 -0
- package/open-sse/config/errorConfig.ts +201 -0
- package/open-sse/config/freeModelCatalog.data.ts +467 -0
- package/open-sse/config/freeModelCatalog.ts +142 -0
- package/open-sse/config/freeTierCatalog.ts +101 -0
- package/open-sse/config/geminiRateLimits.json +34 -0
- package/open-sse/config/glmProvider.ts +488 -0
- package/open-sse/config/imageRegistry.ts +752 -0
- package/open-sse/config/maritalk.ts +18 -0
- package/open-sse/config/mediaServiceKinds.ts +70 -0
- package/open-sse/config/moderationRegistry.ts +89 -0
- package/open-sse/config/musicRegistry.ts +115 -0
- package/open-sse/config/oci.ts +44 -0
- package/open-sse/config/ocrRegistry.ts +82 -0
- package/open-sse/config/ollamaModels.ts +28 -0
- package/open-sse/config/providerErrorRules.ts +218 -0
- package/open-sse/config/providerFieldStrips.ts +42 -0
- package/open-sse/config/providerHeaderProfiles.ts +188 -0
- package/open-sse/config/providerModels.ts +199 -0
- package/open-sse/config/providerPluginManifest.ts +186 -0
- package/open-sse/config/providerPluginManifestRegistry.ts +31 -0
- package/open-sse/config/providerPluginManifestUrl.ts +26 -0
- package/open-sse/config/providerRegistry.ts +257 -0
- package/open-sse/config/providers/index.ts +377 -0
- package/open-sse/config/providers/registry/adapta-web/index.ts +20 -0
- package/open-sse/config/providers/registry/agentrouter/index.ts +24 -0
- package/open-sse/config/providers/registry/agy/index.ts +28 -0
- package/open-sse/config/providers/registry/ai21/index.ts +13 -0
- package/open-sse/config/providers/registry/aimlapi/index.ts +21 -0
- package/open-sse/config/providers/registry/alibaba/cn/index.ts +15 -0
- package/open-sse/config/providers/registry/alibaba/index.ts +15 -0
- package/open-sse/config/providers/registry/anthropic/index.ts +52 -0
- package/open-sse/config/providers/registry/antigravity/index.ts +28 -0
- package/open-sse/config/providers/registry/api-airforce/index.ts +57 -0
- package/open-sse/config/providers/registry/auggie/index.ts +38 -0
- package/open-sse/config/providers/registry/bai/index.ts +14 -0
- package/open-sse/config/providers/registry/baichuan/index.ts +20 -0
- package/open-sse/config/providers/registry/baidu/index.ts +31 -0
- package/open-sse/config/providers/registry/bailian-coding-plan/index.ts +27 -0
- package/open-sse/config/providers/registry/baseten/index.ts +13 -0
- package/open-sse/config/providers/registry/bazaarlink/index.ts +48 -0
- package/open-sse/config/providers/registry/bedrock/index.ts +49 -0
- package/open-sse/config/providers/registry/blackbox/index.ts +25 -0
- package/open-sse/config/providers/registry/blackbox/web/index.ts +19 -0
- package/open-sse/config/providers/registry/bluesminds/index.ts +39 -0
- package/open-sse/config/providers/registry/byteplus/index.ts +21 -0
- package/open-sse/config/providers/registry/bytez/index.ts +17 -0
- package/open-sse/config/providers/registry/cerebras/index.ts +16 -0
- package/open-sse/config/providers/registry/charm-hyper/index.ts +14 -0
- package/open-sse/config/providers/registry/chatgpt-web/index.ts +23 -0
- package/open-sse/config/providers/registry/chipotle/index.ts +14 -0
- package/open-sse/config/providers/registry/chutes/index.ts +12 -0
- package/open-sse/config/providers/registry/claude/index.ts +102 -0
- package/open-sse/config/providers/registry/claude/web/index.ts +16 -0
- package/open-sse/config/providers/registry/cline/index.ts +45 -0
- package/open-sse/config/providers/registry/clinepass/index.ts +47 -0
- package/open-sse/config/providers/registry/cloudflare-ai/index.ts +33 -0
- package/open-sse/config/providers/registry/codebuddy-cn/index.ts +151 -0
- package/open-sse/config/providers/registry/codestral/index.ts +13 -0
- package/open-sse/config/providers/registry/codex/index.ts +115 -0
- package/open-sse/config/providers/registry/cohere/index.ts +28 -0
- package/open-sse/config/providers/registry/command-code/index.ts +143 -0
- package/open-sse/config/providers/registry/copilot-m365-web/index.ts +12 -0
- package/open-sse/config/providers/registry/copilot-web/index.ts +16 -0
- package/open-sse/config/providers/registry/coze/index.ts +12 -0
- package/open-sse/config/providers/registry/crof/index.ts +38 -0
- package/open-sse/config/providers/registry/cursor/index.ts +111 -0
- package/open-sse/config/providers/registry/databricks/index.ts +13 -0
- package/open-sse/config/providers/registry/deepinfra/index.ts +13 -0
- package/open-sse/config/providers/registry/deepseek/index.ts +15 -0
- package/open-sse/config/providers/registry/deepseek/web/index.ts +35 -0
- package/open-sse/config/providers/registry/devin-cli/index.ts +68 -0
- package/open-sse/config/providers/registry/dgrid/index.ts +15 -0
- package/open-sse/config/providers/registry/dify/index.ts +12 -0
- package/open-sse/config/providers/registry/digitalocean/index.ts +11 -0
- package/open-sse/config/providers/registry/dit/index.ts +41 -0
- package/open-sse/config/providers/registry/doubao/index.ts +28 -0
- package/open-sse/config/providers/registry/doubao/web/index.ts +15 -0
- package/open-sse/config/providers/registry/duckduckgo-web/index.ts +19 -0
- package/open-sse/config/providers/registry/factory/index.ts +33 -0
- package/open-sse/config/providers/registry/featherless-ai/index.ts +13 -0
- package/open-sse/config/providers/registry/fireworks/index.ts +35 -0
- package/open-sse/config/providers/registry/freeaiapikey/index.ts +38 -0
- package/open-sse/config/providers/registry/freemodel-dev/index.ts +19 -0
- package/open-sse/config/providers/registry/friendliai/index.ts +16 -0
- package/open-sse/config/providers/registry/galadriel/index.ts +13 -0
- package/open-sse/config/providers/registry/gemini/index.ts +63 -0
- package/open-sse/config/providers/registry/gemini/web/index.ts +16 -0
- package/open-sse/config/providers/registry/gigachat/index.ts +13 -0
- package/open-sse/config/providers/registry/github/index.ts +161 -0
- package/open-sse/config/providers/registry/github/models/index.ts +38 -0
- package/open-sse/config/providers/registry/gitlab-duo/index.ts +29 -0
- package/open-sse/config/providers/registry/gitlawb/gmi/index.ts +19 -0
- package/open-sse/config/providers/registry/gitlawb/index.ts +18 -0
- package/open-sse/config/providers/registry/glhf/index.ts +12 -0
- package/open-sse/config/providers/registry/glm/cn/index.ts +17 -0
- package/open-sse/config/providers/registry/glm/index.ts +16 -0
- package/open-sse/config/providers/registry/glm/t/index.ts +16 -0
- package/open-sse/config/providers/registry/grok-cli/index.ts +32 -0
- package/open-sse/config/providers/registry/grok-web/index.ts +18 -0
- package/open-sse/config/providers/registry/groq/index.ts +25 -0
- package/open-sse/config/providers/registry/hackclub/index.ts +19 -0
- package/open-sse/config/providers/registry/haiper/index.ts +15 -0
- package/open-sse/config/providers/registry/hcnsec/index.ts +11 -0
- package/open-sse/config/providers/registry/heroku/index.ts +13 -0
- package/open-sse/config/providers/registry/huggingchat/index.ts +143 -0
- package/open-sse/config/providers/registry/huggingface/index.ts +20 -0
- package/open-sse/config/providers/registry/hyperbolic/index.ts +21 -0
- package/open-sse/config/providers/registry/ideogram/index.ts +15 -0
- package/open-sse/config/providers/registry/iflytek/index.ts +21 -0
- package/open-sse/config/providers/registry/inclusionai/index.ts +12 -0
- package/open-sse/config/providers/registry/inference-net/index.ts +13 -0
- package/open-sse/config/providers/registry/inner-ai/index.ts +43 -0
- package/open-sse/config/providers/registry/kenari/index.ts +14 -0
- package/open-sse/config/providers/registry/kie/index.ts +27 -0
- package/open-sse/config/providers/registry/kilo-gateway/index.ts +21 -0
- package/open-sse/config/providers/registry/kilocode/index.ts +43 -0
- package/open-sse/config/providers/registry/kimi/coding/index.ts +17 -0
- package/open-sse/config/providers/registry/kimi/coding-apikey/index.ts +9 -0
- package/open-sse/config/providers/registry/kimi/index.ts +17 -0
- package/open-sse/config/providers/registry/kimi/web/index.ts +27 -0
- package/open-sse/config/providers/registry/kiro/index.ts +50 -0
- package/open-sse/config/providers/registry/kluster/index.ts +12 -0
- package/open-sse/config/providers/registry/lambda-ai/index.ts +13 -0
- package/open-sse/config/providers/registry/leonardo/index.ts +15 -0
- package/open-sse/config/providers/registry/liquid/index.ts +12 -0
- package/open-sse/config/providers/registry/llamagate/index.ts +13 -0
- package/open-sse/config/providers/registry/llm7/index.ts +27 -0
- package/open-sse/config/providers/registry/longcat/index.ts +24 -0
- package/open-sse/config/providers/registry/maritalk/index.ts +13 -0
- package/open-sse/config/providers/registry/meta-llama/index.ts +13 -0
- package/open-sse/config/providers/registry/mimocode/index.ts +16 -0
- package/open-sse/config/providers/registry/minimax/cn/index.ts +24 -0
- package/open-sse/config/providers/registry/minimax/index.ts +24 -0
- package/open-sse/config/providers/registry/mistral/index.ts +18 -0
- package/open-sse/config/providers/registry/modal/index.ts +12 -0
- package/open-sse/config/providers/registry/modelscope/index.ts +24 -0
- package/open-sse/config/providers/registry/monsterapi/index.ts +17 -0
- package/open-sse/config/providers/registry/moonshot/index.ts +13 -0
- package/open-sse/config/providers/registry/morph/index.ts +13 -0
- package/open-sse/config/providers/registry/muse-spark-web/index.ts +24 -0
- package/open-sse/config/providers/registry/nanogpt/index.ts +13 -0
- package/open-sse/config/providers/registry/nebius/index.ts +9 -0
- package/open-sse/config/providers/registry/nlpcloud/index.ts +19 -0
- package/open-sse/config/providers/registry/nous-research/index.ts +15 -0
- package/open-sse/config/providers/registry/novita/index.ts +15 -0
- package/open-sse/config/providers/registry/nscale/index.ts +13 -0
- package/open-sse/config/providers/registry/nube/index.ts +17 -0
- package/open-sse/config/providers/registry/nvidia/index.ts +36 -0
- package/open-sse/config/providers/registry/ollama-cloud/index.ts +27 -0
- package/open-sse/config/providers/registry/openadapter/index.ts +25 -0
- package/open-sse/config/providers/registry/openai/index.ts +43 -0
- package/open-sse/config/providers/registry/opencode/go/index.ts +61 -0
- package/open-sse/config/providers/registry/opencode/index.ts +51 -0
- package/open-sse/config/providers/registry/opencode/zen/index.ts +98 -0
- package/open-sse/config/providers/registry/openrouter/index.ts +17 -0
- package/open-sse/config/providers/registry/orcarouter/index.ts +87 -0
- package/open-sse/config/providers/registry/ovhcloud/index.ts +13 -0
- package/open-sse/config/providers/registry/perplexity/index.ts +22 -0
- package/open-sse/config/providers/registry/perplexity/web/index.ts +23 -0
- package/open-sse/config/providers/registry/pioneer/index.ts +41 -0
- package/open-sse/config/providers/registry/pollinations/index.ts +51 -0
- package/open-sse/config/providers/registry/predibase/index.ts +13 -0
- package/open-sse/config/providers/registry/publicai/index.ts +13 -0
- package/open-sse/config/providers/registry/puter/index.ts +70 -0
- package/open-sse/config/providers/registry/qianfan/index.ts +18 -0
- package/open-sse/config/providers/registry/qiniu/index.ts +15 -0
- package/open-sse/config/providers/registry/qoder/index.ts +37 -0
- package/open-sse/config/providers/registry/qwen/index.ts +25 -0
- package/open-sse/config/providers/registry/qwen/web/index.ts +24 -0
- package/open-sse/config/providers/registry/reka/index.ts +18 -0
- package/open-sse/config/providers/registry/requesty/index.ts +11 -0
- package/open-sse/config/providers/registry/sambanova/index.ts +13 -0
- package/open-sse/config/providers/registry/scaleway/index.ts +20 -0
- package/open-sse/config/providers/registry/sensenova/index.ts +27 -0
- package/open-sse/config/providers/registry/siliconflow/index.ts +84 -0
- package/open-sse/config/providers/registry/snowflake/index.ts +13 -0
- package/open-sse/config/providers/registry/sparkdesk/index.ts +20 -0
- package/open-sse/config/providers/registry/stepfun/index.ts +20 -0
- package/open-sse/config/providers/registry/sumopod/index.ts +15 -0
- package/open-sse/config/providers/registry/suno/index.ts +18 -0
- package/open-sse/config/providers/registry/synthetic/index.ts +21 -0
- package/open-sse/config/providers/registry/t3-web/index.ts +45 -0
- package/open-sse/config/providers/registry/tencent/index.ts +25 -0
- package/open-sse/config/providers/registry/theoldllm/index.ts +51 -0
- package/open-sse/config/providers/registry/together/index.ts +20 -0
- package/open-sse/config/providers/registry/tokenrouter/index.ts +44 -0
- package/open-sse/config/providers/registry/trae/index.ts +24 -0
- package/open-sse/config/providers/registry/udio/index.ts +12 -0
- package/open-sse/config/providers/registry/uncloseai/index.ts +19 -0
- package/open-sse/config/providers/registry/upstage/index.ts +13 -0
- package/open-sse/config/providers/registry/v0-vercel/index.ts +13 -0
- package/open-sse/config/providers/registry/venice/index.ts +13 -0
- package/open-sse/config/providers/registry/veoaifree-web/index.ts +15 -0
- package/open-sse/config/providers/registry/vercel-ai-gateway/index.ts +13 -0
- package/open-sse/config/providers/registry/vertex/index.ts +33 -0
- package/open-sse/config/providers/registry/vertex/partner/index.ts +22 -0
- package/open-sse/config/providers/registry/volcengine/index.ts +13 -0
- package/open-sse/config/providers/registry/wafer/index.ts +19 -0
- package/open-sse/config/providers/registry/wandb/index.ts +13 -0
- package/open-sse/config/providers/registry/windsurf/index.ts +119 -0
- package/open-sse/config/providers/registry/x5lab/index.ts +15 -0
- package/open-sse/config/providers/registry/xai/index.ts +18 -0
- package/open-sse/config/providers/registry/xiaomi-mimo/index.ts +13 -0
- package/open-sse/config/providers/registry/yi/index.ts +12 -0
- package/open-sse/config/providers/registry/yuanbao-web/index.ts +37 -0
- package/open-sse/config/providers/registry/zai/index.ts +28 -0
- package/open-sse/config/providers/registry/zed-hosted/index.ts +35 -0
- package/open-sse/config/providers/registry/zenmux/index.ts +87 -0
- package/open-sse/config/providers/registry/zenmux-free/index.ts +40 -0
- package/open-sse/config/providers/shared.ts +766 -0
- package/open-sse/config/registryUtils.ts +134 -0
- package/open-sse/config/rerankRegistry.ts +196 -0
- package/open-sse/config/runway.ts +39 -0
- package/open-sse/config/sap.ts +58 -0
- package/open-sse/config/searchRegistry.ts +317 -0
- package/open-sse/config/toolCloaking.ts +253 -0
- package/open-sse/config/videoRegistry.ts +229 -0
- package/open-sse/config/watsonx.ts +43 -0
- package/open-sse/executors/adapta-web.ts +564 -0
- package/open-sse/executors/antigravity/sseCollect.ts +148 -0
- package/open-sse/executors/antigravity.ts +1716 -0
- package/open-sse/executors/antigravityUpstreamError.ts +25 -0
- package/open-sse/executors/auggie.ts +573 -0
- package/open-sse/executors/azure-openai.ts +48 -0
- package/open-sse/executors/base/headers.ts +93 -0
- package/open-sse/executors/base/reasoningEffort.ts +160 -0
- package/open-sse/executors/base.ts +1315 -0
- package/open-sse/executors/bedrock.ts +714 -0
- package/open-sse/executors/blackbox-web.ts +708 -0
- package/open-sse/executors/chatgpt-web/models.ts +133 -0
- package/open-sse/executors/chatgpt-web.ts +3107 -0
- package/open-sse/executors/chatgptWebErrors.ts +18 -0
- package/open-sse/executors/chatgptWebTools.ts +127 -0
- package/open-sse/executors/chipotle.ts +432 -0
- package/open-sse/executors/claude-web/payload.ts +230 -0
- package/open-sse/executors/claude-web-with-auto-refresh.ts +117 -0
- package/open-sse/executors/claude-web.ts +833 -0
- package/open-sse/executors/claudeIdentity.ts +445 -0
- package/open-sse/executors/cliproxyapi.ts +466 -0
- package/open-sse/executors/cloudflare-ai.ts +97 -0
- package/open-sse/executors/codebuddy-cn.ts +53 -0
- package/open-sse/executors/codex/quota.ts +114 -0
- package/open-sse/executors/codex/tools.ts +165 -0
- package/open-sse/executors/codex.ts +1270 -0
- package/open-sse/executors/commandCode.ts +716 -0
- package/open-sse/executors/copilot-m365-connection.ts +271 -0
- package/open-sse/executors/copilot-m365-frames.ts +279 -0
- package/open-sse/executors/copilot-m365-web.ts +341 -0
- package/open-sse/executors/copilot-web.ts +722 -0
- package/open-sse/executors/cursor/composer.ts +53 -0
- package/open-sse/executors/cursor/prompt.ts +75 -0
- package/open-sse/executors/cursor.ts +1465 -0
- package/open-sse/executors/deepseek-web/stream-format.ts +44 -0
- package/open-sse/executors/deepseek-web-with-auto-refresh.ts +184 -0
- package/open-sse/executors/deepseek-web.ts +1123 -0
- package/open-sse/executors/default/urlNormalizers.ts +64 -0
- package/open-sse/executors/default.ts +873 -0
- package/open-sse/executors/devin-cli.ts +470 -0
- package/open-sse/executors/doubao-web.ts +665 -0
- package/open-sse/executors/duckduckgo-web/challenge.ts +151 -0
- package/open-sse/executors/duckduckgo-web.ts +782 -0
- package/open-sse/executors/firecrawl-fetch.ts +177 -0
- package/open-sse/executors/forceResponsesUpstream.ts +60 -0
- package/open-sse/executors/gemini-business.ts +446 -0
- package/open-sse/executors/gemini-web.ts +413 -0
- package/open-sse/executors/github.ts +376 -0
- package/open-sse/executors/gitlab.ts +793 -0
- package/open-sse/executors/gitlabResponses.ts +191 -0
- package/open-sse/executors/glm.ts +520 -0
- package/open-sse/executors/grok-cli.ts +253 -0
- package/open-sse/executors/grok-web/native-tools.ts +182 -0
- package/open-sse/executors/grok-web/text-cleanup.ts +137 -0
- package/open-sse/executors/grok-web/tool-bridge.ts +666 -0
- package/open-sse/executors/grok-web/types.ts +47 -0
- package/open-sse/executors/grok-web.ts +883 -0
- package/open-sse/executors/huggingchat/jsonlStream.ts +221 -0
- package/open-sse/executors/huggingchat.ts +593 -0
- package/open-sse/executors/index.ts +232 -0
- package/open-sse/executors/inner-ai.ts +764 -0
- package/open-sse/executors/jina-reader-fetch.ts +119 -0
- package/open-sse/executors/kie.ts +109 -0
- package/open-sse/executors/kimi-web.ts +455 -0
- package/open-sse/executors/kimi.ts +133 -0
- package/open-sse/executors/kiro/eventstream.ts +192 -0
- package/open-sse/executors/kiro.ts +821 -0
- package/open-sse/executors/kiroThinking.ts +116 -0
- package/open-sse/executors/lmarena.ts +511 -0
- package/open-sse/executors/mimocode.ts +560 -0
- package/open-sse/executors/muse-spark-web/response-parser.ts +383 -0
- package/open-sse/executors/muse-spark-web.ts +928 -0
- package/open-sse/executors/ninerouter.ts +212 -0
- package/open-sse/executors/nlpcloud.ts +546 -0
- package/open-sse/executors/opencode.ts +336 -0
- package/open-sse/executors/perplexity-web/protocol.ts +503 -0
- package/open-sse/executors/perplexity-web.ts +545 -0
- package/open-sse/executors/poe-web.ts +158 -0
- package/open-sse/executors/pollinations.ts +119 -0
- package/open-sse/executors/puter.ts +59 -0
- package/open-sse/executors/qoder.ts +416 -0
- package/open-sse/executors/qwen-web.ts +474 -0
- package/open-sse/executors/t3-chat-web.ts +582 -0
- package/open-sse/executors/tavily-fetch.ts +103 -0
- package/open-sse/executors/theoldllm.ts +354 -0
- package/open-sse/executors/tinyfish-fetch.ts +131 -0
- package/open-sse/executors/trae.ts +481 -0
- package/open-sse/executors/v0-vercel-web.ts +164 -0
- package/open-sse/executors/venice-web.ts +165 -0
- package/open-sse/executors/veoaifree-web.ts +397 -0
- package/open-sse/executors/vertex.ts +208 -0
- package/open-sse/executors/vertexMedia.ts +341 -0
- package/open-sse/executors/windsurf.ts +706 -0
- package/open-sse/executors/xai.ts +94 -0
- package/open-sse/executors/yuanbao-web.ts +504 -0
- package/open-sse/executors/zed-hosted.ts +364 -0
- package/open-sse/executors/zenmux-free.ts +283 -0
- package/open-sse/handlers/audioSpeech.ts +1060 -0
- package/open-sse/handlers/audioTranscription.ts +554 -0
- package/open-sse/handlers/audioTranslation.ts +135 -0
- package/open-sse/handlers/chatCore/attemptLogging.ts +210 -0
- package/open-sse/handlers/chatCore/backgroundRedirect.ts +41 -0
- package/open-sse/handlers/chatCore/cacheUsageMeta.ts +65 -0
- package/open-sse/handlers/chatCore/cavemanOutputAnalytics.ts +47 -0
- package/open-sse/handlers/chatCore/claudeClassifierCompat.ts +99 -0
- package/open-sse/handlers/chatCore/claudeEffortVariant.ts +62 -0
- package/open-sse/handlers/chatCore/claudeMessageTypes.ts +15 -0
- package/open-sse/handlers/chatCore/claudeSystemRole.ts +48 -0
- package/open-sse/handlers/chatCore/claudeToolDefaults.ts +27 -0
- package/open-sse/handlers/chatCore/claudeUpstreamMessages.ts +143 -0
- package/open-sse/handlers/chatCore/clientUsageBuffer.ts +54 -0
- package/open-sse/handlers/chatCore/clineResponseEnvelope.ts +25 -0
- package/open-sse/handlers/chatCore/codexFailover.ts +41 -0
- package/open-sse/handlers/chatCore/codexQuota.ts +85 -0
- package/open-sse/handlers/chatCore/comboContextCache.ts +63 -0
- package/open-sse/handlers/chatCore/compressionAnalyticsWrite.ts +149 -0
- package/open-sse/handlers/chatCore/compressionCacheStats.ts +53 -0
- package/open-sse/handlers/chatCore/compressionComboPredicates.ts +41 -0
- package/open-sse/handlers/chatCore/compressionSettings.ts +35 -0
- package/open-sse/handlers/chatCore/compressionUsageReceipt.ts +27 -0
- package/open-sse/handlers/chatCore/contextEditingTelemetry.ts +40 -0
- package/open-sse/handlers/chatCore/cooldownClassification.ts +26 -0
- package/open-sse/handlers/chatCore/executionCredentials.ts +72 -0
- package/open-sse/handlers/chatCore/executorClientHeaders.ts +36 -0
- package/open-sse/handlers/chatCore/executorHelpers.ts +151 -0
- package/open-sse/handlers/chatCore/executorProxy.ts +117 -0
- package/open-sse/handlers/chatCore/failureUsage.ts +41 -0
- package/open-sse/handlers/chatCore/gamificationEvent.ts +28 -0
- package/open-sse/handlers/chatCore/headers.ts +65 -0
- package/open-sse/handlers/chatCore/idempotency.ts +65 -0
- package/open-sse/handlers/chatCore/jsonBodyToSse.ts +161 -0
- package/open-sse/handlers/chatCore/keyHealth.ts +113 -0
- package/open-sse/handlers/chatCore/logTruncation.ts +93 -0
- package/open-sse/handlers/chatCore/memoryExtraction.ts +131 -0
- package/open-sse/handlers/chatCore/memorySkillsInjection.ts +165 -0
- package/open-sse/handlers/chatCore/nonStreamingJsonResponse.ts +16 -0
- package/open-sse/handlers/chatCore/nonStreamingResponseBody.ts +155 -0
- package/open-sse/handlers/chatCore/nonStreamingResponseHeaders.ts +46 -0
- package/open-sse/handlers/chatCore/nonStreamingResponseParse.ts +135 -0
- package/open-sse/handlers/chatCore/nonStreamingSse.ts +171 -0
- package/open-sse/handlers/chatCore/nonStreamingUsageStats.ts +90 -0
- package/open-sse/handlers/chatCore/outputStyleTelemetry.ts +53 -0
- package/open-sse/handlers/chatCore/passthroughHelpers.ts +83 -0
- package/open-sse/handlers/chatCore/passthroughToolNames.ts +65 -0
- package/open-sse/handlers/chatCore/pluginOnRequest.ts +65 -0
- package/open-sse/handlers/chatCore/pluginOnResponse.ts +34 -0
- package/open-sse/handlers/chatCore/postCallGuardrailContext.ts +47 -0
- package/open-sse/handlers/chatCore/quotaShareConsumption.ts +41 -0
- package/open-sse/handlers/chatCore/requestFormat.ts +111 -0
- package/open-sse/handlers/chatCore/requestSetup.ts +51 -0
- package/open-sse/handlers/chatCore/responseHeaders.ts +138 -0
- package/open-sse/handlers/chatCore/sanitization.ts +63 -0
- package/open-sse/handlers/chatCore/semanticCache.ts +98 -0
- package/open-sse/handlers/chatCore/semanticCacheStore.ts +73 -0
- package/open-sse/handlers/chatCore/serviceTier.ts +70 -0
- package/open-sse/handlers/chatCore/skillsFormat.ts +33 -0
- package/open-sse/handlers/chatCore/stageTrace.ts +30 -0
- package/open-sse/handlers/chatCore/streamErrorResult.ts +58 -0
- package/open-sse/handlers/chatCore/streamFinalize.ts +48 -0
- package/open-sse/handlers/chatCore/streamingCost.ts +37 -0
- package/open-sse/handlers/chatCore/streamingPipeline.ts +99 -0
- package/open-sse/handlers/chatCore/streamingQuotaShare.ts +54 -0
- package/open-sse/handlers/chatCore/streamingResponseHeaders.ts +39 -0
- package/open-sse/handlers/chatCore/streamingSemanticCacheStore.ts +95 -0
- package/open-sse/handlers/chatCore/streamingUsageStats.ts +79 -0
- package/open-sse/handlers/chatCore/targetFormat.ts +34 -0
- package/open-sse/handlers/chatCore/telemetryHelpers.ts +78 -0
- package/open-sse/handlers/chatCore/upstreamBody.ts +168 -0
- package/open-sse/handlers/chatCore/upstreamExecuteHeaders.ts +71 -0
- package/open-sse/handlers/chatCore/upstreamTimeouts.ts +158 -0
- package/open-sse/handlers/chatCore.ts +4452 -0
- package/open-sse/handlers/embeddings.ts +378 -0
- package/open-sse/handlers/imageGeneration/providers/chatgptWeb.ts +187 -0
- package/open-sse/handlers/imageGeneration/providers/comfyUI.ts +116 -0
- package/open-sse/handlers/imageGeneration/providers/haiper.ts +120 -0
- package/open-sse/handlers/imageGeneration/providers/huggingface.ts +90 -0
- package/open-sse/handlers/imageGeneration/providers/hyperbolic.ts +100 -0
- package/open-sse/handlers/imageGeneration/providers/ideogram.ts +96 -0
- package/open-sse/handlers/imageGeneration/providers/imagen3.ts +136 -0
- package/open-sse/handlers/imageGeneration/providers/leonardo.ts +140 -0
- package/open-sse/handlers/imageGeneration/providers/nvidiaNim.ts +286 -0
- package/open-sse/handlers/imageGeneration/providers/sdWebUI.ts +94 -0
- package/open-sse/handlers/imageGeneration.ts +2880 -0
- package/open-sse/handlers/moderations.ts +82 -0
- package/open-sse/handlers/musicGeneration.ts +640 -0
- package/open-sse/handlers/ocr.ts +79 -0
- package/open-sse/handlers/rerank.ts +210 -0
- package/open-sse/handlers/responseSanitizer/reasoning.ts +149 -0
- package/open-sse/handlers/responseSanitizer.ts +1086 -0
- package/open-sse/handlers/responseTranslator.ts +640 -0
- package/open-sse/handlers/responsesHandler.ts +92 -0
- package/open-sse/handlers/search.ts +1545 -0
- package/open-sse/handlers/sseParser.ts +825 -0
- package/open-sse/handlers/usageExtractor.ts +93 -0
- package/open-sse/handlers/videoGeneration/googleFlow.ts +219 -0
- package/open-sse/handlers/videoGeneration/googleFlowHandler.ts +145 -0
- package/open-sse/handlers/videoGeneration.ts +1264 -0
- package/open-sse/handlers/webFetch.ts +130 -0
- package/open-sse/index.ts +170 -0
- package/open-sse/lib/deepseek-pow-solver.cjs +3 -0
- package/open-sse/lib/deepseek-pow.ts +189 -0
- package/open-sse/lib/sha3_wasm_bg.wasm +0 -0
- package/open-sse/mcp-server/README.md +611 -0
- package/open-sse/mcp-server/audit.ts +478 -0
- package/open-sse/mcp-server/catalog.ts +290 -0
- package/open-sse/mcp-server/descriptionCompressor.ts +243 -0
- package/open-sse/mcp-server/httpAuthContext.ts +42 -0
- package/open-sse/mcp-server/httpTransport.ts +306 -0
- package/open-sse/mcp-server/index.ts +19 -0
- package/open-sse/mcp-server/mcpCallerIdentity.ts +53 -0
- package/open-sse/mcp-server/runtimeHeartbeat.ts +162 -0
- package/open-sse/mcp-server/schemas/a2a.ts +203 -0
- package/open-sse/mcp-server/schemas/audit.ts +121 -0
- package/open-sse/mcp-server/schemas/index.ts +116 -0
- package/open-sse/mcp-server/schemas/pickFastestModel.ts +110 -0
- package/open-sse/mcp-server/schemas/toolDefinition.ts +31 -0
- package/open-sse/mcp-server/schemas/toolSearch.ts +37 -0
- package/open-sse/mcp-server/schemas/tools.ts +1481 -0
- package/open-sse/mcp-server/scopeEnforcement.ts +135 -0
- package/open-sse/mcp-server/server.ts +1370 -0
- package/open-sse/mcp-server/toolCardinality.ts +254 -0
- package/open-sse/mcp-server/toolSearch/catalog.ts +98 -0
- package/open-sse/mcp-server/toolSearch/handler.ts +18 -0
- package/open-sse/mcp-server/toolSearch/index.ts +5 -0
- package/open-sse/mcp-server/toolSearch/register.ts +36 -0
- package/open-sse/mcp-server/toolSearch/search.ts +96 -0
- package/open-sse/mcp-server/toolSearch/signature.ts +92 -0
- package/open-sse/mcp-server/tools/advancedTools.ts +1119 -0
- package/open-sse/mcp-server/tools/agentSkillTools.ts +83 -0
- package/open-sse/mcp-server/tools/compressionTools.ts +451 -0
- package/open-sse/mcp-server/tools/gamificationTools.ts +148 -0
- package/open-sse/mcp-server/tools/githubSkillTools.ts +141 -0
- package/open-sse/mcp-server/tools/memoryTools.ts +137 -0
- package/open-sse/mcp-server/tools/notionTools.ts +106 -0
- package/open-sse/mcp-server/tools/obsidianTools.ts +327 -0
- package/open-sse/mcp-server/tools/pickFastestModel.ts +293 -0
- package/open-sse/mcp-server/tools/pluginTools.ts +216 -0
- package/open-sse/mcp-server/tools/poolTools.ts +205 -0
- package/open-sse/mcp-server/tools/skillTools.ts +119 -0
- package/open-sse/package.json +17 -0
- package/open-sse/services/AGENTS.md +78 -0
- package/open-sse/services/accountFallback.ts +1863 -0
- package/open-sse/services/accountSelector.ts +80 -0
- package/open-sse/services/accountSemaphore.ts +367 -0
- package/open-sse/services/antigravity429Engine.ts +178 -0
- package/open-sse/services/antigravityClientProfile.ts +167 -0
- package/open-sse/services/antigravityCredits.ts +68 -0
- package/open-sse/services/antigravityHeaderScrub.ts +75 -0
- package/open-sse/services/antigravityHeaders.ts +121 -0
- package/open-sse/services/antigravityIdentity.ts +127 -0
- package/open-sse/services/antigravityObfuscation.ts +64 -0
- package/open-sse/services/antigravityProjectBootstrap.ts +145 -0
- package/open-sse/services/antigravityQuotaFamily.ts +56 -0
- package/open-sse/services/antigravityVersion.ts +163 -0
- package/open-sse/services/apiKeyRotator.ts +385 -0
- package/open-sse/services/autoCombo/autoPrefix.ts +61 -0
- package/open-sse/services/autoCombo/builtinCatalog.ts +126 -0
- package/open-sse/services/autoCombo/complexityRouter.ts +111 -0
- package/open-sse/services/autoCombo/engine.ts +314 -0
- package/open-sse/services/autoCombo/index.ts +18 -0
- package/open-sse/services/autoCombo/modePacks.ts +105 -0
- package/open-sse/services/autoCombo/modelFamily.ts +95 -0
- package/open-sse/services/autoCombo/paidModelFilter.ts +44 -0
- package/open-sse/services/autoCombo/persistence.ts +124 -0
- package/open-sse/services/autoCombo/pipelineRouter.ts +418 -0
- package/open-sse/services/autoCombo/providerDiversity.ts +170 -0
- package/open-sse/services/autoCombo/providerRegistryAccessor.ts +9 -0
- package/open-sse/services/autoCombo/requestControls.ts +80 -0
- package/open-sse/services/autoCombo/routerStrategy.ts +375 -0
- package/open-sse/services/autoCombo/scoring.ts +242 -0
- package/open-sse/services/autoCombo/selfHealing.ts +167 -0
- package/open-sse/services/autoCombo/speedRanking.ts +327 -0
- package/open-sse/services/autoCombo/suffixComposition.ts +147 -0
- package/open-sse/services/autoCombo/taskFitness.ts +407 -0
- package/open-sse/services/autoCombo/virtualFactory.ts +446 -0
- package/open-sse/services/autoRefreshDaemon.ts +206 -0
- package/open-sse/services/backgroundTaskDetector.ts +263 -0
- package/open-sse/services/bailianQuotaFetcher.ts +333 -0
- package/open-sse/services/batchProcessor.ts +914 -0
- package/open-sse/services/bedrock.ts +160 -0
- package/open-sse/services/browserBackedChat.ts +849 -0
- package/open-sse/services/browserPool.ts +501 -0
- package/open-sse/services/ccBridgeTransforms.ts +581 -0
- package/open-sse/services/ccWireImageBuiltins.ts +26 -0
- package/open-sse/services/chatgptImageCache.ts +143 -0
- package/open-sse/services/chatgptTlsClient.ts +628 -0
- package/open-sse/services/claudeAdaptiveThinking.ts +52 -0
- package/open-sse/services/claudeCodeCCH.ts +49 -0
- package/open-sse/services/claudeCodeCompatible.ts +1198 -0
- package/open-sse/services/claudeCodeCompatibleBeta.ts +23 -0
- package/open-sse/services/claudeCodeCompatibleThinkingDisplay.ts +34 -0
- package/open-sse/services/claudeCodeConstraints.ts +144 -0
- package/open-sse/services/claudeCodeExtraRemap.ts +18 -0
- package/open-sse/services/claudeCodeFingerprint.ts +46 -0
- package/open-sse/services/claudeCodeObfuscation.ts +116 -0
- package/open-sse/services/claudeCodeToolRemapper.ts +339 -0
- package/open-sse/services/claudeHaikuConstraints.ts +88 -0
- package/open-sse/services/claudeTlsClient.ts +590 -0
- package/open-sse/services/claudeTurnstileSolver.ts +206 -0
- package/open-sse/services/claudeUsageCooldown.ts +51 -0
- package/open-sse/services/claudeWebAutoRefresh.ts +224 -0
- package/open-sse/services/clinepassModels.ts +76 -0
- package/open-sse/services/cloudCodeHeaders.ts +41 -0
- package/open-sse/services/cloudCodeThinking.ts +71 -0
- package/open-sse/services/codeAssistSubscription.ts +83 -0
- package/open-sse/services/codexQuotaFetcher.ts +523 -0
- package/open-sse/services/codexUsageQuotas.ts +270 -0
- package/open-sse/services/codexVerbosity.ts +59 -0
- package/open-sse/services/combo/applyStrategyOrdering.ts +226 -0
- package/open-sse/services/combo/autoConfig.ts +62 -0
- package/open-sse/services/combo/autoStrategy.ts +475 -0
- package/open-sse/services/combo/comboCompatFallback.ts +82 -0
- package/open-sse/services/combo/comboCooldownRetry.ts +237 -0
- package/open-sse/services/combo/comboData.ts +24 -0
- package/open-sse/services/combo/comboPredicates.ts +211 -0
- package/open-sse/services/combo/comboSetup.ts +135 -0
- package/open-sse/services/combo/comboStructure.ts +766 -0
- package/open-sse/services/combo/concurrencyCaps.ts +76 -0
- package/open-sse/services/combo/context.ts +46 -0
- package/open-sse/services/combo/fingerprintExpansion.ts +105 -0
- package/open-sse/services/combo/headroomRanking.ts +91 -0
- package/open-sse/services/combo/providerWildcard.ts +253 -0
- package/open-sse/services/combo/quotaExhaustionCutoff.ts +140 -0
- package/open-sse/services/combo/quotaScoring.ts +311 -0
- package/open-sse/services/combo/quotaShareConcurrency.ts +74 -0
- package/open-sse/services/combo/quotaShareInflight.ts +133 -0
- package/open-sse/services/combo/quotaShareStrategy.ts +349 -0
- package/open-sse/services/combo/quotaStrategies.ts +647 -0
- package/open-sse/services/combo/resolveAutoStrategy.ts +334 -0
- package/open-sse/services/combo/responseValidation.ts +206 -0
- package/open-sse/services/combo/rrState.ts +98 -0
- package/open-sse/services/combo/runtimeUnits.ts +269 -0
- package/open-sse/services/combo/sessionStickiness.ts +301 -0
- package/open-sse/services/combo/shadowRouting.ts +179 -0
- package/open-sse/services/combo/targetExhaustion.ts +160 -0
- package/open-sse/services/combo/targetSorters.ts +174 -0
- package/open-sse/services/combo/targetTimeoutRunner.ts +91 -0
- package/open-sse/services/combo/types.ts +175 -0
- package/open-sse/services/combo/validateQuality.ts +445 -0
- package/open-sse/services/combo.ts +3085 -0
- package/open-sse/services/comboAgentMiddleware.ts +214 -0
- package/open-sse/services/comboConfig.ts +248 -0
- package/open-sse/services/comboManifestMetrics.ts +13 -0
- package/open-sse/services/comboMetrics.ts +480 -0
- package/open-sse/services/compression/adaptiveCompression/computeTarget.ts +31 -0
- package/open-sse/services/compression/adaptiveCompression/ladder.ts +59 -0
- package/open-sse/services/compression/adaptiveCompression/resolveAdaptivePlan.ts +104 -0
- package/open-sse/services/compression/adaptiveCompression/types.ts +61 -0
- package/open-sse/services/compression/aggressive.ts +204 -0
- package/open-sse/services/compression/bodyAdapter.ts +354 -0
- package/open-sse/services/compression/cacheAwareConfig.ts +60 -0
- package/open-sse/services/compression/cachingAware.ts +130 -0
- package/open-sse/services/compression/caveman.ts +602 -0
- package/open-sse/services/compression/cavemanRules.ts +432 -0
- package/open-sse/services/compression/deriveDefaultPlan.ts +59 -0
- package/open-sse/services/compression/diffHelper.ts +219 -0
- package/open-sse/services/compression/engineBreakdown.ts +29 -0
- package/open-sse/services/compression/engineCatalog.ts +91 -0
- package/open-sse/services/compression/engines/cavemanAdapter.ts +454 -0
- package/open-sse/services/compression/engines/ccr/ccrQuery.ts +110 -0
- package/open-sse/services/compression/engines/ccr/index.ts +460 -0
- package/open-sse/services/compression/engines/headroom/encoderComparison.ts +72 -0
- package/open-sse/services/compression/engines/headroom/gcf/decode_generic.ts +711 -0
- package/open-sse/services/compression/engines/headroom/gcf/generic.ts +332 -0
- package/open-sse/services/compression/engines/headroom/gcf/index.ts +9 -0
- package/open-sse/services/compression/engines/headroom/gcf/scalar.ts +336 -0
- package/open-sse/services/compression/engines/headroom/index.ts +286 -0
- package/open-sse/services/compression/engines/headroom/smartcrusher.ts +255 -0
- package/open-sse/services/compression/engines/headroom/tabular.ts +263 -0
- package/open-sse/services/compression/engines/headroom/toon.ts +43 -0
- package/open-sse/services/compression/engines/index.ts +42 -0
- package/open-sse/services/compression/engines/ionizer/index.ts +124 -0
- package/open-sse/services/compression/engines/ionizer/sample.ts +200 -0
- package/open-sse/services/compression/engines/llm/index.ts +346 -0
- package/open-sse/services/compression/engines/llmlingua/constants.ts +55 -0
- package/open-sse/services/compression/engines/llmlingua/index.ts +474 -0
- package/open-sse/services/compression/engines/llmlingua/modelStore.ts +67 -0
- package/open-sse/services/compression/engines/llmlingua/onnxWorker.ts +117 -0
- package/open-sse/services/compression/engines/llmlingua/ultraEntry.ts +109 -0
- package/open-sse/services/compression/engines/llmlingua/worker.ts +373 -0
- package/open-sse/services/compression/engines/mcpAccessibility/collapseRepeated.ts +121 -0
- package/open-sse/services/compression/engines/mcpAccessibility/constants.ts +63 -0
- package/open-sse/services/compression/engines/mcpAccessibility/index.ts +52 -0
- package/open-sse/services/compression/engines/readLifecycle/index.ts +299 -0
- package/open-sse/services/compression/engines/registry.ts +87 -0
- package/open-sse/services/compression/engines/relevance/configSchema.ts +63 -0
- package/open-sse/services/compression/engines/relevance/index.ts +185 -0
- package/open-sse/services/compression/engines/relevance/scorer.ts +85 -0
- package/open-sse/services/compression/engines/rtk/codeStripper.ts +145 -0
- package/open-sse/services/compression/engines/rtk/commandDetector.ts +482 -0
- package/open-sse/services/compression/engines/rtk/configSchema.ts +117 -0
- package/open-sse/services/compression/engines/rtk/deduplicator.ts +37 -0
- package/open-sse/services/compression/engines/rtk/discover.ts +150 -0
- package/open-sse/services/compression/engines/rtk/filterLoader.ts +245 -0
- package/open-sse/services/compression/engines/rtk/filterSchema.ts +207 -0
- package/open-sse/services/compression/engines/rtk/filters/aws.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/biome.json +35 -0
- package/open-sse/services/compression/engines/rtk/filters/build-eslint.json +37 -0
- package/open-sse/services/compression/engines/rtk/filters/build-typescript.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/build-vite.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/build-webpack.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/bundle-install.json +35 -0
- package/open-sse/services/compression/engines/rtk/filters/composer.json +81 -0
- package/open-sse/services/compression/engines/rtk/filters/curl.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/df.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/docker-build.json +78 -0
- package/open-sse/services/compression/engines/rtk/filters/docker-logs.json +42 -0
- package/open-sse/services/compression/engines/rtk/filters/docker-ps.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/dotnet.json +47 -0
- package/open-sse/services/compression/engines/rtk/filters/du.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/error-stacktrace.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/gcloud.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/generic-output.json +32 -0
- package/open-sse/services/compression/engines/rtk/filters/gh.json +98 -0
- package/open-sse/services/compression/engines/rtk/filters/git-branch.json +45 -0
- package/open-sse/services/compression/engines/rtk/filters/git-diff.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/git-log.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/git-status.json +40 -0
- package/open-sse/services/compression/engines/rtk/filters/golangci-lint.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/gradle.json +47 -0
- package/open-sse/services/compression/engines/rtk/filters/json-output.json +40 -0
- package/open-sse/services/compression/engines/rtk/filters/kubectl.json +99 -0
- package/open-sse/services/compression/engines/rtk/filters/make.json +38 -0
- package/open-sse/services/compression/engines/rtk/filters/mypy.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/npm-audit.json +43 -0
- package/open-sse/services/compression/engines/rtk/filters/npm-install.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/nx.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/pip.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/playwright.json +42 -0
- package/open-sse/services/compression/engines/rtk/filters/poetry-install.json +35 -0
- package/open-sse/services/compression/engines/rtk/filters/prettier.json +40 -0
- package/open-sse/services/compression/engines/rtk/filters/ps.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/rsync.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/rubocop.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/ruff.json +40 -0
- package/open-sse/services/compression/engines/rtk/filters/shell-find.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/shell-grep.json +37 -0
- package/open-sse/services/compression/engines/rtk/filters/shell-ls.json +33 -0
- package/open-sse/services/compression/engines/rtk/filters/ssh.json +43 -0
- package/open-sse/services/compression/engines/rtk/filters/systemctl-status.json +43 -0
- package/open-sse/services/compression/engines/rtk/filters/terraform-plan.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/test-cargo.json +42 -0
- package/open-sse/services/compression/engines/rtk/filters/test-go.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/test-jest.json +43 -0
- package/open-sse/services/compression/engines/rtk/filters/test-pytest.json +41 -0
- package/open-sse/services/compression/engines/rtk/filters/test-vitest.json +43 -0
- package/open-sse/services/compression/engines/rtk/filters/tofu-plan.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/turbo.json +34 -0
- package/open-sse/services/compression/engines/rtk/filters/uv-sync.json +35 -0
- package/open-sse/services/compression/engines/rtk/filters/wget.json +34 -0
- package/open-sse/services/compression/engines/rtk/grouper.ts +99 -0
- package/open-sse/services/compression/engines/rtk/index.ts +706 -0
- package/open-sse/services/compression/engines/rtk/learn.ts +290 -0
- package/open-sse/services/compression/engines/rtk/lineFilter.ts +178 -0
- package/open-sse/services/compression/engines/rtk/rawOutput.ts +208 -0
- package/open-sse/services/compression/engines/rtk/renderers/gitDiff.ts +39 -0
- package/open-sse/services/compression/engines/rtk/renderers/index.ts +50 -0
- package/open-sse/services/compression/engines/rtk/renderers/structuredTable.ts +96 -0
- package/open-sse/services/compression/engines/rtk/renderers/terraformPlan.ts +40 -0
- package/open-sse/services/compression/engines/rtk/renderers/testGreen.ts +70 -0
- package/open-sse/services/compression/engines/rtk/renderers/types.ts +13 -0
- package/open-sse/services/compression/engines/rtk/smartTruncate.ts +67 -0
- package/open-sse/services/compression/engines/rtk/splitCompositeCommand.ts +111 -0
- package/open-sse/services/compression/engines/rtk/verify.ts +107 -0
- package/open-sse/services/compression/engines/session-dedup/fuzzy.ts +153 -0
- package/open-sse/services/compression/engines/session-dedup/index.ts +435 -0
- package/open-sse/services/compression/engines/types.ts +77 -0
- package/open-sse/services/compression/entrypointWrap.ts +43 -0
- package/open-sse/services/compression/eval/aggregate.ts +62 -0
- package/open-sse/services/compression/eval/corpus.ts +45 -0
- package/open-sse/services/compression/eval/costMeter.ts +31 -0
- package/open-sse/services/compression/eval/executorModelClient.ts +44 -0
- package/open-sse/services/compression/eval/fidelityCheck.ts +61 -0
- package/open-sse/services/compression/eval/grader.ts +27 -0
- package/open-sse/services/compression/eval/judge.ts +68 -0
- package/open-sse/services/compression/eval/report.ts +44 -0
- package/open-sse/services/compression/eval/runner.ts +135 -0
- package/open-sse/services/compression/eval/savings.ts +30 -0
- package/open-sse/services/compression/eval/seedCorpus.ts +60 -0
- package/open-sse/services/compression/eval/types.ts +65 -0
- package/open-sse/services/compression/fidelityGate.ts +124 -0
- package/open-sse/services/compression/fidelityGateStep.ts +44 -0
- package/open-sse/services/compression/hardBudget.ts +196 -0
- package/open-sse/services/compression/harness/benchmark.ts +318 -0
- package/open-sse/services/compression/harness/budgetGate.ts +62 -0
- package/open-sse/services/compression/harness/index.ts +52 -0
- package/open-sse/services/compression/harness/measure.ts +98 -0
- package/open-sse/services/compression/harness/replay.ts +72 -0
- package/open-sse/services/compression/harness/runner.ts +58 -0
- package/open-sse/services/compression/index.ts +165 -0
- package/open-sse/services/compression/languageDetector.ts +51 -0
- package/open-sse/services/compression/lite.ts +241 -0
- package/open-sse/services/compression/messageContent.ts +89 -0
- package/open-sse/services/compression/outputMode.ts +175 -0
- package/open-sse/services/compression/outputStyles/apply.ts +135 -0
- package/open-sse/services/compression/outputStyles/backCompat.ts +29 -0
- package/open-sse/services/compression/outputStyles/catalog.ts +76 -0
- package/open-sse/services/compression/outputStyles/telemetry.ts +50 -0
- package/open-sse/services/compression/pipelineEngineBreaker.ts +139 -0
- package/open-sse/services/compression/pipelineGuards.ts +45 -0
- package/open-sse/services/compression/planResolution.ts +128 -0
- package/open-sse/services/compression/prefixFreeze.ts +124 -0
- package/open-sse/services/compression/preservation.ts +0 -0
- package/open-sse/services/compression/preserveSystemPromptMode.ts +72 -0
- package/open-sse/services/compression/progressiveAging.ts +145 -0
- package/open-sse/services/compression/quantumLock/index.ts +17 -0
- package/open-sse/services/compression/quantumLock/quantumLock.ts +58 -0
- package/open-sse/services/compression/quantumLock/quantumLockStep.ts +72 -0
- package/open-sse/services/compression/quantumLock/quantumPatterns.ts +80 -0
- package/open-sse/services/compression/quantumLock/strategyWrap.ts +72 -0
- package/open-sse/services/compression/resolveCompressionPlan.ts +28 -0
- package/open-sse/services/compression/resultMemo.ts +83 -0
- package/open-sse/services/compression/riskGate/index.ts +3 -0
- package/open-sse/services/compression/riskGate/riskGate.ts +136 -0
- package/open-sse/services/compression/riskGate/riskGateStep.ts +115 -0
- package/open-sse/services/compression/riskGate/riskPatterns.ts +61 -0
- package/open-sse/services/compression/riskGate/strategyWrap.ts +44 -0
- package/open-sse/services/compression/ruleLoader.ts +273 -0
- package/open-sse/services/compression/rules/_schema.json +31 -0
- package/open-sse/services/compression/rules/de/context.json +38 -0
- package/open-sse/services/compression/rules/de/dedup.json +38 -0
- package/open-sse/services/compression/rules/de/filler.json +70 -0
- package/open-sse/services/compression/rules/de/structural.json +30 -0
- package/open-sse/services/compression/rules/de/ultra.json +107 -0
- package/open-sse/services/compression/rules/en/context.json +88 -0
- package/open-sse/services/compression/rules/en/dedup.json +38 -0
- package/open-sse/services/compression/rules/en/filler.json +129 -0
- package/open-sse/services/compression/rules/en/structural.json +102 -0
- package/open-sse/services/compression/rules/en/ultra.json +107 -0
- package/open-sse/services/compression/rules/es/context.json +87 -0
- package/open-sse/services/compression/rules/es/dedup.json +38 -0
- package/open-sse/services/compression/rules/es/filler.json +110 -0
- package/open-sse/services/compression/rules/es/structural.json +105 -0
- package/open-sse/services/compression/rules/es/ultra.json +107 -0
- package/open-sse/services/compression/rules/fr/context.json +38 -0
- package/open-sse/services/compression/rules/fr/dedup.json +38 -0
- package/open-sse/services/compression/rules/fr/filler.json +70 -0
- package/open-sse/services/compression/rules/fr/structural.json +30 -0
- package/open-sse/services/compression/rules/fr/ultra.json +107 -0
- package/open-sse/services/compression/rules/id/context.json +113 -0
- package/open-sse/services/compression/rules/id/dedup.json +38 -0
- package/open-sse/services/compression/rules/id/filler.json +138 -0
- package/open-sse/services/compression/rules/id/structural.json +111 -0
- package/open-sse/services/compression/rules/id/ultra.json +252 -0
- package/open-sse/services/compression/rules/ja/context.json +38 -0
- package/open-sse/services/compression/rules/ja/dedup.json +38 -0
- package/open-sse/services/compression/rules/ja/filler.json +70 -0
- package/open-sse/services/compression/rules/ja/structural.json +30 -0
- package/open-sse/services/compression/rules/ja/ultra.json +86 -0
- package/open-sse/services/compression/rules/pt-BR/context.json +69 -0
- package/open-sse/services/compression/rules/pt-BR/dedup.json +51 -0
- package/open-sse/services/compression/rules/pt-BR/filler.json +151 -0
- package/open-sse/services/compression/rules/pt-BR/structural.json +78 -0
- package/open-sse/services/compression/rules/pt-BR/ultra.json +192 -0
- package/open-sse/services/compression/rules/zh/dedup.json +38 -0
- package/open-sse/services/compression/rules/zh/filler.json +54 -0
- package/open-sse/services/compression/rules/zh/ultra.json +55 -0
- package/open-sse/services/compression/stackedStepCore.ts +87 -0
- package/open-sse/services/compression/stats.ts +59 -0
- package/open-sse/services/compression/strategySelector.ts +1007 -0
- package/open-sse/services/compression/summarizer.ts +244 -0
- package/open-sse/services/compression/toolResultCompressor.ts +283 -0
- package/open-sse/services/compression/types.ts +479 -0
- package/open-sse/services/compression/ultra.ts +321 -0
- package/open-sse/services/compression/ultraHeuristic.ts +157 -0
- package/open-sse/services/compression/validation.ts +432 -0
- package/open-sse/services/contextHandoff.ts +770 -0
- package/open-sse/services/contextManager.ts +617 -0
- package/open-sse/services/credentialGate.ts +84 -0
- package/open-sse/services/crofUsageFetcher.ts +182 -0
- package/open-sse/services/cursorSessionManager.ts +208 -0
- package/open-sse/services/deepseekQuotaFetcher.ts +244 -0
- package/open-sse/services/deviceTracker.ts +307 -0
- package/open-sse/services/emergencyFallback.ts +162 -0
- package/open-sse/services/errorClassifier.ts +198 -0
- package/open-sse/services/evalRouting.ts +276 -0
- package/open-sse/services/freeWebSearch.ts +154 -0
- package/open-sse/services/fusion.ts +337 -0
- package/open-sse/services/geminiRateLimitTracker.ts +145 -0
- package/open-sse/services/geminiThoughtSignatureStore.ts +329 -0
- package/open-sse/services/genericQuotaFetcher.ts +215 -0
- package/open-sse/services/gigachatAuth.ts +113 -0
- package/open-sse/services/githubCopilotModels.ts +162 -0
- package/open-sse/services/gpt5SamplingGuard.ts +81 -0
- package/open-sse/services/grokTlsClient.ts +607 -0
- package/open-sse/services/hfModelSuggestions.ts +63 -0
- package/open-sse/services/inAppLoginService.ts +256 -0
- package/open-sse/services/intentClassifier.ts +665 -0
- package/open-sse/services/ipFilter.ts +340 -0
- package/open-sse/services/keyGroupAuth.ts +84 -0
- package/open-sse/services/kiroModels.ts +195 -0
- package/open-sse/services/manifestAdapter.ts +134 -0
- package/open-sse/services/mimoThinking.ts +54 -0
- package/open-sse/services/model.ts +738 -0
- package/open-sse/services/modelCapabilities.ts +5 -0
- package/open-sse/services/modelDeprecation.ts +173 -0
- package/open-sse/services/modelFamilyFallback.ts +240 -0
- package/open-sse/services/modelStrip.ts +60 -0
- package/open-sse/services/modelscopePolicy.ts +97 -0
- package/open-sse/services/opencodeOllamaUsage.ts +562 -0
- package/open-sse/services/opencodeQuotaFetcher.ts +351 -0
- package/open-sse/services/payloadRules.ts +474 -0
- package/open-sse/services/perplexityTlsClient.ts +593 -0
- package/open-sse/services/pipeline.ts +189 -0
- package/open-sse/services/provider.ts +460 -0
- package/open-sse/services/providerCooldownTracker.ts +198 -0
- package/open-sse/services/providerCostData.ts +52 -0
- package/open-sse/services/providerDefaultRateLimit.ts +94 -0
- package/open-sse/services/providerRequestDefaults.ts +88 -0
- package/open-sse/services/proxyAutoSelector.ts +58 -0
- package/open-sse/services/qoderCli.ts +987 -0
- package/open-sse/services/qoderCliResolve.ts +111 -0
- package/open-sse/services/quotaFetchThrottle.ts +118 -0
- package/open-sse/services/quotaMonitor.ts +377 -0
- package/open-sse/services/quotaPreflight.ts +349 -0
- package/open-sse/services/qwenThinking.ts +44 -0
- package/open-sse/services/rateLimitManager/headers.ts +94 -0
- package/open-sse/services/rateLimitManager.ts +945 -0
- package/open-sse/services/rateLimitSemaphore.ts +231 -0
- package/open-sse/services/reasoningCache.ts +514 -0
- package/open-sse/services/reasoningTokenBuffer.ts +50 -0
- package/open-sse/services/refreshSerializer.ts +131 -0
- package/open-sse/services/requestDedup.ts +127 -0
- package/open-sse/services/responseModelEcho.ts +79 -0
- package/open-sse/services/responsesInputSanitizer.ts +145 -0
- package/open-sse/services/retryAfterJson.ts +44 -0
- package/open-sse/services/roleNormalizer.ts +283 -0
- package/open-sse/services/searchCache.ts +150 -0
- package/open-sse/services/sessionManager.ts +380 -0
- package/open-sse/services/sessionPool/fingerprintRotator.ts +126 -0
- package/open-sse/services/sessionPool/index.ts +28 -0
- package/open-sse/services/sessionPool/poolRegistry.ts +93 -0
- package/open-sse/services/sessionPool/session.ts +119 -0
- package/open-sse/services/sessionPool/sessionFactory.ts +57 -0
- package/open-sse/services/sessionPool/sessionPool.ts +326 -0
- package/open-sse/services/sessionPool/types.ts +100 -0
- package/open-sse/services/sessionPool/webExecutorWrapper.ts +132 -0
- package/open-sse/services/signatureCache.ts +189 -0
- package/open-sse/services/slidingWindowLimiter.ts +84 -0
- package/open-sse/services/specificityDetector.ts +89 -0
- package/open-sse/services/specificityRules.ts +257 -0
- package/open-sse/services/specificityTypes.ts +43 -0
- package/open-sse/services/streamRecovery.ts +545 -0
- package/open-sse/services/systemPrompt.ts +187 -0
- package/open-sse/services/systemTransforms.ts +532 -0
- package/open-sse/services/taskAwareRouter.ts +326 -0
- package/open-sse/services/taskAwareRouting.ts +553 -0
- package/open-sse/services/thinkingBudget.ts +391 -0
- package/open-sse/services/tierConfig.ts +124 -0
- package/open-sse/services/tierDefaults.json +26 -0
- package/open-sse/services/tierResolver.ts +144 -0
- package/open-sse/services/tierTypes.ts +40 -0
- package/open-sse/services/tlsClientProxy.ts +30 -0
- package/open-sse/services/tokenExtractionConfig.ts +398 -0
- package/open-sse/services/tokenLimitCounter.ts +342 -0
- package/open-sse/services/tokenRefresh.ts +2180 -0
- package/open-sse/services/toolLatencyTracker.ts +89 -0
- package/open-sse/services/toolLimitDetector.ts +87 -0
- package/open-sse/services/toolSchemaSanitizer.ts +165 -0
- package/open-sse/services/usage/antigravity.ts +794 -0
- package/open-sse/services/usage/claude.ts +216 -0
- package/open-sse/services/usage/codebuddy-cn.ts +199 -0
- package/open-sse/services/usage/codex.ts +75 -0
- package/open-sse/services/usage/cursor.ts +161 -0
- package/open-sse/services/usage/glm.ts +220 -0
- package/open-sse/services/usage/kimi.ts +209 -0
- package/open-sse/services/usage/kiro.ts +243 -0
- package/open-sse/services/usage/minimax.ts +346 -0
- package/open-sse/services/usage/quota.ts +85 -0
- package/open-sse/services/usage/scalars.ts +75 -0
- package/open-sse/services/usage.ts +1058 -0
- package/open-sse/services/volumeDetector.ts +224 -0
- package/open-sse/services/webSearchFallback.ts +246 -0
- package/open-sse/services/webSearchRouting.ts +68 -0
- package/open-sse/services/webSessionPoolHealth.ts +287 -0
- package/open-sse/services/wildcardRouter.ts +136 -0
- package/open-sse/services/workflowFSM.ts +340 -0
- package/open-sse/shared/zedAuth.ts +535 -0
- package/open-sse/transformer/responsesTransformer.ts +667 -0
- package/open-sse/translator/bootstrap.ts +27 -0
- package/open-sse/translator/deepseekWebTools.ts +486 -0
- package/open-sse/translator/formats.ts +12 -0
- package/open-sse/translator/helpers/claudeHelper.ts +563 -0
- package/open-sse/translator/helpers/geminiHelper.ts +657 -0
- package/open-sse/translator/helpers/geminiToolsSanitizer.ts +255 -0
- package/open-sse/translator/helpers/jsonUtil.ts +18 -0
- package/open-sse/translator/helpers/maxTokensHelper.ts +21 -0
- package/open-sse/translator/helpers/openaiHelper.ts +244 -0
- package/open-sse/translator/helpers/responsesApiHelper.ts +9 -0
- package/open-sse/translator/helpers/schemaCoercion.ts +408 -0
- package/open-sse/translator/helpers/toolCallHelper.ts +224 -0
- package/open-sse/translator/helpers/toolCallShim.ts +113 -0
- package/open-sse/translator/image/sizeMapper.ts +22 -0
- package/open-sse/translator/index.ts +614 -0
- package/open-sse/translator/paramSupport.ts +70 -0
- package/open-sse/translator/registry.ts +41 -0
- package/open-sse/translator/request/antigravity-to-openai.ts +357 -0
- package/open-sse/translator/request/claude-to-gemini.ts +236 -0
- package/open-sse/translator/request/claude-to-openai.ts +534 -0
- package/open-sse/translator/request/gemini-to-openai.ts +193 -0
- package/open-sse/translator/request/openai-responses/helpers.ts +69 -0
- package/open-sse/translator/request/openai-responses/toResponses.ts +357 -0
- package/open-sse/translator/request/openai-responses.ts +533 -0
- package/open-sse/translator/request/openai-to-claude/thinkingBudget.ts +89 -0
- package/open-sse/translator/request/openai-to-claude/toolResultAdjacency.ts +106 -0
- package/open-sse/translator/request/openai-to-claude.ts +747 -0
- package/open-sse/translator/request/openai-to-cursor.ts +226 -0
- package/open-sse/translator/request/openai-to-gemini/helpers.ts +142 -0
- package/open-sse/translator/request/openai-to-gemini.ts +753 -0
- package/open-sse/translator/request/openai-to-kiro/messageHelpers.ts +109 -0
- package/open-sse/translator/request/openai-to-kiro.ts +889 -0
- package/open-sse/translator/response/claude-to-openai.ts +327 -0
- package/open-sse/translator/response/cursor-to-openai.ts +30 -0
- package/open-sse/translator/response/gemini-to-claude.ts +199 -0
- package/open-sse/translator/response/gemini-to-openai.ts +765 -0
- package/open-sse/translator/response/kiro-to-openai.ts +211 -0
- package/open-sse/translator/response/openai-responses/pureHelpers.ts +92 -0
- package/open-sse/translator/response/openai-responses.ts +1011 -0
- package/open-sse/translator/response/openai-to-antigravity.ts +145 -0
- package/open-sse/translator/response/openai-to-claude.ts +289 -0
- package/open-sse/translator/response/openai-to-gemini-sse.ts +431 -0
- package/open-sse/translator/webTools.ts +531 -0
- package/open-sse/tsconfig.json +25 -0
- package/open-sse/types.d.ts +139 -0
- package/open-sse/utils/agentGoalPolicy.ts +112 -0
- package/open-sse/utils/aiSdkCompat.ts +179 -0
- package/open-sse/utils/anthropicHost.ts +25 -0
- package/open-sse/utils/awsSigV4.ts +139 -0
- package/open-sse/utils/bypassHandler.ts +300 -0
- package/open-sse/utils/cacheControlPolicy.ts +374 -0
- package/open-sse/utils/claudeCodeMetaRequests.ts +87 -0
- package/open-sse/utils/clinepassEnvelope.ts +59 -0
- package/open-sse/utils/comfyuiClient.ts +126 -0
- package/open-sse/utils/composerToolCalls.ts +307 -0
- package/open-sse/utils/cors.ts +13 -0
- package/open-sse/utils/cursorAgentProtobuf/wire.ts +143 -0
- package/open-sse/utils/cursorAgentProtobuf.ts +1400 -0
- package/open-sse/utils/cursorChecksum.ts +139 -0
- package/open-sse/utils/cursorImages.ts +354 -0
- package/open-sse/utils/cursorVersionDetector.ts +74 -0
- package/open-sse/utils/diagnostics.ts +288 -0
- package/open-sse/utils/earlyStreamKeepalive.ts +228 -0
- package/open-sse/utils/error.ts +515 -0
- package/open-sse/utils/estimateSize.ts +35 -0
- package/open-sse/utils/finishReason.ts +36 -0
- package/open-sse/utils/flattenToolHistory.ts +116 -0
- package/open-sse/utils/headers.ts +61 -0
- package/open-sse/utils/heapPressure.ts +81 -0
- package/open-sse/utils/jsonToSse.ts +127 -0
- package/open-sse/utils/keepaliveThreshold.ts +62 -0
- package/open-sse/utils/kieTask.ts +127 -0
- package/open-sse/utils/kiroSanitizer.ts +127 -0
- package/open-sse/utils/logger.ts +190 -0
- package/open-sse/utils/networkProxy.ts +75 -0
- package/open-sse/utils/noThinkingAlias.ts +153 -0
- package/open-sse/utils/number.ts +4 -0
- package/open-sse/utils/ollamaTransform.ts +122 -0
- package/open-sse/utils/opencodeHeaders.ts +98 -0
- package/open-sse/utils/passthroughTailProcessor.ts +299 -0
- package/open-sse/utils/progressTracker.ts +112 -0
- package/open-sse/utils/providerRequestLogging.ts +272 -0
- package/open-sse/utils/proxyDispatcher.ts +507 -0
- package/open-sse/utils/proxyDispatcherCache.ts +124 -0
- package/open-sse/utils/proxyFallback.ts +418 -0
- package/open-sse/utils/proxyFamily.ts +24 -0
- package/open-sse/utils/proxyFamilyResolve.ts +39 -0
- package/open-sse/utils/proxyFetch.ts +666 -0
- package/open-sse/utils/publicCreds.ts +215 -0
- package/open-sse/utils/reasoningContentInjector.ts +73 -0
- package/open-sse/utils/reasoningFields.ts +72 -0
- package/open-sse/utils/requestLogger.ts +386 -0
- package/open-sse/utils/responsesInputNormalization.ts +94 -0
- package/open-sse/utils/responsesStatePolicy.ts +75 -0
- package/open-sse/utils/responsesStreamHelpers.ts +166 -0
- package/open-sse/utils/setupPolyfill.ts +33 -0
- package/open-sse/utils/sha3-512.ts +164 -0
- package/open-sse/utils/sleep.ts +9 -0
- package/open-sse/utils/socksConnectorWithFamily.ts +89 -0
- package/open-sse/utils/sseHeartbeat.ts +119 -0
- package/open-sse/utils/stream.ts +2791 -0
- package/open-sse/utils/streamFailureFinalization.ts +174 -0
- package/open-sse/utils/streamHandler.ts +680 -0
- package/open-sse/utils/streamHelpers.ts +460 -0
- package/open-sse/utils/streamPayloadCollector.ts +700 -0
- package/open-sse/utils/streamReadiness.ts +385 -0
- package/open-sse/utils/streamReadinessPolicy.ts +132 -0
- package/open-sse/utils/textualToolCall.ts +112 -0
- package/open-sse/utils/thinkCloseMarker.ts +77 -0
- package/open-sse/utils/thinkTagParser.ts +146 -0
- package/open-sse/utils/tlsClient.ts +243 -0
- package/open-sse/utils/toolCallArguments.ts +32 -0
- package/open-sse/utils/toolSources.ts +69 -0
- package/open-sse/utils/upstreamResponseHeaders.ts +47 -0
- package/open-sse/utils/urlSanitize.ts +24 -0
- package/open-sse/utils/usageTracking.ts +596 -0
- package/package.json +393 -0
- package/scripts/build/build-next-isolated.mjs +322 -0
- package/scripts/build/colocateOptionals.mjs +144 -0
- package/scripts/build/native-binary-compat.mjs +167 -0
- package/scripts/build/postinstall.mjs +357 -0
- package/scripts/build/postinstallSupport.mjs +45 -0
- package/scripts/build/runtime-env.mjs +140 -0
- package/scripts/build/sync-env.mjs +3 -0
- package/scripts/check/check-supported-node-runtime.ts +20 -0
- package/scripts/dev/responses-ws-proxy.mjs +907 -0
- package/scripts/dev/sync-env.mjs +362 -0
- package/scripts/dev/tls-options.mjs +92 -0
- package/scripts/postinstall.mjs +27 -0
- package/src/domain/assessment/assessor.ts +206 -0
- package/src/domain/assessment/categorizer.ts +118 -0
- package/src/domain/assessment/index.ts +24 -0
- package/src/domain/assessment/migration.ts +111 -0
- package/src/domain/assessment/selfHealer.ts +261 -0
- package/src/domain/assessment/types.ts +361 -0
- package/src/domain/comboResolver.ts +106 -0
- package/src/domain/configAudit.ts +285 -0
- package/src/domain/connectionModelRules.ts +82 -0
- package/src/domain/costRules.ts +631 -0
- package/src/domain/degradation.ts +253 -0
- package/src/domain/fallbackPolicy.ts +160 -0
- package/src/domain/lockoutPolicy.ts +208 -0
- package/src/domain/modelAvailability.ts +41 -0
- package/src/domain/omnirouteResponseMeta.ts +202 -0
- package/src/domain/pipeline.ts +307 -0
- package/src/domain/policyEngine.ts +195 -0
- package/src/domain/prompts.ts +103 -0
- package/src/domain/providerExpiration.ts +255 -0
- package/src/domain/quotaCache.ts +553 -0
- package/src/domain/responses.ts +139 -0
- package/src/domain/tagRouter.ts +64 -0
- package/src/domain/types.ts +123 -0
- package/src/lib/a2a/README.md +748 -0
- package/src/lib/a2a/routingLogger.ts +67 -0
- package/src/lib/a2a/skills/costAnalysis.ts +162 -0
- package/src/lib/a2a/skills/healthReport.ts +155 -0
- package/src/lib/a2a/skills/listCapabilities.ts +72 -0
- package/src/lib/a2a/skills/providerDiscovery.ts +202 -0
- package/src/lib/a2a/skills/quotaManagement.ts +121 -0
- package/src/lib/a2a/skills/smartRouting.ts +89 -0
- package/src/lib/a2a/streaming.ts +149 -0
- package/src/lib/a2a/taskExecution.ts +64 -0
- package/src/lib/a2a/taskManager.ts +240 -0
- package/src/lib/accessTokens/scopes.ts +51 -0
- package/src/lib/acp/index.ts +11 -0
- package/src/lib/acp/manager.ts +202 -0
- package/src/lib/acp/registry.ts +384 -0
- package/src/lib/agentSkills/catalog.ts +256 -0
- package/src/lib/agentSkills/cliRegistryParser.ts +242 -0
- package/src/lib/agentSkills/generator.ts +367 -0
- package/src/lib/agentSkills/openapiParser.ts +201 -0
- package/src/lib/agentSkills/schemas.ts +36 -0
- package/src/lib/agentSkills/types.ts +101 -0
- package/src/lib/api/comboErrorResponse.ts +80 -0
- package/src/lib/api/errorResponse.ts +54 -0
- package/src/lib/api/modelTestRunner.ts +390 -0
- package/src/lib/api/proxyRegistryRouteHandlers.ts +142 -0
- package/src/lib/api/requireCliToolsAuth.ts +5 -0
- package/src/lib/api/requireManagementAuth.ts +118 -0
- package/src/lib/api/serverErrorMessage.ts +36 -0
- package/src/lib/apiBridgeServer.ts +233 -0
- package/src/lib/apiKeyExposure.ts +19 -0
- package/src/lib/arenaEloSync.ts +564 -0
- package/src/lib/audit/activityIcons.ts +69 -0
- package/src/lib/audit/highLevelActions.ts +57 -0
- package/src/lib/audit/timeline.ts +132 -0
- package/src/lib/auth/managementPassword.ts +117 -0
- package/src/lib/batches/costEstimator.ts +130 -0
- package/src/lib/batches/csvToJsonl.ts +248 -0
- package/src/lib/batches/dispatch.ts +53 -0
- package/src/lib/batches/retryFailed.ts +77 -0
- package/src/lib/batches/schemas.ts +38 -0
- package/src/lib/batches/types.ts +78 -0
- package/src/lib/batches/validateJsonl.ts +154 -0
- package/src/lib/benchmarks.ts +33 -0
- package/src/lib/build-profile/featureDisabled.ts +23 -0
- package/src/lib/cacheControlSettings.ts +25 -0
- package/src/lib/cacheLayer.ts +220 -0
- package/src/lib/catalog/openrouterCatalog.ts +177 -0
- package/src/lib/cli-helper/claudeProfileAutoSync.ts +92 -0
- package/src/lib/cli-helper/codexProfileAutoSync.ts +80 -0
- package/src/lib/cli-helper/config-generator/claude.ts +25 -0
- package/src/lib/cli-helper/config-generator/cline.ts +23 -0
- package/src/lib/cli-helper/config-generator/codex.ts +34 -0
- package/src/lib/cli-helper/config-generator/continue.ts +37 -0
- package/src/lib/cli-helper/config-generator/hermes-agent.ts +210 -0
- package/src/lib/cli-helper/config-generator/hermes.ts +47 -0
- package/src/lib/cli-helper/config-generator/hermesHome.ts +40 -0
- package/src/lib/cli-helper/config-generator/index.ts +124 -0
- package/src/lib/cli-helper/config-generator/kilocode.ts +23 -0
- package/src/lib/cli-helper/config-generator/opencode.ts +443 -0
- package/src/lib/cli-helper/doctor/checks.ts +41 -0
- package/src/lib/cli-helper/log-streamer.ts +78 -0
- package/src/lib/cli-helper/tool-detector.ts +165 -0
- package/src/lib/cliTools/batchStatusCache.ts +47 -0
- package/src/lib/cliTools/checkToolConfigStatus.ts +112 -0
- package/src/lib/cloudAgent/agents/codex.ts +148 -0
- package/src/lib/cloudAgent/agents/cursor.ts +205 -0
- package/src/lib/cloudAgent/agents/devin.ts +137 -0
- package/src/lib/cloudAgent/agents/jules.ts +354 -0
- package/src/lib/cloudAgent/api.ts +86 -0
- package/src/lib/cloudAgent/baseAgent.ts +98 -0
- package/src/lib/cloudAgent/credentials.ts +89 -0
- package/src/lib/cloudAgent/db.ts +145 -0
- package/src/lib/cloudAgent/index.ts +8 -0
- package/src/lib/cloudAgent/julesApi.ts +7 -0
- package/src/lib/cloudAgent/registry.ts +29 -0
- package/src/lib/cloudAgent/types.ts +90 -0
- package/src/lib/cloudSync.stub.ts +31 -0
- package/src/lib/cloudSync.ts +210 -0
- package/src/lib/cloudflaredTunnel.ts +933 -0
- package/src/lib/combos/autoPromote.ts +92 -0
- package/src/lib/combos/builderDraft.ts +242 -0
- package/src/lib/combos/builderOptions.ts +681 -0
- package/src/lib/combos/compositeTiers.ts +200 -0
- package/src/lib/combos/controlCenter.ts +271 -0
- package/src/lib/combos/intelligentRouting.ts +192 -0
- package/src/lib/combos/steps.ts +322 -0
- package/src/lib/combos/testHealth.ts +190 -0
- package/src/lib/compliance/index.ts +637 -0
- package/src/lib/compliance/noLog.ts +86 -0
- package/src/lib/compliance/providerAudit.ts +98 -0
- package/src/lib/compression/judgeModelClient.ts +43 -0
- package/src/lib/config/hotReload.ts +115 -0
- package/src/lib/config/runtimeSettings.ts +551 -0
- package/src/lib/consoleInterceptor.ts +136 -0
- package/src/lib/container.ts +122 -0
- package/src/lib/contextWindowResolver.ts +147 -0
- package/src/lib/copilot/codegraphKnowledge.ts +229 -0
- package/src/lib/copilot/engine.ts +372 -0
- package/src/lib/copilot/systemPrompt.ts +189 -0
- package/src/lib/copilot/tools.ts +415 -0
- package/src/lib/credentialHealth/cache.ts +206 -0
- package/src/lib/credentialHealth/scheduler.ts +328 -0
- package/src/lib/dataPaths.ts +122 -0
- package/src/lib/db/AGENTS.md +70 -0
- package/src/lib/db/_rowTypes.ts +45 -0
- package/src/lib/db/accessTokens.ts +183 -0
- package/src/lib/db/adapters/betterSqliteAdapter.ts +58 -0
- package/src/lib/db/adapters/driverFactory.ts +98 -0
- package/src/lib/db/adapters/nodeSqliteAdapter.ts +60 -0
- package/src/lib/db/adapters/nodeSqliteShared.ts +148 -0
- package/src/lib/db/adapters/sqljsAdapter.ts +232 -0
- package/src/lib/db/adapters/types.ts +34 -0
- package/src/lib/db/agentBridgeBypass.ts +81 -0
- package/src/lib/db/agentBridgeMappings.ts +47 -0
- package/src/lib/db/agentBridgeState.ts +115 -0
- package/src/lib/db/apiKeyColumnFallbacks.ts +47 -0
- package/src/lib/db/apiKeyContextSources.ts +107 -0
- package/src/lib/db/apiKeyGroups.ts +318 -0
- package/src/lib/db/apiKeyUsageLimitFields.ts +65 -0
- package/src/lib/db/apiKeys/modelPermissions.ts +122 -0
- package/src/lib/db/apiKeys/rowParsers.ts +161 -0
- package/src/lib/db/apiKeys/types.ts +21 -0
- package/src/lib/db/apiKeys.ts +1492 -0
- package/src/lib/db/backup.ts +708 -0
- package/src/lib/db/batches.ts +450 -0
- package/src/lib/db/callLogStats.ts +235 -0
- package/src/lib/db/caseMapping.ts +80 -0
- package/src/lib/db/cleanup.ts +584 -0
- package/src/lib/db/cliToolState.ts +159 -0
- package/src/lib/db/comboForecast.ts +119 -0
- package/src/lib/db/combos.ts +339 -0
- package/src/lib/db/commandCodeAuth.ts +209 -0
- package/src/lib/db/compression.ts +780 -0
- package/src/lib/db/compressionAnalytics.ts +661 -0
- package/src/lib/db/compressionCacheStats.ts +112 -0
- package/src/lib/db/compressionCombos.ts +491 -0
- package/src/lib/db/compressionRunTelemetry.ts +126 -0
- package/src/lib/db/contextHandoffs.ts +233 -0
- package/src/lib/db/core.ts +1520 -0
- package/src/lib/db/creditBalance.ts +92 -0
- package/src/lib/db/databaseSettings.ts +309 -0
- package/src/lib/db/detailedLogs.ts +170 -0
- package/src/lib/db/discovery.ts +97 -0
- package/src/lib/db/discoveryResults.ts +176 -0
- package/src/lib/db/domainState.ts +630 -0
- package/src/lib/db/encryption.ts +327 -0
- package/src/lib/db/evals.ts +786 -0
- package/src/lib/db/featureFlags.ts +82 -0
- package/src/lib/db/files.ts +170 -0
- package/src/lib/db/freeProxies.ts +360 -0
- package/src/lib/db/gamification.ts +613 -0
- package/src/lib/db/healthCheck.ts +565 -0
- package/src/lib/db/inspectorCustomHosts.ts +88 -0
- package/src/lib/db/inspectorSessions.ts +161 -0
- package/src/lib/db/jsonMigration.ts +321 -0
- package/src/lib/db/memoryVec.ts +138 -0
- package/src/lib/db/middleware.ts +239 -0
- package/src/lib/db/migrationRunner/constants.ts +118 -0
- package/src/lib/db/migrationRunner.ts +1069 -0
- package/src/lib/db/migrations/001_initial_schema.sql +226 -0
- package/src/lib/db/migrations/002_mcp_a2a_tables.sql +95 -0
- package/src/lib/db/migrations/003_provider_node_custom_paths.sql +5 -0
- package/src/lib/db/migrations/004_proxy_registry.sql +31 -0
- package/src/lib/db/migrations/005_combo_agent_fields.sql +19 -0
- package/src/lib/db/migrations/006_detailed_request_logs.sql +42 -0
- package/src/lib/db/migrations/007_search_request_type.sql +4 -0
- package/src/lib/db/migrations/008_registered_keys.sql +65 -0
- package/src/lib/db/migrations/009_requested_model.sql +9 -0
- package/src/lib/db/migrations/010_model_combo_mappings.sql +19 -0
- package/src/lib/db/migrations/011_webhooks.sql +15 -0
- package/src/lib/db/migrations/012_fix_token_input_cache_tokens.sql +15 -0
- package/src/lib/db/migrations/013_quota_snapshots.sql +19 -0
- package/src/lib/db/migrations/014_unified_log_artifacts.sql +15 -0
- package/src/lib/db/migrations/015_create_memories.sql +22 -0
- package/src/lib/db/migrations/016_create_skills.sql +37 -0
- package/src/lib/db/migrations/017_version_manager_upstream_proxy.sql +56 -0
- package/src/lib/db/migrations/018_call_logs_detailed_tokens.sql +6 -0
- package/src/lib/db/migrations/019_context_handoffs.sql +28 -0
- package/src/lib/db/migrations/020_combo_sort_order.sql +16 -0
- package/src/lib/db/migrations/021_combo_call_log_targets.sql +5 -0
- package/src/lib/db/migrations/022_add_memory_fts5.sql +33 -0
- package/src/lib/db/migrations/023_fix_memory_fts_uuid.sql +55 -0
- package/src/lib/db/migrations/024_create_sync_tokens.sql +15 -0
- package/src/lib/db/migrations/025_call_logs_summary_storage.sql +145 -0
- package/src/lib/db/migrations/027_skill_mode_and_metadata.sql +10 -0
- package/src/lib/db/migrations/028_create_files_and_batches.sql +51 -0
- package/src/lib/db/migrations/029_provider_connection_max_concurrent.sql +10 -0
- package/src/lib/db/migrations/030_create_eval_runs.sql +28 -0
- package/src/lib/db/migrations/031_create_eval_suites.sql +27 -0
- package/src/lib/db/migrations/032_apikey_lifecycle.sql +24 -0
- package/src/lib/db/migrations/033_create_reasoning_cache.sql +27 -0
- package/src/lib/db/migrations/034_compression_settings.sql +10 -0
- package/src/lib/db/migrations/035_standard_compression_config.sql +9 -0
- package/src/lib/db/migrations/036_aggressive_compression.sql +4 -0
- package/src/lib/db/migrations/037_ultra_compression.sql +6 -0
- package/src/lib/db/migrations/038_compression_analytics.sql +13 -0
- package/src/lib/db/migrations/039_compression_cache_stats.sql +15 -0
- package/src/lib/db/migrations/040_oneproxy_proxy_fields.sql +24 -0
- package/src/lib/db/migrations/041_compression_receipts.sql +18 -0
- package/src/lib/db/migrations/042_compression_combos.sql +43 -0
- package/src/lib/db/migrations/043_default_compression_combo_pipeline.sql +12 -0
- package/src/lib/db/migrations/044_usage_history_api_key_backfill.sql +27 -0
- package/src/lib/db/migrations/045_compression_tokens.sql +4 -0
- package/src/lib/db/migrations/046_database_settings.sql +44 -0
- package/src/lib/db/migrations/047_aggregation_tables.sql +44 -0
- package/src/lib/db/migrations/048_summary_indexes.sql +29 -0
- package/src/lib/db/migrations/049_compression_analytics_indexes.sql +10 -0
- package/src/lib/db/migrations/050_session_account_affinity.sql +11 -0
- package/src/lib/db/migrations/051_hot_path_db_indexes.sql +10 -0
- package/src/lib/db/migrations/052_api_key_combo_throttle.sql +4 -0
- package/src/lib/db/migrations/053_remove_status_from_files.sql +2 -0
- package/src/lib/db/migrations/054_usage_history_service_tier.sql +4 -0
- package/src/lib/db/migrations/056_mcp_accessibility_compression.sql +8 -0
- package/src/lib/db/migrations/057_provider_connection_quota_window_thresholds.sql +14 -0
- package/src/lib/db/migrations/058_command_code_auth_sessions.sql +19 -0
- package/src/lib/db/migrations/059_manifest_routing.sql +21 -0
- package/src/lib/db/migrations/060_create_gamification.sql +94 -0
- package/src/lib/db/migrations/061_cloud_agent_credentials.sql +9 -0
- package/src/lib/db/migrations/062_usage_history_combo_strategy.sql +4 -0
- package/src/lib/db/migrations/063_add_last_model_to_handoffs.sql +7 -0
- package/src/lib/db/migrations/064_create_session_model_history.sql +19 -0
- package/src/lib/db/migrations/065_middleware_hooks.sql +45 -0
- package/src/lib/db/migrations/066_api_key_groups.sql +47 -0
- package/src/lib/db/migrations/067_relay_proxies.sql +56 -0
- package/src/lib/db/migrations/068_free_proxies.sql +52 -0
- package/src/lib/db/migrations/069_webhook_deliveries.sql +15 -0
- package/src/lib/db/migrations/070_webhooks_kind_metadata.sql +3 -0
- package/src/lib/db/migrations/071_services.sql +19 -0
- package/src/lib/db/migrations/072_free_proxies_fk.sql +27 -0
- package/src/lib/db/migrations/073_per_model_token_limits.sql +61 -0
- package/src/lib/db/migrations/074_discovery_results.sql +20 -0
- package/src/lib/db/migrations/075_api_key_self_service_usage_scopes.sql +51 -0
- package/src/lib/db/migrations/076_create_plugins.sql +31 -0
- package/src/lib/db/migrations/077_api_key_stream_default_mode.sql +3 -0
- package/src/lib/db/migrations/078_quota_consumption.sql +24 -0
- package/src/lib/db/migrations/079_provider_plans.sql +19 -0
- package/src/lib/db/migrations/080_agent_bridge.sql +24 -0
- package/src/lib/db/migrations/081_inspector_custom_hosts.sql +11 -0
- package/src/lib/db/migrations/082_inspector_sessions.sql +18 -0
- package/src/lib/db/migrations/083_memory_vec.sql +26 -0
- package/src/lib/db/migrations/084_playground_presets.sql +15 -0
- package/src/lib/db/migrations/085_quota_pools.sql +39 -0
- package/src/lib/db/migrations/086_api_key_allowed_quotas.sql +8 -0
- package/src/lib/db/migrations/087_quota_pool_connections.sql +21 -0
- package/src/lib/db/migrations/088_quota_groups.sql +28 -0
- package/src/lib/db/migrations/089_add_disable_non_public_to_api_keys.sql +3 -0
- package/src/lib/db/migrations/090_plugin_metrics.sql +9 -0
- package/src/lib/db/migrations/091_plugin_analytics.sql +23 -0
- package/src/lib/db/migrations/092_api_key_context_sources.sql +13 -0
- package/src/lib/db/migrations/093_proxy_enable_toggles.sql +17 -0
- package/src/lib/db/migrations/094_per_key_proxy_toggles.sql +12 -0
- package/src/lib/db/migrations/095_provider_node_custom_headers.sql +5 -0
- package/src/lib/db/migrations/096_sync_context_cache_protection.sql +9 -0
- package/src/lib/db/migrations/097_model_intelligence.sql +25 -0
- package/src/lib/db/migrations/098_clear_semantic_cache_for_key_isolation.sql +4 -0
- package/src/lib/db/migrations/099_proxy_family.sql +5 -0
- package/src/lib/db/migrations/100_cli_access_tokens.sql +18 -0
- package/src/lib/db/migrations/101_api_key_usage_limits.sql +4 -0
- package/src/lib/db/migrations/102_compression_engines_map.sql +5 -0
- package/src/lib/db/migrations/103_strip_legacy_combo_config_keys.sql +54 -0
- package/src/lib/db/migrations/104_normalize_database_cache_size.sql +10 -0
- package/src/lib/db/migrations/105_usage_history_endpoint.sql +6 -0
- package/src/lib/db/migrations/106_quota_allocation_model_caps.sql +32 -0
- package/src/lib/db/migrations/107_quota_combos_quota_share_strategy.sql +25 -0
- package/src/lib/db/migrations/108_provider_quota_reset_events.sql +26 -0
- package/src/lib/db/migrations/109_call_logs_correlation_id.sql +2 -0
- package/src/lib/db/migrations/110_model_context_overrides.sql +17 -0
- package/src/lib/db/migrations/111_memory_typed_decay.sql +10 -0
- package/src/lib/db/migrations/112_batch_item_checkpoints.sql +18 -0
- package/src/lib/db/migrations/113_provider_node_icon_url.sql +5 -0
- package/src/lib/db/migrations/114_mux_service_seed.sql +12 -0
- package/src/lib/db/migrations/115_bifrost_service.sql +9 -0
- package/src/lib/db/migrations/116_call_logs_reasoning_source.sql +13 -0
- package/src/lib/db/migrations/117_proxy_pool_rotation.sql +53 -0
- package/src/lib/db/modelComboMappings.ts +255 -0
- package/src/lib/db/modelContextOverrides.ts +133 -0
- package/src/lib/db/modelIntelligence.ts +232 -0
- package/src/lib/db/models/aliases.ts +61 -0
- package/src/lib/db/models/compat.ts +249 -0
- package/src/lib/db/models/mitmAlias.ts +32 -0
- package/src/lib/db/models/shared.ts +19 -0
- package/src/lib/db/models.ts +936 -0
- package/src/lib/db/notion.ts +48 -0
- package/src/lib/db/obsidian.ts +283 -0
- package/src/lib/db/oneproxy.ts +293 -0
- package/src/lib/db/optimizationSettings.ts +284 -0
- package/src/lib/db/playgroundPresets.ts +167 -0
- package/src/lib/db/pluginMetrics.ts +88 -0
- package/src/lib/db/plugins.ts +280 -0
- package/src/lib/db/prompts.ts +302 -0
- package/src/lib/db/providerLimits.ts +131 -0
- package/src/lib/db/providerNodeSelect.ts +48 -0
- package/src/lib/db/providerPlans.ts +149 -0
- package/src/lib/db/providerStats.ts +68 -0
- package/src/lib/db/providers/columns.ts +116 -0
- package/src/lib/db/providers/nodes.ts +169 -0
- package/src/lib/db/providers/rateLimit.ts +198 -0
- package/src/lib/db/providers.ts +803 -0
- package/src/lib/db/proxies/mappers.ts +181 -0
- package/src/lib/db/proxies/types.ts +78 -0
- package/src/lib/db/proxies.ts +1176 -0
- package/src/lib/db/proxyLogs.ts +35 -0
- package/src/lib/db/quotaConsumption.ts +274 -0
- package/src/lib/db/quotaGroups.ts +147 -0
- package/src/lib/db/quotaModelCaps.ts +128 -0
- package/src/lib/db/quotaPools.ts +548 -0
- package/src/lib/db/quotaResetEvents.ts +334 -0
- package/src/lib/db/quotaSnapshots.ts +209 -0
- package/src/lib/db/readCache.ts +202 -0
- package/src/lib/db/reasoningCache.ts +276 -0
- package/src/lib/db/recovery.ts +33 -0
- package/src/lib/db/registeredKeys.ts +532 -0
- package/src/lib/db/relayProxies.ts +364 -0
- package/src/lib/db/schemaColumns.ts +226 -0
- package/src/lib/db/secrets.ts +28 -0
- package/src/lib/db/semanticCache.ts +117 -0
- package/src/lib/db/serviceModels.ts +79 -0
- package/src/lib/db/sessionAccountAffinity.ts +212 -0
- package/src/lib/db/settings/cacheMetrics.ts +235 -0
- package/src/lib/db/settings/lkgp.ts +49 -0
- package/src/lib/db/settings/pricing.ts +254 -0
- package/src/lib/db/settings/shared.ts +9 -0
- package/src/lib/db/settings.ts +661 -0
- package/src/lib/db/skills.ts +62 -0
- package/src/lib/db/stateReset.ts +30 -0
- package/src/lib/db/stats.ts +71 -0
- package/src/lib/db/syncTokens.ts +163 -0
- package/src/lib/db/tierConfig.ts +88 -0
- package/src/lib/db/tokenLimits.ts +295 -0
- package/src/lib/db/upstreamProxy.ts +247 -0
- package/src/lib/db/usageAnalytics/sources.ts +208 -0
- package/src/lib/db/usageAnalytics.ts +723 -0
- package/src/lib/db/usageLogs.ts +94 -0
- package/src/lib/db/usageSummary.ts +18 -0
- package/src/lib/db/vacuumScheduler.ts +326 -0
- package/src/lib/db/versionManager.ts +377 -0
- package/src/lib/db/webSessionDedup.ts +57 -0
- package/src/lib/db/webhookDeliveries.ts +77 -0
- package/src/lib/db/webhooks.ts +178 -0
- package/src/lib/discovery/index.ts +137 -0
- package/src/lib/display/names.ts +73 -0
- package/src/lib/display/useProviderNodeMap.ts +68 -0
- package/src/lib/docsI18nPath.ts +33 -0
- package/src/lib/docsSanitizer.ts +42 -0
- package/src/lib/embeddings/familyGuard.ts +24 -0
- package/src/lib/embeddings/service.ts +288 -0
- package/src/lib/env/runtimeEnv.ts +166 -0
- package/src/lib/evals/evalRunner/builtinSuites.ts +676 -0
- package/src/lib/evals/evalRunner.ts +301 -0
- package/src/lib/evals/runtime.ts +311 -0
- package/src/lib/events/eventBus.ts +148 -0
- package/src/lib/events/types.ts +181 -0
- package/src/lib/freeProviderRankings.ts +340 -0
- package/src/lib/freeProxyProviders/index.ts +24 -0
- package/src/lib/freeProxyProviders/iplocate.ts +107 -0
- package/src/lib/freeProxyProviders/oneproxy.ts +127 -0
- package/src/lib/freeProxyProviders/proxifly.ts +143 -0
- package/src/lib/freeProxyProviders/types.ts +33 -0
- package/src/lib/freeProxyProviders/webshare.ts +148 -0
- package/src/lib/gamification/antiCheat.ts +160 -0
- package/src/lib/gamification/badges.ts +542 -0
- package/src/lib/gamification/events.ts +187 -0
- package/src/lib/gamification/index.ts +37 -0
- package/src/lib/gamification/invites.ts +127 -0
- package/src/lib/gamification/leaderboard.ts +64 -0
- package/src/lib/gamification/notifications.ts +118 -0
- package/src/lib/gamification/servers.ts +179 -0
- package/src/lib/gamification/sharing.ts +56 -0
- package/src/lib/gamification/streaks.ts +164 -0
- package/src/lib/gamification/xp.ts +152 -0
- package/src/lib/gracefulShutdown.ts +151 -0
- package/src/lib/guardrails/base.ts +65 -0
- package/src/lib/guardrails/index.ts +4 -0
- package/src/lib/guardrails/piiMasker.ts +208 -0
- package/src/lib/guardrails/promptInjection.ts +285 -0
- package/src/lib/guardrails/registry.ts +282 -0
- package/src/lib/guardrails/visionBridge.ts +237 -0
- package/src/lib/guardrails/visionBridgeHelpers.ts +499 -0
- package/src/lib/guardrails/visionBridgeRouter.ts +271 -0
- package/src/lib/headroom/detect.ts +214 -0
- package/src/lib/headroom/process.ts +177 -0
- package/src/lib/idempotencyLayer.ts +105 -0
- package/src/lib/images/imageRouteModel.ts +168 -0
- package/src/lib/initCloudSync.ts +52 -0
- package/src/lib/inspector/agentBridgeMaintenanceApi.ts +70 -0
- package/src/lib/inspector/captureState.ts +90 -0
- package/src/lib/inspector/configPortability.ts +86 -0
- package/src/lib/inspector/harExport.ts +188 -0
- package/src/lib/inspector/matchesTrafficFilter.ts +37 -0
- package/src/lib/inspector/secretMask.ts +6 -0
- package/src/lib/inspector/tproxyCaptureApi.ts +60 -0
- package/src/lib/ipUtils.ts +94 -0
- package/src/lib/jobs/budgetResetJob.ts +40 -0
- package/src/lib/jobs/reasoningCacheCleanupJob.ts +40 -0
- package/src/lib/localDb.ts +797 -0
- package/src/lib/localHealthCheck.ts +267 -0
- package/src/lib/logEnv.ts +164 -0
- package/src/lib/logPayloads.ts +110 -0
- package/src/lib/logRotation.ts +206 -0
- package/src/lib/machineToken.ts +53 -0
- package/src/lib/memory/cache.ts +76 -0
- package/src/lib/memory/embedding/cache.ts +77 -0
- package/src/lib/memory/embedding/index.ts +281 -0
- package/src/lib/memory/embedding/remote.ts +95 -0
- package/src/lib/memory/embedding/staticPotion.ts +253 -0
- package/src/lib/memory/embedding/transformersLocal.ts +153 -0
- package/src/lib/memory/embedding/types.ts +40 -0
- package/src/lib/memory/extraction.ts +195 -0
- package/src/lib/memory/injection.ts +211 -0
- package/src/lib/memory/qdrant.ts +521 -0
- package/src/lib/memory/reindex.ts +102 -0
- package/src/lib/memory/retrieval/scoring.ts +104 -0
- package/src/lib/memory/retrieval.ts +1072 -0
- package/src/lib/memory/schemas.ts +39 -0
- package/src/lib/memory/settings.ts +184 -0
- package/src/lib/memory/store.ts +621 -0
- package/src/lib/memory/summarization.ts +202 -0
- package/src/lib/memory/typedDecay.ts +245 -0
- package/src/lib/memory/types.ts +45 -0
- package/src/lib/memory/vectorStore.ts +425 -0
- package/src/lib/memory/verify.ts +56 -0
- package/src/lib/middleware/cliTokenAuth.ts +91 -0
- package/src/lib/middleware/registry.ts +432 -0
- package/src/lib/middleware/types.ts +129 -0
- package/src/lib/modelAliasSeed.ts +82 -0
- package/src/lib/modelCapabilities.ts +481 -0
- package/src/lib/modelMetadataRegistry.ts +574 -0
- package/src/lib/modelsDevSync/transform.ts +279 -0
- package/src/lib/modelsDevSync.ts +677 -0
- package/src/lib/monitoring/comboHealthAutopilot.ts +494 -0
- package/src/lib/monitoring/observability.ts +336 -0
- package/src/lib/monitoring/providerHealthAutopilot.ts +743 -0
- package/src/lib/monitoring/providerHealthMatrix.ts +621 -0
- package/src/lib/ngrokTunnel.ts +142 -0
- package/src/lib/notion/api.ts +247 -0
- package/src/lib/oauth/codexDeviceFlow.ts +316 -0
- package/src/lib/oauth/config/index.ts +31 -0
- package/src/lib/oauth/connectionPersistence.ts +114 -0
- package/src/lib/oauth/constants/oauth.ts +494 -0
- package/src/lib/oauth/credentialBlob.ts +105 -0
- package/src/lib/oauth/deviceFlowTickets.ts +110 -0
- package/src/lib/oauth/gitlab.ts +103 -0
- package/src/lib/oauth/pasteCredentials.ts +51 -0
- package/src/lib/oauth/providers/agy.ts +15 -0
- package/src/lib/oauth/providers/antigravity.ts +159 -0
- package/src/lib/oauth/providers/claude.ts +170 -0
- package/src/lib/oauth/providers/cline.ts +91 -0
- package/src/lib/oauth/providers/codebuddy-cn.ts +123 -0
- package/src/lib/oauth/providers/codex.ts +214 -0
- package/src/lib/oauth/providers/cursor.ts +15 -0
- package/src/lib/oauth/providers/github.ts +89 -0
- package/src/lib/oauth/providers/gitlab-duo.ts +124 -0
- package/src/lib/oauth/providers/grok-cli.ts +155 -0
- package/src/lib/oauth/providers/index.ts +59 -0
- package/src/lib/oauth/providers/kilocode.ts +77 -0
- package/src/lib/oauth/providers/kimi-coding.ts +135 -0
- package/src/lib/oauth/providers/kiro.ts +185 -0
- package/src/lib/oauth/providers/qoder.ts +81 -0
- package/src/lib/oauth/providers/qwen.ts +82 -0
- package/src/lib/oauth/providers/trae.ts +78 -0
- package/src/lib/oauth/providers/windsurf.ts +64 -0
- package/src/lib/oauth/providers/zed-hosted.ts +89 -0
- package/src/lib/oauth/providers/zed.ts +35 -0
- package/src/lib/oauth/providers.ts +278 -0
- package/src/lib/oauth/services/codexImport.ts +222 -0
- package/src/lib/oauth/services/cursor.ts +219 -0
- package/src/lib/oauth/services/kiro.ts +441 -0
- package/src/lib/oauth/utils/agyAuthImport.ts +259 -0
- package/src/lib/oauth/utils/banner.ts +62 -0
- package/src/lib/oauth/utils/claudeAuthFile.ts +334 -0
- package/src/lib/oauth/utils/claudeAuthImport.ts +259 -0
- package/src/lib/oauth/utils/claudeAuthZipExtract.ts +5 -0
- package/src/lib/oauth/utils/cliProxyAuthImport.ts +142 -0
- package/src/lib/oauth/utils/codexAuthFile.ts +352 -0
- package/src/lib/oauth/utils/codexAuthImport.ts +294 -0
- package/src/lib/oauth/utils/codexAuthZipExtract.ts +5 -0
- package/src/lib/oauth/utils/jsonZipExtract.ts +89 -0
- package/src/lib/oauth/utils/pkce.ts +37 -0
- package/src/lib/oauth/utils/server.ts +122 -0
- package/src/lib/oauth/utils/ui.ts +47 -0
- package/src/lib/obsidian/api.ts +390 -0
- package/src/lib/obsidianSync.ts +110 -0
- package/src/lib/oneproxyRotator.ts +19 -0
- package/src/lib/oneproxySync.ts +182 -0
- package/src/lib/piiSanitizer.ts +416 -0
- package/src/lib/playground/codeExport.ts +408 -0
- package/src/lib/playground/promptImprover.ts +147 -0
- package/src/lib/playground/streamMetrics.ts +61 -0
- package/src/lib/playground/types.ts +114 -0
- package/src/lib/plugins/devMode.ts +65 -0
- package/src/lib/plugins/doctor.ts +138 -0
- package/src/lib/plugins/errors.ts +38 -0
- package/src/lib/plugins/hooks.ts +322 -0
- package/src/lib/plugins/index.ts +72 -0
- package/src/lib/plugins/loader.ts +326 -0
- package/src/lib/plugins/logger.ts +50 -0
- package/src/lib/plugins/manager.ts +579 -0
- package/src/lib/plugins/manifest.ts +213 -0
- package/src/lib/plugins/marketplace.ts +202 -0
- package/src/lib/plugins/pluginWorker.ts +246 -0
- package/src/lib/plugins/sandbox.ts +29 -0
- package/src/lib/plugins/scanner.ts +110 -0
- package/src/lib/plugins/sdk.ts +88 -0
- package/src/lib/plugins/signing.ts +34 -0
- package/src/lib/plugins/testRunner.ts +95 -0
- package/src/lib/plugins/watcher.ts +90 -0
- package/src/lib/pricingSync.ts +456 -0
- package/src/lib/promptCache/index.ts +1 -0
- package/src/lib/promptCache/prefixAnalyzer.ts +81 -0
- package/src/lib/providerModels/cursorAgent.ts +166 -0
- package/src/lib/providerModels/geminiModelsParser.ts +91 -0
- package/src/lib/providerModels/managedAvailableModels.ts +165 -0
- package/src/lib/providerModels/managedModelImport.ts +349 -0
- package/src/lib/providerModels/modelDiscovery.ts +151 -0
- package/src/lib/providers/catalog.ts +246 -0
- package/src/lib/providers/claudeExtraUsage.ts +160 -0
- package/src/lib/providers/claudeFastMode.ts +75 -0
- package/src/lib/providers/codexConnectionDefaults.ts +85 -0
- package/src/lib/providers/codexFastTier.ts +210 -0
- package/src/lib/providers/imageValidation.ts +160 -0
- package/src/lib/providers/managedAvailableModels.ts +21 -0
- package/src/lib/providers/modelListingCapability.ts +26 -0
- package/src/lib/providers/nvidiaValidationModel.ts +24 -0
- package/src/lib/providers/requestDefaults.ts +318 -0
- package/src/lib/providers/serviceKindIndex.ts +0 -0
- package/src/lib/providers/staticModels.ts +170 -0
- package/src/lib/providers/validation/anthropicFormat.ts +319 -0
- package/src/lib/providers/validation/audioMiscProviders.ts +582 -0
- package/src/lib/providers/validation/cloudProviders.ts +669 -0
- package/src/lib/providers/validation/cozeError.ts +56 -0
- package/src/lib/providers/validation/directChatProbe.ts +47 -0
- package/src/lib/providers/validation/embeddingProviders.ts +143 -0
- package/src/lib/providers/validation/headers.ts +122 -0
- package/src/lib/providers/validation/metaAi.ts +117 -0
- package/src/lib/providers/validation/openaiFormat.ts +500 -0
- package/src/lib/providers/validation/searchProviders.ts +199 -0
- package/src/lib/providers/validation/transport.ts +109 -0
- package/src/lib/providers/validation/urlHelpers.ts +114 -0
- package/src/lib/providers/validation/webProvidersA.ts +808 -0
- package/src/lib/providers/validation/webProvidersB.ts +536 -0
- package/src/lib/providers/validation.ts +772 -0
- package/src/lib/providers/webCookieAuth.ts +157 -0
- package/src/lib/providers/xai/thinking.ts +127 -0
- package/src/lib/providers/xai/translators/claude.ts +368 -0
- package/src/lib/providers/xai/translators/gemini.ts +371 -0
- package/src/lib/providers/xai/translators/openai-chat.ts +310 -0
- package/src/lib/providers/xai/translators/openai-responses.ts +77 -0
- package/src/lib/proxyEgress.ts +388 -0
- package/src/lib/proxyHealth/decision.ts +77 -0
- package/src/lib/proxyHealth/scheduler.ts +207 -0
- package/src/lib/proxyHealth/statusPolicy.ts +41 -0
- package/src/lib/proxyHealth.ts +173 -0
- package/src/lib/proxyLogger.ts +240 -0
- package/src/lib/proxyRelay/cloudflareWorkerScript.ts +107 -0
- package/src/lib/quota/QuotaStore.ts +23 -0
- package/src/lib/quota/accountBuckets.ts +225 -0
- package/src/lib/quota/burnRate.ts +111 -0
- package/src/lib/quota/connectionProvider.ts +32 -0
- package/src/lib/quota/connectionRecovery.ts +303 -0
- package/src/lib/quota/dimensions.ts +61 -0
- package/src/lib/quota/enforce.ts +401 -0
- package/src/lib/quota/fairShare.ts +186 -0
- package/src/lib/quota/planRegistry.ts +107 -0
- package/src/lib/quota/planResolver.ts +78 -0
- package/src/lib/quota/quotaCombos.ts +414 -0
- package/src/lib/quota/quotaKey.ts +202 -0
- package/src/lib/quota/quotaModelNaming.ts +84 -0
- package/src/lib/quota/redisQuotaStore.ts +352 -0
- package/src/lib/quota/saturationSignals.ts +559 -0
- package/src/lib/quota/spendRecorder.ts +131 -0
- package/src/lib/quota/sqliteQuotaStore.ts +282 -0
- package/src/lib/quota/storeFactory.ts +124 -0
- package/src/lib/quota/types.ts +94 -0
- package/src/lib/resilience/modelLockoutSettings.ts +95 -0
- package/src/lib/resilience/settings/normalize.ts +359 -0
- package/src/lib/resilience/settings/types.ts +182 -0
- package/src/lib/resilience/settings.ts +386 -0
- package/src/lib/runtime/ports.ts +32 -0
- package/src/lib/search/executeWebSearch.ts +270 -0
- package/src/lib/security/localEndpoints.ts +82 -0
- package/src/lib/semanticCache.ts +377 -0
- package/src/lib/services/ServiceSupervisor.ts +243 -0
- package/src/lib/services/apiKey.ts +40 -0
- package/src/lib/services/bootstrap.ts +133 -0
- package/src/lib/services/embedPath.ts +19 -0
- package/src/lib/services/embedWsProxy.ts +285 -0
- package/src/lib/services/healthCheck.ts +79 -0
- package/src/lib/services/htmlRewriter.ts +185 -0
- package/src/lib/services/installers/bifrost.ts +145 -0
- package/src/lib/services/installers/cliproxy.ts +116 -0
- package/src/lib/services/installers/mux.ts +178 -0
- package/src/lib/services/installers/ninerouter.stub.ts +17 -0
- package/src/lib/services/installers/ninerouter.ts +157 -0
- package/src/lib/services/installers/utils.ts +167 -0
- package/src/lib/services/modelSync.ts +105 -0
- package/src/lib/services/portProbe.ts +104 -0
- package/src/lib/services/registry.ts +42 -0
- package/src/lib/services/reverseProxy.ts +180 -0
- package/src/lib/services/ringBuffer.ts +91 -0
- package/src/lib/services/types.ts +50 -0
- package/src/lib/settingsCache.ts +62 -0
- package/src/lib/skills/a2a.ts +34 -0
- package/src/lib/skills/builtin/browser.ts +22 -0
- package/src/lib/skills/builtins.ts +493 -0
- package/src/lib/skills/custom.ts +41 -0
- package/src/lib/skills/executor.ts +196 -0
- package/src/lib/skills/githubCollector.ts +426 -0
- package/src/lib/skills/hybrid.ts +67 -0
- package/src/lib/skills/injection.ts +307 -0
- package/src/lib/skills/interception.ts +343 -0
- package/src/lib/skills/providerSettings.ts +14 -0
- package/src/lib/skills/registry.ts +398 -0
- package/src/lib/skills/sandbox.ts +178 -0
- package/src/lib/skills/schemas.ts +43 -0
- package/src/lib/skills/skillssh.ts +73 -0
- package/src/lib/skills/types.ts +61 -0
- package/src/lib/source.ts +7 -0
- package/src/lib/spend/batchWriter.ts +208 -0
- package/src/lib/sseTextTransform.ts +346 -0
- package/src/lib/streamingPiiTransform.ts +350 -0
- package/src/lib/sync/bundle.ts +208 -0
- package/src/lib/sync/tokens.ts +107 -0
- package/src/lib/system/autoUpdate.ts +400 -0
- package/src/lib/system/globalPackagePath.ts +49 -0
- package/src/lib/system/versionCheck.ts +163 -0
- package/src/lib/tailscaleTunnel.ts +1201 -0
- package/src/lib/tokenHealthCheck.ts +829 -0
- package/src/lib/toolPolicy.ts +150 -0
- package/src/lib/translator/streamTransform.ts +27 -0
- package/src/lib/translatorEvents.ts +40 -0
- package/src/lib/usage/aggregateHistory.ts +212 -0
- package/src/lib/usage/apiKeySelfService.ts +420 -0
- package/src/lib/usage/apiKeyUsageLimits.ts +578 -0
- package/src/lib/usage/callLogArtifacts.ts +337 -0
- package/src/lib/usage/callLogs/format.ts +129 -0
- package/src/lib/usage/callLogs.ts +928 -0
- package/src/lib/usage/callLogsBoundedQueries.ts +42 -0
- package/src/lib/usage/codexResetCredits.ts +355 -0
- package/src/lib/usage/comboForecast.ts +441 -0
- package/src/lib/usage/comboHealth.ts +545 -0
- package/src/lib/usage/comboHealthDashboard.ts +109 -0
- package/src/lib/usage/comboScoringInspector.ts +416 -0
- package/src/lib/usage/completedRequestDetails.ts +103 -0
- package/src/lib/usage/costCalculator.ts +279 -0
- package/src/lib/usage/fetcher.ts +483 -0
- package/src/lib/usage/flatRateProviders.ts +59 -0
- package/src/lib/usage/internalUsageCommand.ts +788 -0
- package/src/lib/usage/migrations.ts +471 -0
- package/src/lib/usage/pendingRequestScope.ts +26 -0
- package/src/lib/usage/providerLimits/quotaNormalize.ts +72 -0
- package/src/lib/usage/providerLimits.ts +997 -0
- package/src/lib/usage/providerWindowCosts.ts +571 -0
- package/src/lib/usage/resilienceExplain.ts +468 -0
- package/src/lib/usage/routeExplain.ts +747 -0
- package/src/lib/usage/tokenAccounting.ts +212 -0
- package/src/lib/usage/usageEvents.ts +91 -0
- package/src/lib/usage/usageHistory/helpers.ts +85 -0
- package/src/lib/usage/usageHistory.ts +916 -0
- package/src/lib/usage/usageStats.ts +581 -0
- package/src/lib/usageAnalytics.ts +372 -0
- package/src/lib/usageDb.ts +38 -0
- package/src/lib/versionManager/binaryManager.ts +240 -0
- package/src/lib/versionManager/healthMonitor.ts +71 -0
- package/src/lib/versionManager/index.ts +155 -0
- package/src/lib/versionManager/processManager.ts +155 -0
- package/src/lib/versionManager/releaseChecker.ts +98 -0
- package/src/lib/vscode/familyFirstModelIds.ts +92 -0
- package/src/lib/vscode/modelPresentation.ts +132 -0
- package/src/lib/vscode/reasoningMetadata.ts +183 -0
- package/src/lib/vscode/serviceTierVariants.ts +202 -0
- package/src/lib/vscode/tokenizedRequest.ts +79 -0
- package/src/lib/webhookDispatcher.ts +221 -0
- package/src/lib/webhooks/eventDescriptions.ts +76 -0
- package/src/lib/webhooks/integrations/discord.ts +49 -0
- package/src/lib/webhooks/integrations/slack.ts +45 -0
- package/src/lib/webhooks/integrations/telegram.ts +67 -0
- package/src/lib/ws/handshake.ts +129 -0
- package/src/lib/zed-oauth/confirmedAccounts.ts +38 -0
- package/src/lib/zed-oauth/credentialFingerprint.ts +23 -0
- package/src/lib/zed-oauth/dockerDetect.ts +38 -0
- package/src/lib/zed-oauth/importUtils.ts +46 -0
- package/src/lib/zed-oauth/keychain-reader.stub.ts +28 -0
- package/src/lib/zed-oauth/keychain-reader.ts +231 -0
- package/src/mitm/_internal/bypass.cjs +170 -0
- package/src/mitm/_internal/forwardTarget.cjs +55 -0
- package/src/mitm/_internal/ingest.cjs +82 -0
- package/src/mitm/cert/generate.ts +41 -0
- package/src/mitm/cert/install.stub.ts +23 -0
- package/src/mitm/cert/install.ts +440 -0
- package/src/mitm/dataDir.ts +41 -0
- package/src/mitm/detection/antigravity.ts +33 -0
- package/src/mitm/detection/claudeCode.ts +25 -0
- package/src/mitm/detection/codex.ts +25 -0
- package/src/mitm/detection/copilot.ts +39 -0
- package/src/mitm/detection/cursor.ts +31 -0
- package/src/mitm/detection/index.ts +53 -0
- package/src/mitm/detection/kiro.ts +30 -0
- package/src/mitm/detection/openCode.ts +32 -0
- package/src/mitm/detection/zed.ts +26 -0
- package/src/mitm/dns/dnsConfig.ts +242 -0
- package/src/mitm/dns/provision.ts +92 -0
- package/src/mitm/handlers/antigravity.ts +192 -0
- package/src/mitm/handlers/base.ts +333 -0
- package/src/mitm/handlers/claudeCode.ts +56 -0
- package/src/mitm/handlers/codex.ts +55 -0
- package/src/mitm/handlers/copilot.ts +55 -0
- package/src/mitm/handlers/cursor.ts +55 -0
- package/src/mitm/handlers/kiro.ts +58 -0
- package/src/mitm/handlers/openCode.ts +55 -0
- package/src/mitm/handlers/trae.ts +24 -0
- package/src/mitm/handlers/zed.ts +55 -0
- package/src/mitm/inspector/agentBridgeHook.ts +137 -0
- package/src/mitm/inspector/buffer.ts +201 -0
- package/src/mitm/inspector/contextKey.ts +98 -0
- package/src/mitm/inspector/conversationNormalizer.ts +393 -0
- package/src/mitm/inspector/diagnostics.ts +67 -0
- package/src/mitm/inspector/httpProxyServer.ts +272 -0
- package/src/mitm/inspector/kindDetector.ts +87 -0
- package/src/mitm/inspector/llmMetadataExtractor.ts +183 -0
- package/src/mitm/inspector/pricing.ts +57 -0
- package/src/mitm/inspector/processAttribution.ts +107 -0
- package/src/mitm/inspector/sseMerger.ts +316 -0
- package/src/mitm/inspector/systemProxyConfig.ts +316 -0
- package/src/mitm/inspector/types.ts +112 -0
- package/src/mitm/manager.runtime.ts +5 -0
- package/src/mitm/manager.stub.ts +44 -0
- package/src/mitm/manager.ts +762 -0
- package/src/mitm/maskSecrets.ts +31 -0
- package/src/mitm/passthrough.ts +76 -0
- package/src/mitm/sanitizeHeaders.ts +61 -0
- package/src/mitm/server.cjs +786 -0
- package/src/mitm/socketTimeouts.ts +24 -0
- package/src/mitm/systemCommands.ts +280 -0
- package/src/mitm/targets/antigravity.ts +85 -0
- package/src/mitm/targets/claudeCode.ts +37 -0
- package/src/mitm/targets/codex.ts +30 -0
- package/src/mitm/targets/copilot.ts +32 -0
- package/src/mitm/targets/cursor.ts +33 -0
- package/src/mitm/targets/index.ts +75 -0
- package/src/mitm/targets/kiro.ts +64 -0
- package/src/mitm/targets/openCode.ts +34 -0
- package/src/mitm/targets/trae.ts +32 -0
- package/src/mitm/targets/zed.ts +32 -0
- package/src/mitm/tproxy/caTrust.ts +120 -0
- package/src/mitm/tproxy/captureManager.ts +118 -0
- package/src/mitm/tproxy/captureMode.ts +226 -0
- package/src/mitm/tproxy/commands.ts +122 -0
- package/src/mitm/tproxy/dynamicCert.ts +119 -0
- package/src/mitm/tproxy/native/README.md +55 -0
- package/src/mitm/tproxy/native/binding.gyp +9 -0
- package/src/mitm/tproxy/native/transparent.c +147 -0
- package/src/mitm/tproxy/setup.ts +68 -0
- package/src/mitm/tproxy/tlsCapture.ts +368 -0
- package/src/mitm/tproxy/transparentSocket.ts +131 -0
- package/src/mitm/types.ts +75 -0
- package/src/mitm/upstreamTrust.ts +40 -0
- package/src/models/index.ts +29 -0
- package/src/server/auth/loginGuard.ts +130 -0
- package/src/server/authz/accessScopes.ts +62 -0
- package/src/server/authz/accessTokenAuth.ts +67 -0
- package/src/server/authz/assertAuth.ts +88 -0
- package/src/server/authz/classify.ts +135 -0
- package/src/server/authz/context.ts +44 -0
- package/src/server/authz/csrf.ts +85 -0
- package/src/server/authz/headers.ts +76 -0
- package/src/server/authz/peerStamp.ts +99 -0
- package/src/server/authz/pipeline.ts +370 -0
- package/src/server/authz/policies/clientApi.ts +72 -0
- package/src/server/authz/policies/management.ts +298 -0
- package/src/server/authz/policies/public.ts +9 -0
- package/src/server/authz/routeGuard.ts +233 -0
- package/src/server/authz/types.ts +77 -0
- package/src/server/cors/origins.ts +172 -0
- package/src/server/origin/publicOrigin.ts +270 -0
- package/src/server/ws/liveServer.ts +630 -0
- package/src/server/ws/liveServerAllowList.ts +106 -0
- package/src/server/ws/types.ts +57 -0
- package/src/shared/components/Avatar.tsx +81 -0
- package/src/shared/components/Badge.tsx +68 -0
- package/src/shared/components/Breadcrumbs.tsx +103 -0
- package/src/shared/components/Button.tsx +85 -0
- package/src/shared/components/Card.tsx +141 -0
- package/src/shared/components/Checkbox.tsx +38 -0
- package/src/shared/components/CloudSyncStatus.tsx +104 -0
- package/src/shared/components/Collapsible.tsx +93 -0
- package/src/shared/components/CollapsibleSection.tsx +66 -0
- package/src/shared/components/ColumnToggle.tsx +100 -0
- package/src/shared/components/CommandPalette.tsx +375 -0
- package/src/shared/components/ConsoleLogViewer.tsx +326 -0
- package/src/shared/components/CursorAuthModal.tsx +198 -0
- package/src/shared/components/DataTable.tsx +195 -0
- package/src/shared/components/DegradationBadge.tsx +41 -0
- package/src/shared/components/DistributeProxiesButton.tsx +74 -0
- package/src/shared/components/EmptyState.tsx +121 -0
- package/src/shared/components/ErrorPageScaffold.tsx +91 -0
- package/src/shared/components/FilterBar.tsx +197 -0
- package/src/shared/components/Footer.tsx +169 -0
- package/src/shared/components/Header.tsx +284 -0
- package/src/shared/components/InfoTooltip.tsx +34 -0
- package/src/shared/components/Input.tsx +155 -0
- package/src/shared/components/KiroAuthModal.tsx +425 -0
- package/src/shared/components/KiroOAuthWrapper.tsx +116 -0
- package/src/shared/components/KiroSocialOAuthModal.tsx +202 -0
- package/src/shared/components/LanguageSelector.tsx +106 -0
- package/src/shared/components/LinkifiedText.tsx +30 -0
- package/src/shared/components/Loading.tsx +128 -0
- package/src/shared/components/LocaleAutoDetect.tsx +43 -0
- package/src/shared/components/MaintenanceBanner.tsx +87 -0
- package/src/shared/components/ManualConfigModal.tsx +51 -0
- package/src/shared/components/Modal.tsx +240 -0
- package/src/shared/components/ModelRoutingSection.tsx +323 -0
- package/src/shared/components/ModelSelectModal.tsx +618 -0
- package/src/shared/components/MonacoEditor.tsx +23 -0
- package/src/shared/components/NavigationProgress.tsx +105 -0
- package/src/shared/components/NoAuthAccountCard.tsx +539 -0
- package/src/shared/components/NoAuthProviderCard.tsx +40 -0
- package/src/shared/components/NoAuthProviderToggle.tsx +36 -0
- package/src/shared/components/NotificationToast.tsx +206 -0
- package/src/shared/components/OAuthModal.tsx +992 -0
- package/src/shared/components/OmniRouteLogo.tsx +86 -0
- package/src/shared/components/PresetSlider.tsx +64 -0
- package/src/shared/components/PricingModal.tsx +211 -0
- package/src/shared/components/ProviderIcon.tsx +263 -0
- package/src/shared/components/ProviderTestSlideOver.tsx +560 -0
- package/src/shared/components/ProxyConfigModal.tsx +781 -0
- package/src/shared/components/ProxyLogDetail.tsx +192 -0
- package/src/shared/components/ProxyLogger.tsx +573 -0
- package/src/shared/components/PwaRegister.tsx +22 -0
- package/src/shared/components/RequestLoggerDetail.tsx +797 -0
- package/src/shared/components/RequestLoggerV2.tsx +1628 -0
- package/src/shared/components/RiskNoticeModal.tsx +81 -0
- package/src/shared/components/SegmentedControl.tsx +69 -0
- package/src/shared/components/Select.tsx +110 -0
- package/src/shared/components/Sidebar.tsx +726 -0
- package/src/shared/components/SkillsConceptCard.tsx +84 -0
- package/src/shared/components/SystemMonitor.tsx +179 -0
- package/src/shared/components/Textarea.tsx +29 -0
- package/src/shared/components/ThemeProvider.tsx +14 -0
- package/src/shared/components/ThemeToggle.tsx +52 -0
- package/src/shared/components/Toggle.tsx +102 -0
- package/src/shared/components/TokenHealthBadge.tsx +113 -0
- package/src/shared/components/Tooltip.tsx +193 -0
- package/src/shared/components/TraeAuthModal.tsx +334 -0
- package/src/shared/components/UsageAnalytics.tsx +414 -0
- package/src/shared/components/UsageStats.tsx +693 -0
- package/src/shared/components/analytics/ApiKeyFilterDropdown.tsx +205 -0
- package/src/shared/components/analytics/CustomRangePicker.tsx +195 -0
- package/src/shared/components/analytics/TimeRangeSelector.tsx +49 -0
- package/src/shared/components/analytics/chartColors.ts +12 -0
- package/src/shared/components/analytics/charts.tsx +1023 -0
- package/src/shared/components/analytics/index.tsx +28 -0
- package/src/shared/components/analytics/rechartsCore.tsx +85 -0
- package/src/shared/components/analytics/rechartsDonuts.tsx +195 -0
- package/src/shared/components/analytics/rechartsUsageCharts.tsx +312 -0
- package/src/shared/components/cli/CliComparisonCard.tsx +82 -0
- package/src/shared/components/cli/CliConceptCard.tsx +58 -0
- package/src/shared/components/cli/CliToolCard.tsx +152 -0
- package/src/shared/components/cli/index.ts +8 -0
- package/src/shared/components/compression/CompressionPipelineEditor.tsx +175 -0
- package/src/shared/components/compression/EngineConfigForm.tsx +78 -0
- package/src/shared/components/compression/EngineConfigPage.tsx +411 -0
- package/src/shared/components/compression/compressionPipelineModel.ts +78 -0
- package/src/shared/components/docs/APIReference.stories.tsx +35 -0
- package/src/shared/components/docs/APIReference.tsx +83 -0
- package/src/shared/components/docs/Callout.stories.tsx +40 -0
- package/src/shared/components/docs/Callout.tsx +38 -0
- package/src/shared/components/docs/CodeBlock.stories.tsx +25 -0
- package/src/shared/components/docs/CodeBlock.tsx +52 -0
- package/src/shared/components/docs/DocsBreadcrumbs.stories.tsx +20 -0
- package/src/shared/components/docs/DocsBreadcrumbs.tsx +46 -0
- package/src/shared/components/docs/DocsSidebar.stories.tsx +31 -0
- package/src/shared/components/docs/DocsSidebar.tsx +77 -0
- package/src/shared/components/docs/DocsThemeProvider.tsx +21 -0
- package/src/shared/components/docs/Tabs.stories.tsx +26 -0
- package/src/shared/components/docs/Tabs.tsx +50 -0
- package/src/shared/components/docs/tokens.ts +38 -0
- package/src/shared/components/flow/FlowCanvas.tsx +151 -0
- package/src/shared/components/flow/StatusDot.tsx +36 -0
- package/src/shared/components/flow/edgeStyles.ts +32 -0
- package/src/shared/components/index.tsx +49 -0
- package/src/shared/components/layouts/AuthLayout.tsx +28 -0
- package/src/shared/components/layouts/DashboardLayout.tsx +131 -0
- package/src/shared/components/layouts/index.tsx +3 -0
- package/src/shared/components/lobeProviderIcons.ts +488 -0
- package/src/shared/components/logTableStyles.ts +7 -0
- package/src/shared/components/modelSelectModalHelpers.ts +75 -0
- package/src/shared/components/oauthBlobSubmit.ts +42 -0
- package/src/shared/components/proxyAssignment.ts +40 -0
- package/src/shared/components/requestLoggerPreferences.ts +44 -0
- package/src/shared/components/requestLoggerSignature.ts +56 -0
- package/src/shared/constants/agentSkills.ts +457 -0
- package/src/shared/constants/antigravityClientProfile.ts +29 -0
- package/src/shared/constants/apiKeyPolicyScopes.ts +5 -0
- package/src/shared/constants/appConfig.ts +12 -0
- package/src/shared/constants/batch.ts +1 -0
- package/src/shared/constants/batchEndpoints.ts +11 -0
- package/src/shared/constants/bodySize.ts +39 -0
- package/src/shared/constants/cliCompatProviders.ts +88 -0
- package/src/shared/constants/cliTools.ts +862 -0
- package/src/shared/constants/clientIdentityProfiles.ts +89 -0
- package/src/shared/constants/colors.ts +147 -0
- package/src/shared/constants/comboConfigMode.ts +9 -0
- package/src/shared/constants/config.ts +44 -0
- package/src/shared/constants/dashboardCsrf.ts +1 -0
- package/src/shared/constants/endpointCategories.ts +133 -0
- package/src/shared/constants/errorCodes.ts +245 -0
- package/src/shared/constants/featureFlagDefinitions.ts +495 -0
- package/src/shared/constants/headers.ts +16 -0
- package/src/shared/constants/homeWidgets.ts +5 -0
- package/src/shared/constants/index.ts +4 -0
- package/src/shared/constants/managementScopes.ts +31 -0
- package/src/shared/constants/mcpScopes.ts +78 -0
- package/src/shared/constants/mitmToolHosts.ts +31 -0
- package/src/shared/constants/modal.ts +5 -0
- package/src/shared/constants/modelCompat.ts +9 -0
- package/src/shared/constants/modelSpecs.ts +607 -0
- package/src/shared/constants/models.ts +40 -0
- package/src/shared/constants/openRouterPreset.ts +11 -0
- package/src/shared/constants/pricing/default-pricing.ts +16 -0
- package/src/shared/constants/pricing/frontier-labs.ts +386 -0
- package/src/shared/constants/pricing/inference-hosts.ts +208 -0
- package/src/shared/constants/pricing/oauth-subscriptions.ts +599 -0
- package/src/shared/constants/pricing/regional.ts +168 -0
- package/src/shared/constants/pricing/shared-tiers.ts +162 -0
- package/src/shared/constants/pricing.ts +40 -0
- package/src/shared/constants/providers/apikey/enterprise-cloud.ts +214 -0
- package/src/shared/constants/providers/apikey/frontier-labs.ts +253 -0
- package/src/shared/constants/providers/apikey/gateways.ts +662 -0
- package/src/shared/constants/providers/apikey/index.ts +21 -0
- package/src/shared/constants/providers/apikey/inference-hosts.ts +328 -0
- package/src/shared/constants/providers/apikey/regional.ts +372 -0
- package/src/shared/constants/providers/apikey/specialty-media.ts +266 -0
- package/src/shared/constants/providers/audio.ts +71 -0
- package/src/shared/constants/providers/cloud-agent.ts +36 -0
- package/src/shared/constants/providers/local.ts +162 -0
- package/src/shared/constants/providers/noauth.ts +123 -0
- package/src/shared/constants/providers/oauth.ts +231 -0
- package/src/shared/constants/providers/search.ts +125 -0
- package/src/shared/constants/providers/system.ts +16 -0
- package/src/shared/constants/providers/upstream-proxy.ts +36 -0
- package/src/shared/constants/providers/web-cookie.ts +364 -0
- package/src/shared/constants/providers.ts +449 -0
- package/src/shared/constants/publicApiRoutes.ts +62 -0
- package/src/shared/constants/responsesPreviousResponseId.ts +5 -0
- package/src/shared/constants/routingStrategies.ts +216 -0
- package/src/shared/constants/selfServiceScopes.ts +20 -0
- package/src/shared/constants/serviceKinds.ts +34 -0
- package/src/shared/constants/sidebarGroupVisibility.ts +31 -0
- package/src/shared/constants/sidebarVisibility/sections.ts +769 -0
- package/src/shared/constants/sidebarVisibility/types.ts +161 -0
- package/src/shared/constants/sidebarVisibility.ts +291 -0
- package/src/shared/constants/spawnCapablePrefixes.ts +35 -0
- package/src/shared/constants/statusColors.ts +17 -0
- package/src/shared/constants/upstreamHeaders.ts +42 -0
- package/src/shared/constants/visionBridgeDefaults.ts +88 -0
- package/src/shared/constants/visionModels.ts +68 -0
- package/src/shared/contracts/quota.ts +138 -0
- package/src/shared/hooks/cli/useToolBatchStatuses.ts +54 -0
- package/src/shared/hooks/index.ts +3 -0
- package/src/shared/hooks/useCopyToClipboard.ts +38 -0
- package/src/shared/hooks/useDisplayBaseUrl.ts +49 -0
- package/src/shared/hooks/useElectron.ts +197 -0
- package/src/shared/hooks/useTheme.ts +59 -0
- package/src/shared/http/apiErrorMessage.ts +19 -0
- package/src/shared/lib/persistLocale.ts +19 -0
- package/src/shared/middleware/bodySizeGuard.ts +97 -0
- package/src/shared/middleware/chatBodyAdmission.ts +161 -0
- package/src/shared/middleware/correlationId.ts +43 -0
- package/src/shared/network/outboundUrlGuard.ts +276 -0
- package/src/shared/network/remoteImageFetch.ts +182 -0
- package/src/shared/network/safeOutboundFetch.ts +372 -0
- package/src/shared/providers/webSessionCredentials.ts +308 -0
- package/src/shared/reasoning/effortStandardization.ts +124 -0
- package/src/shared/schemas/agentBridge.ts +37 -0
- package/src/shared/schemas/cliCatalog.ts +66 -0
- package/src/shared/schemas/inspector.ts +47 -0
- package/src/shared/schemas/memory.ts +142 -0
- package/src/shared/schemas/playground.ts +67 -0
- package/src/shared/schemas/qdrant.ts +39 -0
- package/src/shared/schemas/quota.ts +61 -0
- package/src/shared/schemas/searchTools.ts +39 -0
- package/src/shared/schemas/validation.ts +154 -0
- package/src/shared/services/apiKeyResolver.ts +44 -0
- package/src/shared/services/backupService.ts +233 -0
- package/src/shared/services/claudeCliConfig.ts +17 -0
- package/src/shared/services/cliRuntime.ts +1099 -0
- package/src/shared/services/cloudSyncScheduler.ts +135 -0
- package/src/shared/services/droidCustomModels.ts +118 -0
- package/src/shared/services/initializeCloudSync.ts +31 -0
- package/src/shared/services/loginShellPath.ts +87 -0
- package/src/shared/services/modelSyncScheduler.ts +225 -0
- package/src/shared/services/opencodeConfig.ts +140 -0
- package/src/shared/services/providerLimitsSyncScheduler.ts +72 -0
- package/src/shared/types/cliBatchStatus.ts +18 -0
- package/src/shared/types/index.ts +3 -0
- package/src/shared/types/pagination.ts +61 -0
- package/src/shared/types/utilization.ts +405 -0
- package/src/shared/utils/a11yAudit.ts +140 -0
- package/src/shared/utils/api.ts +112 -0
- package/src/shared/utils/apiAuth.ts +354 -0
- package/src/shared/utils/apiKey.ts +92 -0
- package/src/shared/utils/apiKeyPolicy.ts +680 -0
- package/src/shared/utils/apiResponse.ts +79 -0
- package/src/shared/utils/bulkApiKeyParser.ts +113 -0
- package/src/shared/utils/circuitBreaker.ts +611 -0
- package/src/shared/utils/classify429.ts +253 -0
- package/src/shared/utils/cliCompat.ts +5 -0
- package/src/shared/utils/clineAuth.ts +62 -0
- package/src/shared/utils/clipboard.ts +49 -0
- package/src/shared/utils/cloud.ts +41 -0
- package/src/shared/utils/cn.ts +12 -0
- package/src/shared/utils/codexBaseUrl.ts +32 -0
- package/src/shared/utils/codexConfig.ts +30 -0
- package/src/shared/utils/compressionHeaderEcho.ts +59 -0
- package/src/shared/utils/cors.ts +24 -0
- package/src/shared/utils/costEstimator.ts +126 -0
- package/src/shared/utils/dashboardCsrf.ts +196 -0
- package/src/shared/utils/featureFlags.ts +113 -0
- package/src/shared/utils/fetchError.ts +26 -0
- package/src/shared/utils/fetchTimeout.ts +78 -0
- package/src/shared/utils/formatting.ts +183 -0
- package/src/shared/utils/freeModels.ts +112 -0
- package/src/shared/utils/index.ts +39 -0
- package/src/shared/utils/inputSanitizer.ts +339 -0
- package/src/shared/utils/linkify.ts +54 -0
- package/src/shared/utils/logRedaction.ts +108 -0
- package/src/shared/utils/logger.ts +173 -0
- package/src/shared/utils/machine.ts +5 -0
- package/src/shared/utils/machineId.ts +167 -0
- package/src/shared/utils/maskEmail.ts +77 -0
- package/src/shared/utils/modelCatalogSearch.ts +84 -0
- package/src/shared/utils/noAuthProviders.ts +79 -0
- package/src/shared/utils/nodeRuntimeSupport.ts +112 -0
- package/src/shared/utils/parseApiKeys.ts +41 -0
- package/src/shared/utils/providerDisplayLabel.ts +41 -0
- package/src/shared/utils/providerHints.ts +73 -0
- package/src/shared/utils/providerModelAliases.ts +68 -0
- package/src/shared/utils/rateLimiter.ts +243 -0
- package/src/shared/utils/releaseNotes.ts +53 -0
- package/src/shared/utils/requestId.ts +102 -0
- package/src/shared/utils/requestTelemetry.ts +189 -0
- package/src/shared/utils/requestTimeout.ts +64 -0
- package/src/shared/utils/resolveOmniRouteBaseUrl.ts +24 -0
- package/src/shared/utils/runtimeTimeouts.ts +257 -0
- package/src/shared/utils/secretsValidator.ts +135 -0
- package/src/shared/utils/secureRandom.ts +66 -0
- package/src/shared/utils/serviceTierLabels.ts +42 -0
- package/src/shared/utils/shuffleDeck.ts +147 -0
- package/src/shared/utils/sidebarRouteMatch.ts +43 -0
- package/src/shared/utils/streamTracker.ts +187 -0
- package/src/shared/utils/structuredLogger.ts +219 -0
- package/src/shared/utils/tiktokenCounter.ts +21 -0
- package/src/shared/utils/turkishText.ts +66 -0
- package/src/shared/utils/upstreamError.ts +112 -0
- package/src/shared/validation/compressionConfigSchemas.ts +234 -0
- package/src/shared/validation/freeProxySchemas.ts +111 -0
- package/src/shared/validation/helpers.ts +117 -0
- package/src/shared/validation/oneproxySchemas.ts +14 -0
- package/src/shared/validation/providerSchema.ts +51 -0
- package/src/shared/validation/providerSpecificData.ts +354 -0
- package/src/shared/validation/schemas/apiV1.ts +297 -0
- package/src/shared/validation/schemas/auth.ts +200 -0
- package/src/shared/validation/schemas/cli.ts +86 -0
- package/src/shared/validation/schemas/cloud.ts +53 -0
- package/src/shared/validation/schemas/combo.ts +373 -0
- package/src/shared/validation/schemas/evals.ts +86 -0
- package/src/shared/validation/schemas/gemini.ts +59 -0
- package/src/shared/validation/schemas/keys.ts +144 -0
- package/src/shared/validation/schemas/misc.ts +203 -0
- package/src/shared/validation/schemas/payloadRules.ts +64 -0
- package/src/shared/validation/schemas/pricing.ts +40 -0
- package/src/shared/validation/schemas/provider.ts +430 -0
- package/src/shared/validation/schemas/proxy.ts +243 -0
- package/src/shared/validation/schemas/routing.ts +88 -0
- package/src/shared/validation/schemas/settings.ts +267 -0
- package/src/shared/validation/schemas/translator.ts +44 -0
- package/src/shared/validation/schemas.ts +18 -0
- package/src/shared/validation/settingsSchemas.ts +396 -0
- package/src/sse/handlers/chat.ts +1750 -0
- package/src/sse/handlers/chatHelpers.ts +859 -0
- package/src/sse/handlers/requestBody.ts +24 -0
- package/src/sse/handlers/resolveRoutingModel.ts +17 -0
- package/src/sse/services/auth.ts +2446 -0
- package/src/sse/services/cooldownAwareRetry.ts +162 -0
- package/src/sse/services/model.ts +254 -0
- package/src/sse/services/noAuthProviderSettings.ts +18 -0
- package/src/sse/services/noAuthProxyResolution.ts +111 -0
- package/src/sse/services/sessionAffinityPin.ts +247 -0
- package/src/sse/services/streamState.ts +218 -0
- package/src/sse/services/tokenRefresh.ts +275 -0
- package/src/sse/utils/logger.ts +37 -0
- package/src/types/databaseSettings.ts +124 -0
- package/src/types/global.d.ts +122 -0
- package/src/types/index.ts +10 -0
- package/src/types/provider.ts +9 -0
- package/src/types/sqljs.d.ts +32 -0
|
@@ -0,0 +1,2446 @@
|
|
|
1
|
+
import { randomUUID, createHash } from "crypto";
|
|
2
|
+
import {
|
|
3
|
+
getProviderConnections,
|
|
4
|
+
getProviderNodes,
|
|
5
|
+
validateApiKey,
|
|
6
|
+
updateProviderConnection,
|
|
7
|
+
clearConnectionErrorIfUnchanged,
|
|
8
|
+
getSettings,
|
|
9
|
+
getCachedSettings,
|
|
10
|
+
} from "@/lib/localDb";
|
|
11
|
+
import {
|
|
12
|
+
DEFAULT_QUOTA_THRESHOLD_PERCENT,
|
|
13
|
+
getQuotaCache,
|
|
14
|
+
getQuotaWindowStatus,
|
|
15
|
+
isQuotaExhaustedForRequest,
|
|
16
|
+
} from "@/domain/quotaCache";
|
|
17
|
+
import { getQuotaScopeLabelForProvider } from "@omniroute/open-sse/services/antigravityQuotaFamily.ts";
|
|
18
|
+
import {
|
|
19
|
+
isAccountUnavailable,
|
|
20
|
+
getUnavailableUntil,
|
|
21
|
+
getEarliestRateLimitedUntil,
|
|
22
|
+
cooldownUntilMs,
|
|
23
|
+
formatRetryAfter,
|
|
24
|
+
checkFallbackError,
|
|
25
|
+
isModelLocked,
|
|
26
|
+
getModelLockoutInfo,
|
|
27
|
+
lockModel,
|
|
28
|
+
hasPerModelQuota,
|
|
29
|
+
getRuntimeProviderProfile,
|
|
30
|
+
recordModelLockoutFailure,
|
|
31
|
+
} from "@omniroute/open-sse/services/accountFallback.ts";
|
|
32
|
+
import { isLocalProvider } from "@omniroute/open-sse/config/providerRegistry.ts";
|
|
33
|
+
import { COOLDOWN_MS, RateLimitReason } from "@omniroute/open-sse/config/constants.ts";
|
|
34
|
+
import {
|
|
35
|
+
preflightQuota,
|
|
36
|
+
isQuotaPreflightEnabled,
|
|
37
|
+
} from "@omniroute/open-sse/services/quotaPreflight.ts";
|
|
38
|
+
import { resolveResilienceSettings } from "@/lib/resilience/settings";
|
|
39
|
+
import { resolveModelLockoutSettings } from "@/lib/resilience/modelLockoutSettings";
|
|
40
|
+
import { syncHealthFromDB, type KeyHealth } from "@omniroute/open-sse/services/apiKeyRotator.ts";
|
|
41
|
+
import {
|
|
42
|
+
classifyProviderError,
|
|
43
|
+
PROVIDER_ERROR_TYPES,
|
|
44
|
+
} from "@omniroute/open-sse/services/errorClassifier.ts";
|
|
45
|
+
|
|
46
|
+
import {
|
|
47
|
+
getCodexModelScope,
|
|
48
|
+
getCodexQuotaWindowFilterForModel,
|
|
49
|
+
toCodexBaseQuotaWindowName,
|
|
50
|
+
toCodexScopedQuotaWindowName,
|
|
51
|
+
} from "@omniroute/open-sse/config/codexQuotaScopes.ts";
|
|
52
|
+
import {
|
|
53
|
+
getProviderById,
|
|
54
|
+
getProviderAlias,
|
|
55
|
+
resolveProviderId,
|
|
56
|
+
NOAUTH_PROVIDERS,
|
|
57
|
+
WEB_COOKIE_PROVIDERS,
|
|
58
|
+
} from "@/shared/constants/providers";
|
|
59
|
+
import { isModelExcludedByConnection } from "@/domain/connectionModelRules";
|
|
60
|
+
import {
|
|
61
|
+
applySessionAffinityPin,
|
|
62
|
+
formatSessionKeyForLog,
|
|
63
|
+
resolveSessionAffinityTtlMs,
|
|
64
|
+
selectSessionAffinityConnection,
|
|
65
|
+
} from "./sessionAffinityPin";
|
|
66
|
+
import { isNoAuthProviderBlockedBySettings } from "./noAuthProviderSettings";
|
|
67
|
+
import { resolveAccountProxiesFromRegistry } from "./noAuthProxyResolution";
|
|
68
|
+
import * as log from "../utils/logger";
|
|
69
|
+
import { fisherYatesShuffle, getNextFromDeckSync } from "@/shared/utils/shuffleDeck";
|
|
70
|
+
|
|
71
|
+
type JsonRecord = Record<string, unknown>;
|
|
72
|
+
|
|
73
|
+
interface ProviderConnectionView {
|
|
74
|
+
id: string;
|
|
75
|
+
provider: string;
|
|
76
|
+
email: string | null;
|
|
77
|
+
isActive: boolean;
|
|
78
|
+
rateLimitedUntil: string | null;
|
|
79
|
+
testStatus: string | null;
|
|
80
|
+
apiKey: string | null;
|
|
81
|
+
accessToken: string | null;
|
|
82
|
+
refreshToken: string | null;
|
|
83
|
+
tokenExpiresAt: string | null;
|
|
84
|
+
expiresAt: string | null;
|
|
85
|
+
projectId: string | null;
|
|
86
|
+
defaultModel: string | null;
|
|
87
|
+
providerSpecificData: JsonRecord;
|
|
88
|
+
lastUsedAt: string | null;
|
|
89
|
+
consecutiveUseCount: number;
|
|
90
|
+
priority: number;
|
|
91
|
+
lastError: string | null;
|
|
92
|
+
lastErrorType: string | null;
|
|
93
|
+
lastErrorSource: string | null;
|
|
94
|
+
errorCode: string | number | null;
|
|
95
|
+
backoffLevel: number;
|
|
96
|
+
maxConcurrent: number | null;
|
|
97
|
+
// Per-window quota cutoff overrides — null means "no overrides, inherit
|
|
98
|
+
// resilience-settings defaults." Read by getProviderCredentialsWithQuotaPreflight
|
|
99
|
+
// to decide whether to invoke the upstream usage fetcher.
|
|
100
|
+
quotaWindowThresholds: Record<string, number> | null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface RecoverableConnectionState {
|
|
104
|
+
connectionId: string;
|
|
105
|
+
testStatus?: string | null;
|
|
106
|
+
lastError?: string | null;
|
|
107
|
+
rateLimitedUntil?: string | null;
|
|
108
|
+
errorCode?: string | number | null;
|
|
109
|
+
lastErrorType?: string | null;
|
|
110
|
+
lastErrorSource?: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
interface CredentialSelectionOptions {
|
|
114
|
+
allowSuppressedConnections?: boolean;
|
|
115
|
+
allowRateLimitedConnections?: boolean;
|
|
116
|
+
bypassQuotaPolicy?: boolean;
|
|
117
|
+
forcedConnectionId?: string | null;
|
|
118
|
+
excludeConnectionIds?: string[] | null;
|
|
119
|
+
sessionKey?: string | null;
|
|
120
|
+
sessionAffinityTtlMs?: number | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
interface CooldownInspectionState {
|
|
124
|
+
connection: ProviderConnectionView;
|
|
125
|
+
connectionCooldownMs: number | null;
|
|
126
|
+
codexScopeCooldownMs: number | null;
|
|
127
|
+
retryableModelCooldownMs: number | null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const MIN_QUOTA_THRESHOLD_PERCENT = 1;
|
|
131
|
+
const MAX_QUOTA_THRESHOLD_PERCENT = 100;
|
|
132
|
+
const NON_RETRYABLE_MODEL_LOCKOUT_REASONS = new Set(["not_found", "not_found_local"]);
|
|
133
|
+
// Antigravity Gemini family 429 with no parseable upstream hint: seed the backoff at
|
|
134
|
+
// this base. Real upstream Retry-After hints still win — they flow through
|
|
135
|
+
// `exactCooldownMs` (usedUpstreamRetryHint), not this base. (#5222)
|
|
136
|
+
const ANTIGRAVITY_FAMILY_INFERRED_BASE_COOLDOWN_MS = 30_000;
|
|
137
|
+
|
|
138
|
+
function asRecord(value: unknown): JsonRecord {
|
|
139
|
+
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function toStringOrNull(value: unknown): string | null {
|
|
143
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function toNumber(value: unknown, fallback = 0): number {
|
|
147
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
148
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
149
|
+
const parsed = Number(value);
|
|
150
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
151
|
+
}
|
|
152
|
+
return fallback;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function toNullableNumber(value: unknown): number | null {
|
|
156
|
+
if (value === null || value === undefined) return null;
|
|
157
|
+
const parsed = toNumber(value, Number.NaN);
|
|
158
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function toProviderConnection(value: unknown): ProviderConnectionView {
|
|
162
|
+
const row = asRecord(value);
|
|
163
|
+
// Only accept the per-window override map when it's a plain object —
|
|
164
|
+
// anything else collapses to null so the preflight gate treats it as "no
|
|
165
|
+
// overrides set."
|
|
166
|
+
const rawThresholds = row.quotaWindowThresholds;
|
|
167
|
+
const quotaWindowThresholds: Record<string, number> | null =
|
|
168
|
+
rawThresholds && typeof rawThresholds === "object" && !Array.isArray(rawThresholds)
|
|
169
|
+
? (rawThresholds as Record<string, number>)
|
|
170
|
+
: null;
|
|
171
|
+
return {
|
|
172
|
+
id: toStringOrNull(row.id) || "",
|
|
173
|
+
provider: toStringOrNull(row.provider) || "",
|
|
174
|
+
email: toStringOrNull(row.email),
|
|
175
|
+
isActive: row.isActive === true,
|
|
176
|
+
rateLimitedUntil: toStringOrNull(row.rateLimitedUntil),
|
|
177
|
+
testStatus: toStringOrNull(row.testStatus),
|
|
178
|
+
apiKey: toStringOrNull(row.apiKey),
|
|
179
|
+
accessToken: toStringOrNull(row.accessToken),
|
|
180
|
+
refreshToken: toStringOrNull(row.refreshToken),
|
|
181
|
+
tokenExpiresAt: toStringOrNull(row.tokenExpiresAt),
|
|
182
|
+
expiresAt: toStringOrNull(row.expiresAt),
|
|
183
|
+
projectId: toStringOrNull(row.projectId),
|
|
184
|
+
defaultModel: toStringOrNull(row.defaultModel),
|
|
185
|
+
providerSpecificData: asRecord(row.providerSpecificData),
|
|
186
|
+
lastUsedAt: toStringOrNull(row.lastUsedAt),
|
|
187
|
+
consecutiveUseCount: toNumber(row.consecutiveUseCount, 0),
|
|
188
|
+
priority: toNumber(row.priority, 999),
|
|
189
|
+
lastError: toStringOrNull(row.lastError),
|
|
190
|
+
lastErrorType: toStringOrNull(row.lastErrorType),
|
|
191
|
+
lastErrorSource: toStringOrNull(row.lastErrorSource),
|
|
192
|
+
errorCode:
|
|
193
|
+
typeof row.errorCode === "string" || typeof row.errorCode === "number" ? row.errorCode : null,
|
|
194
|
+
backoffLevel: toNumber(row.backoffLevel, 0),
|
|
195
|
+
maxConcurrent: toNullableNumber(row.maxConcurrent),
|
|
196
|
+
quotaWindowThresholds,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function toBooleanOrDefault(value: unknown, fallback: boolean): boolean {
|
|
201
|
+
return typeof value === "boolean" ? value : fallback;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function readHeaderValue(
|
|
205
|
+
headers:
|
|
206
|
+
| Headers
|
|
207
|
+
| { get?: (name: string) => string | null }
|
|
208
|
+
| Record<string, string | string[] | undefined>
|
|
209
|
+
| null
|
|
210
|
+
| undefined,
|
|
211
|
+
name: string
|
|
212
|
+
): string | null {
|
|
213
|
+
if (!headers) return null;
|
|
214
|
+
|
|
215
|
+
if (typeof (headers as Headers).get === "function") {
|
|
216
|
+
const value = (headers as Headers).get(name) || (headers as Headers).get(name.toLowerCase());
|
|
217
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const recordHeaders = headers as Record<string, string | string[] | undefined>;
|
|
221
|
+
const value =
|
|
222
|
+
recordHeaders[name] || recordHeaders[name.toLowerCase()] || recordHeaders[name.toUpperCase()];
|
|
223
|
+
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
return typeof value[0] === "string" && value[0].trim().length > 0 ? value[0].trim() : null;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function normalizeSessionKey(value: unknown, prefix: string): string | null {
|
|
232
|
+
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
233
|
+
const trimmed = value.trim();
|
|
234
|
+
if (trimmed.length <= 180 && /^[A-Za-z0-9._:-]+$/.test(trimmed)) {
|
|
235
|
+
return `${prefix}:${trimmed}`;
|
|
236
|
+
}
|
|
237
|
+
return `${prefix}:sha256:${createHash("sha256").update(trimmed).digest("hex")}`;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function extractTextForSessionHash(value: unknown): string | null {
|
|
241
|
+
if (typeof value === "string") return value;
|
|
242
|
+
if (Array.isArray(value)) {
|
|
243
|
+
const parts = value
|
|
244
|
+
.map((item) => {
|
|
245
|
+
if (typeof item === "string") return item;
|
|
246
|
+
const record = asRecord(item);
|
|
247
|
+
if (typeof record.text === "string") return record.text;
|
|
248
|
+
if (typeof record.content === "string") return record.content;
|
|
249
|
+
return null;
|
|
250
|
+
})
|
|
251
|
+
.filter(Boolean) as string[];
|
|
252
|
+
return parts.length > 0 ? parts.join("\n") : JSON.stringify(value);
|
|
253
|
+
}
|
|
254
|
+
if (value && typeof value === "object") return JSON.stringify(value);
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function getFirstInputText(body: unknown): string | null {
|
|
259
|
+
const record = asRecord(body);
|
|
260
|
+
if (record.input !== undefined) {
|
|
261
|
+
if (typeof record.input === "string") return record.input;
|
|
262
|
+
if (Array.isArray(record.input)) {
|
|
263
|
+
for (const item of record.input) {
|
|
264
|
+
const itemRecord = asRecord(item);
|
|
265
|
+
const text = extractTextForSessionHash(itemRecord.content ?? item);
|
|
266
|
+
if (text && text.trim().length > 0) return text;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const text = extractTextForSessionHash(record.input);
|
|
270
|
+
if (text && text.trim().length > 0) return text;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (Array.isArray(record.messages)) {
|
|
274
|
+
const userMessage = record.messages.find((message) => asRecord(message).role === "user");
|
|
275
|
+
const firstMessage = userMessage ?? record.messages[0];
|
|
276
|
+
const text = extractTextForSessionHash(asRecord(firstMessage).content ?? firstMessage);
|
|
277
|
+
if (text && text.trim().length > 0) return text;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function extractSessionAffinityKey(
|
|
284
|
+
body: unknown,
|
|
285
|
+
headers?: Headers | { get?: (name: string) => string | null } | null
|
|
286
|
+
): string | null {
|
|
287
|
+
const headerKey = normalizeSessionKey(
|
|
288
|
+
readHeaderValue(headers, "x-codex-session-id") ??
|
|
289
|
+
readHeaderValue(headers, "x-session-id") ??
|
|
290
|
+
readHeaderValue(headers, "x-omniroute-session"),
|
|
291
|
+
"header"
|
|
292
|
+
);
|
|
293
|
+
if (headerKey) return headerKey;
|
|
294
|
+
|
|
295
|
+
const record = asRecord(body);
|
|
296
|
+
const metadata = asRecord(record.metadata);
|
|
297
|
+
const explicitKey =
|
|
298
|
+
normalizeSessionKey(metadata.session_id, "metadata") ??
|
|
299
|
+
normalizeSessionKey(metadata.sessionId, "metadata") ??
|
|
300
|
+
normalizeSessionKey(record.conversation_id, "conversation") ??
|
|
301
|
+
normalizeSessionKey(record.session_id, "session") ??
|
|
302
|
+
normalizeSessionKey(record.prompt_cache_key, "prompt-cache");
|
|
303
|
+
if (explicitKey) return explicitKey;
|
|
304
|
+
|
|
305
|
+
const inputText = getFirstInputText(body);
|
|
306
|
+
if (!inputText || inputText.trim().length === 0) return null;
|
|
307
|
+
return `input:sha256:${createHash("sha256").update(inputText.slice(0, 4096)).digest("hex")}`;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function getCodexLimitPolicy(providerSpecificData: JsonRecord): {
|
|
311
|
+
use5h: boolean;
|
|
312
|
+
useWeekly: boolean;
|
|
313
|
+
} {
|
|
314
|
+
const policy = asRecord(providerSpecificData.codexLimitPolicy);
|
|
315
|
+
return {
|
|
316
|
+
use5h: toBooleanOrDefault(policy.use5h, true),
|
|
317
|
+
useWeekly: toBooleanOrDefault(policy.useWeekly, true),
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
interface QuotaLimitPolicy {
|
|
322
|
+
enabled: boolean;
|
|
323
|
+
thresholdPercent: number;
|
|
324
|
+
windows: string[];
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
interface QuotaCacheView {
|
|
328
|
+
quotas?: Record<
|
|
329
|
+
string,
|
|
330
|
+
{
|
|
331
|
+
remainingPercentage?: number;
|
|
332
|
+
resetAt?: string | null;
|
|
333
|
+
}
|
|
334
|
+
>;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function normalizeQuotaThreshold(
|
|
338
|
+
value: unknown,
|
|
339
|
+
fallback = DEFAULT_QUOTA_THRESHOLD_PERCENT
|
|
340
|
+
): number {
|
|
341
|
+
const parsed = toNumber(value, fallback);
|
|
342
|
+
return Math.min(MAX_QUOTA_THRESHOLD_PERCENT, Math.max(MIN_QUOTA_THRESHOLD_PERCENT, parsed));
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function normalizeWindowName(windowName: unknown): string | null {
|
|
346
|
+
if (typeof windowName !== "string") return null;
|
|
347
|
+
const normalized = windowName.trim().toLowerCase();
|
|
348
|
+
return normalized.length > 0 ? normalized : null;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function uniqueWindows(windows: string[]): string[] {
|
|
352
|
+
return [...new Set(windows)];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function normalizeCodexWindowName(windowName: unknown): string | null {
|
|
356
|
+
if (typeof windowName !== "string") return null;
|
|
357
|
+
const normalized = windowName.trim().toLowerCase();
|
|
358
|
+
if (normalized === "session (5h)" || normalized === "5h" || normalized === "five_hour") {
|
|
359
|
+
return "session";
|
|
360
|
+
}
|
|
361
|
+
if (normalized === "weekly (7d)" || normalized === "7d" || normalized === "seven_day") {
|
|
362
|
+
return "weekly";
|
|
363
|
+
}
|
|
364
|
+
return toCodexBaseQuotaWindowName(normalized);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function applyCodexWindowPolicy(rawWindows: string[], providerSpecificData: JsonRecord): string[] {
|
|
368
|
+
const codexPolicy = getCodexLimitPolicy(providerSpecificData);
|
|
369
|
+
const normalizedRaw = rawWindows.map(normalizeCodexWindowName).filter(Boolean) as string[];
|
|
370
|
+
|
|
371
|
+
// Preserve explicitly configured custom windows, but enforce canonical Codex windows
|
|
372
|
+
// from toggles so weekly exhaustion is never skipped when useWeekly=true.
|
|
373
|
+
let windows = [...normalizedRaw];
|
|
374
|
+
windows = windows.filter((windowName) => {
|
|
375
|
+
if (windowName === "session") return codexPolicy.use5h;
|
|
376
|
+
if (windowName === "weekly") return codexPolicy.useWeekly;
|
|
377
|
+
return true;
|
|
378
|
+
});
|
|
379
|
+
if (codexPolicy.use5h) windows.push("session");
|
|
380
|
+
if (codexPolicy.useWeekly) windows.push("weekly");
|
|
381
|
+
|
|
382
|
+
return uniqueWindows(windows);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function getCodexScopeRateLimitedUntil(
|
|
386
|
+
providerSpecificData: JsonRecord,
|
|
387
|
+
model: string | null
|
|
388
|
+
): string | null {
|
|
389
|
+
if (!model) return null;
|
|
390
|
+
const scope = getCodexModelScope(model);
|
|
391
|
+
const scopeMap = asRecord(providerSpecificData.codexScopeRateLimitedUntil);
|
|
392
|
+
const value = scopeMap[scope];
|
|
393
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isCodexScopeUnavailable(
|
|
397
|
+
connection: ProviderConnectionView,
|
|
398
|
+
model: string | null
|
|
399
|
+
): boolean {
|
|
400
|
+
const until = getCodexScopeRateLimitedUntil(connection.providerSpecificData, model);
|
|
401
|
+
if (!until) return false;
|
|
402
|
+
return new Date(until).getTime() > Date.now();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function getEarliestCodexScopeRateLimitedUntil(
|
|
406
|
+
connections: ProviderConnectionView[],
|
|
407
|
+
model: string | null
|
|
408
|
+
): string | null {
|
|
409
|
+
let earliest: string | null = null;
|
|
410
|
+
let earliestMs = Infinity;
|
|
411
|
+
|
|
412
|
+
for (const conn of connections) {
|
|
413
|
+
const until = getCodexScopeRateLimitedUntil(conn.providerSpecificData, model);
|
|
414
|
+
if (!until) continue;
|
|
415
|
+
const ms = new Date(until).getTime();
|
|
416
|
+
if (!Number.isFinite(ms) || ms <= Date.now()) continue;
|
|
417
|
+
if (ms < earliestMs) {
|
|
418
|
+
earliest = until;
|
|
419
|
+
earliestMs = ms;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return earliest;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function normalizeStatus(value: string | null): string {
|
|
427
|
+
return (value || "").trim().toLowerCase();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function isTerminalConnectionStatus(connection: ProviderConnectionView): boolean {
|
|
431
|
+
const status = normalizeStatus(connection.testStatus);
|
|
432
|
+
return status === "credits_exhausted" || status === "banned" || status === "expired";
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function resolveTerminalConnectionStatus(
|
|
436
|
+
status: number,
|
|
437
|
+
result: { permanent?: boolean; creditsExhausted?: boolean },
|
|
438
|
+
providerErrorType: string | null = null
|
|
439
|
+
): string | null {
|
|
440
|
+
if (result.creditsExhausted || status === 402) return "credits_exhausted";
|
|
441
|
+
if (
|
|
442
|
+
providerErrorType === PROVIDER_ERROR_TYPES.PROJECT_ROUTE_ERROR ||
|
|
443
|
+
providerErrorType === PROVIDER_ERROR_TYPES.OAUTH_INVALID_TOKEN
|
|
444
|
+
) {
|
|
445
|
+
return null;
|
|
446
|
+
}
|
|
447
|
+
if (result.permanent || providerErrorType === PROVIDER_ERROR_TYPES.FORBIDDEN) {
|
|
448
|
+
return "banned";
|
|
449
|
+
}
|
|
450
|
+
if (
|
|
451
|
+
providerErrorType === PROVIDER_ERROR_TYPES.ACCOUNT_DEACTIVATED ||
|
|
452
|
+
providerErrorType === PROVIDER_ERROR_TYPES.UNAUTHORIZED ||
|
|
453
|
+
status === 401
|
|
454
|
+
) {
|
|
455
|
+
return "expired";
|
|
456
|
+
}
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export function resolveQuotaLimitPolicy(
|
|
461
|
+
provider: string,
|
|
462
|
+
providerSpecificData: JsonRecord
|
|
463
|
+
): QuotaLimitPolicy {
|
|
464
|
+
const rawPolicy = asRecord(providerSpecificData.limitPolicy);
|
|
465
|
+
const rawWindows = Array.isArray(rawPolicy.windows) ? rawPolicy.windows : [];
|
|
466
|
+
const windows = rawWindows.map(normalizeWindowName).filter(Boolean) as string[];
|
|
467
|
+
|
|
468
|
+
if (provider === "codex") {
|
|
469
|
+
const defaultWindows = applyCodexWindowPolicy(windows, providerSpecificData);
|
|
470
|
+
const enabled = toBooleanOrDefault(rawPolicy.enabled, defaultWindows.length > 0);
|
|
471
|
+
|
|
472
|
+
return {
|
|
473
|
+
enabled,
|
|
474
|
+
thresholdPercent: normalizeQuotaThreshold(rawPolicy.thresholdPercent),
|
|
475
|
+
windows: defaultWindows,
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
return {
|
|
480
|
+
enabled: toBooleanOrDefault(rawPolicy.enabled, false),
|
|
481
|
+
thresholdPercent: normalizeQuotaThreshold(rawPolicy.thresholdPercent),
|
|
482
|
+
windows,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
export function evaluateQuotaLimitPolicy(
|
|
487
|
+
provider: string,
|
|
488
|
+
connection: ProviderConnectionView,
|
|
489
|
+
requestedModel: string | null = null
|
|
490
|
+
): { blocked: boolean; reasons: string[]; resetAt: string | null } {
|
|
491
|
+
const policy = resolveQuotaLimitPolicy(provider, connection.providerSpecificData);
|
|
492
|
+
if (!policy.enabled || policy.windows.length === 0) {
|
|
493
|
+
return { blocked: false, reasons: [], resetAt: null };
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const reasons: string[] = [];
|
|
497
|
+
const resetCandidates: Array<string | null> = [];
|
|
498
|
+
|
|
499
|
+
for (const windowName of policy.windows) {
|
|
500
|
+
const effectiveWindowName =
|
|
501
|
+
provider === "codex" ? toCodexScopedQuotaWindowName(windowName, requestedModel) : windowName;
|
|
502
|
+
const status = getQuotaWindowStatus(
|
|
503
|
+
connection.id,
|
|
504
|
+
effectiveWindowName,
|
|
505
|
+
policy.thresholdPercent
|
|
506
|
+
);
|
|
507
|
+
if (!status?.reachedThreshold) continue;
|
|
508
|
+
reasons.push(`${effectiveWindowName} usage ${Math.round(status.usedPercentage)}%`);
|
|
509
|
+
resetCandidates.push(status.resetAt);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return {
|
|
513
|
+
blocked: reasons.length > 0,
|
|
514
|
+
reasons,
|
|
515
|
+
resetAt: getEarliestFutureDate(resetCandidates),
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function parseFutureDateMs(value: string | null): number | null {
|
|
520
|
+
if (!value) return null;
|
|
521
|
+
// Tolerate numeric-epoch strings (e.g. "1781696905131.0") as well as ISO
|
|
522
|
+
// strings — the rate_limited_until TEXT column can hold either (#3954).
|
|
523
|
+
const ms = cooldownUntilMs(value);
|
|
524
|
+
if (!Number.isFinite(ms) || ms <= Date.now()) return null;
|
|
525
|
+
return ms;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function getEarliestFutureDate(candidates: Array<string | null>): string | null {
|
|
529
|
+
return (
|
|
530
|
+
candidates
|
|
531
|
+
.map((candidate) => ({
|
|
532
|
+
raw: candidate,
|
|
533
|
+
ms: parseFutureDateMs(candidate),
|
|
534
|
+
}))
|
|
535
|
+
.filter((entry) => entry.ms !== null)
|
|
536
|
+
.sort((a, b) => (a.ms as number) - (b.ms as number))[0]?.raw || null
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
function isRetryableModelLockoutReason(reason: unknown): boolean {
|
|
541
|
+
return typeof reason === "string" && reason.length > 0
|
|
542
|
+
? !NON_RETRYABLE_MODEL_LOCKOUT_REASONS.has(reason)
|
|
543
|
+
: false;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function pushClampedPercentage(percentages: number[], value: number): void {
|
|
547
|
+
if (Number.isFinite(value)) {
|
|
548
|
+
percentages.push(Math.max(0, Math.min(100, value)));
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
function isResetAtInPast(resetAt: string | null): boolean {
|
|
553
|
+
if (!resetAt) return false;
|
|
554
|
+
const resetMs = new Date(resetAt).getTime();
|
|
555
|
+
return Number.isFinite(resetMs) && resetMs <= Date.now();
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function collectPolicyQuotaHeadroomPercentages(
|
|
559
|
+
provider: string,
|
|
560
|
+
connection: ProviderConnectionView,
|
|
561
|
+
policy: QuotaLimitPolicy,
|
|
562
|
+
requestedModel: string | null
|
|
563
|
+
): number[] {
|
|
564
|
+
const percentages: number[] = [];
|
|
565
|
+
const seenWindows = new Set<string>();
|
|
566
|
+
|
|
567
|
+
for (const windowName of policy.windows) {
|
|
568
|
+
const scopedWindow =
|
|
569
|
+
provider === "codex" ? toCodexScopedQuotaWindowName(windowName, requestedModel) : windowName;
|
|
570
|
+
const normalizedWindow = normalizeWindowName(scopedWindow);
|
|
571
|
+
if (!normalizedWindow || seenWindows.has(normalizedWindow)) continue;
|
|
572
|
+
seenWindows.add(normalizedWindow);
|
|
573
|
+
|
|
574
|
+
const status = getQuotaWindowStatus(connection.id, normalizedWindow, policy.thresholdPercent);
|
|
575
|
+
if (status) pushClampedPercentage(percentages, status.remainingPercentage);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return percentages;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function collectCachedQuotaHeadroomPercentages(
|
|
582
|
+
provider: string,
|
|
583
|
+
connection: ProviderConnectionView,
|
|
584
|
+
requestedModel: string | null
|
|
585
|
+
): number[] {
|
|
586
|
+
const quotaEntry = getQuotaCache(connection.id) as QuotaCacheView | null;
|
|
587
|
+
const rawQuotas = quotaEntry?.quotas || {};
|
|
588
|
+
const codexWindowFilter =
|
|
589
|
+
provider === "codex" ? getCodexQuotaWindowFilterForModel(requestedModel) : undefined;
|
|
590
|
+
const percentages: number[] = [];
|
|
591
|
+
|
|
592
|
+
for (const [quotaName, quota] of Object.entries(rawQuotas)) {
|
|
593
|
+
if (codexWindowFilter && !codexWindowFilter(quotaName)) continue;
|
|
594
|
+
if (!quota || isResetAtInPast(toStringOrNull(quota.resetAt))) continue;
|
|
595
|
+
pushClampedPercentage(percentages, toNumber(quota.remainingPercentage, Number.NaN));
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
return percentages;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function getConnectionQuotaHeadroomPercent(
|
|
602
|
+
provider: string,
|
|
603
|
+
connection: ProviderConnectionView,
|
|
604
|
+
requestedModel: string | null = null
|
|
605
|
+
): number | null {
|
|
606
|
+
const policy = resolveQuotaLimitPolicy(provider, connection.providerSpecificData);
|
|
607
|
+
const policyPercentages = collectPolicyQuotaHeadroomPercentages(
|
|
608
|
+
provider,
|
|
609
|
+
connection,
|
|
610
|
+
policy,
|
|
611
|
+
requestedModel
|
|
612
|
+
);
|
|
613
|
+
const percentages =
|
|
614
|
+
policyPercentages.length > 0
|
|
615
|
+
? policyPercentages
|
|
616
|
+
: collectCachedQuotaHeadroomPercentages(provider, connection, requestedModel);
|
|
617
|
+
|
|
618
|
+
return percentages.length > 0 ? Math.min(...percentages) : null;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
function getConnectionErrorPenalty(connection: ProviderConnectionView): number {
|
|
622
|
+
const errorType = normalizeStatus(connection.lastErrorType);
|
|
623
|
+
const errorSource = normalizeStatus(connection.lastErrorSource);
|
|
624
|
+
const numericErrorCode = toNumber(connection.errorCode, 0);
|
|
625
|
+
|
|
626
|
+
let penalty = 0;
|
|
627
|
+
if (connection.lastError) penalty += 6;
|
|
628
|
+
|
|
629
|
+
if (
|
|
630
|
+
errorType === "rate_limited" ||
|
|
631
|
+
errorType === "quota_exhausted" ||
|
|
632
|
+
errorType === "quota" ||
|
|
633
|
+
numericErrorCode === 429
|
|
634
|
+
) {
|
|
635
|
+
penalty += 24;
|
|
636
|
+
} else if (numericErrorCode === 401 || numericErrorCode === 403 || errorSource === "oauth") {
|
|
637
|
+
penalty += 18;
|
|
638
|
+
} else if (numericErrorCode >= 500) {
|
|
639
|
+
penalty += 10;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return penalty;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function getConnectionRecencyPenalty(connection: ProviderConnectionView): number {
|
|
646
|
+
if (!connection.lastUsedAt) return 0;
|
|
647
|
+
const ageMs = Date.now() - new Date(connection.lastUsedAt).getTime();
|
|
648
|
+
if (!Number.isFinite(ageMs)) return 0;
|
|
649
|
+
if (ageMs < 15_000) return 3;
|
|
650
|
+
if (ageMs < 60_000) return 2;
|
|
651
|
+
if (ageMs < 5 * 60_000) return 1;
|
|
652
|
+
return 0;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function getP2CConnectionScore(
|
|
656
|
+
provider: string,
|
|
657
|
+
connection: ProviderConnectionView,
|
|
658
|
+
requestedModel: string | null = null
|
|
659
|
+
): { score: number; quotaHeadroomPercent: number | null } {
|
|
660
|
+
const quotaBlocked = evaluateQuotaLimitPolicy(provider, connection, requestedModel).blocked;
|
|
661
|
+
const quotaExhausted = isQuotaExhaustedForRequest(connection.id, provider, requestedModel);
|
|
662
|
+
const quotaHeadroomPercent = getConnectionQuotaHeadroomPercent(
|
|
663
|
+
provider,
|
|
664
|
+
connection,
|
|
665
|
+
requestedModel
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
let quotaPenalty = 0;
|
|
669
|
+
if (quotaHeadroomPercent !== null) {
|
|
670
|
+
quotaPenalty += Math.round((100 - quotaHeadroomPercent) / 8);
|
|
671
|
+
if (quotaHeadroomPercent <= 10) quotaPenalty += 10;
|
|
672
|
+
else if (quotaHeadroomPercent <= 25) quotaPenalty += 4;
|
|
673
|
+
} else if (!quotaBlocked && !quotaExhausted) {
|
|
674
|
+
quotaPenalty += 4;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const score =
|
|
678
|
+
(quotaExhausted ? 200 : 0) +
|
|
679
|
+
(quotaBlocked ? 80 : 0) +
|
|
680
|
+
getConnectionErrorPenalty(connection) +
|
|
681
|
+
Math.min(40, (connection.backoffLevel || 0) * 8) +
|
|
682
|
+
quotaPenalty +
|
|
683
|
+
Math.min(12, (connection.consecutiveUseCount || 0) * 2) +
|
|
684
|
+
getConnectionRecencyPenalty(connection) +
|
|
685
|
+
Math.min(6, Math.max(0, connection.priority || 0) - 1);
|
|
686
|
+
|
|
687
|
+
return { score, quotaHeadroomPercent };
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function compareP2CConnections(
|
|
691
|
+
provider: string,
|
|
692
|
+
a: ProviderConnectionView,
|
|
693
|
+
b: ProviderConnectionView,
|
|
694
|
+
requestedModel: string | null = null
|
|
695
|
+
): number {
|
|
696
|
+
const aScore = getP2CConnectionScore(provider, a, requestedModel);
|
|
697
|
+
const bScore = getP2CConnectionScore(provider, b, requestedModel);
|
|
698
|
+
if (aScore.score !== bScore.score) {
|
|
699
|
+
return aScore.score - bScore.score;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const aHeadroom = aScore.quotaHeadroomPercent ?? -1;
|
|
703
|
+
const bHeadroom = bScore.quotaHeadroomPercent ?? -1;
|
|
704
|
+
if (aHeadroom !== bHeadroom) {
|
|
705
|
+
return bHeadroom - aHeadroom;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if ((a.priority || 999) !== (b.priority || 999)) {
|
|
709
|
+
return (a.priority || 999) - (b.priority || 999);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
return a.id.localeCompare(b.id);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Sentinel connection id used for the synthetic credentials of no-auth /
|
|
717
|
+
* keyless providers. It is NOT a real DB row, so it
|
|
718
|
+
* cannot carry cooldown state — the account-fallback loop must be able to
|
|
719
|
+
* exclude it (#3061), otherwise it gets re-selected forever.
|
|
720
|
+
*/
|
|
721
|
+
const SYNTHETIC_NOAUTH_CONNECTION_ID = "noauth";
|
|
722
|
+
|
|
723
|
+
type AnonymousFallbackProviderDefinition = {
|
|
724
|
+
anonymousFallback?: boolean;
|
|
725
|
+
noAuth?: boolean;
|
|
726
|
+
};
|
|
727
|
+
|
|
728
|
+
function buildSyntheticNoAuthCredentials(providerSpecificData: JsonRecord = {}): {
|
|
729
|
+
apiKey: null;
|
|
730
|
+
accessToken: null;
|
|
731
|
+
refreshToken: null;
|
|
732
|
+
expiresAt: null;
|
|
733
|
+
projectId: null;
|
|
734
|
+
defaultModel: null;
|
|
735
|
+
copilotToken: null;
|
|
736
|
+
providerSpecificData: JsonRecord;
|
|
737
|
+
connectionId: typeof SYNTHETIC_NOAUTH_CONNECTION_ID;
|
|
738
|
+
testStatus: "active";
|
|
739
|
+
lastError: null;
|
|
740
|
+
lastErrorType: null;
|
|
741
|
+
lastErrorSource: null;
|
|
742
|
+
errorCode: null;
|
|
743
|
+
rateLimitedUntil: null;
|
|
744
|
+
maxConcurrent: null;
|
|
745
|
+
allRateLimited?: never;
|
|
746
|
+
allExpired?: never;
|
|
747
|
+
retryAfter?: never;
|
|
748
|
+
retryAfterHuman?: never;
|
|
749
|
+
} {
|
|
750
|
+
return {
|
|
751
|
+
apiKey: null,
|
|
752
|
+
accessToken: null,
|
|
753
|
+
refreshToken: null,
|
|
754
|
+
expiresAt: null,
|
|
755
|
+
projectId: null,
|
|
756
|
+
defaultModel: null,
|
|
757
|
+
copilotToken: null,
|
|
758
|
+
providerSpecificData,
|
|
759
|
+
connectionId: SYNTHETIC_NOAUTH_CONNECTION_ID,
|
|
760
|
+
testStatus: "active",
|
|
761
|
+
lastError: null,
|
|
762
|
+
lastErrorType: null,
|
|
763
|
+
lastErrorSource: null,
|
|
764
|
+
errorCode: null,
|
|
765
|
+
rateLimitedUntil: null,
|
|
766
|
+
maxConcurrent: null,
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* #4954 / #5217 (Gap 1) — no-auth providers persist a connection row whose
|
|
772
|
+
* `providerSpecificData` carries `fingerprints` + `accountProxies`. Hydrate those
|
|
773
|
+
* and resolve by-id Proxy Pool references to live records (./noAuthProxyResolution)
|
|
774
|
+
* so the executor gets a resolved inline `proxy`. Best-effort: failures → empty.
|
|
775
|
+
*/
|
|
776
|
+
async function loadNoAuthProviderSpecificData(providerId: string): Promise<JsonRecord> {
|
|
777
|
+
try {
|
|
778
|
+
const connectionsRaw = await getProviderConnections({ provider: providerId });
|
|
779
|
+
const connections = (Array.isArray(connectionsRaw) ? connectionsRaw : []).map(
|
|
780
|
+
toProviderConnection
|
|
781
|
+
);
|
|
782
|
+
const hydrated: JsonRecord = {};
|
|
783
|
+
for (const conn of connections) {
|
|
784
|
+
const psd = conn.providerSpecificData;
|
|
785
|
+
if (!psd || typeof psd !== "object") continue;
|
|
786
|
+
if (Array.isArray(psd.fingerprints) && !Array.isArray(hydrated.fingerprints)) {
|
|
787
|
+
hydrated.fingerprints = psd.fingerprints;
|
|
788
|
+
}
|
|
789
|
+
if (Array.isArray(psd.accountProxies) && !Array.isArray(hydrated.accountProxies)) {
|
|
790
|
+
hydrated.accountProxies = psd.accountProxies;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (Array.isArray(hydrated.accountProxies)) {
|
|
794
|
+
hydrated.accountProxies = await resolveAccountProxiesFromRegistry(hydrated.accountProxies);
|
|
795
|
+
}
|
|
796
|
+
return hydrated;
|
|
797
|
+
} catch {
|
|
798
|
+
return {};
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
function providerCanUseSyntheticNoAuthFallback(providerId: string): boolean {
|
|
803
|
+
const providerDef = getProviderById(providerId) as
|
|
804
|
+
AnonymousFallbackProviderDefinition | undefined;
|
|
805
|
+
const noAuthProviderDef = (
|
|
806
|
+
NOAUTH_PROVIDERS as Record<string, AnonymousFallbackProviderDefinition | undefined>
|
|
807
|
+
)[providerId];
|
|
808
|
+
const webCookieProviderDef = (
|
|
809
|
+
WEB_COOKIE_PROVIDERS as Record<string, AnonymousFallbackProviderDefinition | undefined>
|
|
810
|
+
)[providerId];
|
|
811
|
+
return (
|
|
812
|
+
providerDef?.anonymousFallback === true ||
|
|
813
|
+
noAuthProviderDef?.noAuth === true ||
|
|
814
|
+
webCookieProviderDef?.noAuth === true
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
async function maybeSyntheticNoAuthFallback(
|
|
819
|
+
providerId: string,
|
|
820
|
+
excludedConnectionIds: Set<string>
|
|
821
|
+
) {
|
|
822
|
+
if (!providerCanUseSyntheticNoAuthFallback(providerId)) return null;
|
|
823
|
+
if (excludedConnectionIds.has(SYNTHETIC_NOAUTH_CONNECTION_ID)) return null;
|
|
824
|
+
// #4954: hydrate per-account proxy/rotation config off the connection row so
|
|
825
|
+
// no-auth executors (opencode, mimocode) actually honor configured proxies.
|
|
826
|
+
const providerSpecificData = await loadNoAuthProviderSpecificData(providerId);
|
|
827
|
+
return buildSyntheticNoAuthCredentials(providerSpecificData);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
function normalizeExcludedConnectionIds(
|
|
831
|
+
excludeConnectionId: string | null,
|
|
832
|
+
extraExcludedConnectionIds: string[] | null | undefined
|
|
833
|
+
): Set<string> {
|
|
834
|
+
const normalized = new Set<string>();
|
|
835
|
+
|
|
836
|
+
if (typeof excludeConnectionId === "string" && excludeConnectionId.trim().length > 0) {
|
|
837
|
+
normalized.add(excludeConnectionId.trim());
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
if (Array.isArray(extraExcludedConnectionIds)) {
|
|
841
|
+
for (const connectionId of extraExcludedConnectionIds) {
|
|
842
|
+
if (typeof connectionId === "string" && connectionId.trim().length > 0) {
|
|
843
|
+
normalized.add(connectionId.trim());
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
return normalized;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
function formatConnectionPrefixesForLog(ids: Iterable<string>, max = 6): string {
|
|
852
|
+
const prefixes = Array.from(ids)
|
|
853
|
+
.filter((id) => typeof id === "string" && id.length > 0)
|
|
854
|
+
.slice(0, max)
|
|
855
|
+
.map((id) => `${id.slice(0, 8)}...`);
|
|
856
|
+
return prefixes.length > 0 ? prefixes.join(",") : "none";
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function buildQuotaPreflightRateLimitedResult(
|
|
860
|
+
provider: string,
|
|
861
|
+
blockedByPreflight: Array<{
|
|
862
|
+
id: string;
|
|
863
|
+
quotaPercent?: number;
|
|
864
|
+
resetAt?: string | null;
|
|
865
|
+
}>
|
|
866
|
+
) {
|
|
867
|
+
const retryAfter =
|
|
868
|
+
getEarliestFutureDate(blockedByPreflight.map((entry) => entry.resetAt ?? null)) ||
|
|
869
|
+
new Date(Date.now() + 5 * 60 * 1000).toISOString();
|
|
870
|
+
const blockedSummary = blockedByPreflight
|
|
871
|
+
.map((entry) => {
|
|
872
|
+
const percent = Number.isFinite(entry.quotaPercent)
|
|
873
|
+
? `${Math.round((entry.quotaPercent as number) * 100)}%`
|
|
874
|
+
: "quota exhausted";
|
|
875
|
+
return `${entry.id.slice(0, 8)}(${percent})`;
|
|
876
|
+
})
|
|
877
|
+
.join("; ");
|
|
878
|
+
|
|
879
|
+
log.info("AUTH", `${provider} | quota preflight filtered account(s): ${blockedSummary}`);
|
|
880
|
+
|
|
881
|
+
return {
|
|
882
|
+
allRateLimited: true,
|
|
883
|
+
retryAfter,
|
|
884
|
+
retryAfterHuman: formatRetryAfter(retryAfter),
|
|
885
|
+
lastError: `All ${provider} accounts blocked by quota preflight`,
|
|
886
|
+
lastErrorCode: 429,
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
function quotaPreflightUnavailableUntil(resetAt?: string | null): string {
|
|
891
|
+
const resetMs = parseFutureDateMs(resetAt ?? null);
|
|
892
|
+
return new Date(resetMs ?? Date.now() + 5 * 60 * 1000).toISOString();
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
async function markQuotaPreflightAccountUnavailable(
|
|
896
|
+
provider: string,
|
|
897
|
+
connectionId: string,
|
|
898
|
+
preflight: { quotaPercent?: number; resetAt?: string | null },
|
|
899
|
+
requestedModel: string | null
|
|
900
|
+
): Promise<string> {
|
|
901
|
+
const unavailableUntil = quotaPreflightUnavailableUntil(preflight.resetAt ?? null);
|
|
902
|
+
const percentLabel = Number.isFinite(preflight.quotaPercent)
|
|
903
|
+
? `${Math.round((preflight.quotaPercent as number) * 100)}%`
|
|
904
|
+
: "exhausted";
|
|
905
|
+
const modelLabel = requestedModel ? ` for ${requestedModel}` : "";
|
|
906
|
+
|
|
907
|
+
await updateProviderConnection(connectionId, {
|
|
908
|
+
rateLimitedUntil: unavailableUntil,
|
|
909
|
+
testStatus: "unavailable",
|
|
910
|
+
lastError: `Quota preflight blocked${modelLabel}: ${percentLabel}`,
|
|
911
|
+
lastErrorType: "quota_exhausted",
|
|
912
|
+
lastErrorSource: "quota_preflight",
|
|
913
|
+
errorCode: 429,
|
|
914
|
+
lastErrorAt: new Date().toISOString(),
|
|
915
|
+
});
|
|
916
|
+
|
|
917
|
+
return unavailableUntil;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// Provider-scoped mutexes prevent race conditions during account selection without
|
|
921
|
+
// serializing unrelated providers behind a single global lock.
|
|
922
|
+
const selectionMutexes = new Map<string, Promise<void>>();
|
|
923
|
+
|
|
924
|
+
function getSelectionMutexKey(provider: string, options: CredentialSelectionOptions): string {
|
|
925
|
+
return [
|
|
926
|
+
resolveProviderId(provider) || provider,
|
|
927
|
+
options.forcedConnectionId ? `forced:${options.forcedConnectionId}` : "pool",
|
|
928
|
+
].join(":");
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function createSelectionLock(key: string) {
|
|
932
|
+
const currentMutex = selectionMutexes.get(key) ?? Promise.resolve();
|
|
933
|
+
let resolveMutex: (() => void) | undefined;
|
|
934
|
+
const nextMutex = new Promise<void>((resolve) => {
|
|
935
|
+
resolveMutex = resolve;
|
|
936
|
+
});
|
|
937
|
+
selectionMutexes.set(key, nextMutex);
|
|
938
|
+
|
|
939
|
+
return {
|
|
940
|
+
wait: currentMutex,
|
|
941
|
+
release: () => {
|
|
942
|
+
resolveMutex?.();
|
|
943
|
+
if (selectionMutexes.get(key) === nextMutex) {
|
|
944
|
+
selectionMutexes.delete(key);
|
|
945
|
+
}
|
|
946
|
+
},
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// ─── Anti-Thundering Herd: per-connection mutex for markAccountUnavailable ───
|
|
951
|
+
// Prevents multiple concurrent requests from marking the same connection
|
|
952
|
+
// unavailable in parallel, which was the root cause of cascading 502 lockouts.
|
|
953
|
+
const markMutexes = new Map<string, Promise<void>>();
|
|
954
|
+
|
|
955
|
+
// Strict-Random shuffle deck moved to src/shared/utils/shuffleDeck.ts
|
|
956
|
+
// auth.ts uses getNextFromDeckSync inside the provider-scoped selection mutex.
|
|
957
|
+
// Re-export for backwards compat with existing test imports.
|
|
958
|
+
export { fisherYatesShuffle, getNextFromDeckSync as getNextFromDeck };
|
|
959
|
+
|
|
960
|
+
/**
|
|
961
|
+
* Resolve provider aliases (e.g., nvidia -> nvidia_nim) for DB lookup
|
|
962
|
+
*/
|
|
963
|
+
async function getProviderSearchPool(provider: string): Promise<string[]> {
|
|
964
|
+
const canonicalProvider = resolveProviderId(provider);
|
|
965
|
+
const canonicalAlias = getProviderAlias(canonicalProvider);
|
|
966
|
+
|
|
967
|
+
if (provider === "nvidia") {
|
|
968
|
+
return ["nvidia", "nvidia_nim"];
|
|
969
|
+
}
|
|
970
|
+
if (provider === "nvidia_nim") {
|
|
971
|
+
return ["nvidia_nim", "nvidia"];
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
const searchPool = new Set([provider, canonicalProvider, canonicalAlias].filter(Boolean));
|
|
975
|
+
|
|
976
|
+
// Built-in providers already resolve through static ids/aliases. Only
|
|
977
|
+
// compatible/custom providers need provider_nodes expansion back to the
|
|
978
|
+
// generated internal connection ids. (#3058)
|
|
979
|
+
if (getProviderById(canonicalProvider)) {
|
|
980
|
+
return Array.from(searchPool);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
// Custom provider nodes are referenced by user-facing prefixes in combos
|
|
984
|
+
// (for example "78code/gpt-5.4"), but live credentials are stored under
|
|
985
|
+
// internal provider ids like openai-compatible-responses-<uuid>.
|
|
986
|
+
try {
|
|
987
|
+
const providerNodes = await getProviderNodes();
|
|
988
|
+
for (const node of Array.isArray(providerNodes) ? providerNodes : []) {
|
|
989
|
+
const nodeRecord = asRecord(node);
|
|
990
|
+
const nodePrefix = typeof nodeRecord.prefix === "string" ? nodeRecord.prefix.trim() : "";
|
|
991
|
+
const nodeId = typeof nodeRecord.id === "string" ? nodeRecord.id.trim() : "";
|
|
992
|
+
if (!nodePrefix || !nodeId) continue;
|
|
993
|
+
if (
|
|
994
|
+
nodePrefix === provider ||
|
|
995
|
+
nodePrefix === canonicalProvider ||
|
|
996
|
+
nodePrefix === canonicalAlias
|
|
997
|
+
) {
|
|
998
|
+
searchPool.add(nodeId);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
} catch {
|
|
1002
|
+
// Best-effort alias expansion only.
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
return Array.from(searchPool);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Get provider credentials from localDb
|
|
1010
|
+
* Filters out unavailable accounts and returns the selected account based on strategy
|
|
1011
|
+
* @param {string} provider - Provider name
|
|
1012
|
+
* @param {string|null} excludeConnectionId - Connection ID to exclude (for retry with next account)
|
|
1013
|
+
*/
|
|
1014
|
+
export async function getProviderCredentials(
|
|
1015
|
+
provider: string,
|
|
1016
|
+
excludeConnectionId: string | null = null,
|
|
1017
|
+
allowedConnections: string[] | null = null,
|
|
1018
|
+
requestedModel: string | null = null,
|
|
1019
|
+
options: CredentialSelectionOptions = {}
|
|
1020
|
+
) {
|
|
1021
|
+
const selectionLock = createSelectionLock(getSelectionMutexKey(provider, options));
|
|
1022
|
+
|
|
1023
|
+
try {
|
|
1024
|
+
await selectionLock.wait;
|
|
1025
|
+
|
|
1026
|
+
// No-auth providers (e.g. opencode) need no DB connection — return synthetic credentials
|
|
1027
|
+
// so the executor receives a valid credentials object without auth headers being added.
|
|
1028
|
+
const resolvedId = resolveProviderId(provider);
|
|
1029
|
+
const providerMaps: Record<string, { noAuth?: boolean } | undefined>[] = [
|
|
1030
|
+
NOAUTH_PROVIDERS as Record<string, { noAuth?: boolean } | undefined>,
|
|
1031
|
+
WEB_COOKIE_PROVIDERS as Record<string, { noAuth?: boolean } | undefined>,
|
|
1032
|
+
];
|
|
1033
|
+
if (providerMaps.some((map) => map[resolvedId]?.noAuth)) {
|
|
1034
|
+
if (await isNoAuthProviderBlockedBySettings(resolvedId)) return null;
|
|
1035
|
+
// #3061: there is only one synthetic "noauth" connection for a no-auth
|
|
1036
|
+
// provider. If the caller already tried and excluded it (account-fallback
|
|
1037
|
+
// after a persistent upstream error), do NOT hand it back — that would let
|
|
1038
|
+
// the chat fallback loop re-select "noauth" forever (no real DB row → no
|
|
1039
|
+
// cooldown to brake it), writing logs every iteration until the disk fills.
|
|
1040
|
+
// Returning null here lets the handler stop after a single attempt.
|
|
1041
|
+
const excludedForNoAuth = normalizeExcludedConnectionIds(
|
|
1042
|
+
excludeConnectionId,
|
|
1043
|
+
options.excludeConnectionIds
|
|
1044
|
+
);
|
|
1045
|
+
return await maybeSyntheticNoAuthFallback(resolvedId, excludedForNoAuth);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
const allowSuppressedConnections = options.allowSuppressedConnections === true;
|
|
1049
|
+
const allowRateLimitedConnections =
|
|
1050
|
+
allowSuppressedConnections || options.allowRateLimitedConnections === true;
|
|
1051
|
+
const bypassQuotaPolicy = options.bypassQuotaPolicy === true;
|
|
1052
|
+
let forcedConnectionId =
|
|
1053
|
+
typeof options.forcedConnectionId === "string" && options.forcedConnectionId.trim().length > 0
|
|
1054
|
+
? options.forcedConnectionId.trim()
|
|
1055
|
+
: null;
|
|
1056
|
+
const excludedConnectionIds = normalizeExcludedConnectionIds(
|
|
1057
|
+
excludeConnectionId,
|
|
1058
|
+
options.excludeConnectionIds
|
|
1059
|
+
);
|
|
1060
|
+
|
|
1061
|
+
// Fetched early so the session-affinity-pin override (#5903) can consult
|
|
1062
|
+
// the TTL before forcedConnectionId narrows the connection pool.
|
|
1063
|
+
const settings = await getSettings();
|
|
1064
|
+
const sessionAffinityTtlMs = resolveSessionAffinityTtlMs(provider, options, settings);
|
|
1065
|
+
|
|
1066
|
+
// Fix #922: Check for aliases (nvidia/nvidia_nim) to ensure credentials are found
|
|
1067
|
+
const providersToSearch = await getProviderSearchPool(provider);
|
|
1068
|
+
const connectionResults = await Promise.all(
|
|
1069
|
+
providersToSearch.map((p) => getProviderConnections({ provider: p, isActive: true }))
|
|
1070
|
+
);
|
|
1071
|
+
const connectionsRaw = connectionResults.filter(Array.isArray).flat();
|
|
1072
|
+
|
|
1073
|
+
let connections = (Array.isArray(connectionsRaw) ? connectionsRaw : [])
|
|
1074
|
+
.map(toProviderConnection)
|
|
1075
|
+
.filter((conn) => conn.id.length > 0);
|
|
1076
|
+
// allowedConnections: restrict to specific connection IDs (from API key policy, #363)
|
|
1077
|
+
if (allowedConnections && allowedConnections.length > 0) {
|
|
1078
|
+
connections = connections.filter((conn) => allowedConnections.includes(conn.id));
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// #5903: an active session-affinity pin outranks a per-request reset-aware
|
|
1082
|
+
// forcedConnectionId (see sessionAffinityPin leaf for the full rationale).
|
|
1083
|
+
forcedConnectionId =
|
|
1084
|
+
applySessionAffinityPin({
|
|
1085
|
+
forcedConnectionId,
|
|
1086
|
+
options,
|
|
1087
|
+
sessionAffinityTtlMs,
|
|
1088
|
+
connections,
|
|
1089
|
+
provider,
|
|
1090
|
+
requestedModel,
|
|
1091
|
+
excludedConnectionIds,
|
|
1092
|
+
isTerminalConnectionStatus,
|
|
1093
|
+
isCodexScopeUnavailable,
|
|
1094
|
+
isQuotaPolicyBlocked: (c) =>
|
|
1095
|
+
evaluateQuotaLimitPolicy(provider, c as ProviderConnectionView, requestedModel).blocked,
|
|
1096
|
+
}) ?? forcedConnectionId;
|
|
1097
|
+
|
|
1098
|
+
if (forcedConnectionId) {
|
|
1099
|
+
connections = connections.filter((conn) => conn.id === forcedConnectionId);
|
|
1100
|
+
}
|
|
1101
|
+
const activeConnectionsCount = connections.length;
|
|
1102
|
+
const rawConnectionsCount = connectionsRaw.length;
|
|
1103
|
+
const blockedByForcedConnection = forcedConnectionId
|
|
1104
|
+
? rawConnectionsCount - connections.length
|
|
1105
|
+
: 0;
|
|
1106
|
+
const blockedByAllowedConnections =
|
|
1107
|
+
allowedConnections && allowedConnections.length > 0
|
|
1108
|
+
? Math.max(0, rawConnectionsCount - connections.length - blockedByForcedConnection)
|
|
1109
|
+
: 0;
|
|
1110
|
+
const forcedIdForLog = forcedConnectionId ? `${forcedConnectionId.slice(0, 8)}...` : "none";
|
|
1111
|
+
|
|
1112
|
+
log.debug(
|
|
1113
|
+
"AUTH",
|
|
1114
|
+
`${provider} | active=${activeConnectionsCount}, excluded=${excludedConnectionIds.size} (${formatConnectionPrefixesForLog(excludedConnectionIds)}), forcedId=${forcedIdForLog}, blocked_forced=${blockedByForcedConnection}, blocked_allowed=${blockedByAllowedConnections}`
|
|
1115
|
+
);
|
|
1116
|
+
if (provider === "antigravity" && (forcedConnectionId || allowedConnections?.length)) {
|
|
1117
|
+
const reasons: string[] = [];
|
|
1118
|
+
if (forcedConnectionId) reasons.push(`forcedConnectionId kept ${connections.length}`);
|
|
1119
|
+
if (allowedConnections?.length) {
|
|
1120
|
+
reasons.push(`allowedConnections=${allowedConnections.length}`);
|
|
1121
|
+
}
|
|
1122
|
+
log.info("AUTH", `${provider} selection constrained: ${reasons.join(", ")}`);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
if (connections.length === 0) {
|
|
1126
|
+
// Check all connections (including inactive) to see if rate limited
|
|
1127
|
+
// Fix #922: Also search aliases here
|
|
1128
|
+
const allConnectionsResults = await Promise.all(
|
|
1129
|
+
providersToSearch.map((p) => getProviderConnections({ provider: p }))
|
|
1130
|
+
);
|
|
1131
|
+
let allConnections = (allConnectionsResults.filter(Array.isArray).flat() as unknown[])
|
|
1132
|
+
.map(toProviderConnection)
|
|
1133
|
+
.filter((conn) => conn.id.length > 0);
|
|
1134
|
+
if (allowedConnections && allowedConnections.length > 0) {
|
|
1135
|
+
allConnections = allConnections.filter((conn) => allowedConnections.includes(conn.id));
|
|
1136
|
+
}
|
|
1137
|
+
if (forcedConnectionId) {
|
|
1138
|
+
allConnections = allConnections.filter((conn) => conn.id === forcedConnectionId);
|
|
1139
|
+
}
|
|
1140
|
+
log.debug("AUTH", `${provider} | all connections (incl inactive): ${allConnections.length}`);
|
|
1141
|
+
if (allConnections.length > 0) {
|
|
1142
|
+
const earliest = getEarliestRateLimitedUntil(allConnections);
|
|
1143
|
+
if (earliest) {
|
|
1144
|
+
log.warn(
|
|
1145
|
+
"AUTH",
|
|
1146
|
+
`${provider} | all ${allConnections.length} accounts rate limited (${formatRetryAfter(earliest)})`
|
|
1147
|
+
);
|
|
1148
|
+
return {
|
|
1149
|
+
allRateLimited: true,
|
|
1150
|
+
retryAfter: earliest,
|
|
1151
|
+
retryAfterHuman: formatRetryAfter(earliest),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
log.warn("AUTH", `${provider} | ${allConnections.length} accounts found but none active`);
|
|
1155
|
+
allConnections.forEach((c) => {
|
|
1156
|
+
log.debug(
|
|
1157
|
+
"AUTH",
|
|
1158
|
+
` → ${c.id?.slice(0, 8)} | isActive=${c.isActive} | rateLimitedUntil=${c.rateLimitedUntil || "none"} | testStatus=${c.testStatus}`
|
|
1159
|
+
);
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
// If every existing connection is in a terminal state (expired/banned/
|
|
1163
|
+
// credits_exhausted), surface that as a re-auth signal instead of the
|
|
1164
|
+
// generic "No credentials" 400. The classic case is AWS SSO/Kiro
|
|
1165
|
+
// refresh tokens hitting their 90-day TTL: all connections flip to
|
|
1166
|
+
// is_active=0 with testStatus=banned|expired, and without this branch
|
|
1167
|
+
// the dashboard sees a misleading "bad_request" code.
|
|
1168
|
+
const terminalConnections = allConnections.filter(isTerminalConnectionStatus);
|
|
1169
|
+
if (terminalConnections.length === allConnections.length) {
|
|
1170
|
+
const syntheticFallback = await maybeSyntheticNoAuthFallback(
|
|
1171
|
+
resolvedId,
|
|
1172
|
+
excludedConnectionIds
|
|
1173
|
+
);
|
|
1174
|
+
if (syntheticFallback) return syntheticFallback;
|
|
1175
|
+
|
|
1176
|
+
const statusCounts = new Map<string, number>();
|
|
1177
|
+
for (const c of terminalConnections) {
|
|
1178
|
+
const key = normalizeStatus(c.testStatus) || "expired";
|
|
1179
|
+
statusCounts.set(key, (statusCounts.get(key) || 0) + 1);
|
|
1180
|
+
}
|
|
1181
|
+
const dominantStatus =
|
|
1182
|
+
[...statusCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] || "expired";
|
|
1183
|
+
return {
|
|
1184
|
+
allExpired: true,
|
|
1185
|
+
expiredCount: terminalConnections.length,
|
|
1186
|
+
expiredStatus: dominantStatus,
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
const syntheticFallback = await maybeSyntheticNoAuthFallback(
|
|
1191
|
+
resolvedId,
|
|
1192
|
+
excludedConnectionIds
|
|
1193
|
+
);
|
|
1194
|
+
if (syntheticFallback) return syntheticFallback;
|
|
1195
|
+
log.warn("AUTH", `No credentials for ${provider}`);
|
|
1196
|
+
return null;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Auto-decay backoffLevel for accounts whose rateLimitedUntil has passed.
|
|
1200
|
+
// Without this, high backoffLevel permanently deprioritizes accounts even
|
|
1201
|
+
// after the rate limit window expires, creating a deadlock where the account
|
|
1202
|
+
// needs a successful request to reset but never gets selected.
|
|
1203
|
+
for (const c of connections) {
|
|
1204
|
+
if (
|
|
1205
|
+
c.backoffLevel > 0 &&
|
|
1206
|
+
!isTerminalConnectionStatus(c) &&
|
|
1207
|
+
!isAccountUnavailable(c.rateLimitedUntil)
|
|
1208
|
+
) {
|
|
1209
|
+
c.backoffLevel = 0;
|
|
1210
|
+
updateProviderConnection(c.id, {
|
|
1211
|
+
backoffLevel: 0,
|
|
1212
|
+
testStatus: "active",
|
|
1213
|
+
lastError: null,
|
|
1214
|
+
lastErrorAt: null,
|
|
1215
|
+
lastErrorType: null,
|
|
1216
|
+
lastErrorSource: null,
|
|
1217
|
+
errorCode: null,
|
|
1218
|
+
}).catch(() => {});
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
let modelLockedCount = 0;
|
|
1223
|
+
let familyLockedCount = 0;
|
|
1224
|
+
// Filter out unavailable accounts and excluded connection
|
|
1225
|
+
const availableConnections = connections.filter((c) => {
|
|
1226
|
+
if (excludedConnectionIds.has(c.id)) return false;
|
|
1227
|
+
if (requestedModel && isModelExcludedByConnection(requestedModel, c.providerSpecificData)) {
|
|
1228
|
+
return false;
|
|
1229
|
+
}
|
|
1230
|
+
if (!allowSuppressedConnections) {
|
|
1231
|
+
if (!allowRateLimitedConnections && isAccountUnavailable(c.rateLimitedUntil)) return false;
|
|
1232
|
+
if (isTerminalConnectionStatus(c)) return false;
|
|
1233
|
+
if (provider === "codex" && isCodexScopeUnavailable(c, requestedModel)) return false;
|
|
1234
|
+
// Per-model lockout: if this specific model/family is locked on this connection, skip it
|
|
1235
|
+
if (requestedModel && isModelLocked(provider, c.id, requestedModel)) {
|
|
1236
|
+
if (
|
|
1237
|
+
provider === "antigravity" &&
|
|
1238
|
+
getQuotaScopeLabelForProvider(provider, requestedModel) === "family"
|
|
1239
|
+
) {
|
|
1240
|
+
familyLockedCount += 1;
|
|
1241
|
+
} else {
|
|
1242
|
+
modelLockedCount += 1;
|
|
1243
|
+
}
|
|
1244
|
+
return false;
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return true;
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
log.debug(
|
|
1251
|
+
"AUTH",
|
|
1252
|
+
`${provider} | available: ${availableConnections.length}/${connections.length}`
|
|
1253
|
+
);
|
|
1254
|
+
if (provider === "antigravity") {
|
|
1255
|
+
log.info(
|
|
1256
|
+
"AUTH",
|
|
1257
|
+
`${provider} selection candidates model=${requestedModel || "none"}: active=${activeConnectionsCount}, excluded=${excludedConnectionIds.size}, modelLocked=${modelLockedCount}, familyLocked=${familyLockedCount}, eligible=${availableConnections.length}`
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
connections.forEach((c) => {
|
|
1261
|
+
const excluded = excludedConnectionIds.has(c.id);
|
|
1262
|
+
const rateLimited = isAccountUnavailable(c.rateLimitedUntil);
|
|
1263
|
+
const terminalStatus = isTerminalConnectionStatus(c);
|
|
1264
|
+
const codexScopeLimited = provider === "codex" && isCodexScopeUnavailable(c, requestedModel);
|
|
1265
|
+
const modelLocked =
|
|
1266
|
+
Boolean(requestedModel) && isModelLocked(provider, c.id, requestedModel as string);
|
|
1267
|
+
const modelExcluded =
|
|
1268
|
+
Boolean(requestedModel) &&
|
|
1269
|
+
isModelExcludedByConnection(requestedModel as string, c.providerSpecificData);
|
|
1270
|
+
if (excluded || rateLimited) {
|
|
1271
|
+
log.debug(
|
|
1272
|
+
"AUTH",
|
|
1273
|
+
` → ${c.id?.slice(0, 8)} | ${excluded ? "excluded" : ""} ${rateLimited ? `rateLimited until ${c.rateLimitedUntil}` : ""}${allowSuppressedConnections && rateLimited ? " (retained for combo live test)" : ""}`
|
|
1274
|
+
);
|
|
1275
|
+
} else if (modelExcluded) {
|
|
1276
|
+
log.debug(
|
|
1277
|
+
"AUTH",
|
|
1278
|
+
` → ${c.id?.slice(0, 8)} | excluded by per-account model rule for ${requestedModel}`
|
|
1279
|
+
);
|
|
1280
|
+
} else if (terminalStatus) {
|
|
1281
|
+
log.debug(
|
|
1282
|
+
"AUTH",
|
|
1283
|
+
allowSuppressedConnections
|
|
1284
|
+
? ` → ${c.id?.slice(0, 8)} | retained terminal status=${c.testStatus} for combo live test`
|
|
1285
|
+
: ` → ${c.id?.slice(0, 8)} | skipped terminal status=${c.testStatus}`
|
|
1286
|
+
);
|
|
1287
|
+
} else if (codexScopeLimited) {
|
|
1288
|
+
const scopeUntil = getCodexScopeRateLimitedUntil(c.providerSpecificData, requestedModel);
|
|
1289
|
+
log.debug(
|
|
1290
|
+
"AUTH",
|
|
1291
|
+
allowSuppressedConnections
|
|
1292
|
+
? ` → ${c.id?.slice(0, 8)} | retained codex scope-limited account until ${scopeUntil} for combo live test`
|
|
1293
|
+
: ` → ${c.id?.slice(0, 8)} | codex scope-limited until ${scopeUntil}`
|
|
1294
|
+
);
|
|
1295
|
+
} else if (modelLocked) {
|
|
1296
|
+
const lockout = getModelLockoutInfo(provider, c.id, requestedModel);
|
|
1297
|
+
log.debug(
|
|
1298
|
+
"AUTH",
|
|
1299
|
+
allowSuppressedConnections
|
|
1300
|
+
? ` → ${c.id?.slice(0, 8)} | retained model lockout for ${requestedModel} (${lockout?.remainingMs || 0}ms remaining) for combo live test`
|
|
1301
|
+
: ` → ${c.id?.slice(0, 8)} | model-locked for ${requestedModel} (${lockout?.remainingMs || 0}ms remaining)`
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
if (availableConnections.length === 0) {
|
|
1307
|
+
const cooldownStates: CooldownInspectionState[] = connections.map((connection) => {
|
|
1308
|
+
const connectionCooldownMs = parseFutureDateMs(connection.rateLimitedUntil);
|
|
1309
|
+
const codexScopeCooldownMs =
|
|
1310
|
+
provider === "codex"
|
|
1311
|
+
? parseFutureDateMs(
|
|
1312
|
+
getCodexScopeRateLimitedUntil(connection.providerSpecificData, requestedModel)
|
|
1313
|
+
)
|
|
1314
|
+
: null;
|
|
1315
|
+
const modelLockout = requestedModel
|
|
1316
|
+
? getModelLockoutInfo(provider, connection.id, requestedModel)
|
|
1317
|
+
: null;
|
|
1318
|
+
const retryableModelCooldownMs =
|
|
1319
|
+
modelLockout &&
|
|
1320
|
+
modelLockout.remainingMs > 0 &&
|
|
1321
|
+
isRetryableModelLockoutReason(modelLockout.reason)
|
|
1322
|
+
? Date.now() + modelLockout.remainingMs
|
|
1323
|
+
: null;
|
|
1324
|
+
|
|
1325
|
+
return {
|
|
1326
|
+
connection,
|
|
1327
|
+
connectionCooldownMs,
|
|
1328
|
+
codexScopeCooldownMs,
|
|
1329
|
+
retryableModelCooldownMs,
|
|
1330
|
+
};
|
|
1331
|
+
});
|
|
1332
|
+
|
|
1333
|
+
const cooldownCandidates = cooldownStates
|
|
1334
|
+
.flatMap((state) => {
|
|
1335
|
+
const candidates: Array<{ ms: number; connection: ProviderConnectionView }> = [];
|
|
1336
|
+
if (state.connectionCooldownMs !== null) {
|
|
1337
|
+
candidates.push({ ms: state.connectionCooldownMs, connection: state.connection });
|
|
1338
|
+
}
|
|
1339
|
+
if (state.codexScopeCooldownMs !== null) {
|
|
1340
|
+
candidates.push({ ms: state.codexScopeCooldownMs, connection: state.connection });
|
|
1341
|
+
}
|
|
1342
|
+
if (state.retryableModelCooldownMs !== null) {
|
|
1343
|
+
candidates.push({ ms: state.retryableModelCooldownMs, connection: state.connection });
|
|
1344
|
+
}
|
|
1345
|
+
return candidates;
|
|
1346
|
+
})
|
|
1347
|
+
.sort((a, b) => a.ms - b.ms);
|
|
1348
|
+
|
|
1349
|
+
const allBlockedByModelCooldown =
|
|
1350
|
+
Boolean(requestedModel) &&
|
|
1351
|
+
cooldownStates.length > 0 &&
|
|
1352
|
+
cooldownStates.every((state) => {
|
|
1353
|
+
const hasModelSpecificCooldown =
|
|
1354
|
+
state.codexScopeCooldownMs !== null || state.retryableModelCooldownMs !== null;
|
|
1355
|
+
return hasModelSpecificCooldown && state.connectionCooldownMs === null;
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
const earliestCandidate = cooldownCandidates[0];
|
|
1359
|
+
const earliest =
|
|
1360
|
+
earliestCandidate?.ms && Number.isFinite(earliestCandidate.ms)
|
|
1361
|
+
? new Date(earliestCandidate.ms).toISOString()
|
|
1362
|
+
: null;
|
|
1363
|
+
|
|
1364
|
+
if (earliest) {
|
|
1365
|
+
const earliestConn = earliestCandidate?.connection;
|
|
1366
|
+
log.warn(
|
|
1367
|
+
"AUTH",
|
|
1368
|
+
allBlockedByModelCooldown
|
|
1369
|
+
? `${provider} | all ${connections.length} active accounts cooling down for model ${requestedModel} (${formatRetryAfter(earliest)}) | lastErrorCode=${earliestConn?.errorCode}, lastError=${earliestConn?.lastError?.slice(0, 50)}`
|
|
1370
|
+
: `${provider} | all ${connections.length} active accounts rate limited (${formatRetryAfter(earliest)}) | lastErrorCode=${earliestConn?.errorCode}, lastError=${earliestConn?.lastError?.slice(0, 50)}`
|
|
1371
|
+
);
|
|
1372
|
+
return {
|
|
1373
|
+
allRateLimited: true,
|
|
1374
|
+
retryAfter: earliest,
|
|
1375
|
+
retryAfterHuman: formatRetryAfter(earliest),
|
|
1376
|
+
lastError: earliestConn?.lastError || null,
|
|
1377
|
+
lastErrorCode: allBlockedByModelCooldown ? 429 : earliestConn?.errorCode || null,
|
|
1378
|
+
cooldownScope: allBlockedByModelCooldown ? "model" : "connection",
|
|
1379
|
+
cooldownModel: allBlockedByModelCooldown ? requestedModel : null,
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
const syntheticFallback = await maybeSyntheticNoAuthFallback(
|
|
1383
|
+
resolvedId,
|
|
1384
|
+
excludedConnectionIds
|
|
1385
|
+
);
|
|
1386
|
+
if (syntheticFallback) return syntheticFallback;
|
|
1387
|
+
log.warn("AUTH", `${provider} | all ${connections.length} accounts unavailable`);
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
let policyEligibleConnections = availableConnections;
|
|
1392
|
+
const blockedByPolicy: Array<{
|
|
1393
|
+
id: string;
|
|
1394
|
+
reasons: string[];
|
|
1395
|
+
resetAt: string | null;
|
|
1396
|
+
}> = [];
|
|
1397
|
+
|
|
1398
|
+
if (!bypassQuotaPolicy) {
|
|
1399
|
+
policyEligibleConnections = availableConnections.filter((connection) => {
|
|
1400
|
+
const evaluation = evaluateQuotaLimitPolicy(provider, connection, requestedModel);
|
|
1401
|
+
if (!evaluation.blocked) return true;
|
|
1402
|
+
|
|
1403
|
+
blockedByPolicy.push({
|
|
1404
|
+
id: connection.id,
|
|
1405
|
+
reasons: evaluation.reasons,
|
|
1406
|
+
resetAt: evaluation.resetAt,
|
|
1407
|
+
});
|
|
1408
|
+
return false;
|
|
1409
|
+
});
|
|
1410
|
+
} else if (availableConnections.length > 0) {
|
|
1411
|
+
log.debug("AUTH", `${provider} | bypassing quota policy for combo live test`);
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
if (blockedByPolicy.length > 0) {
|
|
1415
|
+
log.info(
|
|
1416
|
+
"AUTH",
|
|
1417
|
+
`${provider} | quota policy filtered ${blockedByPolicy.length} account(s): ${blockedByPolicy
|
|
1418
|
+
.map((entry) => `${entry.id.slice(0, 8)}(${entry.reasons.join(", ")})`)
|
|
1419
|
+
.join("; ")}`
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
if (policyEligibleConnections.length === 0 && availableConnections.length > 0) {
|
|
1424
|
+
const earliestResetAt = getEarliestFutureDate(blockedByPolicy.map((entry) => entry.resetAt));
|
|
1425
|
+
const earliestResetMs = parseFutureDateMs(earliestResetAt);
|
|
1426
|
+
|
|
1427
|
+
const retryAfter = earliestResetMs
|
|
1428
|
+
? new Date(earliestResetMs).toISOString()
|
|
1429
|
+
: new Date(Date.now() + 5 * 60 * 1000).toISOString();
|
|
1430
|
+
|
|
1431
|
+
return {
|
|
1432
|
+
allRateLimited: true,
|
|
1433
|
+
retryAfter,
|
|
1434
|
+
retryAfterHuman: formatRetryAfter(retryAfter),
|
|
1435
|
+
lastError: `All ${provider} accounts reached configured quota threshold`,
|
|
1436
|
+
lastErrorCode: 429,
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
// Quota-aware: filter out accounts with exhausted quota for the requested scope.
|
|
1441
|
+
const withQuota = policyEligibleConnections.filter(
|
|
1442
|
+
(c) => !isQuotaExhaustedForRequest(c.id, provider, requestedModel)
|
|
1443
|
+
);
|
|
1444
|
+
const exhaustedQuota = policyEligibleConnections.filter((c) =>
|
|
1445
|
+
isQuotaExhaustedForRequest(c.id, provider, requestedModel)
|
|
1446
|
+
);
|
|
1447
|
+
|
|
1448
|
+
if (exhaustedQuota.length > 0) {
|
|
1449
|
+
log.info(
|
|
1450
|
+
"AUTH",
|
|
1451
|
+
`${provider} | quota-aware: ${withQuota.length} with quota, skipping ${exhaustedQuota.length} exhausted`
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
if (withQuota.length === 0 && exhaustedQuota.length > 0) {
|
|
1456
|
+
// All remaining eligible accounts are exhausted
|
|
1457
|
+
const earliestResetAt = getEarliestFutureDate(
|
|
1458
|
+
exhaustedQuota.map((c) => {
|
|
1459
|
+
const entry = getQuotaCache(c.id);
|
|
1460
|
+
return entry?.nextResetAt || null;
|
|
1461
|
+
})
|
|
1462
|
+
);
|
|
1463
|
+
const earliestResetMs = parseFutureDateMs(earliestResetAt);
|
|
1464
|
+
const retryAfter = earliestResetMs
|
|
1465
|
+
? new Date(earliestResetMs).toISOString()
|
|
1466
|
+
: new Date(Date.now() + 5 * 60 * 1000).toISOString();
|
|
1467
|
+
|
|
1468
|
+
return {
|
|
1469
|
+
allRateLimited: true,
|
|
1470
|
+
retryAfter,
|
|
1471
|
+
retryAfterHuman: formatRetryAfter(retryAfter),
|
|
1472
|
+
lastError: `All ${provider} accounts have exhausted their quota`,
|
|
1473
|
+
lastErrorCode: 429,
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
const orderedConnections = withQuota;
|
|
1478
|
+
|
|
1479
|
+
const strategy = settings.fallbackStrategy || "fill-first";
|
|
1480
|
+
|
|
1481
|
+
let connection;
|
|
1482
|
+
const affinityConnection = await selectSessionAffinityConnection(
|
|
1483
|
+
provider,
|
|
1484
|
+
options.sessionKey,
|
|
1485
|
+
orderedConnections,
|
|
1486
|
+
sessionAffinityTtlMs
|
|
1487
|
+
);
|
|
1488
|
+
if (affinityConnection) {
|
|
1489
|
+
connection = affinityConnection;
|
|
1490
|
+
} else if (options.sessionKey) {
|
|
1491
|
+
log.info(
|
|
1492
|
+
"AUTH",
|
|
1493
|
+
`session_key=${formatSessionKeyForLog(options.sessionKey)} has no available affinity target`
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
if (connection) {
|
|
1498
|
+
// Session affinity selected a connection before global sticky routing.
|
|
1499
|
+
} else if (strategy === "round-robin") {
|
|
1500
|
+
const stickyLimit = toNumber((settings as Record<string, unknown>).stickyRoundRobinLimit, 3);
|
|
1501
|
+
|
|
1502
|
+
// If excluding account(s) (fallback scenario), skip sticky logic and go straight to LRU.
|
|
1503
|
+
// This prevents same-model retries from getting stuck on a failed account.
|
|
1504
|
+
const isFallbackScenario = excludeConnectionId !== null || excludedConnectionIds.size > 0;
|
|
1505
|
+
|
|
1506
|
+
if (!isFallbackScenario) {
|
|
1507
|
+
// Sort by lastUsed (most recent first) to find current candidate
|
|
1508
|
+
const byRecency = [...orderedConnections].sort((a: any, b: any) => {
|
|
1509
|
+
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
1510
|
+
if (!a.lastUsedAt) return 1;
|
|
1511
|
+
if (!b.lastUsedAt) return -1;
|
|
1512
|
+
return new Date(b.lastUsedAt).getTime() - new Date(a.lastUsedAt).getTime();
|
|
1513
|
+
});
|
|
1514
|
+
|
|
1515
|
+
const current = byRecency[0];
|
|
1516
|
+
const currentCount = current?.consecutiveUseCount || 0;
|
|
1517
|
+
|
|
1518
|
+
if (current && current.lastUsedAt && currentCount < stickyLimit) {
|
|
1519
|
+
// Stay with current account
|
|
1520
|
+
connection = current;
|
|
1521
|
+
log.debug(
|
|
1522
|
+
"AUTH",
|
|
1523
|
+
`${provider} round-robin: staying with ${current.id?.slice(0, 8)}... (count=${currentCount}/${stickyLimit})`
|
|
1524
|
+
);
|
|
1525
|
+
// Update lastUsedAt and increment count (await to ensure persistence)
|
|
1526
|
+
await updateProviderConnection(connection.id, {
|
|
1527
|
+
lastUsedAt: new Date().toISOString(),
|
|
1528
|
+
consecutiveUseCount: (connection.consecutiveUseCount || 0) + 1,
|
|
1529
|
+
});
|
|
1530
|
+
} else {
|
|
1531
|
+
// Pick the least recently used (excluding current if possible)
|
|
1532
|
+
// Also penalize accounts with high backoffLevel (previously rate-limited)
|
|
1533
|
+
// so they don't get immediately re-selected after cooldown (#340)
|
|
1534
|
+
const sortedByOldest = [...orderedConnections].sort((a: any, b: any) => {
|
|
1535
|
+
// Penalize previously rate-limited accounts (backoffLevel > 0)
|
|
1536
|
+
const aBackoff = a.backoffLevel || 0;
|
|
1537
|
+
const bBackoff = b.backoffLevel || 0;
|
|
1538
|
+
if (aBackoff !== bBackoff) return aBackoff - bBackoff; // lower backoff first
|
|
1539
|
+
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
1540
|
+
if (!a.lastUsedAt) return -1;
|
|
1541
|
+
if (!b.lastUsedAt) return 1;
|
|
1542
|
+
return new Date(a.lastUsedAt).getTime() - new Date(b.lastUsedAt).getTime();
|
|
1543
|
+
});
|
|
1544
|
+
|
|
1545
|
+
connection = sortedByOldest[0];
|
|
1546
|
+
log.debug(
|
|
1547
|
+
"AUTH",
|
|
1548
|
+
`${provider} round-robin: switching to LRU ${connection.id?.slice(0, 8)}... (current count=${currentCount} >= limit=${stickyLimit} or no lastUsedAt)`
|
|
1549
|
+
);
|
|
1550
|
+
|
|
1551
|
+
// Update lastUsedAt and reset count to 1 (await to ensure persistence)
|
|
1552
|
+
await updateProviderConnection(connection.id, {
|
|
1553
|
+
lastUsedAt: new Date().toISOString(),
|
|
1554
|
+
consecutiveUseCount: 1,
|
|
1555
|
+
});
|
|
1556
|
+
}
|
|
1557
|
+
} else {
|
|
1558
|
+
// Fallback scenario: excluded an account due to failure
|
|
1559
|
+
// Always pick the least recently used to ensure proper cycling
|
|
1560
|
+
// Also penalize accounts with high backoffLevel (#340)
|
|
1561
|
+
const sortedByOldest = [...orderedConnections].sort((a: any, b: any) => {
|
|
1562
|
+
const aBackoff = a.backoffLevel || 0;
|
|
1563
|
+
const bBackoff = b.backoffLevel || 0;
|
|
1564
|
+
if (aBackoff !== bBackoff) return aBackoff - bBackoff;
|
|
1565
|
+
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
1566
|
+
if (!a.lastUsedAt) return -1;
|
|
1567
|
+
if (!b.lastUsedAt) return 1;
|
|
1568
|
+
return new Date(a.lastUsedAt).getTime() - new Date(b.lastUsedAt).getTime();
|
|
1569
|
+
});
|
|
1570
|
+
|
|
1571
|
+
connection = sortedByOldest[0];
|
|
1572
|
+
log.info(
|
|
1573
|
+
"AUTH",
|
|
1574
|
+
`${provider} round-robin: FALLBACK MODE - excluded_count=${excludedConnectionIds.size} excluded=${formatConnectionPrefixesForLog(excludedConnectionIds)} picked_lru=${connection.id?.slice(0, 8)}...`
|
|
1575
|
+
);
|
|
1576
|
+
|
|
1577
|
+
// Update lastUsedAt and reset count to 1 (await to ensure persistence)
|
|
1578
|
+
await updateProviderConnection(connection.id, {
|
|
1579
|
+
lastUsedAt: new Date().toISOString(),
|
|
1580
|
+
consecutiveUseCount: 1,
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
} else if (strategy === "p2c") {
|
|
1584
|
+
const candidatePool = withQuota.length > 0 ? withQuota : orderedConnections;
|
|
1585
|
+
// Power of Two Choices: sample from the quota-eligible pool and compare
|
|
1586
|
+
// health instead of defaulting to random-first selection.
|
|
1587
|
+
if (candidatePool.length <= 2) {
|
|
1588
|
+
connection = [...candidatePool].sort((a, b) =>
|
|
1589
|
+
compareP2CConnections(provider, a, b, requestedModel)
|
|
1590
|
+
)[0];
|
|
1591
|
+
} else {
|
|
1592
|
+
const i =
|
|
1593
|
+
parseInt(randomUUID().replace(/-/g, "").substring(0, 8), 16) % candidatePool.length;
|
|
1594
|
+
let j =
|
|
1595
|
+
parseInt(randomUUID().replace(/-/g, "").substring(0, 8), 16) % (candidatePool.length - 1);
|
|
1596
|
+
if (j >= i) j++;
|
|
1597
|
+
const a = candidatePool[i];
|
|
1598
|
+
const b = candidatePool[j];
|
|
1599
|
+
connection = compareP2CConnections(provider, a, b, requestedModel) <= 0 ? a : b;
|
|
1600
|
+
}
|
|
1601
|
+
} else if (strategy === "random") {
|
|
1602
|
+
// Random: Fisher-Yates-inspired random pick
|
|
1603
|
+
const idx =
|
|
1604
|
+
parseInt(randomUUID().replace(/-/g, "").substring(0, 8), 16) % orderedConnections.length;
|
|
1605
|
+
connection = orderedConnections[idx];
|
|
1606
|
+
} else if (strategy === "least-used") {
|
|
1607
|
+
// Least Used: pick the one with oldest lastUsedAt
|
|
1608
|
+
const sorted = [...orderedConnections].sort((a, b) => {
|
|
1609
|
+
if (!a.lastUsedAt && !b.lastUsedAt) return (a.priority || 999) - (b.priority || 999);
|
|
1610
|
+
if (!a.lastUsedAt) return -1;
|
|
1611
|
+
if (!b.lastUsedAt) return 1;
|
|
1612
|
+
return new Date(a.lastUsedAt).getTime() - new Date(b.lastUsedAt).getTime();
|
|
1613
|
+
});
|
|
1614
|
+
connection = sorted[0];
|
|
1615
|
+
} else if (strategy === "cost-optimized") {
|
|
1616
|
+
// Cost Optimized: sort by priority ascending (lower = cheaper/preferred)
|
|
1617
|
+
// Future: can be enhanced with actual cost data per provider
|
|
1618
|
+
const sorted = [...orderedConnections].sort(
|
|
1619
|
+
(a, b) => (a.priority || 999) - (b.priority || 999)
|
|
1620
|
+
);
|
|
1621
|
+
connection = sorted[0];
|
|
1622
|
+
} else if (strategy === "strict-random") {
|
|
1623
|
+
// Strict Random: shuffle deck — uses each account once before reshuffling
|
|
1624
|
+
const ids = orderedConnections.map((c) => c.id);
|
|
1625
|
+
const selectedId = getNextFromDeckSync(`conn:${provider}`, ids);
|
|
1626
|
+
connection = orderedConnections.find((c) => c.id === selectedId) || orderedConnections[0];
|
|
1627
|
+
} else {
|
|
1628
|
+
// Default: fill-first (already sorted by priority in getProviderConnections)
|
|
1629
|
+
connection = orderedConnections[0];
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
if (provider === "antigravity" && connection) {
|
|
1633
|
+
log.info(
|
|
1634
|
+
"AUTH",
|
|
1635
|
+
`${provider} selected account=${connection.id?.slice(0, 8)}... eligible=${orderedConnections.length} excluded=${excludedConnectionIds.size}`
|
|
1636
|
+
);
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
const apiKeyHealth = connection.providerSpecificData?.apiKeyHealth as
|
|
1640
|
+
Record<string, KeyHealth> | undefined;
|
|
1641
|
+
if (apiKeyHealth) {
|
|
1642
|
+
syncHealthFromDB(connection.id, apiKeyHealth);
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
return {
|
|
1646
|
+
apiKey: connection.apiKey,
|
|
1647
|
+
accessToken: connection.accessToken,
|
|
1648
|
+
refreshToken: connection.refreshToken,
|
|
1649
|
+
expiresAt: connection.tokenExpiresAt || connection.expiresAt || null,
|
|
1650
|
+
projectId: connection.projectId,
|
|
1651
|
+
// #474: surface the connection's configured defaultModel so the chat /
|
|
1652
|
+
// embeddings handlers can resolve a bare model name (e.g. an alias that
|
|
1653
|
+
// resolved to "auto") to a real provider model ID before the upstream call.
|
|
1654
|
+
defaultModel: connection.defaultModel || null,
|
|
1655
|
+
copilotToken:
|
|
1656
|
+
typeof connection.providerSpecificData.copilotToken === "string"
|
|
1657
|
+
? connection.providerSpecificData.copilotToken
|
|
1658
|
+
: null,
|
|
1659
|
+
providerSpecificData: connection.providerSpecificData,
|
|
1660
|
+
// Fields the generic quota fetcher (open-sse/services/genericQuotaFetcher.ts)
|
|
1661
|
+
// needs to delegate to getUsageForProvider for any provider — kept aliased
|
|
1662
|
+
// (`id` + `connectionId`) for back-compat with callers that already use the
|
|
1663
|
+
// connectionId name.
|
|
1664
|
+
id: connection.id,
|
|
1665
|
+
provider: connection.provider,
|
|
1666
|
+
email: connection.email,
|
|
1667
|
+
connectionId: connection.id,
|
|
1668
|
+
// Include current status for optimization check
|
|
1669
|
+
testStatus: connection.testStatus,
|
|
1670
|
+
lastError: connection.lastError,
|
|
1671
|
+
lastErrorType: connection.lastErrorType,
|
|
1672
|
+
lastErrorSource: connection.lastErrorSource,
|
|
1673
|
+
errorCode: connection.errorCode,
|
|
1674
|
+
rateLimitedUntil: connection.rateLimitedUntil,
|
|
1675
|
+
maxConcurrent: connection.maxConcurrent,
|
|
1676
|
+
// Surface per-window quota overrides so the preflight latency gate in
|
|
1677
|
+
// getProviderCredentialsWithQuotaPreflight can see them. Without this,
|
|
1678
|
+
// user-set cutoffs would silently never enforce.
|
|
1679
|
+
quotaWindowThresholds: connection.quotaWindowThresholds ?? null,
|
|
1680
|
+
};
|
|
1681
|
+
} finally {
|
|
1682
|
+
selectionLock.release();
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
export async function getProviderCredentialsWithQuotaPreflight(
|
|
1687
|
+
provider: string,
|
|
1688
|
+
excludeConnectionId: string | null = null,
|
|
1689
|
+
allowedConnections: string[] | null = null,
|
|
1690
|
+
requestedModel: string | null = null,
|
|
1691
|
+
options: CredentialSelectionOptions = {}
|
|
1692
|
+
) {
|
|
1693
|
+
if (options.bypassQuotaPolicy === true) {
|
|
1694
|
+
return getProviderCredentials(
|
|
1695
|
+
provider,
|
|
1696
|
+
excludeConnectionId,
|
|
1697
|
+
allowedConnections,
|
|
1698
|
+
requestedModel,
|
|
1699
|
+
options
|
|
1700
|
+
);
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
const blockedByPreflight: Array<{
|
|
1704
|
+
id: string;
|
|
1705
|
+
quotaPercent?: number;
|
|
1706
|
+
resetAt?: string | null;
|
|
1707
|
+
}> = [];
|
|
1708
|
+
const excludedConnectionIds = normalizeExcludedConnectionIds(
|
|
1709
|
+
excludeConnectionId,
|
|
1710
|
+
options.excludeConnectionIds
|
|
1711
|
+
);
|
|
1712
|
+
|
|
1713
|
+
const resilience = resolveResilienceSettings(await getCachedSettings());
|
|
1714
|
+
const { defaultThresholdPercent, warnThresholdPercent, providerWindowDefaults } =
|
|
1715
|
+
resilience.quotaPreflight;
|
|
1716
|
+
const providerWindowMap = providerWindowDefaults[provider] || {};
|
|
1717
|
+
const providerHasDefaults = Object.keys(providerWindowMap).length > 0;
|
|
1718
|
+
// The factory default is "block at 2% remaining" — effectively "right
|
|
1719
|
+
// before 429." Skipping preflight at that level is a clean no-op. If an
|
|
1720
|
+
// operator has raised the global to anything stricter (e.g. 20% remaining
|
|
1721
|
+
// = stop at 80% used), preflight needs to run for every connection so the
|
|
1722
|
+
// tighter floor is honored.
|
|
1723
|
+
const FACTORY_NO_OP_REMAINING_PERCENT = 2;
|
|
1724
|
+
const globalDefaultIsRestrictive = defaultThresholdPercent > FACTORY_NO_OP_REMAINING_PERCENT;
|
|
1725
|
+
|
|
1726
|
+
while (true) {
|
|
1727
|
+
const credentials = await getProviderCredentials(
|
|
1728
|
+
provider,
|
|
1729
|
+
null,
|
|
1730
|
+
allowedConnections,
|
|
1731
|
+
requestedModel,
|
|
1732
|
+
{
|
|
1733
|
+
...options,
|
|
1734
|
+
excludeConnectionIds: Array.from(excludedConnectionIds),
|
|
1735
|
+
}
|
|
1736
|
+
);
|
|
1737
|
+
|
|
1738
|
+
if (!credentials) {
|
|
1739
|
+
if (blockedByPreflight.length > 0) {
|
|
1740
|
+
return buildQuotaPreflightRateLimitedResult(provider, blockedByPreflight);
|
|
1741
|
+
}
|
|
1742
|
+
return null;
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
if (
|
|
1746
|
+
("allRateLimited" in credentials && credentials.allRateLimited) ||
|
|
1747
|
+
("allExpired" in credentials && credentials.allExpired)
|
|
1748
|
+
) {
|
|
1749
|
+
if (
|
|
1750
|
+
"allRateLimited" in credentials &&
|
|
1751
|
+
credentials.allRateLimited &&
|
|
1752
|
+
blockedByPreflight.length > 0
|
|
1753
|
+
) {
|
|
1754
|
+
return buildQuotaPreflightRateLimitedResult(provider, blockedByPreflight);
|
|
1755
|
+
}
|
|
1756
|
+
return credentials;
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
const connectionId = credentials.connectionId;
|
|
1760
|
+
if (!connectionId) {
|
|
1761
|
+
return credentials;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1764
|
+
// Cascading resolver: per-connection override → per-(provider, window)
|
|
1765
|
+
// default → global default. Used per-window when the fetcher exposes
|
|
1766
|
+
// multiple windows, and once (with window=null) for single-signal
|
|
1767
|
+
// fetchers. The warn fallback is uniform — windows don't need their own
|
|
1768
|
+
// warn levels in v1.
|
|
1769
|
+
const perConnectionWindowOverrides =
|
|
1770
|
+
(credentials as { quotaWindowThresholds?: Record<string, number> | null })
|
|
1771
|
+
.quotaWindowThresholds || {};
|
|
1772
|
+
|
|
1773
|
+
// Latency gate: skip the upstream usage fetch entirely when there's
|
|
1774
|
+
// nothing to enforce. Preflight is only worth its cost when at least
|
|
1775
|
+
// one of the following is true:
|
|
1776
|
+
// • a per-connection override on this row
|
|
1777
|
+
// • a per-(provider, window) default in resilience settings
|
|
1778
|
+
// • the legacy `quotaPreflightEnabled` flag in providerSpecificData
|
|
1779
|
+
// • the global default is stricter than the factory no-op level
|
|
1780
|
+
// (factory = 2% remaining, basically "right before 429" — anything
|
|
1781
|
+
// stricter means the operator wants enforcement everywhere)
|
|
1782
|
+
// Otherwise the resolver would return the factory default for every
|
|
1783
|
+
// window, and a near-exhausted account would still be caught by the
|
|
1784
|
+
// normal 429 → cooldown path.
|
|
1785
|
+
// Explicit per-connection opt-out always wins over global/provider defaults.
|
|
1786
|
+
// isQuotaPreflightEnabled is strict-=== true (back-compat), so it returns
|
|
1787
|
+
// false for both "not set" and "explicit false" — we need an explicit check
|
|
1788
|
+
// here to distinguish them.
|
|
1789
|
+
const legacyForceDisable =
|
|
1790
|
+
(credentials as { providerSpecificData?: Record<string, unknown> }).providerSpecificData
|
|
1791
|
+
?.quotaPreflightEnabled === false;
|
|
1792
|
+
if (legacyForceDisable) return credentials;
|
|
1793
|
+
|
|
1794
|
+
const hasConnectionOverrides = Object.keys(perConnectionWindowOverrides).length > 0;
|
|
1795
|
+
const legacyForceEnable = isQuotaPreflightEnabled(credentials);
|
|
1796
|
+
if (
|
|
1797
|
+
!hasConnectionOverrides &&
|
|
1798
|
+
!providerHasDefaults &&
|
|
1799
|
+
!legacyForceEnable &&
|
|
1800
|
+
!globalDefaultIsRestrictive
|
|
1801
|
+
) {
|
|
1802
|
+
return credentials;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
// Returns the minimum-remaining cutoff for a window — matches the
|
|
1806
|
+
// dashboard's quota bars so the number the user types in the modal
|
|
1807
|
+
// means the same thing as the percentage rendered on the bar.
|
|
1808
|
+
const resolveMinRemainingPercent = (windowName: string | null): number => {
|
|
1809
|
+
if (windowName !== null) {
|
|
1810
|
+
const lookupWindowNames =
|
|
1811
|
+
provider === "codex"
|
|
1812
|
+
? uniqueWindows(
|
|
1813
|
+
[windowName, toCodexBaseQuotaWindowName(windowName)].filter(Boolean) as string[]
|
|
1814
|
+
)
|
|
1815
|
+
: [windowName];
|
|
1816
|
+
for (const lookupWindowName of lookupWindowNames) {
|
|
1817
|
+
const override = perConnectionWindowOverrides[lookupWindowName];
|
|
1818
|
+
if (typeof override === "number") return override;
|
|
1819
|
+
const providerDefault = providerWindowMap[lookupWindowName];
|
|
1820
|
+
if (typeof providerDefault === "number") return providerDefault;
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return defaultThresholdPercent;
|
|
1824
|
+
};
|
|
1825
|
+
const preflightCredentials =
|
|
1826
|
+
requestedModel && provider === "codex" ? { ...credentials, requestedModel } : credentials;
|
|
1827
|
+
const preflight = await preflightQuota(provider, connectionId, preflightCredentials, {
|
|
1828
|
+
resolveMinRemainingPercent,
|
|
1829
|
+
resolveWarnRemainingPercent: () => warnThresholdPercent,
|
|
1830
|
+
});
|
|
1831
|
+
if (preflight.proceed) {
|
|
1832
|
+
return credentials;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
const unavailableUntil = await markQuotaPreflightAccountUnavailable(
|
|
1836
|
+
provider,
|
|
1837
|
+
connectionId,
|
|
1838
|
+
preflight,
|
|
1839
|
+
requestedModel
|
|
1840
|
+
);
|
|
1841
|
+
blockedByPreflight.push({
|
|
1842
|
+
id: connectionId,
|
|
1843
|
+
quotaPercent: preflight.quotaPercent,
|
|
1844
|
+
resetAt: unavailableUntil,
|
|
1845
|
+
});
|
|
1846
|
+
excludedConnectionIds.add(connectionId);
|
|
1847
|
+
|
|
1848
|
+
log.info(
|
|
1849
|
+
"AUTH",
|
|
1850
|
+
`${provider} | preflight blocked ${connectionId.slice(0, 8)}${
|
|
1851
|
+
Number.isFinite(preflight.quotaPercent)
|
|
1852
|
+
? ` at ${Math.round((preflight.quotaPercent as number) * 100)}%`
|
|
1853
|
+
: ""
|
|
1854
|
+
} until ${unavailableUntil}`
|
|
1855
|
+
);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
/**
|
|
1860
|
+
* Mark account as unavailable — reads backoffLevel from DB, calculates cooldown with exponential backoff, saves new level
|
|
1861
|
+
* @param {string} connectionId
|
|
1862
|
+
* @param {number} status - HTTP status code
|
|
1863
|
+
* @param {string} errorText - Error message
|
|
1864
|
+
* @param {string|null} provider
|
|
1865
|
+
* @param {string|null} model - Model name for per-model lockout
|
|
1866
|
+
* @returns {{ shouldFallback: boolean, cooldownMs: number }}
|
|
1867
|
+
*/
|
|
1868
|
+
export async function markAccountUnavailable(
|
|
1869
|
+
connectionId: string,
|
|
1870
|
+
status: number,
|
|
1871
|
+
errorText: string,
|
|
1872
|
+
provider: string | null = null,
|
|
1873
|
+
model: string | null = null,
|
|
1874
|
+
providerProfile = null,
|
|
1875
|
+
options: {
|
|
1876
|
+
persistUnavailableState?: boolean;
|
|
1877
|
+
/** Caller is the combo engine — it records its own model-level lockouts. */
|
|
1878
|
+
isCombo?: boolean;
|
|
1879
|
+
} = {}
|
|
1880
|
+
) {
|
|
1881
|
+
const currentMutex = markMutexes.get(connectionId) || Promise.resolve();
|
|
1882
|
+
let resolveMutex: (() => void) | undefined;
|
|
1883
|
+
markMutexes.set(
|
|
1884
|
+
connectionId,
|
|
1885
|
+
new Promise((resolve) => {
|
|
1886
|
+
resolveMutex = resolve;
|
|
1887
|
+
})
|
|
1888
|
+
);
|
|
1889
|
+
|
|
1890
|
+
try {
|
|
1891
|
+
await currentMutex;
|
|
1892
|
+
|
|
1893
|
+
// Read current connection to get backoffLevel
|
|
1894
|
+
const connectionsRaw = await getProviderConnections({ provider });
|
|
1895
|
+
const connections = (Array.isArray(connectionsRaw) ? connectionsRaw : [])
|
|
1896
|
+
.map(toProviderConnection)
|
|
1897
|
+
.filter((connection) => connection.id.length > 0);
|
|
1898
|
+
const conn = connections.find((connection) => connection.id === connectionId);
|
|
1899
|
+
const backoffLevel = conn?.backoffLevel || 0;
|
|
1900
|
+
|
|
1901
|
+
// T06/T10/T36: terminal statuses should not be overwritten by transient cooldown state.
|
|
1902
|
+
if (conn && isTerminalConnectionStatus(conn)) {
|
|
1903
|
+
log.info(
|
|
1904
|
+
"AUTH",
|
|
1905
|
+
`${connectionId.slice(0, 8)} terminal status=${conn.testStatus}, skipping cooldown overwrite`
|
|
1906
|
+
);
|
|
1907
|
+
return { shouldFallback: true, cooldownMs: 0 };
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
// ─── Anti-Thundering Herd Guard ─────────────────────────────────
|
|
1911
|
+
// If this connection was ALREADY marked unavailable by a prior concurrent
|
|
1912
|
+
// request (within the mutex window), skip re-marking to avoid resetting
|
|
1913
|
+
// the cooldown timer or double-incrementing the backoff level.
|
|
1914
|
+
// Uses cooldownUntilMs (not a raw `new Date()`) because `rate_limited_until`
|
|
1915
|
+
// can hold a numeric-epoch string (e.g. the Antigravity full-quota path) —
|
|
1916
|
+
// see #3954.
|
|
1917
|
+
const existingCooldownMs = conn?.rateLimitedUntil
|
|
1918
|
+
? cooldownUntilMs(conn.rateLimitedUntil)
|
|
1919
|
+
: NaN;
|
|
1920
|
+
if (Number.isFinite(existingCooldownMs) && existingCooldownMs > Date.now()) {
|
|
1921
|
+
log.info(
|
|
1922
|
+
"AUTH",
|
|
1923
|
+
`${connectionId.slice(0, 8)} already marked unavailable (until ${conn?.rateLimitedUntil}), skipping duplicate mark`
|
|
1924
|
+
);
|
|
1925
|
+
return {
|
|
1926
|
+
shouldFallback: true,
|
|
1927
|
+
cooldownMs: existingCooldownMs - Date.now(),
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1931
|
+
// T09: Codex scope-aware lockout guard (codex vs spark independent pools).
|
|
1932
|
+
if (provider === "codex" && model) {
|
|
1933
|
+
const scopeRateLimitedUntil = getCodexScopeRateLimitedUntil(
|
|
1934
|
+
conn?.providerSpecificData || {},
|
|
1935
|
+
model
|
|
1936
|
+
);
|
|
1937
|
+
if (scopeRateLimitedUntil && new Date(scopeRateLimitedUntil).getTime() > Date.now()) {
|
|
1938
|
+
log.info(
|
|
1939
|
+
"AUTH",
|
|
1940
|
+
`${connectionId.slice(0, 8)} already scope-limited for ${getCodexModelScope(model)} (until ${scopeRateLimitedUntil}), skipping duplicate mark`
|
|
1941
|
+
);
|
|
1942
|
+
return {
|
|
1943
|
+
shouldFallback: true,
|
|
1944
|
+
cooldownMs: new Date(scopeRateLimitedUntil).getTime() - Date.now(),
|
|
1945
|
+
};
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
const effectiveProviderProfile =
|
|
1950
|
+
providerProfile || (provider ? await getRuntimeProviderProfile(provider) : null);
|
|
1951
|
+
// #4530 follow-up: the combo.ts lockout sites forward the admin-configured
|
|
1952
|
+
// maxCooldownMs cap to recordModelLockoutFailure, but the markAccountUnavailable
|
|
1953
|
+
// lockout sites (per-model quota, grok-web 403, local 404) never did, so the cap
|
|
1954
|
+
// fell back to BACKOFF_CONFIG.max here. Resolve it once and pass it at every site.
|
|
1955
|
+
const mlSettings = resolveModelLockoutSettings(await getCachedSettings());
|
|
1956
|
+
const fallbackResult = checkFallbackError(
|
|
1957
|
+
status,
|
|
1958
|
+
errorText,
|
|
1959
|
+
backoffLevel,
|
|
1960
|
+
model,
|
|
1961
|
+
provider,
|
|
1962
|
+
null,
|
|
1963
|
+
effectiveProviderProfile
|
|
1964
|
+
);
|
|
1965
|
+
|
|
1966
|
+
// Read passthroughModels from connection config (user-configured per-model quota)
|
|
1967
|
+
const connProviderSpecificData = (conn?.providerSpecificData as Record<string, unknown>) || {};
|
|
1968
|
+
const connectionPassthroughModels = connProviderSpecificData.passthroughModels as
|
|
1969
|
+
boolean | undefined;
|
|
1970
|
+
// #2997: per-connection opt-out of the TRANSIENT connection cooldown. When set,
|
|
1971
|
+
// a recoverable failure records lastError/backoff but does NOT cool the
|
|
1972
|
+
// connection, so getProviderCredentials keeps selecting it. Terminal states
|
|
1973
|
+
// (banned/expired/credits_exhausted) are unaffected — they are resolved below
|
|
1974
|
+
// via resolveTerminalConnectionStatus() and still take the connection out.
|
|
1975
|
+
// NOTE: this first cut scopes the opt-out to the CONNECTION-level cooldown only;
|
|
1976
|
+
// per-model lockout branches (per-model quota 403/404, codex scope) are left
|
|
1977
|
+
// as-is — extending disableCooling to model lockout is a follow-up.
|
|
1978
|
+
const disableCooling = connProviderSpecificData.disableCooling === true;
|
|
1979
|
+
|
|
1980
|
+
const isPerModelQuotaProvider = hasPerModelQuota(provider, model, connectionPassthroughModels);
|
|
1981
|
+
const modelLockoutOptions = { maxCooldownMs: effectiveProviderProfile?.maxCooldownMs };
|
|
1982
|
+
if (
|
|
1983
|
+
isPerModelQuotaProvider &&
|
|
1984
|
+
provider &&
|
|
1985
|
+
provider !== "codex" &&
|
|
1986
|
+
model &&
|
|
1987
|
+
(status === 404 || status === 429 || status >= 500)
|
|
1988
|
+
) {
|
|
1989
|
+
const reason =
|
|
1990
|
+
status === 404
|
|
1991
|
+
? "not_found"
|
|
1992
|
+
: status === 429 && fallbackResult.reason === RateLimitReason.QUOTA_EXHAUSTED
|
|
1993
|
+
? "quota_exhausted"
|
|
1994
|
+
: status === 429
|
|
1995
|
+
? "rate_limited"
|
|
1996
|
+
: "server_error";
|
|
1997
|
+
|
|
1998
|
+
// #5976: a bare 500 is intermittent and NOT model-specific — skip
|
|
1999
|
+
// lockout/cooldown ONLY for the exact 500 (the contract its own tests pin:
|
|
2000
|
+
// combo-provider-cooldown-sibling.test.ts — "Gemini 503 should NOT skip
|
|
2001
|
+
// cooldown"). 502/503/504 keep the pre-#6216 model-lockout path: cooldownMs
|
|
2002
|
+
// 0 hot-loops the failing upstream (broke resilience-http-e2e on the PR).
|
|
2003
|
+
if (status === 500) {
|
|
2004
|
+
updateProviderConnection(connectionId, {
|
|
2005
|
+
lastErrorType: reason,
|
|
2006
|
+
lastError: `Model ${model} ${reason}`,
|
|
2007
|
+
lastErrorAt: new Date().toISOString(),
|
|
2008
|
+
errorCode: status,
|
|
2009
|
+
}).catch(() => {});
|
|
2010
|
+
log.info(
|
|
2011
|
+
"AUTH",
|
|
2012
|
+
`Server error for ${provider}:${model} — ${status} ${reason} (no model lockout, connection stays active for sibling models)`
|
|
2013
|
+
);
|
|
2014
|
+
return { shouldFallback: true, cooldownMs: 0 };
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
const quotaScope = getQuotaScopeLabelForProvider(provider, model);
|
|
2018
|
+
const antigravityFamilyInferredBaseCooldownMs =
|
|
2019
|
+
provider === "antigravity" && quotaScope === "family" && status === 429
|
|
2020
|
+
? ANTIGRAVITY_FAMILY_INFERRED_BASE_COOLDOWN_MS
|
|
2021
|
+
: null;
|
|
2022
|
+
const lockout = recordModelLockoutFailure(
|
|
2023
|
+
provider,
|
|
2024
|
+
connectionId,
|
|
2025
|
+
model,
|
|
2026
|
+
reason,
|
|
2027
|
+
status,
|
|
2028
|
+
status === 404
|
|
2029
|
+
? (effectiveProviderProfile?.baseCooldownMs ?? COOLDOWN_MS.notFoundLocal)
|
|
2030
|
+
: (antigravityFamilyInferredBaseCooldownMs ??
|
|
2031
|
+
fallbackResult.baseCooldownMs ??
|
|
2032
|
+
effectiveProviderProfile?.baseCooldownMs ??
|
|
2033
|
+
0),
|
|
2034
|
+
effectiveProviderProfile,
|
|
2035
|
+
{
|
|
2036
|
+
...modelLockoutOptions,
|
|
2037
|
+
exactCooldownMs:
|
|
2038
|
+
fallbackResult.usedUpstreamRetryHint === true
|
|
2039
|
+
? fallbackResult.cooldownMs
|
|
2040
|
+
: (fallbackResult.quotaResetHintMs ?? null),
|
|
2041
|
+
maxCooldownMs: mlSettings.maxCooldownMs,
|
|
2042
|
+
}
|
|
2043
|
+
);
|
|
2044
|
+
// Update last error for observability (without changing terminal status)
|
|
2045
|
+
updateProviderConnection(connectionId, {
|
|
2046
|
+
lastErrorType: reason,
|
|
2047
|
+
lastError: `Model ${model} ${reason}`,
|
|
2048
|
+
lastErrorAt: new Date().toISOString(),
|
|
2049
|
+
errorCode: status,
|
|
2050
|
+
}).catch(() => {});
|
|
2051
|
+
log.info(
|
|
2052
|
+
"AUTH",
|
|
2053
|
+
`Model-only lockout for ${provider}:${model} — ${status} ${reason} ${Math.ceil(lockout.cooldownMs / 1000)}s (failureCount=${lockout.failureCount}, connection stays active)`
|
|
2054
|
+
);
|
|
2055
|
+
return { shouldFallback: true, cooldownMs: lockout.cooldownMs };
|
|
2056
|
+
}
|
|
2057
|
+
const result = fallbackResult;
|
|
2058
|
+
const { shouldFallback, cooldownMs: rawCooldownMs, newBackoffLevel, reason } = result;
|
|
2059
|
+
if (!shouldFallback) return { shouldFallback: false, cooldownMs: 0 };
|
|
2060
|
+
const providerErrorType = classifyProviderError(status, errorText, provider);
|
|
2061
|
+
|
|
2062
|
+
if (provider && resolveProviderId(provider) === "grok-web" && status === 403 && model) {
|
|
2063
|
+
const lockout = recordModelLockoutFailure(
|
|
2064
|
+
provider,
|
|
2065
|
+
connectionId,
|
|
2066
|
+
model,
|
|
2067
|
+
"forbidden",
|
|
2068
|
+
status,
|
|
2069
|
+
effectiveProviderProfile?.baseCooldownMs ?? COOLDOWN_MS.serviceUnavailable,
|
|
2070
|
+
effectiveProviderProfile,
|
|
2071
|
+
{ maxCooldownMs: mlSettings.maxCooldownMs }
|
|
2072
|
+
);
|
|
2073
|
+
updateProviderConnection(connectionId, {
|
|
2074
|
+
lastErrorType: "forbidden",
|
|
2075
|
+
lastError: `Mode ${model} forbidden for this Grok account`,
|
|
2076
|
+
lastErrorAt: new Date().toISOString(),
|
|
2077
|
+
errorCode: status,
|
|
2078
|
+
}).catch(() => {});
|
|
2079
|
+
log.info(
|
|
2080
|
+
"AUTH",
|
|
2081
|
+
`Mode-only lockout for ${provider}:${model} — 403 forbidden ${Math.ceil(lockout.cooldownMs / 1000)}s (connection stays active)`
|
|
2082
|
+
);
|
|
2083
|
+
return { shouldFallback: true, cooldownMs: lockout.cooldownMs };
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
const terminalStatus = resolveTerminalConnectionStatus(
|
|
2087
|
+
status,
|
|
2088
|
+
result as { permanent?: boolean; creditsExhausted?: boolean },
|
|
2089
|
+
providerErrorType
|
|
2090
|
+
);
|
|
2091
|
+
const cooldownMs = terminalStatus ? 0 : rawCooldownMs;
|
|
2092
|
+
|
|
2093
|
+
// ── #3027: per-model subscription/permission 403 → model-only lockout ──
|
|
2094
|
+
if (isPerModelQuotaProvider && status === 403 && provider && model && !terminalStatus) {
|
|
2095
|
+
const lockout = recordModelLockoutFailure(
|
|
2096
|
+
provider,
|
|
2097
|
+
connectionId,
|
|
2098
|
+
model,
|
|
2099
|
+
"forbidden",
|
|
2100
|
+
status,
|
|
2101
|
+
fallbackResult.baseCooldownMs ??
|
|
2102
|
+
effectiveProviderProfile?.baseCooldownMs ??
|
|
2103
|
+
COOLDOWN_MS.serviceUnavailable,
|
|
2104
|
+
effectiveProviderProfile,
|
|
2105
|
+
{
|
|
2106
|
+
...modelLockoutOptions,
|
|
2107
|
+
exactCooldownMs:
|
|
2108
|
+
fallbackResult.usedUpstreamRetryHint === true ? fallbackResult.cooldownMs : null,
|
|
2109
|
+
maxCooldownMs: mlSettings.maxCooldownMs,
|
|
2110
|
+
}
|
|
2111
|
+
);
|
|
2112
|
+
updateProviderConnection(connectionId, {
|
|
2113
|
+
lastErrorType: "forbidden",
|
|
2114
|
+
lastError: `Model ${model} forbidden (per-model access/subscription)`,
|
|
2115
|
+
lastErrorAt: new Date().toISOString(),
|
|
2116
|
+
errorCode: status,
|
|
2117
|
+
}).catch(() => {});
|
|
2118
|
+
log.info(
|
|
2119
|
+
"AUTH",
|
|
2120
|
+
`Model-only lockout for ${provider}:${model} — 403 forbidden ${Math.ceil(lockout.cooldownMs / 1000)}s (per-model quota provider, connection stays active)`
|
|
2121
|
+
);
|
|
2122
|
+
return { shouldFallback: true, cooldownMs: lockout.cooldownMs };
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
// ── 404 model-only lockout: connection stays active ──
|
|
2126
|
+
// For local providers (detected by URL), a 404 means the specific model
|
|
2127
|
+
// doesn't exist or isn't available for this account — it should NOT lock
|
|
2128
|
+
// out the entire connection.
|
|
2129
|
+
const connBaseUrl = (conn?.providerSpecificData as Record<string, unknown>)?.baseUrl as
|
|
2130
|
+
string | undefined;
|
|
2131
|
+
|
|
2132
|
+
if (isLocalProvider(connBaseUrl) && status === 404 && provider && model) {
|
|
2133
|
+
const lockout = recordModelLockoutFailure(
|
|
2134
|
+
provider,
|
|
2135
|
+
connectionId,
|
|
2136
|
+
model,
|
|
2137
|
+
"not_found",
|
|
2138
|
+
status,
|
|
2139
|
+
status === 404
|
|
2140
|
+
? (effectiveProviderProfile?.baseCooldownMs ?? COOLDOWN_MS.notFoundLocal)
|
|
2141
|
+
: COOLDOWN_MS.notFoundLocal,
|
|
2142
|
+
effectiveProviderProfile,
|
|
2143
|
+
{ maxCooldownMs: mlSettings.maxCooldownMs }
|
|
2144
|
+
);
|
|
2145
|
+
updateProviderConnection(connectionId, {
|
|
2146
|
+
lastErrorType: "not_found",
|
|
2147
|
+
lastError: `Model ${model} not_found`,
|
|
2148
|
+
lastErrorAt: new Date().toISOString(),
|
|
2149
|
+
errorCode: status,
|
|
2150
|
+
}).catch(() => {});
|
|
2151
|
+
log.info(
|
|
2152
|
+
"AUTH",
|
|
2153
|
+
`Model-only lockout for ${provider}:${model} — 404 not_found ${Math.ceil(lockout.cooldownMs / 1000)}s (failureCount=${lockout.failureCount}, connection stays active)`
|
|
2154
|
+
);
|
|
2155
|
+
return { shouldFallback: true, cooldownMs: lockout.cooldownMs };
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
const errorMsg = typeof errorText === "string" ? errorText.slice(0, 100) : "Provider error";
|
|
2159
|
+
|
|
2160
|
+
// T09: Codex per-scope lockout (do not block the whole account globally).
|
|
2161
|
+
if (provider === "codex" && status === 429 && model && conn) {
|
|
2162
|
+
const scope = getCodexModelScope(model);
|
|
2163
|
+
const existingScopeMap = asRecord(conn.providerSpecificData.codexScopeRateLimitedUntil);
|
|
2164
|
+
const persistedScopeUntil = getCodexScopeRateLimitedUntil(conn.providerSpecificData, model);
|
|
2165
|
+
const scopeRateLimitedUntil = persistedScopeUntil || getUnavailableUntil(cooldownMs);
|
|
2166
|
+
const scopeCooldownMs = Math.max(new Date(scopeRateLimitedUntil).getTime() - Date.now(), 0);
|
|
2167
|
+
|
|
2168
|
+
await updateProviderConnection(connectionId, {
|
|
2169
|
+
testStatus: "unavailable",
|
|
2170
|
+
lastError: errorMsg,
|
|
2171
|
+
errorCode: status,
|
|
2172
|
+
lastErrorAt: new Date().toISOString(),
|
|
2173
|
+
backoffLevel: newBackoffLevel ?? backoffLevel,
|
|
2174
|
+
providerSpecificData: {
|
|
2175
|
+
...conn.providerSpecificData,
|
|
2176
|
+
codexScopeRateLimitedUntil: {
|
|
2177
|
+
...existingScopeMap,
|
|
2178
|
+
[scope]: scopeRateLimitedUntil,
|
|
2179
|
+
},
|
|
2180
|
+
},
|
|
2181
|
+
});
|
|
2182
|
+
|
|
2183
|
+
if (scopeCooldownMs > 0) {
|
|
2184
|
+
lockModel(provider, connectionId, model, reason || "unknown", scopeCooldownMs);
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
if (status && errorMsg) {
|
|
2188
|
+
console.error(`❌ ${provider} [${status}] (${scope}): ${errorMsg}`);
|
|
2189
|
+
}
|
|
2190
|
+
|
|
2191
|
+
return { shouldFallback: true, cooldownMs: scopeCooldownMs };
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
const baseUpdate = {
|
|
2195
|
+
lastError: errorMsg,
|
|
2196
|
+
lastErrorType: providerErrorType,
|
|
2197
|
+
errorCode: status,
|
|
2198
|
+
lastErrorAt: new Date().toISOString(),
|
|
2199
|
+
backoffLevel: newBackoffLevel ?? backoffLevel,
|
|
2200
|
+
};
|
|
2201
|
+
const persistUnavailableState = options.persistUnavailableState !== false;
|
|
2202
|
+
|
|
2203
|
+
if (!persistUnavailableState) {
|
|
2204
|
+
// Combo-managed transient failure (e.g. 429): keep the connection clean in
|
|
2205
|
+
// the DB, but record an in-memory model lockout so credential selection
|
|
2206
|
+
// skips this exact provider+connection+model while it cools down — other
|
|
2207
|
+
// models on the same connection stay usable.
|
|
2208
|
+
if (provider && model && cooldownMs > 0) {
|
|
2209
|
+
lockModel(provider, connectionId, model, reason || "unknown", cooldownMs);
|
|
2210
|
+
}
|
|
2211
|
+
await updateProviderConnection(connectionId, {
|
|
2212
|
+
...baseUpdate,
|
|
2213
|
+
});
|
|
2214
|
+
} else if (cooldownMs > 0 && !disableCooling) {
|
|
2215
|
+
await updateProviderConnection(connectionId, {
|
|
2216
|
+
...baseUpdate,
|
|
2217
|
+
rateLimitedUntil: getUnavailableUntil(cooldownMs),
|
|
2218
|
+
testStatus: "unavailable",
|
|
2219
|
+
});
|
|
2220
|
+
} else {
|
|
2221
|
+
await updateProviderConnection(connectionId, {
|
|
2222
|
+
...baseUpdate,
|
|
2223
|
+
rateLimitedUntil: null,
|
|
2224
|
+
...(terminalStatus ? { testStatus: terminalStatus } : {}),
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
// T-AUTODISABLE: If auto-disable setting is enabled and error is permanent/terminal,
|
|
2229
|
+
// mark account as inactive so it is never retried again.
|
|
2230
|
+
// Uses getCachedSettings() to avoid DB overhead on hot error path.
|
|
2231
|
+
// NOTE: For permanent bans we disable immediately — no threshold needed,
|
|
2232
|
+
// because a permanent ban (403 "Verify your account" / ToS violation) will
|
|
2233
|
+
// NEVER recover, so retrying is pointless regardless of attempt count.
|
|
2234
|
+
if ((result as { permanent?: boolean }).permanent) {
|
|
2235
|
+
try {
|
|
2236
|
+
const settings = await getCachedSettings();
|
|
2237
|
+
const autoDisableEnabled = settings.autoDisableBannedAccounts ?? false;
|
|
2238
|
+
if (autoDisableEnabled) {
|
|
2239
|
+
await updateProviderConnection(connectionId, { isActive: false });
|
|
2240
|
+
log.info(
|
|
2241
|
+
"AUTH",
|
|
2242
|
+
`Auto-disabled ${connectionId.slice(0, 8)} — permanent ban detected (autoDisableBannedAccounts=true)`
|
|
2243
|
+
);
|
|
2244
|
+
}
|
|
2245
|
+
} catch (e) {
|
|
2246
|
+
log.info("AUTH", `Auto-disable check failed (non-fatal): ${e}`);
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
if (provider && status && errorMsg) {
|
|
2251
|
+
console.error(`❌ ${provider} [${status}]: ${errorMsg}`);
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
return { shouldFallback: true, cooldownMs };
|
|
2255
|
+
} finally {
|
|
2256
|
+
if (resolveMutex) resolveMutex();
|
|
2257
|
+
// Cleanup stale mutex entries (avoid memory leak)
|
|
2258
|
+
markMutexes.delete(connectionId);
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
/**
|
|
2263
|
+
* Clear account error status (only if currently has error)
|
|
2264
|
+
* Optimized to avoid unnecessary DB updates
|
|
2265
|
+
*/
|
|
2266
|
+
export async function clearAccountError(
|
|
2267
|
+
connectionId: string,
|
|
2268
|
+
currentConnection: Partial<RecoverableConnectionState>
|
|
2269
|
+
) {
|
|
2270
|
+
// Only update if currently has error status
|
|
2271
|
+
const hasError =
|
|
2272
|
+
(currentConnection.testStatus && currentConnection.testStatus !== "active") ||
|
|
2273
|
+
currentConnection.lastError ||
|
|
2274
|
+
currentConnection.rateLimitedUntil ||
|
|
2275
|
+
currentConnection.errorCode ||
|
|
2276
|
+
currentConnection.lastErrorType ||
|
|
2277
|
+
currentConnection.lastErrorSource;
|
|
2278
|
+
|
|
2279
|
+
if (!hasError) return; // Skip if already clean
|
|
2280
|
+
|
|
2281
|
+
await updateProviderConnection(connectionId, {
|
|
2282
|
+
testStatus: "active",
|
|
2283
|
+
lastError: null,
|
|
2284
|
+
lastErrorAt: null,
|
|
2285
|
+
lastErrorType: null,
|
|
2286
|
+
lastErrorSource: null,
|
|
2287
|
+
errorCode: null,
|
|
2288
|
+
rateLimitedUntil: null,
|
|
2289
|
+
backoffLevel: 0,
|
|
2290
|
+
});
|
|
2291
|
+
log.info("AUTH", `Account ${connectionId.slice(0, 8)} error cleared`);
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
/**
|
|
2295
|
+
* Optional CAS token. When provided, the clear is performed via an atomic
|
|
2296
|
+
* conditional UPDATE (clearConnectionErrorIfUnchanged) that aborts if the row
|
|
2297
|
+
* was written by a concurrent path between the caller's snapshot read and this
|
|
2298
|
+
* clear. Closes the TOCTOU window in the quota-recovery path. When omitted,
|
|
2299
|
+
* the clear is unconditional (preserves existing post-success-call behavior).
|
|
2300
|
+
*/
|
|
2301
|
+
export interface RecoveredStateExpectation {
|
|
2302
|
+
testStatus: string | null;
|
|
2303
|
+
lastErrorAt: string | null;
|
|
2304
|
+
rateLimitedUntil: string | null;
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
export async function clearRecoveredProviderState(
|
|
2308
|
+
credentials: Partial<RecoverableConnectionState> | null,
|
|
2309
|
+
expectedState?: RecoveredStateExpectation
|
|
2310
|
+
): Promise<{ applied: boolean }> {
|
|
2311
|
+
if (!credentials?.connectionId) return { applied: false };
|
|
2312
|
+
if (expectedState) {
|
|
2313
|
+
const applied = await clearConnectionErrorIfUnchanged(credentials.connectionId, expectedState);
|
|
2314
|
+
if (!applied) {
|
|
2315
|
+
log.info(
|
|
2316
|
+
"AUTH",
|
|
2317
|
+
`Skipped recovery clear for ${credentials.connectionId.slice(0, 8)} — state changed concurrently (CAS miss)`
|
|
2318
|
+
);
|
|
2319
|
+
return { applied: false };
|
|
2320
|
+
}
|
|
2321
|
+
log.info("AUTH", `Account ${credentials.connectionId.slice(0, 8)} error cleared (CAS)`);
|
|
2322
|
+
return { applied: true };
|
|
2323
|
+
}
|
|
2324
|
+
await clearAccountError(credentials.connectionId, credentials);
|
|
2325
|
+
return { applied: true };
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
type AuthRequestHeaders = Headers | Record<string, string | string[] | undefined>;
|
|
2329
|
+
|
|
2330
|
+
type AuthRequestLike = {
|
|
2331
|
+
headers?: AuthRequestHeaders | null;
|
|
2332
|
+
url?: string | null;
|
|
2333
|
+
};
|
|
2334
|
+
|
|
2335
|
+
function readNonEmptyUrlToken(request: AuthRequestLike): string | null {
|
|
2336
|
+
if (typeof request?.url !== "string" || request.url.trim().length === 0) return null;
|
|
2337
|
+
|
|
2338
|
+
try {
|
|
2339
|
+
const url = new URL(request.url, "http://localhost");
|
|
2340
|
+
|
|
2341
|
+
const segments = url.pathname
|
|
2342
|
+
.split("/")
|
|
2343
|
+
.map((segment) => segment.trim())
|
|
2344
|
+
.filter(Boolean);
|
|
2345
|
+
|
|
2346
|
+
if (segments[0] === "vscode" && segments[1]) {
|
|
2347
|
+
const decodedSegment = decodeURIComponent(segments[1]).trim();
|
|
2348
|
+
if (decodedSegment.length > 0) return decodedSegment;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
if (segments[0] === "api" && segments[1] === "v1" && segments[2] === "vscode") {
|
|
2352
|
+
if (segments[3] && segments[3] !== "raw" && segments[3] !== "combos") {
|
|
2353
|
+
const decodedSegment = decodeURIComponent(segments[3]).trim();
|
|
2354
|
+
if (decodedSegment.length > 0) return decodedSegment;
|
|
2355
|
+
}
|
|
2356
|
+
|
|
2357
|
+
if ((segments[3] === "raw" || segments[3] === "combos") && segments[4]) {
|
|
2358
|
+
const decodedSegment = decodeURIComponent(segments[4]).trim();
|
|
2359
|
+
if (decodedSegment.length > 0) return decodedSegment;
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
// NOTE: query-string token fallbacks (`?token=`/`?key=`/`?apiKey=`/`?api_key=`)
|
|
2364
|
+
// were intentionally REMOVED. They are a broad credential-in-URL surface that
|
|
2365
|
+
// leaks into access logs, Referer headers and proxy logs, and — because this
|
|
2366
|
+
// extractor also feeds management auth — would let `?token=<mgmt-key>`
|
|
2367
|
+
// authenticate management routes. The VS Code integration only needs the
|
|
2368
|
+
// path-scoped `/vscode/<token>/…` form above. (security review, #3300 follow-up)
|
|
2369
|
+
} catch {
|
|
2370
|
+
return null;
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
return null;
|
|
2374
|
+
}
|
|
2375
|
+
|
|
2376
|
+
/**
|
|
2377
|
+
* Extract API key from request auth inputs.
|
|
2378
|
+
*
|
|
2379
|
+
* Honors explicit auth headers and (for client-facing routes only) a
|
|
2380
|
+
* path-scoped URL token:
|
|
2381
|
+
* - `Authorization: Bearer <key>` (OpenAI / OmniRoute / Codex CLI / Bearer clients)
|
|
2382
|
+
* - `x-api-key: <key>` (Anthropic Messages API contract — Claude Code,
|
|
2383
|
+
* `@anthropic-ai/sdk`, any SDK that sets `anthropic-version`)
|
|
2384
|
+
* - `/vscode/<key>/...` (path-scoped tokenized aliases — only when `allowUrl`)
|
|
2385
|
+
*
|
|
2386
|
+
* When multiple inputs are present, explicit auth headers win.
|
|
2387
|
+
*
|
|
2388
|
+
* The `x-api-key` fallback only triggers when the request also carries an
|
|
2389
|
+
* `anthropic-version` header — the documented signal that the caller is
|
|
2390
|
+
* speaking the Anthropic Messages API contract. Without this scoping,
|
|
2391
|
+
* non-Anthropic SDKs that happen to set `x-api-key` (or local-mode tools
|
|
2392
|
+
* with placeholder keys) would be treated as authenticated attempts and
|
|
2393
|
+
* rejected by per-route gates that compare against OmniRoute keys.
|
|
2394
|
+
*
|
|
2395
|
+
* `opts.allowUrl` (default `true`) gates the path-scoped URL token. Management
|
|
2396
|
+
* auth MUST pass `allowUrl: false` — a credential in the URL must never
|
|
2397
|
+
* authenticate a management route (it leaks into logs/Referer and would widen
|
|
2398
|
+
* the management surface). See the #3300 security follow-up.
|
|
2399
|
+
*/
|
|
2400
|
+
export function extractApiKey(request: AuthRequestLike, opts?: { allowUrl?: boolean }) {
|
|
2401
|
+
const authHeader =
|
|
2402
|
+
readHeaderValue(request?.headers, "Authorization") ||
|
|
2403
|
+
readHeaderValue(request?.headers, "authorization");
|
|
2404
|
+
if (typeof authHeader === "string") {
|
|
2405
|
+
const trimmedHeader = authHeader.trim();
|
|
2406
|
+
if (trimmedHeader.toLowerCase().startsWith("bearer ")) {
|
|
2407
|
+
return trimmedHeader.slice(7).trim() || null;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
// Issue #2225: Anthropic Messages API clients authenticate via x-api-key.
|
|
2412
|
+
// Gate the fallback on the anthropic-version header so we don't trip up
|
|
2413
|
+
// local-mode requests from non-Anthropic clients that send placeholder
|
|
2414
|
+
// x-api-key values (which would otherwise be rejected as Invalid API key).
|
|
2415
|
+
const anthropicVersion =
|
|
2416
|
+
readHeaderValue(request?.headers, "anthropic-version") ||
|
|
2417
|
+
readHeaderValue(request?.headers, "Anthropic-Version");
|
|
2418
|
+
if (anthropicVersion) {
|
|
2419
|
+
const xApiKey =
|
|
2420
|
+
readHeaderValue(request?.headers, "x-api-key") ||
|
|
2421
|
+
readHeaderValue(request?.headers, "X-Api-Key");
|
|
2422
|
+
if (typeof xApiKey === "string") {
|
|
2423
|
+
const trimmed = xApiKey.trim();
|
|
2424
|
+
if (trimmed.length > 0) return trimmed;
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
if (opts?.allowUrl === false) return null;
|
|
2429
|
+
return readNonEmptyUrlToken(request);
|
|
2430
|
+
}
|
|
2431
|
+
|
|
2432
|
+
/**
|
|
2433
|
+
* Validate API key (optional - for local use can skip).
|
|
2434
|
+
* Feature #1350: Supports OMNIROUTE_API_KEY / ROUTER_API_KEY env vars as
|
|
2435
|
+
* persistent passthrough keys that always validate, surviving Docker
|
|
2436
|
+
* restarts and backup restores without DB dependency.
|
|
2437
|
+
*/
|
|
2438
|
+
export async function isValidApiKey(apiKey: string) {
|
|
2439
|
+
if (!apiKey) return false;
|
|
2440
|
+
|
|
2441
|
+
// Persistent env-var key — always valid regardless of DB state (#1350)
|
|
2442
|
+
const envKey = process.env.OMNIROUTE_API_KEY || process.env.ROUTER_API_KEY;
|
|
2443
|
+
if (envKey && apiKey === envKey) return true;
|
|
2444
|
+
|
|
2445
|
+
return await validateApiKey(apiKey);
|
|
2446
|
+
}
|