cartethyia 2.7.8 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -3
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js +1 -0
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-CXsaOAO2.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js +1 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-CgoPc5B9.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-D9bFQern.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js +1 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BwNC_-Cx.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-febLU4r1.js} +1 -1
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-M6fvR5Wz.js} +1 -1
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js +56 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js +1 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/{assert-CidQVoNo.js → assert-CqTLw5e7.js} +1 -1
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-C83EqLB0.js} +1 -1
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
- package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-D1xn7pIe.js} +1 -1
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/favicon.webp +0 -0
- package/dist/dashboard/assets/brand/login_register.webp +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
- package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/og_image.webp +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
- package/dist/dashboard/assets/{card-_HwAEqFF.js → card-DU3Lq5Lm.js} +1 -1
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js +1 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CEL5Sg_J.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-BjFR5UHy.js} +1 -1
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-HvBW0AjI.js} +1 -1
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/{entry-COaC-irN.js → entry-CECVELyy.js} +1 -1
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js +1 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-DLW4i8zK.js} +1 -1
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/{index-CgKmFngv.js → index-1-fCqe64.js} +2 -2
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2BirKry.js → inline-DGvU2oLK.js} +1 -1
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/{input-D-qV9dKY.js → input-iNnO1X2K.js} +1 -1
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-0q8UGypb.js} +1 -1
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-C0w2bQjJ.js} +1 -1
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/{live-DGizF06-.js → live-M5aJ_xCa.js} +1 -1
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
- package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
- package/dist/dashboard/assets/{network-C9UE-bOr.js → network-BKeQGT3K.js} +1 -1
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-CivAk3da.js} +1 -1
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-CpzvI5ep.js} +1 -1
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/providers/devin.svg +9 -0
- package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
- package/dist/dashboard/assets/providers/windsurf.svg +10 -0
- package/dist/dashboard/assets/providers/windsurf.svg.gz +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/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
- package/dist/dashboard/assets/query-keys-IKLh0YFd.js.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-BFQX2VBc.js +1 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/{select-BCOcv8WK.js → select-CXbck0jG.js} +2 -2
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js +1 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DggRiCxE.js} +1 -1
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/{state-DXbGTx7N.js → state-ClFzfbYp.js} +1 -1
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/story/25817331.webp +0 -0
- package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
- package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
- package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
- package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
- package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
- package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
- package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
- package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-CTIFxKqS.js} +1 -1
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BClG3yWj.js} +1 -1
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.webp +0 -0
- package/dist/dashboard/console-backgrounds_initial.webp +0 -0
- package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
- package/dist/dashboard/index.html +3 -3
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +59 -56
- package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
- package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/package.json +1 -1
- package/src/boot/app.ts +10 -13
- package/src/boot/dependencies.ts +12 -4
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/cooldowns.ts +1 -1
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +20 -6
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +50 -31
- 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/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -2
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +93 -0
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -0
- package/src/console/providers/catalog/discover-constants.ts +6 -0
- package/src/console/providers/catalog/model-operations.ts +122 -10
- package/src/console/providers/catalog/provider-operations.ts +116 -8
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +65 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +249 -4
- package/src/console/quota/account-quota-global.ts +97 -19
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +6 -18
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/operations.ts +31 -46
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/shared/errors.ts +33 -6
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +3 -3
- package/src/network/pool/byte-accounting.ts +3 -2
- package/src/network/pool/selector.ts +182 -39
- package/src/network/pool-cooldown-store.ts +89 -14
- package/src/network/pool-health.ts +49 -61
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/ssrf.ts +6 -6
- package/src/observability/event-log.ts +7 -361
- package/src/observability/event-query.ts +18 -4
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +15 -25
- 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 +30 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +28 -2
- package/src/persistence/ttl-cache.ts +20 -2
- package/src/protocol/codecs.ts +1 -1
- package/src/protocol/dsml.ts +35 -87
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +14 -14
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +4 -5
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/stream-error-frames.ts +13 -3
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +1 -1
- package/src/protocol/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream/send-claude-messages.ts +15 -4
- package/src/protocol/upstream-parsing.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +78 -17
- package/src/providers/authentication/oauth-client.ts +1 -1
- package/src/providers/authentication/oauth-device-flow.ts +98 -8
- package/src/providers/authentication/oauth-refresh-service.ts +153 -59
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +117 -27
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +74 -33
- package/src/providers/discovery/probing-service.ts +293 -165
- 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 +121 -2
- package/src/providers/integrations/antigravity/antigravity.ts +13 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +191 -35
- package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
- package/src/providers/integrations/buddy/buddy-identity.ts +89 -6
- package/src/providers/integrations/buddy/buddy-media.ts +4 -5
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
- package/src/providers/integrations/buddy/capabilities.ts +6 -43
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +23 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +38 -27
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +745 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +35 -20
- package/src/providers/integrations/cursor/cursor-shared.ts +26 -5
- package/src/providers/integrations/cursor/cursor.ts +139 -70
- 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/cursor/protocol/tool-canonical.ts +26 -100
- package/src/providers/integrations/devin/devin-auth.ts +353 -0
- package/src/providers/integrations/devin/devin-catalog.ts +207 -0
- package/src/providers/integrations/devin/devin-http.ts +91 -0
- package/src/providers/integrations/devin/devin-quota.ts +214 -0
- package/src/providers/integrations/devin/devin-shared.ts +111 -0
- package/src/providers/integrations/devin/devin.ts +539 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +558 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory-oauth.ts +17 -44
- package/src/providers/integrations/factory/factory.ts +2 -2
- 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 +60 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
- package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
- package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
- package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
- package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
- package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
- package/src/providers/integrations/freepi/freepi.ts +292 -0
- package/src/providers/integrations/gemini.ts +2 -2
- package/src/providers/integrations/grok/grok-oauth.ts +48 -45
- 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 +94 -0
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +13 -21
- package/src/providers/integrations/hermes/index.ts +2 -0
- 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-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- 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/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +208 -0
- package/src/providers/integrations/perch/perch-quota.ts +123 -0
- package/src/providers/integrations/perch/perch-realm.ts +82 -0
- package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
- package/src/providers/integrations/perch/perch.ts +305 -0
- package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
- package/src/providers/integrations/qoder/chat-proto.ts +328 -328
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +90 -40
- package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +26 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
- package/src/providers/integrations/qoder/qoder-checkin.ts +6 -6
- package/src/providers/integrations/qoder/qoder-grpc.ts +210 -7
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -108
- package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
- package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
- package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
- package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
- package/src/providers/integrations/qoder/qoder.ts +3 -7
- package/src/providers/integrations/trae/trae-catalog.ts +9 -14
- package/src/providers/integrations/trae/trae-headers.ts +36 -11
- package/src/providers/integrations/trae/trae-oauth.ts +14 -17
- package/src/providers/integrations/trae/trae-protocol.ts +12 -11
- package/src/providers/integrations/trae/trae-quota.ts +96 -36
- package/src/providers/integrations/trae/trae-realm.ts +74 -15
- package/src/providers/integrations/trae/trae.ts +99 -26
- 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 +204 -0
- package/src/providers/operations/account-error-classification.ts +235 -278
- package/src/providers/operations/account-health-service.ts +273 -26
- package/src/providers/operations/account-refresh-status.ts +269 -0
- package/src/providers/operations/account-tier.ts +66 -0
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +42 -150
- package/src/providers/operations/cooldown-rules.ts +56 -0
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +102 -32
- 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/provider-contracts.ts +33 -2
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +99 -14
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- 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 +96 -18
- package/src/security/abuse.ts +71 -0
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/transport/dispatch/attempt-finalize.ts +14 -13
- package/src/transport/dispatch/attempt-loop.ts +71 -17
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +9 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/streaming/finalize.ts +9 -6
- package/src/transport/dispatch/streaming/stream.ts +9 -36
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +67 -1
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +129 -37
- 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 +418 -33
- 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 +9 -2
- 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 +34 -6
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/daily-checkin.ts +1 -1
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/scheduler.ts +22 -4
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js +0 -1
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
- package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
- package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.png +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/favicon.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
- package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
- package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
- package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
- package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
- package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
- package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
- package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
- package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
- package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
- package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
- package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-YSoQOUh6.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-fnCsxgNO.js +0 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
- package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
- package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
- package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
- package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
- package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
- package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
- 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-CTxoqyYB.js → app-DIXLjojg.js} +0 -0
- /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-DIXLjojg.js.gz} +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Account tier derivation from the plan string the quota collector reported.
|
|
3
|
+
*
|
|
4
|
+
* The plan string (`provider_accounts.quota_plan`) is a raw, per-provider
|
|
5
|
+
* label; this module normalizes it to the three-tier taxonomy the cooldown
|
|
6
|
+
* rules consume (`free | paid | pro | null`, D14). It is a pure function of
|
|
7
|
+
* the provider id and the plan text — no database access, no state.
|
|
8
|
+
*
|
|
9
|
+
* The mapping is deliberately conservative, following the same posture as
|
|
10
|
+
* `plan-gate.ts`: a tier is only claimed when the string proves it. "free"
|
|
11
|
+
* requires the shared free marker set (exported there), "pro" requires a
|
|
12
|
+
* team/enterprise/org signal, and "paid" is only assigned for providers whose
|
|
13
|
+
* plan strings are evidenced (Trae, the buddy family, Cursor). Everything else
|
|
14
|
+
* — an unknown provider, an unrecognized plan, a `null` plan — resolves to
|
|
15
|
+
* `null`, which keeps the legacy behavior intact (unknown tier ⇒ no rule
|
|
16
|
+
* applies ⇒ the old constants drive the cooldown).
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { FREE_PLAN_MARKERS } from "../../transport/routing/plan-gate";
|
|
20
|
+
import { BUDDY_PROVIDER_IDS } from "../provider-metadata";
|
|
21
|
+
import { QODER_CHECKIN_PROVIDER_IDS } from "../integrations/qoder/qoder-checkin";
|
|
22
|
+
import { TRAE_PROVIDER_IDS } from "../integrations/trae/trae-realm";
|
|
23
|
+
|
|
24
|
+
/** The three-tier taxonomy for cooldown rules. `null` = unknown. */
|
|
25
|
+
export type AccountTier = "free" | "paid" | "pro" | null;
|
|
26
|
+
|
|
27
|
+
/** Team/enterprise/org signals that prove a "pro" tier. */
|
|
28
|
+
const PRO_PLAN_MARKERS: readonly string[] = ["team", "enterprise", "org", "pro"];
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Maps a provider's plan string to a tier.
|
|
32
|
+
*
|
|
33
|
+
* `providerId` is normalized case-insensitively; a `null`/empty plan is
|
|
34
|
+
* unknown (`null`). The "free" check runs before any provider branch because a
|
|
35
|
+
* proven-free label is the strongest signal (e.g. CodeBuddy's
|
|
36
|
+
* `personal_free_user`, Trae's `"Free Plan Subscription"`).
|
|
37
|
+
*/
|
|
38
|
+
export function mapPlanToTier(providerId: string, plan: string | null): AccountTier {
|
|
39
|
+
const lower = (plan ?? "").trim().toLowerCase();
|
|
40
|
+
if (lower.length === 0) return null;
|
|
41
|
+
// Free is only claimed when the string proves it — the same marker set the
|
|
42
|
+
// routing plan-gate uses (imported, not copied), so the two cannot disagree
|
|
43
|
+
// about an account.
|
|
44
|
+
if (FREE_PLAN_MARKERS.some((marker) => lower.includes(marker))) return "free";
|
|
45
|
+
|
|
46
|
+
if ((QODER_CHECKIN_PROVIDER_IDS as readonly string[]).includes(providerId.toLowerCase())) {
|
|
47
|
+
// Qoder's `userType` is `personal_standard` by default; team/enterprise/
|
|
48
|
+
// org suffixes prove a higher tier. `personal_standard` itself is not
|
|
49
|
+
// verified against the taxonomy, so it stays unknown rather than guessed.
|
|
50
|
+
if (PRO_PLAN_MARKERS.some((marker) => lower.includes(marker))) return "pro";
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (BUDDY_PROVIDER_IDS.has(providerId.toLowerCase())) {
|
|
55
|
+
if (lower.includes("enterprise") || lower.includes("team")) return "pro";
|
|
56
|
+
return "paid";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Trae (paid plans other than the free subscription) and Cursor (a non-free
|
|
60
|
+
// `membershipType`/`planName` is a paying plan by construction).
|
|
61
|
+
if (TRAE_PROVIDER_IDS.has(providerId.toLowerCase())) return "paid";
|
|
62
|
+
if (providerId.toLowerCase() === "cursor") return "paid";
|
|
63
|
+
|
|
64
|
+
// Unknown provider: no claim. Legacy behavior applies.
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* Discovery is owned by the background client-version monitor. Request paths
|
|
12
12
|
* only call the synchronous `get`/`snapshot` accessors and never fetch.
|
|
13
13
|
*/
|
|
14
|
-
import { getCachedVersion, resetVersionCacheForTesting } from "./provider-
|
|
14
|
+
import { getCachedVersion, resetVersionCacheForTesting } from "./provider-caches";
|
|
15
15
|
import type { OutboundFetch } from "../provider-contracts";
|
|
16
16
|
import { composeAbortSignal } from "../authentication/oauth-flow-store";
|
|
17
17
|
|
|
@@ -16,15 +16,6 @@ import {
|
|
|
16
16
|
buildGrokShellUserAgent,
|
|
17
17
|
} from "./cli-platform";
|
|
18
18
|
|
|
19
|
-
async function qoderVersion(response: Response): Promise<string | null> {
|
|
20
|
-
try {
|
|
21
|
-
const parsed = (await response.json()) as { version?: unknown };
|
|
22
|
-
return isSemverish(parsed.version) ? parsed.version.trim() : null;
|
|
23
|
-
} catch {
|
|
24
|
-
return null;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
19
|
/**
|
|
29
20
|
* Newest Trae IDE version from the official changelog.
|
|
30
21
|
*
|
|
@@ -67,17 +58,12 @@ async function traeVersion(response: Response): Promise<string | null> {
|
|
|
67
58
|
}
|
|
68
59
|
}
|
|
69
60
|
|
|
70
|
-
async function clineClientVersion(response: Response): Promise<string | null> {
|
|
71
|
-
const data = (await response.json()) as { version?: unknown };
|
|
72
|
-
return isSemverish(data.version) ? data.version.trim() : null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
61
|
/**
|
|
76
62
|
* Newest Cursor build from the official download API, as the IDE's own header
|
|
77
63
|
* spells it.
|
|
78
64
|
*
|
|
79
65
|
* Cursor's `x-cursor-client-version` is not the IDE semver on its own: the wire
|
|
80
|
-
* value is `cli-<version>-<sha7>` (observed live as `cli-2026.
|
|
66
|
+
* value is `cli-<version>-<sha7>` (observed live as `cli-2026.11.05-86047df`).
|
|
81
67
|
* The download API is the only source that returns both halves — `version` and
|
|
82
68
|
* `commitSha` — so they are joined here rather than guessed. A semver alone
|
|
83
69
|
* would be a different identity than the one the IDE sends.
|
|
@@ -95,41 +81,6 @@ async function cursorVersion(response: Response): Promise<string | null> {
|
|
|
95
81
|
}
|
|
96
82
|
}
|
|
97
83
|
|
|
98
|
-
async function clineSdkVersion(response: Response): Promise<string | null> {
|
|
99
|
-
const data = (await response.json()) as {
|
|
100
|
-
version?: unknown;
|
|
101
|
-
"dist-tags"?: { latest?: unknown };
|
|
102
|
-
};
|
|
103
|
-
const candidate = data.version ?? data["dist-tags"]?.latest;
|
|
104
|
-
return isSemverish(candidate) ? candidate.trim() : null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async function kimiVersion(response: Response): Promise<string | null> {
|
|
108
|
-
const data = (await response.json()) as { info?: { version?: unknown } };
|
|
109
|
-
return isSemverish(data.info?.version) ? data.info.version.trim() : null;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function workbuddyDesktopVersion(response: Response): Promise<string | null> {
|
|
113
|
-
try {
|
|
114
|
-
const data = (await response.json()) as { version?: unknown; productVersion?: unknown };
|
|
115
|
-
const candidate = data.productVersion ?? data.version;
|
|
116
|
-
return typeof candidate === "string" && /^\d+\.\d+\.\d+(?:\.\d+)?(?:[-+][\w.-]+)?$/.test(candidate.trim())
|
|
117
|
-
? candidate.trim()
|
|
118
|
-
: null;
|
|
119
|
-
} catch {
|
|
120
|
-
return null;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async function kiroCaskVersion(response: Response): Promise<string | null> {
|
|
125
|
-
try {
|
|
126
|
-
const data = (await response.json()) as { version?: unknown };
|
|
127
|
-
return isSemverish(data.version) ? data.version.trim() : null;
|
|
128
|
-
} catch {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
84
|
async function codeBuddyCnVersion(response: Response): Promise<string | null> {
|
|
134
85
|
try {
|
|
135
86
|
const data = (await response.json()) as { version?: unknown };
|
|
@@ -232,7 +183,7 @@ const KIRO_NODE_VERSION = "24.18.0";
|
|
|
232
183
|
export const VERSION_SOURCES = {
|
|
233
184
|
antigravity: {
|
|
234
185
|
key: "antigravity",
|
|
235
|
-
fallback: "2.
|
|
186
|
+
fallback: "2.29.0",
|
|
236
187
|
sources: [
|
|
237
188
|
{
|
|
238
189
|
url: "https://antigravity-hub-auto-updater-974169037036.us-central1.run.app/manifest/latest-arm64-mac.yml",
|
|
@@ -248,12 +199,7 @@ export const VERSION_SOURCES = {
|
|
|
248
199
|
// `@qoder-ai/qodercli/latest`) may report a newer CLI, but the CLI and
|
|
249
200
|
// IDE are different products — the chat surface identity is the IDE's.
|
|
250
201
|
fallback: "1.1.80",
|
|
251
|
-
sources: [
|
|
252
|
-
{
|
|
253
|
-
url: "https://registry.npmjs.org/@qoder-ai/qodercli/latest",
|
|
254
|
-
extract: qoderVersion,
|
|
255
|
-
},
|
|
256
|
-
],
|
|
202
|
+
sources: [{ url: "https://registry.npmjs.org/@qoder-ai/qodercli/latest" }],
|
|
257
203
|
},
|
|
258
204
|
opencode: {
|
|
259
205
|
key: "opencode",
|
|
@@ -261,21 +207,21 @@ export const VERSION_SOURCES = {
|
|
|
261
207
|
// under `@opencode/cli`, and this feed is what its own installer reads.
|
|
262
208
|
// Fallback = the current latest release; raise it whenever the package
|
|
263
209
|
// moves so a cold process does not present a stale client build.
|
|
264
|
-
fallback: "2.2.
|
|
210
|
+
fallback: "2.2.6",
|
|
265
211
|
minVersion: "2.0.0",
|
|
266
212
|
sources: [{ url: "https://opencode.ai/update/api/latest/cli/npm" }],
|
|
267
213
|
},
|
|
268
214
|
commandcode: {
|
|
269
215
|
key: "commandcode",
|
|
270
|
-
// npm `command-code` latest as of 2026-
|
|
216
|
+
// npm `command-code` latest as of 2026-11-07. The CLI sends this as
|
|
271
217
|
// `x-command-code-version`, so a stale fallback presents a client build
|
|
272
218
|
// the upstream no longer ships — raise it whenever the package moves.
|
|
273
|
-
fallback: "1.88.
|
|
219
|
+
fallback: "1.88.5",
|
|
274
220
|
sources: [{ url: "https://registry.npmjs.org/command-code/latest" }],
|
|
275
221
|
},
|
|
276
222
|
grok: {
|
|
277
223
|
key: "grok",
|
|
278
|
-
fallback: "1.0.
|
|
224
|
+
fallback: "1.0.77",
|
|
279
225
|
sources: [
|
|
280
226
|
{ url: "https://storage.googleapis.com/grok-build-public-artifacts/cli/stable" },
|
|
281
227
|
{ url: "https://registry.npmjs.org/@xai-official/grok/latest" },
|
|
@@ -286,85 +232,45 @@ export const VERSION_SOURCES = {
|
|
|
286
232
|
fallback: "4.1.26",
|
|
287
233
|
minVersion: "4.1.23",
|
|
288
234
|
sources: [
|
|
289
|
-
{
|
|
290
|
-
url: "https://raw.githubusercontent.com/cline/cline/main/apps/vscode/package.json",
|
|
291
|
-
extract: clineClientVersion,
|
|
292
|
-
},
|
|
235
|
+
{ url: "https://raw.githubusercontent.com/cline/cline/main/apps/vscode/package.json" },
|
|
293
236
|
],
|
|
294
237
|
},
|
|
295
238
|
clineSdk: {
|
|
296
239
|
key: "cline-sdk",
|
|
297
240
|
fallback: "0.2.0",
|
|
298
|
-
sources: [{ url: "https://registry.npmjs.org/@cline/sdk/latest"
|
|
241
|
+
sources: [{ url: "https://registry.npmjs.org/@cline/sdk/latest" }],
|
|
299
242
|
},
|
|
300
243
|
clineCli: {
|
|
301
244
|
key: "cline-cli",
|
|
302
245
|
fallback: "3.0.74",
|
|
303
|
-
sources: [{ url: "https://registry.npmjs.org/cline/latest"
|
|
246
|
+
sources: [{ url: "https://registry.npmjs.org/cline/latest" }],
|
|
304
247
|
},
|
|
305
248
|
codex: {
|
|
306
249
|
key: "codex",
|
|
307
|
-
fallback: "0.
|
|
250
|
+
fallback: "0.167.0",
|
|
308
251
|
sources: [{ url: "https://registry.npmjs.org/@openai/codex/latest" }],
|
|
309
252
|
},
|
|
310
|
-
workbuddyClient: {
|
|
311
|
-
key: "workbuddy-client",
|
|
312
|
-
fallback: "5.9.4.42593613",
|
|
313
|
-
sources: [
|
|
314
|
-
{
|
|
315
|
-
url: "https://www.workbuddy.ai/v2/update?platform=workbuddy-win32-x64-user",
|
|
316
|
-
extract: workbuddyDesktopVersion,
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
url: "https://www.workbuddy.ai/v2/update?platform=workbuddy-darwin-arm64",
|
|
320
|
-
extract: workbuddyDesktopVersion,
|
|
321
|
-
},
|
|
322
|
-
],
|
|
323
|
-
},
|
|
324
|
-
workbuddyCnClient: {
|
|
325
|
-
key: "workbuddy-cn-client",
|
|
326
|
-
fallback: "5.9.3.42398134",
|
|
327
|
-
sources: [
|
|
328
|
-
{
|
|
329
|
-
url: "https://www.workbuddy.cn/v2/update?platform=workbuddy-win32-x64-user",
|
|
330
|
-
extract: workbuddyDesktopVersion,
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
url: "https://www.workbuddy.cn/v2/update?platform=workbuddy-darwin-arm64",
|
|
334
|
-
extract: workbuddyDesktopVersion,
|
|
335
|
-
},
|
|
336
|
-
],
|
|
337
|
-
},
|
|
338
|
-
workbuddyCli: {
|
|
339
|
-
key: "workbuddy",
|
|
340
|
-
fallback: "2.178.1",
|
|
341
|
-
sources: [
|
|
342
|
-
{ url: "https://registry.npmjs.org/@tencent-ai/codebuddy-code/latest" },
|
|
343
|
-
{ url: "https://registry.npmmirror.com/@tencent-ai/codebuddy-code/latest" },
|
|
344
|
-
],
|
|
345
|
-
},
|
|
346
253
|
kimiCli: {
|
|
347
254
|
key: "kimi-cli",
|
|
348
255
|
fallback: "1.52.0",
|
|
349
|
-
sources: [{ url: "https://pypi.org/pypi/kimi-cli/json"
|
|
256
|
+
sources: [{ url: "https://pypi.org/pypi/kimi-cli/json" }],
|
|
350
257
|
},
|
|
351
258
|
kiro: {
|
|
352
259
|
key: "kiro",
|
|
353
|
-
fallback: "1.4.
|
|
260
|
+
fallback: "1.4.121",
|
|
354
261
|
sources: [
|
|
355
262
|
{
|
|
356
263
|
// Kiro's downloads page exposes no stable version string. Homebrew
|
|
357
264
|
// tracks the official installer URL and exposes its version as JSON;
|
|
358
265
|
// keep the product page parser as a fallback.
|
|
359
266
|
url: "https://formulae.brew.sh/api/cask/kiro.json",
|
|
360
|
-
extract: kiroCaskVersion,
|
|
361
267
|
},
|
|
362
268
|
{ url: "https://kiro.dev/downloads/", extract: kiroVersion },
|
|
363
269
|
],
|
|
364
270
|
},
|
|
365
271
|
codebuddy: {
|
|
366
272
|
key: "codebuddy",
|
|
367
|
-
fallback: "2.
|
|
273
|
+
fallback: "2.181.0",
|
|
368
274
|
sources: [
|
|
369
275
|
{ url: "https://registry.npmjs.org/@tencent-ai/codebuddy-code/latest" },
|
|
370
276
|
{ url: "https://registry.npmmirror.com/@tencent-ai/codebuddy-code/latest" },
|
|
@@ -372,7 +278,7 @@ export const VERSION_SOURCES = {
|
|
|
372
278
|
},
|
|
373
279
|
codebuddyCn: {
|
|
374
280
|
key: "codebuddy-cn",
|
|
375
|
-
fallback: "4.12.
|
|
281
|
+
fallback: "4.12.3.42658816",
|
|
376
282
|
sources: [
|
|
377
283
|
{
|
|
378
284
|
// Official CN builds are listed by Homebrew's maintained cask feed;
|
|
@@ -387,7 +293,7 @@ export const VERSION_SOURCES = {
|
|
|
387
293
|
// Current `@anthropic-ai/claude-code` release, so the billing
|
|
388
294
|
// `cc_version=` suffix and the `claude-cli/` User-Agent stay on what
|
|
389
295
|
// upstream ships.
|
|
390
|
-
fallback: "2.1.
|
|
296
|
+
fallback: "2.1.319",
|
|
391
297
|
sources: [{ url: "https://registry.npmjs.org/@anthropic-ai/claude-code/latest" }],
|
|
392
298
|
},
|
|
393
299
|
claudeSdk: {
|
|
@@ -404,7 +310,7 @@ export const VERSION_SOURCES = {
|
|
|
404
310
|
},
|
|
405
311
|
github: {
|
|
406
312
|
key: "github-copilot-chat",
|
|
407
|
-
fallback: "0.43.
|
|
313
|
+
fallback: "0.43.2026040705",
|
|
408
314
|
sources: [
|
|
409
315
|
{
|
|
410
316
|
url: "https://api.github.com/repos/microsoft/vscode-copilot-chat/releases/latest",
|
|
@@ -414,7 +320,7 @@ export const VERSION_SOURCES = {
|
|
|
414
320
|
},
|
|
415
321
|
kilo: {
|
|
416
322
|
key: "kilo-code",
|
|
417
|
-
fallback: "7.8.
|
|
323
|
+
fallback: "7.8.27",
|
|
418
324
|
sources: [{ url: "https://open-vsx.org/api/kilocode/kilo-code" }],
|
|
419
325
|
},
|
|
420
326
|
muse: {
|
|
@@ -436,12 +342,27 @@ export const VERSION_SOURCES = {
|
|
|
436
342
|
},
|
|
437
343
|
],
|
|
438
344
|
},
|
|
345
|
+
freepi: {
|
|
346
|
+
key: "freepi",
|
|
347
|
+
// The free-pi CLI version — the `x-client-version` the gateway reports.
|
|
348
|
+
// Fallback = the unpacked 0.6.14 bundle; npm discovery replaces it.
|
|
349
|
+
fallback: "0.6.14",
|
|
350
|
+
sources: [{ url: "https://registry.npmjs.org/free-pi-cli/latest" }],
|
|
351
|
+
},
|
|
352
|
+
perch: {
|
|
353
|
+
key: "perch",
|
|
354
|
+
// The official Perch CLI, spawned by the adapter for hosted inference.
|
|
355
|
+
fallback: "2.4.125",
|
|
356
|
+
sources: [{ url: "https://registry.npmjs.org/perchai-cli/latest" }],
|
|
357
|
+
},
|
|
439
358
|
cursor: {
|
|
440
359
|
key: "cursor",
|
|
441
|
-
// Fallback = the last observed wire version
|
|
442
|
-
// one monitor tick; it is only what a cold
|
|
443
|
-
// successful fetch.
|
|
444
|
-
|
|
360
|
+
// Fallback = the last observed wire version (CLI ~2026.11.07-306d153).
|
|
361
|
+
// Discovery replaces it within one monitor tick; it is only what a cold
|
|
362
|
+
// process sends before the first successful fetch. Kept equal to
|
|
363
|
+
// `FALLBACK_CLIENT_VERSION` in the cursor adapter so the badge and the
|
|
364
|
+
// request header always send one identity.
|
|
365
|
+
fallback: "cli-3.29.9-306d153",
|
|
445
366
|
sources: [
|
|
446
367
|
{
|
|
447
368
|
url: "https://cursor.com/api/download?platform=win32-x64-user&releaseTrack=stable",
|
|
@@ -455,7 +376,7 @@ export const VERSION_SOURCES = {
|
|
|
455
376
|
// comment this replaced claimed no semver existed and pinned a date tag
|
|
456
377
|
// (`v2026.9.24`) as the version — a tag, not a release, and not the
|
|
457
378
|
// identity the client sends.
|
|
458
|
-
fallback: "0.
|
|
379
|
+
fallback: "0.23.0",
|
|
459
380
|
sources: [
|
|
460
381
|
{
|
|
461
382
|
url: "https://api.github.com/repos/NousResearch/hermes-agent/releases/latest",
|
|
@@ -465,7 +386,7 @@ export const VERSION_SOURCES = {
|
|
|
465
386
|
},
|
|
466
387
|
zcode: {
|
|
467
388
|
key: "zcode",
|
|
468
|
-
fallback: "3.
|
|
389
|
+
fallback: "3.17.2",
|
|
469
390
|
sources: [
|
|
470
391
|
{
|
|
471
392
|
url: "https://api.github.com/repos/zai-org/ZCode/releases/latest",
|
|
@@ -480,6 +401,8 @@ const resolvers = {
|
|
|
480
401
|
qoder: createClientVersionResolver({ ...VERSION_SOURCES.qoder, client: "qoder" }),
|
|
481
402
|
hermes: createClientVersionResolver({ ...VERSION_SOURCES.hermes, client: "hermes" }),
|
|
482
403
|
trae: createClientVersionResolver({ ...VERSION_SOURCES.trae, client: "trae" }),
|
|
404
|
+
freepi: createClientVersionResolver({ ...VERSION_SOURCES.freepi, client: "freepi" }),
|
|
405
|
+
perch: createClientVersionResolver({ ...VERSION_SOURCES.perch, client: "perch" }),
|
|
483
406
|
cursor: createClientVersionResolver({ ...VERSION_SOURCES.cursor, client: "cursor" }),
|
|
484
407
|
opencode: createClientVersionResolver({ ...VERSION_SOURCES.opencode, client: "opencode" }),
|
|
485
408
|
commandcode: createClientVersionResolver({ ...VERSION_SOURCES.commandcode, client: "command-code" }),
|
|
@@ -488,9 +411,6 @@ const resolvers = {
|
|
|
488
411
|
clineSdk: createClientVersionResolver({ ...VERSION_SOURCES.clineSdk, client: "cline-sdk" }),
|
|
489
412
|
clineCli: createClientVersionResolver({ ...VERSION_SOURCES.clineCli, client: "cline-cli" }),
|
|
490
413
|
codex: createClientVersionResolver({ ...VERSION_SOURCES.codex, client: "codex" }),
|
|
491
|
-
workbuddyClient: createClientVersionResolver({ ...VERSION_SOURCES.workbuddyClient, client: "workbuddy" }),
|
|
492
|
-
workbuddyCnClient: createClientVersionResolver({ ...VERSION_SOURCES.workbuddyCnClient, client: "workbuddy-cn" }),
|
|
493
|
-
workbuddyCli: createClientVersionResolver({ ...VERSION_SOURCES.workbuddyCli, client: "codebuddy" }),
|
|
494
414
|
kimiCli: createClientVersionResolver({ ...VERSION_SOURCES.kimiCli, client: "kimi" }),
|
|
495
415
|
codebuddy: createClientVersionResolver({ ...VERSION_SOURCES.codebuddy, client: "codebuddy" }),
|
|
496
416
|
codebuddyCn: createClientVersionResolver({ ...VERSION_SOURCES.codebuddyCn, client: "codebuddy" }),
|
|
@@ -520,8 +440,6 @@ const PROVIDER_VERSION_RESOLVERS: Readonly<Record<string, ClientVersionResolver>
|
|
|
520
440
|
traecn: resolvers.trae,
|
|
521
441
|
cursor: resolvers.cursor,
|
|
522
442
|
commandcode: resolvers.commandcode,
|
|
523
|
-
workbuddy: resolvers.workbuddyClient,
|
|
524
|
-
workbuddycn: resolvers.workbuddyCnClient,
|
|
525
443
|
cb: resolvers.codebuddy,
|
|
526
444
|
cbcn: resolvers.codebuddyCn,
|
|
527
445
|
kimi: resolvers.kimiCli,
|
|
@@ -641,37 +559,11 @@ export const _resetClineCliVersionCache = accessor("clineCli").reset;
|
|
|
641
559
|
|
|
642
560
|
export const getCodexVersion = accessor("codex").get;
|
|
643
561
|
|
|
644
|
-
export const getWorkBuddyClientVersion = accessor("workbuddyClient").get;
|
|
645
|
-
export const getWorkBuddyCnClientVersion = accessor("workbuddyCnClient").get;
|
|
646
|
-
export const getWorkBuddyCliVersion = accessor("workbuddyCli").get;
|
|
647
|
-
|
|
648
|
-
export function buildWorkBuddyUserAgent(
|
|
649
|
-
identity = "WB",
|
|
650
|
-
clientVersion = getWorkBuddyClientVersion(),
|
|
651
|
-
cliVersion = getWorkBuddyCliVersion(),
|
|
652
|
-
): string {
|
|
653
|
-
// 1:1 with codebuddy2api. The CLI profile is `CLI/<v> CodeBuddy/<v>` and the
|
|
654
|
-
// WorkBuddy profile is `WorkBuddy/<wb> workbuddy-ai/<wb> CLI/<cli>`, which
|
|
655
|
-
// sends NO SDK headers — two separate profiles, not one string with a switch.
|
|
656
|
-
// Whether SDK headers ride along is decided by `workbuddyHeaders`, not here, so
|
|
657
|
-
// this builder only decides the UA text.
|
|
658
|
-
//
|
|
659
|
-
// The second token is the wire spelling `workbuddy-ai`, NOT the display
|
|
660
|
-
// brand `WorkBuddy AI`. This is what an official client actually sends; the
|
|
661
|
-
// product is branded with a space in the UI and in docs, and copying that
|
|
662
|
-
// branding into the header produced a UA no real client emits — which the
|
|
663
|
-
// intl gateway answers with 403 `11140`, the same refusal it gives a
|
|
664
|
-
// wrong-brand header. Product name ≠ wire token.
|
|
665
|
-
if (identity === "CLI") return `CLI/${cliVersion} CodeBuddy/${cliVersion}`;
|
|
666
|
-
return `WorkBuddy/${clientVersion} workbuddy-ai/${clientVersion} CLI/${cliVersion}`;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
export const _resetWorkBuddyCnClientVersionCache = accessor("workbuddyCnClient").reset;
|
|
670
|
-
|
|
671
562
|
export const getKimiCliVersion = accessor("kimiCli").get;
|
|
672
563
|
|
|
673
564
|
export const getCodeBuddyVersion = accessor("codebuddy").get;
|
|
674
565
|
export const getCodeBuddyCnVersion = accessor("codebuddyCn").get;
|
|
566
|
+
|
|
675
567
|
/**
|
|
676
568
|
* The CodeBuddy User-Agent.
|
|
677
569
|
*
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static in-code registry of provider × category × tier cooldown rules (D19).
|
|
3
|
+
*
|
|
4
|
+
* The registry ships empty by default: before a rule is filled in, behavior is
|
|
5
|
+
* byte-identical to the old hardcoded constants. Rules are keyed by
|
|
6
|
+
* `(providerId, category, tier)` and, when present, replace the provider's old
|
|
7
|
+
* cooldown constant for that combination — they sit between the provider-stated
|
|
8
|
+
* window (which always wins, D18) and the old constant/env fallback.
|
|
9
|
+
*
|
|
10
|
+
* The initial content is the example from the approved proposal (part 03):
|
|
11
|
+
* Trae's daily-quota verdict (`model_unreachable`, upstream 4008) cools a free
|
|
12
|
+
* account for a full day and a paid/pro account for 15 minutes (D17 — `paid`
|
|
13
|
+
* never gets `0`, which would hammer the upstream on a wrong verdict).
|
|
14
|
+
*/
|
|
15
|
+
import type { AccountErrorCategory } from "./account-error-classification";
|
|
16
|
+
import type { AccountTier } from "./account-tier";
|
|
17
|
+
|
|
18
|
+
export type CooldownRuleKey = {
|
|
19
|
+
readonly providerId: string;
|
|
20
|
+
readonly category: AccountErrorCategory;
|
|
21
|
+
readonly tier: AccountTier;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type TierRules = Partial<Record<NonNullable<AccountTier>, number>>;
|
|
25
|
+
type CategoryRules = Partial<Record<AccountErrorCategory, TierRules>>;
|
|
26
|
+
type ProviderRules = Record<string, CategoryRules>;
|
|
27
|
+
|
|
28
|
+
const DAY = 24 * 60 * 60 * 1000;
|
|
29
|
+
const MINUTE = 60 * 1000;
|
|
30
|
+
|
|
31
|
+
const TRAE_RULES: CategoryRules = {
|
|
32
|
+
model_unreachable: {
|
|
33
|
+
free: DAY,
|
|
34
|
+
paid: 15 * MINUTE,
|
|
35
|
+
pro: 15 * MINUTE,
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const COOLDOWN_RULES: ProviderRules = {
|
|
40
|
+
trae: TRAE_RULES,
|
|
41
|
+
// Trae CN is the same upstream product under a second realm id — the
|
|
42
|
+
// classifier already treats the two identically, so the rules alias.
|
|
43
|
+
traecn: TRAE_RULES,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Resolves a cooldown rule for `(providerId, category, tier)`.
|
|
48
|
+
*
|
|
49
|
+
* Returns `undefined` when no rule exists — for an unknown provider, an
|
|
50
|
+
* unstored category, or an unknown tier — which is the signal to keep the old
|
|
51
|
+
* constant/fallback behavior.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveCooldownRule(key: CooldownRuleKey): number | undefined {
|
|
54
|
+
if (key.tier === null || key.tier === undefined) return undefined;
|
|
55
|
+
return COOLDOWN_RULES[key.providerId.toLowerCase()]?.[key.category]?.[key.tier];
|
|
56
|
+
}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* `bundledModelCatalog` is called during startup seeding and again whenever a
|
|
5
|
-
* caller rebuilds the routing/console catalog. Caching the loader *promise*
|
|
6
|
-
* (not just the resolved value) makes concurrent and repeated calls for one
|
|
7
|
-
* provider share a single load, and lets the dynamic catalog imports run once
|
|
8
|
-
* per process. A rejected load is evicted so a later call can retry.
|
|
2
|
+
* In-process caches for model catalogs, model discovery, and client/provider versions.
|
|
9
3
|
*/
|
|
4
|
+
|
|
10
5
|
import type { ModelDefinition } from "../provider-model-definition";
|
|
11
6
|
import { trackModelCatalogLoad } from "../../observability/performance-metrics";
|
|
12
7
|
import { resolveRedisClient } from "../../persistence/redis";
|
|
13
8
|
import { cachedRead } from "../../console/shared/read-through-cache";
|
|
9
|
+
import { TtlCacheFamily } from "../../persistence/ttl-cache";
|
|
10
|
+
import { retryWithBackoff } from "../../network/retry";
|
|
11
|
+
|
|
12
|
+
/* -------------------------------------------------------------------------- */
|
|
13
|
+
/* 1. Model Catalog Cache */
|
|
14
|
+
/* -------------------------------------------------------------------------- */
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Provider entries retained before the least-recently-used catalog is evicted.
|
|
@@ -37,8 +38,7 @@ const catalogCache = new Map<string, Promise<readonly ModelDefinition[]>>();
|
|
|
37
38
|
/**
|
|
38
39
|
* Evicts the least-recently-used provider before inserting a new one once the
|
|
39
40
|
* cache is at its bound. `Map` preserves insertion order and every cache hit
|
|
40
|
-
* re-inserts its entry at the tail, so the head is the LRU key.
|
|
41
|
-
* bound the process-lifetime cache pinned one catalog per provider forever.
|
|
41
|
+
* re-inserts its entry at the tail, so the head is the LRU key.
|
|
42
42
|
*/
|
|
43
43
|
function evictLeastRecentlyUsedCatalog(maxEntries: number): void {
|
|
44
44
|
if (catalogCache.size < maxEntries) return;
|
|
@@ -87,13 +87,65 @@ export function resetModelCatalogCacheForTesting(): void {
|
|
|
87
87
|
catalogCache.clear();
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
/**
|
|
91
|
-
* Live entry count, for the `/metrics` gauge.
|
|
92
|
-
*
|
|
93
|
-
* Exported so a rebuild that saturates the cap is visible from outside the
|
|
94
|
-
* process: before this, every in-process cache except the quota tier was
|
|
95
|
-
* invisible, and growth could only be found with a heap dump.
|
|
96
|
-
*/
|
|
90
|
+
/** Live entry count, for the `/metrics` gauge. */
|
|
97
91
|
export function modelCatalogCacheSize(): number {
|
|
98
92
|
return catalogCache.size;
|
|
99
93
|
}
|
|
94
|
+
|
|
95
|
+
/* -------------------------------------------------------------------------- */
|
|
96
|
+
/* 2. Model Discovery Cache */
|
|
97
|
+
/* -------------------------------------------------------------------------- */
|
|
98
|
+
|
|
99
|
+
const MODEL_DISCOVERY_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
100
|
+
const discoveryCaches = new TtlCacheFamily<readonly ModelDefinition[]>({
|
|
101
|
+
defaultTtlMs: MODEL_DISCOVERY_CACHE_TTL_MS,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
export interface CachedModelDiscoveryOptions {
|
|
105
|
+
readonly ttlMs?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Returns cached models, retrying null/empty loads on the next call. */
|
|
109
|
+
export async function getCachedModelDiscovery(
|
|
110
|
+
key: string,
|
|
111
|
+
loader: () => Promise<readonly ModelDefinition[] | null>,
|
|
112
|
+
options: CachedModelDiscoveryOptions = {},
|
|
113
|
+
): Promise<readonly ModelDefinition[] | null> {
|
|
114
|
+
return discoveryCaches.for(options.ttlMs).load(key, loader, {
|
|
115
|
+
namespace: "model-discovery",
|
|
116
|
+
shouldCache: (models) => models.length > 0,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Drops all cached discoveries. Test-only. */
|
|
121
|
+
export function resetModelDiscoveryCacheForTesting(): void {
|
|
122
|
+
discoveryCaches.clear();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* -------------------------------------------------------------------------- */
|
|
126
|
+
/* 3. Provider Version Cache */
|
|
127
|
+
/* -------------------------------------------------------------------------- */
|
|
128
|
+
|
|
129
|
+
const VERSION_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
130
|
+
const versionCaches = new TtlCacheFamily<string>({ defaultTtlMs: VERSION_CACHE_TTL_MS });
|
|
131
|
+
|
|
132
|
+
export interface CachedVersionOptions {
|
|
133
|
+
readonly ttlMs?: number;
|
|
134
|
+
readonly maxRetries?: number;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function getCachedVersion(
|
|
138
|
+
key: string,
|
|
139
|
+
loader: () => Promise<string | null>,
|
|
140
|
+
options: CachedVersionOptions = {},
|
|
141
|
+
): Promise<string | null> {
|
|
142
|
+
const loadWithRetry = () => retryWithBackoff(loader, { maxRetries: options.maxRetries ?? 2 });
|
|
143
|
+
return versionCaches.for(options.ttlMs).load(key, loadWithRetry, {
|
|
144
|
+
namespace: "provider-version",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Drops all cached versions. Test-only. */
|
|
149
|
+
export function resetVersionCacheForTesting(): void {
|
|
150
|
+
versionCaches.clear();
|
|
151
|
+
}
|
|
@@ -60,6 +60,9 @@ export async function seedBundledModels(
|
|
|
60
60
|
// states the tier, so the flag is carried rather than derived.
|
|
61
61
|
freeTier: definition.freeTier ?? null,
|
|
62
62
|
dialect: definition.dialect ?? null,
|
|
63
|
+
// Display-only: a static catalog that declares no warnings clears any
|
|
64
|
+
// stale value on the next boot rather than leaving an old banner.
|
|
65
|
+
warningMetadata: definition.warnings ?? null,
|
|
63
66
|
source: "builtin",
|
|
64
67
|
sourceUpdatedAt: now,
|
|
65
68
|
enabled: true,
|
|
@@ -90,6 +93,7 @@ export async function seedBundledModels(
|
|
|
90
93
|
proOnly: sql`excluded.pro_only`,
|
|
91
94
|
freeTier: sql`excluded.free_tier`,
|
|
92
95
|
dialect: sql`excluded.dialect`,
|
|
96
|
+
warningMetadata: sql`excluded.warning_metadata`,
|
|
93
97
|
source: sql`'builtin'`,
|
|
94
98
|
sourceUpdatedAt: sql`excluded.source_updated_at`,
|
|
95
99
|
},
|
|
@@ -10,7 +10,7 @@ import { ProviderRegistry } from "../provider-registry";
|
|
|
10
10
|
import { OpenAICompatibleAdapter } from "../adapters/compatible-adapter";
|
|
11
11
|
import { resolveByokWireProfile } from "./byok-wire-profile";
|
|
12
12
|
import { BUNDLED_PROVIDER_MODULES } from "../default-registry";
|
|
13
|
-
import { getCachedModels } from "./
|
|
13
|
+
import { getCachedModels } from "./provider-caches";
|
|
14
14
|
import { seedBundledModels } from "./provider-catalog-seeder";
|
|
15
15
|
import type { CartethyiaDatabase } from "../../persistence/db-handle";
|
|
16
16
|
import { providers } from "../../persistence/schema";
|