cartethyia 2.7.9 → 2.8.1
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 +6 -5
- package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BE3qwwfC.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CRZdmMIX.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-BE40s3u5.js → OverviewPage-0yfhSI1C.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CFNcATJJ.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BTlkq_Uk.js → api-keys-2hc12Uz2.js} +1 -1
- package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js +1 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-A1-v8-03.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CJ4Zty89.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-DkjUouAj.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-B-LVLV6o.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2aDLyyg.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DNcAdMK-.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DgrIH0hw.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-ecPvG_8g.js → pagination-iUoI8GeE.js} +1 -1
- package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
- package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
- package/dist/dashboard/assets/providers/sensenova.png +0 -0
- package/dist/dashboard/assets/providers/zro.svg +3 -0
- package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
- package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
- package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +11 -14
- package/src/boot/dependencies.ts +5 -7
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/providers.ts +6 -5
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +28 -8
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +40 -28
- package/src/console/auth/account-reset.ts +7 -9
- package/src/console/backup/contracts.ts +4 -0
- package/src/console/backup/export-endpoint.ts +7 -5
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -4
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +7 -13
- package/src/console/observability/live.ts +2 -2
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/contracts.ts +9 -3
- package/src/console/providers/catalog/model-operations.ts +2 -3
- package/src/console/providers/catalog/provider-operations.ts +1 -1
- package/src/console/providers/catalog/routes.ts +3 -2
- package/src/console/providers/catalog/store.ts +1914 -1902
- package/src/console/providers/detail/routes.ts +1 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/providers/oauth/callback-listener.ts +30 -11
- package/src/console/providers/oauth/device-egress.ts +123 -0
- package/src/console/providers/oauth/routes.ts +123 -16
- package/src/console/quota/account-quota-global.ts +14 -24
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +11 -23
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +32 -47
- package/src/console/routing/pools/probe-verdict.ts +2 -2
- package/src/console/routing/pools/relay-deploy.ts +1 -1
- package/src/console/routing/pools/store.ts +4 -4
- package/src/console/shared/errors.ts +33 -6
- package/src/main.ts +2 -3
- package/src/network/client.ts +67 -0
- package/src/network/egress/bidi-session.ts +322 -0
- package/src/network/egress/dial.ts +201 -0
- package/src/network/egress/factory.ts +191 -0
- package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
- package/src/network/egress/tls-profile.ts +123 -0
- package/src/network/egress/ws.ts +175 -0
- package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
- package/src/network/{types.ts → pool/agent-config.ts} +1 -1
- package/src/network/pool/agent.ts +2 -2
- package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
- package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
- package/src/network/pool/resolver.ts +10 -849
- package/src/network/pool/selector.ts +184 -41
- package/src/network/ssrf.ts +7 -7
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
- package/src/observability/event-log.ts +7 -361
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +16 -26
- package/src/observability/telemetry-reconciliation.ts +9 -37
- package/src/observability/telemetry-row.ts +125 -0
- package/src/persistence/db-mode.ts +4 -1
- package/src/persistence/dialect.ts +18 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +17 -0
- package/src/persistence/ttl-cache.ts +21 -3
- package/src/protocol/codecs.ts +59 -2
- package/src/protocol/dsml.ts +34 -86
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/request/chat.ts +10 -10
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +34 -22
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/messages.ts +34 -7
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +15 -0
- package/src/protocol/upstream/send-claude-messages.ts +2 -2
- package/src/providers/adapters/compatible-adapter.ts +76 -12
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +105 -11
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -758
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +137 -36
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +20 -6
- package/src/providers/discovery/probing-service.ts +22 -2
- package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
- package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +16 -1
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +12 -12
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
- package/src/providers/integrations/buddy/headers.ts +311 -0
- package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
- package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +5 -6
- package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
- package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
- package/src/providers/integrations/clixad/provider.ts +145 -0
- package/src/providers/integrations/codex/codex-oauth.ts +8 -5
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
- package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
- package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
- package/src/providers/integrations/cursor/cursor-request.ts +26 -12
- package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
- package/src/providers/integrations/cursor/cursor.ts +574 -110
- package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
- package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
- package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
- package/src/providers/integrations/deepai/deepai-common.ts +145 -0
- package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
- package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
- package/src/providers/integrations/deepai/provider.ts +42 -0
- package/src/providers/integrations/devin/devin-auth.ts +7 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
- package/src/providers/integrations/factory/factory-oauth.ts +33 -51
- package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
- package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
- package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
- package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
- package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
- package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
- package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
- package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
- package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
- package/src/providers/integrations/freebuff/freebuff.ts +682 -0
- package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
- package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
- package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
- package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
- package/src/providers/integrations/freepi/freepi-session.ts +158 -0
- package/src/providers/integrations/freepi/freepi.ts +80 -54
- package/src/providers/integrations/github/github-discovery.ts +30 -13
- package/src/providers/integrations/github/github-oauth.ts +217 -44
- package/src/providers/integrations/github/github-quota.ts +22 -5
- package/src/providers/integrations/github/github.ts +40 -32
- package/src/providers/integrations/grok/grok-oauth.ts +52 -49
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
- package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
- package/src/providers/integrations/kilo/kilo.ts +1 -1
- package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/ollamacloud/index.ts +2 -0
- package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
- package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-protocol.ts +0 -6
- package/src/providers/integrations/perch/perch-quota.ts +2 -16
- package/src/providers/integrations/perch/perch.ts +6 -16
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
- package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
- package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
- package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
- package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
- package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
- package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
- package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
- package/src/providers/integrations/qoder/qoder-types.ts +9 -0
- package/src/providers/integrations/qoder/qoder.ts +3 -26
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-protocol.ts +9 -5
- package/src/providers/integrations/trae/trae-quota.ts +21 -29
- package/src/providers/integrations/trae/trae-realm.ts +38 -0
- package/src/providers/integrations/trae/trae.ts +7 -24
- package/src/providers/integrations/vercel/provider.ts +117 -0
- package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
- package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
- package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
- package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
- package/src/providers/integrations/zro/zro.ts +205 -0
- package/src/providers/operations/account-error-classification.ts +199 -307
- package/src/providers/operations/account-health-service.ts +82 -1
- package/src/providers/operations/account-refresh-status.ts +36 -37
- package/src/providers/operations/account-tier.ts +15 -16
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +100 -81
- package/src/providers/operations/cooldown-rules.ts +11 -16
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +118 -51
- package/src/providers/operations/provider-rules/github.ts +48 -0
- package/src/providers/operations/provider-rules/grok.ts +33 -0
- package/src/providers/operations/provider-rules/inception.ts +49 -0
- package/src/providers/operations/provider-rules/index.ts +32 -0
- package/src/providers/operations/provider-rules/perch.ts +37 -0
- package/src/providers/operations/provider-rules/qoder.ts +70 -0
- package/src/providers/operations/provider-rules/trae.ts +81 -0
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +6 -4
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +70 -10
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/quota-limit-windows.ts +16 -5
- package/src/providers/quota/quota-support.ts +1 -1
- package/src/providers/quota/quota-window-parser.ts +90 -18
- package/src/providers/quota/refresh.ts +100 -21
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +15 -14
- package/src/transport/dispatch/attempt-loop.ts +73 -19
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +8 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +10 -7
- package/src/transport/dispatch/streaming/stream.ts +9 -37
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +63 -0
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +16 -30
- package/src/transport/guards/body-policy.ts +7 -1
- package/src/transport/guards/error-lifecycle.ts +13 -1
- package/src/transport/guards/request-context.ts +22 -14
- package/src/transport/request/preparer.ts +81 -71
- package/src/transport/routing/bounded-lru.ts +14 -0
- package/src/transport/routing/drain-reserve.ts +129 -0
- package/src/transport/routing/plan-gate.ts +7 -1
- package/src/transport/routing/round-robin.ts +60 -0
- package/src/transport/routing/route-catalog.ts +123 -111
- package/src/transport/routing/route-model.ts +51 -9
- package/src/transport/routing/router.ts +393 -32
- package/src/transport/shutdown-notice.ts +1 -1
- package/src/transport/surface/adapters.ts +11 -2
- package/src/transport/surface/chat/adapter.ts +2 -2
- package/src/transport/surface/chat/encode.ts +47 -4
- package/src/transport/surface/chat/parse.ts +2 -12
- package/src/transport/surface/completion.ts +44 -33
- package/src/transport/surface/content-parts.ts +21 -0
- package/src/transport/surface/messages/adapter.ts +7 -1
- package/src/transport/surface/messages/encode.ts +11 -3
- package/src/transport/surface/messages/parse.ts +2 -1
- package/src/transport/surface/messages/stream.ts +33 -17
- package/src/transport/surface/responses/encode.ts +22 -5
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/buddy-growth-tasks.ts +8 -8
- package/src/workers/daily-checkin.ts +4 -4
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/zcode-gift-claim.ts +1 -1
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/src/network/pool-health.ts +0 -210
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
- package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
- package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
- package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
- package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
- package/src/providers/integrations/qoder/chat-proto.ts +0 -328
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
- package/src/providers/operations/model-discovery-cache.ts +0 -34
- package/src/providers/operations/probe-fetch.ts +0 -15
- package/src/providers/operations/provider-version-cache.ts +0 -30
- package/src/providers/provider-capabilities.ts +0 -33
- package/src/providers/provider-credential-envelope.ts +0 -43
- /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
- /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
- /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
- /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
- /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
|
@@ -86,7 +86,6 @@ export function cliMappingSourceKeys(toolId: string, sourceModel: string): reado
|
|
|
86
86
|
|
|
87
87
|
const HARD_COOLDOWN_CATEGORIES: Readonly<Record<string, true>> = {
|
|
88
88
|
quota_exhausted: true,
|
|
89
|
-
policy_blocked: true,
|
|
90
89
|
auth_invalidated: true,
|
|
91
90
|
};
|
|
92
91
|
|
|
@@ -528,7 +527,8 @@ class RouteCatalogRepository {
|
|
|
528
527
|
}
|
|
529
528
|
|
|
530
529
|
// Per-tenant pool selection strategy; an absent row reads as the
|
|
531
|
-
// `least_loaded` default at selection time.
|
|
530
|
+
// `least_loaded` default at selection time. The local map resolves
|
|
531
|
+
// per-candidate during the build; it is NOT stored in RouteSnapshot.
|
|
532
532
|
const poolRouting: Record<string, PoolRoutingSetting> = {};
|
|
533
533
|
for (const row of poolSettingRows) {
|
|
534
534
|
if (tenantId === undefined || row.tenantId === tenantId) {
|
|
@@ -662,6 +662,72 @@ class RouteCatalogRepository {
|
|
|
662
662
|
return limit === undefined ? {} : { network_pool_provider_limit: limit };
|
|
663
663
|
}
|
|
664
664
|
|
|
665
|
+
/**
|
|
666
|
+
* The field set shared by every `RoutedCandidate` literal in the fan-out
|
|
667
|
+
* below. The four sites used to re-declare the same ~15-field shape, so a
|
|
668
|
+
* field added to one had to be added to all four. `opts` carries only the
|
|
669
|
+
* deltas that genuinely differ per site; health stamping is deliberately
|
|
670
|
+
* NOT merged here — it happens at each site (inside the pool-account
|
|
671
|
+
* literal, never for configured-pool tenants, conditional for public,
|
|
672
|
+
* after construction for account rows), and collapsing those branches
|
|
673
|
+
* would change routing.
|
|
674
|
+
*/
|
|
675
|
+
function buildCandidateBase(
|
|
676
|
+
model: MergedModelRow,
|
|
677
|
+
capabilityProfile: Record<string, boolean>,
|
|
678
|
+
opts: {
|
|
679
|
+
readonly tenantId: string | null;
|
|
680
|
+
/** `false` emits `requires_account: false` (credential-less route). */
|
|
681
|
+
readonly requiresAccount?: boolean;
|
|
682
|
+
readonly ownerTenantId?: string | null;
|
|
683
|
+
readonly userAgent?: string;
|
|
684
|
+
readonly accountId?: string;
|
|
685
|
+
readonly proOnly?: boolean;
|
|
686
|
+
readonly accountPlan?: string | null;
|
|
687
|
+
readonly maxInflight?: number;
|
|
688
|
+
readonly pools?: {
|
|
689
|
+
readonly ids: readonly string[];
|
|
690
|
+
readonly limits: Record<string, number>;
|
|
691
|
+
readonly weights: Record<string, number>;
|
|
692
|
+
/** `undefined` (from `resolveNetworkPools`) means no routing strategy. */
|
|
693
|
+
readonly routing?: (PoolRoutingSetting & { tenantId: string }) | undefined;
|
|
694
|
+
};
|
|
695
|
+
},
|
|
696
|
+
): RoutedCandidate {
|
|
697
|
+
return {
|
|
698
|
+
provider_id: model.providerId,
|
|
699
|
+
model_id: model.modelId,
|
|
700
|
+
wire_family: model.wireFamily as WireFamily,
|
|
701
|
+
...(model.dialect == null ? {} : { dialect: model.dialect }),
|
|
702
|
+
service_kind: model.serviceKind,
|
|
703
|
+
endpoint: model.endpointPath,
|
|
704
|
+
...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
|
|
705
|
+
capability_profile: capabilityProfile,
|
|
706
|
+
...(opts.userAgent === undefined ? {} : { user_agent: opts.userAgent }),
|
|
707
|
+
tenant_id: opts.tenantId,
|
|
708
|
+
...(model.freeTier === true ? { free_tier: true } : {}),
|
|
709
|
+
// Public credential-less candidates have no account to own them.
|
|
710
|
+
owner_tenant_id: opts.ownerTenantId ?? null,
|
|
711
|
+
...(opts.accountId === undefined ? {} : { provider_account_id: opts.accountId }),
|
|
712
|
+
...(opts.proOnly === true ? { pro_only: true } : {}),
|
|
713
|
+
...(opts.accountPlan === null || opts.accountPlan === undefined
|
|
714
|
+
? {}
|
|
715
|
+
: { account_plan: opts.accountPlan }),
|
|
716
|
+
...(opts.maxInflight === undefined ? {} : { max_inflight: opts.maxInflight }),
|
|
717
|
+
...(opts.requiresAccount === false ? { requires_account: false as const } : {}),
|
|
718
|
+
...(opts.pools
|
|
719
|
+
? {
|
|
720
|
+
network_pool_ids: opts.pools.ids,
|
|
721
|
+
network_pool_required: true,
|
|
722
|
+
network_pool_limits: opts.pools.limits,
|
|
723
|
+
network_pool_weights: opts.pools.weights,
|
|
724
|
+
...(opts.pools.routing ? { network_pool_routing: opts.pools.routing } : {}),
|
|
725
|
+
...providerLimitFor(model.providerId, opts.tenantId),
|
|
726
|
+
}
|
|
727
|
+
: {}),
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
665
731
|
// Group usable accounts per provider (not per provider-tenant). Built-in
|
|
666
732
|
// providers are `tenant_id IS NULL` but their accounts are per-tenant, so
|
|
667
733
|
// grouping by `providerTenantId` would make every global model look
|
|
@@ -716,38 +782,30 @@ class RouteCatalogRepository {
|
|
|
716
782
|
const tenantPools = resolveNetworkPools(model.providerId, tenantOwnerId);
|
|
717
783
|
if (!tenantPools) continue;
|
|
718
784
|
emittedPoolAccount = true;
|
|
719
|
-
const tenantCandidate
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
health_status: "cooldown" as const,
|
|
744
|
-
cooldown_kind: hardCooldownCategory(first.lastErrorCategory) ? "hard" : "soft",
|
|
745
|
-
...(first.cooldownUntil && first.cooldownUntil.getTime() > Date.now()
|
|
746
|
-
? { cooldown_until: first.cooldownUntil.getTime() }
|
|
747
|
-
: {}),
|
|
748
|
-
}
|
|
749
|
-
: {}),
|
|
750
|
-
};
|
|
785
|
+
const tenantCandidate = buildCandidateBase(model, capabilityProfile, {
|
|
786
|
+
tenantId: tenantOwnerId,
|
|
787
|
+
requiresAccount: false,
|
|
788
|
+
pools: {
|
|
789
|
+
ids: [poolId],
|
|
790
|
+
limits: tenantPools.limits,
|
|
791
|
+
weights: tenantPools.weights,
|
|
792
|
+
routing: tenantPools.routing,
|
|
793
|
+
},
|
|
794
|
+
});
|
|
795
|
+
// Pool-account health from the row: a spent egress is excluded
|
|
796
|
+
// exactly like a cooling account, and the deadline rides along so
|
|
797
|
+
// `plan()` can quote the real reset on an all-cooling answer.
|
|
798
|
+
if (first.status === "disabled") {
|
|
799
|
+
tenantCandidate.health_status = "disabled";
|
|
800
|
+
} else if (first.status === "cooldown") {
|
|
801
|
+
tenantCandidate.health_status = "cooldown";
|
|
802
|
+
tenantCandidate.cooldown_kind = hardCooldownCategory(first.lastErrorCategory)
|
|
803
|
+
? "hard"
|
|
804
|
+
: "soft";
|
|
805
|
+
if (first.cooldownUntil && first.cooldownUntil.getTime() > Date.now()) {
|
|
806
|
+
tenantCandidate.cooldown_until = first.cooldownUntil.getTime();
|
|
807
|
+
}
|
|
808
|
+
}
|
|
751
809
|
if (tenantId === undefined || tenantId === tenantOwnerId) {
|
|
752
810
|
candidates.push(tenantCandidate);
|
|
753
811
|
}
|
|
@@ -757,27 +815,16 @@ class RouteCatalogRepository {
|
|
|
757
815
|
for (const tId of configuredPoolTenants) {
|
|
758
816
|
const tenantPools = resolveNetworkPools(model.providerId, tId);
|
|
759
817
|
if (tenantPools) {
|
|
760
|
-
const tenantCandidate
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
...(model.freeTier === true ? { free_tier: true } : {}),
|
|
771
|
-
// Public credential-less candidates have no account to own them.
|
|
772
|
-
owner_tenant_id: null,
|
|
773
|
-
requires_account: false as const,
|
|
774
|
-
network_pool_ids: tenantPools.ids,
|
|
775
|
-
network_pool_required: true,
|
|
776
|
-
network_pool_limits: tenantPools.limits,
|
|
777
|
-
network_pool_weights: tenantPools.weights,
|
|
778
|
-
...(tenantPools.routing ? { network_pool_routing: tenantPools.routing } : {}),
|
|
779
|
-
...providerLimitFor(model.providerId, tId),
|
|
780
|
-
};
|
|
818
|
+
const tenantCandidate = buildCandidateBase(model, capabilityProfile, {
|
|
819
|
+
tenantId: tId,
|
|
820
|
+
requiresAccount: false,
|
|
821
|
+
pools: {
|
|
822
|
+
ids: tenantPools.ids,
|
|
823
|
+
limits: tenantPools.limits,
|
|
824
|
+
weights: tenantPools.weights,
|
|
825
|
+
routing: tenantPools.routing,
|
|
826
|
+
},
|
|
827
|
+
});
|
|
781
828
|
if (tenantId === undefined || tenantId === tId) {
|
|
782
829
|
candidates.push(tenantCandidate);
|
|
783
830
|
}
|
|
@@ -787,33 +834,17 @@ class RouteCatalogRepository {
|
|
|
787
834
|
const networkPools = providerRequiresAccount
|
|
788
835
|
? undefined
|
|
789
836
|
: resolveNetworkPools(model.providerId, providerTenantId);
|
|
790
|
-
const candidate
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
// Public credential-less candidates have no account to own them.
|
|
802
|
-
owner_tenant_id: null,
|
|
803
|
-
...(providerRequiresAccount
|
|
804
|
-
? { health_status: "disabled" as const }
|
|
805
|
-
: { requires_account: false as const }),
|
|
806
|
-
...(networkPools
|
|
807
|
-
? {
|
|
808
|
-
network_pool_ids: networkPools.ids,
|
|
809
|
-
network_pool_required: true,
|
|
810
|
-
network_pool_limits: networkPools.limits,
|
|
811
|
-
network_pool_weights: networkPools.weights,
|
|
812
|
-
...(networkPools.routing ? { network_pool_routing: networkPools.routing } : {}),
|
|
813
|
-
...providerLimitFor(model.providerId, providerTenantId),
|
|
814
|
-
}
|
|
815
|
-
: {}),
|
|
816
|
-
};
|
|
837
|
+
const candidate = buildCandidateBase(model, capabilityProfile, {
|
|
838
|
+
tenantId: providerTenantId,
|
|
839
|
+
// A provider that requires an account but has none is unusable: the
|
|
840
|
+
// public candidate is stamped disabled below. A genuinely
|
|
841
|
+
// credential-less provider carries `requires_account: false` instead.
|
|
842
|
+
...(providerRequiresAccount ? {} : { requiresAccount: false }),
|
|
843
|
+
...(networkPools ? { pools: networkPools } : {}),
|
|
844
|
+
});
|
|
845
|
+
if (providerRequiresAccount) {
|
|
846
|
+
candidate.health_status = "disabled";
|
|
847
|
+
}
|
|
817
848
|
if (tenantId === undefined || candidate.tenant_id === null || candidate.tenant_id === tenantId) {
|
|
818
849
|
candidates.push(candidate);
|
|
819
850
|
}
|
|
@@ -831,46 +862,28 @@ class RouteCatalogRepository {
|
|
|
831
862
|
}
|
|
832
863
|
const networkPools = resolveNetworkPools(model.providerId, rowTenantId);
|
|
833
864
|
const routeUserAgent = resolveUserAgent(model.providerId, rowTenantId);
|
|
834
|
-
const candidate
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
wire_family: model.wireFamily as WireFamily,
|
|
838
|
-
...(model.dialect == null ? {} : { dialect: model.dialect }),
|
|
839
|
-
service_kind: model.serviceKind,
|
|
840
|
-
endpoint: model.endpointPath,
|
|
841
|
-
...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
|
|
842
|
-
capability_profile: capabilityProfile,
|
|
843
|
-
...(routeUserAgent === undefined ? {} : { user_agent: routeUserAgent }),
|
|
844
|
-
...(model.freeTier === true ? { free_tier: true } : {}),
|
|
845
|
-
tenant_id: rowTenantId,
|
|
846
|
-
provider_account_id: account.id,
|
|
865
|
+
const candidate = buildCandidateBase(model, capabilityProfile, {
|
|
866
|
+
tenantId: rowTenantId,
|
|
867
|
+
accountId: account.id,
|
|
847
868
|
// The account's owning tenant (null = shared pool-wide) — the bucket
|
|
848
869
|
// key for admission, distinct from the requesting tenant.
|
|
849
|
-
|
|
870
|
+
ownerTenantId: account.tenantId ?? null,
|
|
850
871
|
// The plan gate is per (account, model): the model may be refused on
|
|
851
872
|
// a free plan and the account may be on one. Both ride here because
|
|
852
873
|
// `plan()` sees the candidate and nothing else.
|
|
853
|
-
...(model.proOnly === true ? {
|
|
874
|
+
...(model.proOnly === true ? { proOnly: true } : {}),
|
|
854
875
|
...(account.quotaPlan === null || account.quotaPlan === undefined
|
|
855
876
|
? {}
|
|
856
|
-
: {
|
|
877
|
+
: { accountPlan: account.quotaPlan }),
|
|
857
878
|
// Provider-wide concurrency ceiling from Routing Strategy; legacy
|
|
858
879
|
// account overrides are never read here.
|
|
859
880
|
...(() => {
|
|
860
881
|
const resolved = resolveMaxInflight(model.providerId, rowTenantId);
|
|
861
|
-
return resolved === undefined ? {} : {
|
|
882
|
+
return resolved === undefined ? {} : { maxInflight: resolved };
|
|
862
883
|
})(),
|
|
863
|
-
...(
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
network_pool_ids: networkPools.ids,
|
|
867
|
-
network_pool_limits: networkPools.limits,
|
|
868
|
-
network_pool_weights: networkPools.weights,
|
|
869
|
-
...(networkPools.routing ? { network_pool_routing: networkPools.routing } : {}),
|
|
870
|
-
...providerLimitFor(model.providerId, rowTenantId),
|
|
871
|
-
}
|
|
872
|
-
: {}),
|
|
873
|
-
};
|
|
884
|
+
...(routeUserAgent === undefined ? {} : { userAgent: routeUserAgent }),
|
|
885
|
+
...(networkPools ? { pools: networkPools } : {}),
|
|
886
|
+
});
|
|
874
887
|
if (account.status === "cooldown") {
|
|
875
888
|
// A row that still says `cooldown` stays excluded until the sweeper
|
|
876
889
|
// flips it back to `active`. An *expired* deadline used to read as
|
|
@@ -995,7 +1008,6 @@ class RouteCatalogRepository {
|
|
|
995
1008
|
cli_aliases: cliAliases,
|
|
996
1009
|
combos,
|
|
997
1010
|
...(routingMap ? { providerRouting: routingMap } : {}),
|
|
998
|
-
...(Object.keys(poolRouting).length > 0 ? { poolRouting } : {}),
|
|
999
1011
|
...(invokeDisabledTenants.size > 0 ? { invokeDisabledTenants } : {}),
|
|
1000
1012
|
};
|
|
1001
1013
|
}
|
|
@@ -108,6 +108,8 @@ export interface RouteCandidate {
|
|
|
108
108
|
readonly quota_windows?: readonly ProviderQuotaWindow[];
|
|
109
109
|
/** A successful Start Plan balance authoritatively lists its model grants. */
|
|
110
110
|
readonly quota_entitlements_known?: boolean;
|
|
111
|
+
/** Normalized quota/plan fact stamped at plan time (unified engine). */
|
|
112
|
+
readonly quota_fact?: NormalizedQuotaFact;
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
/**
|
|
@@ -141,6 +143,27 @@ export type RoutedCandidate = RouteCandidate & {
|
|
|
141
143
|
* activity is read live via `sharedClaudeSlowLanes.isActive`).
|
|
142
144
|
*/
|
|
143
145
|
lane?: "slow";
|
|
146
|
+
/**
|
|
147
|
+
* Normalized quota/plan fact stamped at plan time by the routing decision
|
|
148
|
+
* engine. The decision engine reads this instead of re-deriving window state.
|
|
149
|
+
*/
|
|
150
|
+
quota_fact?: NormalizedQuotaFact;
|
|
151
|
+
/**
|
|
152
|
+
* Operator-configured account priority (0 when unset). Higher ranks ahead
|
|
153
|
+
* within the same rank group, before usage measurement.
|
|
154
|
+
*/
|
|
155
|
+
account_priority?: number;
|
|
156
|
+
/**
|
|
157
|
+
* True when the account's remaining quota fraction is at or below the
|
|
158
|
+
* configured reserve percent. A reserved account stays eligible but orders
|
|
159
|
+
* behind non-reserve siblings.
|
|
160
|
+
*/
|
|
161
|
+
in_reserve?: boolean;
|
|
162
|
+
/**
|
|
163
|
+
* Drain urgency score: headroom fraction / remaining hours until reset.
|
|
164
|
+
* Higher = quota about to expire unused, ranked first within a rank group.
|
|
165
|
+
*/
|
|
166
|
+
drain_score?: number;
|
|
144
167
|
};
|
|
145
168
|
|
|
146
169
|
/**
|
|
@@ -256,10 +279,13 @@ export interface RoutePlan {
|
|
|
256
279
|
|
|
257
280
|
/** How eligible a candidate is and why — written once, read by every layer. */
|
|
258
281
|
export const ROUTING_RANK = {
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
282
|
+
/** Fresh candidate with a positive known quota / above its usage floor. */
|
|
283
|
+
FRESH_KNOWN: 0,
|
|
284
|
+
/** Fresh candidate whose quota state is unknown (no read, unsupported, stale). */
|
|
285
|
+
FRESH_UNKNOWN: 1,
|
|
286
|
+
SLOW: 2,
|
|
287
|
+
COOLING: 3,
|
|
288
|
+
SATURATED: 4,
|
|
263
289
|
} as const;
|
|
264
290
|
export type RoutingRank = (typeof ROUTING_RANK)[keyof typeof ROUTING_RANK];
|
|
265
291
|
|
|
@@ -275,6 +301,22 @@ export interface RoutingDecision {
|
|
|
275
301
|
readonly saturated?: boolean;
|
|
276
302
|
}
|
|
277
303
|
|
|
304
|
+
/**
|
|
305
|
+
* The normalized quota/plan fact the unified routing engine evaluates per
|
|
306
|
+
* candidate. Produced once per candidate before `evaluateCandidate`, so the
|
|
307
|
+
* decision engine never re-reads quota sources or re-derives window state.
|
|
308
|
+
*/
|
|
309
|
+
export interface NormalizedQuotaFact {
|
|
310
|
+
/** `available` = positive known balance; `exhausted` = known spent/below floor. */
|
|
311
|
+
readonly quotaState: "available" | "exhausted" | "unknown";
|
|
312
|
+
readonly quotaSource: "live_cache" | "snapshot" | "unsupported" | "none";
|
|
313
|
+
/** Epoch ms of the observation, when one exists (used for freshness). */
|
|
314
|
+
readonly quotaObservedAt: number | null;
|
|
315
|
+
/** True when the observed quota is older than the freshness horizon. */
|
|
316
|
+
readonly isStale: boolean;
|
|
317
|
+
readonly usageFloorState: "above" | "below" | "unknown";
|
|
318
|
+
}
|
|
319
|
+
|
|
278
320
|
import type { ComboStrategy, PoolRoutingStrategy, ProviderRoutingStrategy } from "../../persistence/schema";
|
|
279
321
|
import { providerRoutingStrategy } from "../../persistence/schema";
|
|
280
322
|
|
|
@@ -299,8 +341,6 @@ export interface RouteSnapshot {
|
|
|
299
341
|
readonly created_at: number;
|
|
300
342
|
/** Optional per-provider routing preferences keyed by tenant. */
|
|
301
343
|
readonly providerRouting?: ProviderRoutingMap;
|
|
302
|
-
/** Optional per-tenant pool selection strategy (absent = `least_loaded`). */
|
|
303
|
-
readonly poolRouting?: Readonly<Record<string, PoolRoutingSetting>>;
|
|
304
344
|
/**
|
|
305
345
|
* Tenants whose invoke switch is off, so `/v1/*` must be refused outright.
|
|
306
346
|
*
|
|
@@ -319,6 +359,9 @@ export type EligibilityReason =
|
|
|
319
359
|
| "cooldown_hard"
|
|
320
360
|
| "model_cooldown"
|
|
321
361
|
| "quota_exhausted"
|
|
362
|
+
| "quota_unknown"
|
|
363
|
+
| "plan_gate"
|
|
364
|
+
| "capability_unsupported"
|
|
322
365
|
| "disabled"
|
|
323
366
|
|
|
324
367
|
export interface EligibilityDecision {
|
|
@@ -392,6 +435,8 @@ const ELIGIBILITY_REASON_LABELS: Readonly<Record<string, string>> = {
|
|
|
392
435
|
disabled: "all accounts are disabled",
|
|
393
436
|
credit_floor_reached: "credit or quota is exhausted",
|
|
394
437
|
quota_exhausted: "every account has an exhausted quota window or is below its configured usage floor",
|
|
438
|
+
quota_unknown: "accounts have no known quota state (unknown, unsupported, or stale)",
|
|
439
|
+
plan_gate: "the plan explicitly proves these accounts cannot serve this model",
|
|
395
440
|
capability_unsupported: "the accounts serving this model do not support the request's capabilities (e.g. images, tools, or reasoning)",
|
|
396
441
|
};
|
|
397
442
|
|
|
@@ -703,9 +748,6 @@ export class InMemoryRouteSnapshotService implements RouteSnapshotService {
|
|
|
703
748
|
...(built.cli_aliases ? { cli_aliases: Object.freeze({ ...built.cli_aliases }) } : {}),
|
|
704
749
|
combos: Object.freeze({ ...built.combos }),
|
|
705
750
|
...(providerRouting ? { providerRouting } : {}),
|
|
706
|
-
// Unfrozen copy: deepFreeze must reach the inner per-tenant settings —
|
|
707
|
-
// a pre-frozen record trips its is-frozen guard and skips recursion.
|
|
708
|
-
...(built.poolRouting ? { poolRouting: { ...built.poolRouting } } : {}),
|
|
709
751
|
created_at: built.created_at ?? Date.now(),
|
|
710
752
|
});
|
|
711
753
|
// A mutation during the build means this snapshot describes a catalog that
|