cartethyia 2.8.0 → 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 +3 -3
- package/dist/dashboard/assets/{BannedPage-Cc0vKpMG.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-Bqj2aa1T.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-CXsaOAO2.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BeLpJ4ma.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-DnV0uZ3m.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-CBxAjo63.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-B5yEE0k6.js → HealthEventsModal-Clq8E9cW.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BWFLECmz.js → InjectSystemPromptPanel-6Teoq9Se.js} +1 -1
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CgoPc5B9.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-D9bFQern.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-B_p4tL8k.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-D_0PiZtg.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-CLI2bJTK.js → ProvidersPage-C3fYuu6i.js} +1 -1
- 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-DA-a1iSN.js → QuotaPage-D1RV_2BX.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-CctTga2C.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-febLU4r1.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-M6fvR5Wz.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-nyeuRqz9.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BFOlvrJC.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-CqTLw5e7.js → assert-BMcj1xZE.js} +1 -1
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-C83EqLB0.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-D1xn7pIe.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-DU3Lq5Lm.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-Dw1U_drK.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CEL5Sg_J.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BjFR5UHy.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-HvBW0AjI.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CECVELyy.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-DYYofQ7W.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSu3gFlt.js → entry-DScKYvZj.js} +3 -3
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DLW4i8zK.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-1-fCqe64.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DGvU2oLK.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-iNnO1X2K.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-0q8UGypb.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-C0w2bQjJ.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-M5aJ_xCa.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-BKeQGT3K.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-CivAk3da.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-CpzvI5ep.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/{routing-BFQX2VBc.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-CXbck0jG.js → select-oO1FxMVb.js} +1 -1
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-C_XvMHh9.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DggRiCxE.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-ClFzfbYp.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-CTIFxKqS.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BClG3yWj.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 +51 -51
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +1 -1
- package/src/boot/dependencies.ts +4 -6
- package/src/config/providers.ts +6 -5
- package/src/config/spec.ts +8 -8
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -2
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/observability/live.ts +2 -2
- 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 +2 -2
- package/src/console/providers/catalog/store.ts +1914 -1907
- 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-tenant.ts +5 -5
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +1 -1
- 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/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/{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} +7 -7
- 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 +2 -2
- package/src/network/ssrf.ts +1 -1
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/observability/telemetry-buffer.ts +1 -1
- package/src/persistence/schema.ts +9 -0
- package/src/persistence/ttl-cache.ts +1 -1
- package/src/protocol/codecs.ts +58 -1
- package/src/protocol/request/messages.ts +31 -18
- package/src/protocol/response/messages.ts +34 -7
- 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 +5 -0
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +7 -3
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -739
- package/src/providers/default-registry.ts +76 -0
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +6 -2
- package/src/providers/discovery/probing-service.ts +7 -0
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +11 -0
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +10 -10
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +5 -5
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +4 -4
- package/src/providers/integrations/buddy/{buddy-identity.ts → headers.ts} +138 -140
- 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/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +3 -4
- 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/cursor/cursor-auth.ts +1 -1
- 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-shared.ts +1 -1
- package/src/providers/integrations/cursor/cursor.ts +485 -70
- 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/factory/factory-oauth.ts +16 -7
- package/src/providers/integrations/freebuff/freebuff.ts +2 -2
- 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 +4 -4
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/hermes/hermes.ts +34 -5
- 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-oauth.ts +2 -2
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-protocol.ts +0 -3
- package/src/providers/integrations/perch/perch.ts +3 -3
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +19 -113
- package/src/providers/integrations/qoder/qoder-auth.ts +8 -1
- package/src/providers/integrations/qoder/qoder-catalog.ts +1 -1
- package/src/providers/integrations/qoder/qoder-chat.ts +25 -8
- package/src/providers/integrations/qoder/qoder-checkin.ts +1 -1
- 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 -25
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-quota.ts +15 -1
- 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/zro/zro.ts +2 -1
- package/src/providers/operations/account-refresh-status.ts +14 -0
- package/src/providers/operations/client-versions.ts +95 -30
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/provider-caches.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +22 -25
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +2 -2
- package/src/providers/provider-metadata.ts +30 -0
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/refresh.ts +25 -3
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/attempt-loop.ts +3 -3
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +1 -1
- package/src/transport/dispatch/upstream.ts +1 -1
- package/src/transport/shutdown-notice.ts +1 -1
- 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-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +0 -2
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/src/console/providers/catalog/discover-constants.ts +0 -6
- package/src/network/pool-health.ts +0 -198
- 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-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 -188
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -179
- 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 -870
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -481
- /package/dist/dashboard/assets/{app-DIXLjojg.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-DIXLjojg.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{byte-accounting.ts → accounting.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
- /package/src/network/{rate-limit-verdict.ts → verdict.ts} +0 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// SenseNova providers (CN + Intl) — bearer-authenticated OpenAI-compatible
|
|
2
|
+
// chat + image generation.
|
|
3
|
+
//
|
|
4
|
+
// SenseNova API keys are per-site: keys created on platform.sensenova.cn are
|
|
5
|
+
// rejected by token.sensenova.ai with 401 {"error":{"code":16,"message":"Forbidden"}}
|
|
6
|
+
// (and vice versa), so each deployment is its own provider with its own host
|
|
7
|
+
// and catalog — the same split as CodeBuddy cb/cbcn.
|
|
8
|
+
//
|
|
9
|
+
// Wire facts:
|
|
10
|
+
// - Chat is OpenAI-compatible `/v1/chat/completions` with Bearer auth.
|
|
11
|
+
// - Image generation is `/v1/images/generations` (OpenAI-shaped `{model,
|
|
12
|
+
// prompt, n, size, output_format, response_format, watermark,
|
|
13
|
+
// prompt_extend}`), answering `{data: [{url|b64_json}]}`.
|
|
14
|
+
// - Thinking streams under `reasoning` (delta + message) rather than
|
|
15
|
+
// `reasoning_content`; the shared compatible adapter's chat decoder maps
|
|
16
|
+
// it onto the canonical reasoning event.
|
|
17
|
+
|
|
18
|
+
import { defineModel, type ModelDefinition } from "../../provider-model-definition";
|
|
19
|
+
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
20
|
+
import {
|
|
21
|
+
fetchOpenAICompatibleModels,
|
|
22
|
+
} from "../../discovery/openai-model-discovery";
|
|
23
|
+
|
|
24
|
+
/** Chat path below each realm's `/v1` base root. */
|
|
25
|
+
const SENSENOVA_CHAT_PATH = "/chat/completions";
|
|
26
|
+
/** Image-generation path below each realm's `/v1` base root. */
|
|
27
|
+
const SENSENOVA_IMAGE_PATH = "/images/generations";
|
|
28
|
+
|
|
29
|
+
export const SENSENOVA_PROVIDER_ID = "sensenova" as const;
|
|
30
|
+
export const SENSENOVA_INTL_PROVIDER_ID = "sensenova-intl" as const;
|
|
31
|
+
|
|
32
|
+
function sensenovaSpec(providerId: string): ApiKeyProviderSpec {
|
|
33
|
+
return {
|
|
34
|
+
provider_id: providerId as ApiKeyProviderSpec["provider_id"],
|
|
35
|
+
endpoint_paths_by_wire_family: { chat: SENSENOVA_CHAT_PATH },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** SenseNova CN adapter spec. */
|
|
40
|
+
export const SENSENOVA_SPEC: ApiKeyProviderSpec = sensenovaSpec(SENSENOVA_PROVIDER_ID);
|
|
41
|
+
|
|
42
|
+
/** SenseNova Intl adapter spec. */
|
|
43
|
+
export const SENSENOVA_INTL_SPEC: ApiKeyProviderSpec = sensenovaSpec(SENSENOVA_INTL_PROVIDER_ID);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Shared chat roster (both realms expose the same model families; the intl
|
|
47
|
+
* deployment advertises fewer static rows, and live discovery fills both).
|
|
48
|
+
*
|
|
49
|
+
* Image rows are media-generation rows (serviceKind `imageGeneration`), not
|
|
50
|
+
* chat rows — they answer `/v1/images/generations` and are routed by the
|
|
51
|
+
* native image route.
|
|
52
|
+
*/
|
|
53
|
+
const SENSENOVA_CHAT_MODELS: readonly string[] = [
|
|
54
|
+
"sensenova-6.8-flash",
|
|
55
|
+
"sensenova-6.8-flash-lite",
|
|
56
|
+
"sensenova-6.7-flash-lite",
|
|
57
|
+
"deepseek-flash",
|
|
58
|
+
"deepseek-v4-flash",
|
|
59
|
+
"glm-5.3",
|
|
60
|
+
"glm-5.2",
|
|
61
|
+
"kimi-k3",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
function makeChatModels(providerId: string): ModelDefinition[] {
|
|
65
|
+
return SENSENOVA_CHAT_MODELS.map((id) =>
|
|
66
|
+
defineModel({
|
|
67
|
+
id,
|
|
68
|
+
providerId,
|
|
69
|
+
wireFamily: "chat",
|
|
70
|
+
endpoint: SENSENOVA_CHAT_PATH,
|
|
71
|
+
ctx: 200_000,
|
|
72
|
+
out: 32_000,
|
|
73
|
+
reasoning: true,
|
|
74
|
+
toolCall: true,
|
|
75
|
+
}),
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function makeImageModels(providerId: string): ModelDefinition[] {
|
|
80
|
+
return [
|
|
81
|
+
defineModel({
|
|
82
|
+
id: "sensenova-u1.5-lite",
|
|
83
|
+
providerId,
|
|
84
|
+
wireFamily: "chat",
|
|
85
|
+
serviceKind: "imageGeneration",
|
|
86
|
+
endpoint: SENSENOVA_IMAGE_PATH,
|
|
87
|
+
ctx: null,
|
|
88
|
+
out: null,
|
|
89
|
+
toolCall: false,
|
|
90
|
+
output: ["image"],
|
|
91
|
+
}),
|
|
92
|
+
defineModel({
|
|
93
|
+
id: "sensenova-u1.5-fast",
|
|
94
|
+
providerId,
|
|
95
|
+
wireFamily: "chat",
|
|
96
|
+
serviceKind: "imageGeneration",
|
|
97
|
+
endpoint: SENSENOVA_IMAGE_PATH,
|
|
98
|
+
ctx: null,
|
|
99
|
+
out: null,
|
|
100
|
+
toolCall: false,
|
|
101
|
+
output: ["image"],
|
|
102
|
+
}),
|
|
103
|
+
defineModel({
|
|
104
|
+
id: "sensenova-u1-fast",
|
|
105
|
+
providerId,
|
|
106
|
+
wireFamily: "chat",
|
|
107
|
+
serviceKind: "imageGeneration",
|
|
108
|
+
endpoint: SENSENOVA_IMAGE_PATH,
|
|
109
|
+
ctx: null,
|
|
110
|
+
out: null,
|
|
111
|
+
toolCall: false,
|
|
112
|
+
output: ["image"],
|
|
113
|
+
}),
|
|
114
|
+
];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Full CN catalog: chat + image rows. */
|
|
118
|
+
export const SENSENOVA_MODELS: readonly ModelDefinition[] = [
|
|
119
|
+
...makeChatModels(SENSENOVA_PROVIDER_ID),
|
|
120
|
+
...makeImageModels(SENSENOVA_PROVIDER_ID),
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
/** Full Intl catalog: chat + image rows. */
|
|
124
|
+
export const SENSENOVA_INTL_MODELS: readonly ModelDefinition[] = [
|
|
125
|
+
...makeChatModels(SENSENOVA_INTL_PROVIDER_ID),
|
|
126
|
+
...makeImageModels(SENSENOVA_INTL_PROVIDER_ID),
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
/** Live `/v1/models` listing for one realm. */
|
|
130
|
+
export function discoverSensenovaModels(options: {
|
|
131
|
+
readonly baseUrl: string;
|
|
132
|
+
readonly credential?: string;
|
|
133
|
+
readonly fetcher?: typeof fetch;
|
|
134
|
+
readonly providerId: string;
|
|
135
|
+
}): Promise<readonly ModelDefinition[] | null> {
|
|
136
|
+
return fetchOpenAICompatibleModels({
|
|
137
|
+
baseUrl: options.baseUrl,
|
|
138
|
+
providerId: options.providerId,
|
|
139
|
+
...(typeof options.credential === "string" && options.credential.trim().length > 0
|
|
140
|
+
? { headers: { authorization: `Bearer ${options.credential}` } }
|
|
141
|
+
: {}),
|
|
142
|
+
...(options.fetcher === undefined ? {} : { fetcher: options.fetcher }),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -317,6 +317,13 @@ function logTraeQuotaMiss(errors: readonly string[]): void {
|
|
|
317
317
|
log.warn(`[quota] trae surfaces unavailable: ${errors.join("; ")}`);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
+
/** Only this exact response from both quota surfaces on both realms is terminal auth evidence. */
|
|
321
|
+
function isTraeAuthInvalidation(errors: readonly string[]): boolean {
|
|
322
|
+
return errors.length === 4 && errors.every((error) =>
|
|
323
|
+
/HTTP 401\s+\{[^}]*"code"\s*:\s*1001\b/i.test(error),
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
|
|
320
327
|
/**
|
|
321
328
|
* Reads one Trae account's quota.
|
|
322
329
|
*
|
|
@@ -421,7 +428,14 @@ export async function fetchTraeQuota(
|
|
|
421
428
|
// The detail is kept for the log instead, where it cannot be read as a
|
|
422
429
|
// balance.
|
|
423
430
|
logTraeQuotaMiss(errors);
|
|
424
|
-
|
|
431
|
+
const authInvalidated = isTraeAuthInvalidation(errors);
|
|
432
|
+
return {
|
|
433
|
+
source: "trae",
|
|
434
|
+
plan: null,
|
|
435
|
+
windows: [],
|
|
436
|
+
error: authInvalidated ? errors.join("; ") : null,
|
|
437
|
+
...(authInvalidated ? { authInvalidated: true } : {}),
|
|
438
|
+
};
|
|
425
439
|
}
|
|
426
440
|
return {
|
|
427
441
|
source: "trae",
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// Vercel AI Gateway provider — TypeScript, Vercel AI Gateway, Bun gateway.
|
|
2
|
+
//
|
|
3
|
+
// Vercel AI Gateway is an OpenAI-compatible routing front for 500+ models
|
|
4
|
+
// across providers. The API key (`vck_...`) is bearer-authenticated against
|
|
5
|
+
// `https://ai-gateway.vercel.sh/v1`.
|
|
6
|
+
//
|
|
7
|
+
// Verified live 2026-11-11 with a free-tier key:
|
|
8
|
+
// - GET /v1/models → 200, 506 rows (OpenRouter-shaped list)
|
|
9
|
+
// - POST /v1/chat/completions → 200 for nvidia/nemotron-3.5-lightning-free
|
|
10
|
+
// - POST /v1/chat/completions → 403 `no_providers_available` for the other
|
|
11
|
+
// zero-priced rows (reflection/beam*, humansand/ampersand-v0.1,
|
|
12
|
+
// stealth/glyph-cluster) — listed at $0 but gated behind a paid/Pro plan.
|
|
13
|
+
// - GET /v1/credits → { balance, token_pass, total_used }
|
|
14
|
+
//
|
|
15
|
+
// The static roster below carries the five $0-priced rows, so the free section
|
|
16
|
+
// is populated before any fetch. Four of them are marked `proOnly` because the
|
|
17
|
+
// upstream refuses them on a free plan (verified live); discovery still finds
|
|
18
|
+
// them and the badge tracks the upstream's own listing.
|
|
19
|
+
|
|
20
|
+
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
21
|
+
import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
|
|
22
|
+
import { defineModel, type ModelDefinition } from "../../provider-model-definition";
|
|
23
|
+
|
|
24
|
+
const VERCEL_PROVIDER_ID = "vercel" as const;
|
|
25
|
+
|
|
26
|
+
/** Chat path below the `/v1` base root. */
|
|
27
|
+
const VERCEL_CHAT_PATH = "/chat/completions";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Vercel AI Gateway adapter spec: plain bearer, OpenAI-compatible chat.
|
|
31
|
+
*
|
|
32
|
+
* The gateway accepts standard OpenAI fields (`max_tokens`, `temperature`,
|
|
33
|
+
* `stop`, `tools`, `tool_choice`, `reasoning`, `response_format`, …) and
|
|
34
|
+
* reports usage/cost in extended `provider_metadata`. No bespoke headers are
|
|
35
|
+
* required beyond the bearer, so the generic API-key adapter serves it.
|
|
36
|
+
*/
|
|
37
|
+
export const VERCEL_SPEC: ApiKeyProviderSpec = {
|
|
38
|
+
provider_id: VERCEL_PROVIDER_ID,
|
|
39
|
+
endpoint_paths_by_wire_family: {},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Default rows for the Vercel AI Gateway provider (2026-11-11).
|
|
44
|
+
*
|
|
45
|
+
* Verified live with a free-tier key: only
|
|
46
|
+
* `nvidia/nemotron-3.5-lightning-free` is served on a free plan; the other
|
|
47
|
+
* zero-priced listing rows are refused with 403 `no_providers_available`, so
|
|
48
|
+
* they are not seeded. The two billed rows (`meituan/longcat-2.5`,
|
|
49
|
+
* `inception/mercury-3`) are the operator's picks and carry the capabilities
|
|
50
|
+
* the upstream itself declares — LongCat is the vision-capable coding row,
|
|
51
|
+
* Mercury 3 is the diffusion row. Everything else comes from live discovery.
|
|
52
|
+
*/
|
|
53
|
+
export const VERCEL_DEFAULT_MODELS: readonly ModelDefinition[] = [
|
|
54
|
+
defineModel({
|
|
55
|
+
id: "nvidia/nemotron-3.5-lightning-free",
|
|
56
|
+
wireFamily: "chat",
|
|
57
|
+
endpoint: VERCEL_CHAT_PATH,
|
|
58
|
+
ctx: 1_000_000,
|
|
59
|
+
out: 65_000,
|
|
60
|
+
reasoning: true,
|
|
61
|
+
toolCall: true,
|
|
62
|
+
free: true,
|
|
63
|
+
freeTier: true,
|
|
64
|
+
}),
|
|
65
|
+
defineModel({
|
|
66
|
+
id: "meituan/longcat-2.5",
|
|
67
|
+
wireFamily: "chat",
|
|
68
|
+
endpoint: VERCEL_CHAT_PATH,
|
|
69
|
+
ctx: 1_048_576,
|
|
70
|
+
out: 131_072,
|
|
71
|
+
vision: true,
|
|
72
|
+
reasoning: true,
|
|
73
|
+
toolCall: true,
|
|
74
|
+
}),
|
|
75
|
+
defineModel({
|
|
76
|
+
id: "inception/mercury-3",
|
|
77
|
+
wireFamily: "chat",
|
|
78
|
+
endpoint: VERCEL_CHAT_PATH,
|
|
79
|
+
ctx: 1_000_000,
|
|
80
|
+
out: 131_072,
|
|
81
|
+
reasoning: true,
|
|
82
|
+
toolCall: true,
|
|
83
|
+
}),
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Live `/v1/models` listing.
|
|
88
|
+
*
|
|
89
|
+
* The listing requires the API key, so the credential is forwarded when
|
|
90
|
+
* present; an unauthenticated fetch fails cleanly and the static roster stays
|
|
91
|
+
* authoritative. Every fetched row is kept as the shared reader resolved it
|
|
92
|
+
* (limits/modalities/reasoning/tool flags come from the upstream's own JSON).
|
|
93
|
+
*
|
|
94
|
+
* A fetched id the static roster already knows keeps the roster row whole, not
|
|
95
|
+
* the listing's fields: the upstream does not publish `reasoning`/`tool_call`
|
|
96
|
+
* keys or tier flags, so the shared reader would overwrite the roster's
|
|
97
|
+
* reasoning/tool/freeTier/proOnly statements with its conservative defaults.
|
|
98
|
+
* The roster is the canonical metadata for the models we know; the listing only
|
|
99
|
+
* adds genuinely new ids.
|
|
100
|
+
*/
|
|
101
|
+
export async function discoverVercelModels(options: {
|
|
102
|
+
readonly baseUrl: string;
|
|
103
|
+
readonly credential?: string;
|
|
104
|
+
readonly fetcher?: typeof fetch;
|
|
105
|
+
}): Promise<readonly ModelDefinition[] | null> {
|
|
106
|
+
const listed = await fetchOpenAICompatibleModels({
|
|
107
|
+
baseUrl: options.baseUrl,
|
|
108
|
+
providerId: "vercel",
|
|
109
|
+
...(typeof options.credential === "string" && options.credential.trim().length > 0
|
|
110
|
+
? { headers: { authorization: `Bearer ${options.credential}` } }
|
|
111
|
+
: {}),
|
|
112
|
+
...(options.fetcher === undefined ? {} : { fetcher: options.fetcher }),
|
|
113
|
+
});
|
|
114
|
+
if (listed === null) return null;
|
|
115
|
+
const known = new Map(VERCEL_DEFAULT_MODELS.map((model) => [model.modelId, model]));
|
|
116
|
+
return listed.map((model) => known.get(model.modelId) ?? model);
|
|
117
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Vercel AI Gateway quota collector.
|
|
2
|
+
//
|
|
3
|
+
// Reads `GET /v1/credits` (Bearer) — the gateway's credit surface. It returns
|
|
4
|
+
// a remaining balance (`balance`, USD string), an optional `token_pass`, and
|
|
5
|
+
// the total spend (`total_used`, USD string). No ceiling is reported (balance
|
|
6
|
+
// is remaining, not a limit), so the window carries absolute remaining/used
|
|
7
|
+
// values and no percent — the pooled credit sum still works. Never throws: a
|
|
8
|
+
// failed read returns a null-result so the router treats it as unknown rather
|
|
9
|
+
// than dead.
|
|
10
|
+
|
|
11
|
+
import type {
|
|
12
|
+
FetchLike,
|
|
13
|
+
ProviderQuotaResult,
|
|
14
|
+
ProviderQuotaWindow,
|
|
15
|
+
} from "../../quota/quota-contracts";
|
|
16
|
+
import {
|
|
17
|
+
cleanError,
|
|
18
|
+
number,
|
|
19
|
+
unsupportedQuota,
|
|
20
|
+
} from "../../quota/quota-contracts";
|
|
21
|
+
import type { QuotaCollectionContext } from "../../quota/quota-support";
|
|
22
|
+
|
|
23
|
+
const VERCEL_CREDITS_URL = "https://ai-gateway.vercel.sh/v1/credits";
|
|
24
|
+
|
|
25
|
+
function readCredits(
|
|
26
|
+
credential: string,
|
|
27
|
+
fetcher: FetchLike,
|
|
28
|
+
): Promise<Record<string, unknown> | null> {
|
|
29
|
+
return fetcher(VERCEL_CREDITS_URL, {
|
|
30
|
+
method: "GET",
|
|
31
|
+
headers: {
|
|
32
|
+
authorization: `Bearer ${credential}`,
|
|
33
|
+
accept: "application/json",
|
|
34
|
+
},
|
|
35
|
+
signal: AbortSignal.timeout(15_000),
|
|
36
|
+
})
|
|
37
|
+
.then(async (res) => {
|
|
38
|
+
if (!res.ok) return null;
|
|
39
|
+
try {
|
|
40
|
+
return (await res.json()) as Record<string, unknown>;
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
})
|
|
45
|
+
.catch(() => null);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Reads the Vercel AI Gateway credit balance and returns a normalized result. */
|
|
49
|
+
export async function fetchVercelQuota(
|
|
50
|
+
credential: string,
|
|
51
|
+
fetcher: FetchLike,
|
|
52
|
+
_context?: QuotaCollectionContext,
|
|
53
|
+
): Promise<ProviderQuotaResult> {
|
|
54
|
+
try {
|
|
55
|
+
const credits = await readCredits(credential, fetcher);
|
|
56
|
+
if (!credits) {
|
|
57
|
+
return unsupportedQuota("vercel");
|
|
58
|
+
}
|
|
59
|
+
const balance = number(credits["balance"]);
|
|
60
|
+
const totalUsed = number(credits["total_used"]);
|
|
61
|
+
if (balance === null && totalUsed === null) {
|
|
62
|
+
return {
|
|
63
|
+
source: "vercel",
|
|
64
|
+
plan: null,
|
|
65
|
+
windows: [],
|
|
66
|
+
error: "Vercel AI Gateway /v1/credits returned no usable numbers",
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const windows: ProviderQuotaWindow[] = [
|
|
70
|
+
{
|
|
71
|
+
kind: "credits",
|
|
72
|
+
label: "AI Gateway credits",
|
|
73
|
+
accounting: "pooled",
|
|
74
|
+
usedPercent: null,
|
|
75
|
+
remainingPercent: null,
|
|
76
|
+
resetsAt: null,
|
|
77
|
+
used: totalUsed,
|
|
78
|
+
limit: null,
|
|
79
|
+
remaining: balance,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
return {
|
|
83
|
+
source: "vercel",
|
|
84
|
+
plan: null,
|
|
85
|
+
windows,
|
|
86
|
+
error: null,
|
|
87
|
+
};
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
source: "vercel",
|
|
91
|
+
plan: null,
|
|
92
|
+
windows: [],
|
|
93
|
+
error: cleanError(error),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -135,8 +135,8 @@ export class XaiOAuthClient extends OAuthDeviceFlow {
|
|
|
135
135
|
protected override readonly tokenUrl = XAI_TOKEN_URL;
|
|
136
136
|
protected override readonly scopes = XAI_SCOPE;
|
|
137
137
|
|
|
138
|
-
override async startDeviceAuth(
|
|
139
|
-
const response = await this.
|
|
138
|
+
override async startDeviceAuth(context?: OAuthDeviceFlowContext): Promise<OAuthDeviceStartResult> {
|
|
139
|
+
const response = await this.fetchFor(context)(XAI_DEVICE_URL, {
|
|
140
140
|
method: "POST",
|
|
141
141
|
headers: formHeaders(),
|
|
142
142
|
body: new URLSearchParams({ client_id: XAI_CLIENT_ID, scope: XAI_SCOPE }),
|
|
@@ -157,9 +157,9 @@ export class XaiOAuthClient extends OAuthDeviceFlow {
|
|
|
157
157
|
|
|
158
158
|
override async pollDeviceAuth(
|
|
159
159
|
deviceAuthId: string,
|
|
160
|
-
|
|
160
|
+
context?: OAuthDeviceFlowContext,
|
|
161
161
|
): Promise<OAuthDevicePollResult> {
|
|
162
|
-
const response = await this.
|
|
162
|
+
const response = await this.fetchFor(context)(XAI_TOKEN_URL, {
|
|
163
163
|
method: "POST",
|
|
164
164
|
headers: formHeaders(),
|
|
165
165
|
body: new URLSearchParams({
|
|
@@ -203,7 +203,7 @@ export class XaiOAuthClient extends OAuthDeviceFlow {
|
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
205
|
const result = this.parseTokenResponse(payload);
|
|
206
|
-
const identity = await fetchXaiIdentity(result.access, this.
|
|
206
|
+
const identity = await fetchXaiIdentity(result.access, this.fetchFor(context));
|
|
207
207
|
const authState = xaiAuthState(identity);
|
|
208
208
|
return {
|
|
209
209
|
status: "complete",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
import { createHash } from "node:crypto";
|
|
23
23
|
import { sleep } from "../../../shared/sleep";
|
|
24
24
|
import { asRecord, asTrimmedString } from "../../../shared/coerce";
|
|
25
|
-
import type { ValidatedFetch } from "../../../network/
|
|
25
|
+
import type { ValidatedFetch } from "../../../network/egress/fetch";
|
|
26
26
|
|
|
27
27
|
const ZCODE = "https://zcode.z.ai";
|
|
28
28
|
const BILLING = `${ZCODE}/api/v1/zcode-plan/billing`;
|
|
@@ -62,10 +62,10 @@ export class ZcodeStartPlanOAuthClient extends OAuthDeviceFlow {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
override async startDeviceAuth(
|
|
65
|
-
|
|
65
|
+
context?: OAuthDeviceFlowContext,
|
|
66
66
|
): Promise<OAuthDeviceStartResult & { providerState: string }> {
|
|
67
67
|
const pollToken = crypto.randomBytes(32).toString("hex");
|
|
68
|
-
const response = await this.
|
|
68
|
+
const response = await this.fetchFor(context)(INIT_URL, {
|
|
69
69
|
method: "POST",
|
|
70
70
|
headers: { ...JSON_HEADERS, authorization: `Bearer ${pollToken}` },
|
|
71
71
|
body: JSON.stringify({ provider: "zai" }),
|
|
@@ -95,7 +95,7 @@ export class ZcodeStartPlanOAuthClient extends OAuthDeviceFlow {
|
|
|
95
95
|
if (!pollToken) {
|
|
96
96
|
return { status: "failed", reason: "sign-in session lost its poll token" };
|
|
97
97
|
}
|
|
98
|
-
const response = await this.
|
|
98
|
+
const response = await this.fetchFor(context)(`${POLL_BASE}/${encodeURIComponent(deviceAuthId)}`, {
|
|
99
99
|
headers: { ...JSON_HEADERS, authorization: `Bearer ${pollToken}` },
|
|
100
100
|
});
|
|
101
101
|
if (response.status === 404) {
|
|
@@ -45,7 +45,6 @@ const ZRO_MODELS_RAW: readonly {
|
|
|
45
45
|
}[] = [
|
|
46
46
|
{ id: "deepseek-v4-flash-0731", contextLimit: 1_048_576, outputLimit: 64_000 },
|
|
47
47
|
{ id: "deepseek-v4.1-flash", contextLimit: 1_048_576, outputLimit: 64_000 },
|
|
48
|
-
{ id: "glm-5.3-flash", contextLimit: 1_048_576, outputLimit: 64_000 },
|
|
49
48
|
] as const;
|
|
50
49
|
|
|
51
50
|
export const ZRO_MODELS: readonly ModelDefinition[] = ZRO_MODELS_RAW.map((row) =>
|
|
@@ -79,6 +78,8 @@ export const ZRO_MODELS: readonly ModelDefinition[] = ZRO_MODELS_RAW.map((row) =
|
|
|
79
78
|
*/
|
|
80
79
|
export function zroModelDiscovery(): () => Promise<ProviderModelDiscovery> {
|
|
81
80
|
return async () => async (input) => {
|
|
81
|
+
// dynamic-import: cycle-break — model discovery is only imported at call time,
|
|
82
|
+
// so a provider that never runs discovery never pays for the OpenAI discovery graph.
|
|
82
83
|
const { fetchOpenAICompatibleModels } = await import("../../discovery/openai-model-discovery");
|
|
83
84
|
const base = input.baseUrl.replace(/\/+$/, "");
|
|
84
85
|
const models = await fetchOpenAICompatibleModels({
|
|
@@ -21,6 +21,7 @@ export type RefreshAccountStatusCode =
|
|
|
21
21
|
| "not_oauth"
|
|
22
22
|
| "static_token"
|
|
23
23
|
| "no_refresher"
|
|
24
|
+
| "auth_invalidated"
|
|
24
25
|
| "refresh_failed";
|
|
25
26
|
|
|
26
27
|
export interface RefreshAccountStatusOutcome {
|
|
@@ -54,6 +55,7 @@ interface LoadedAccount {
|
|
|
54
55
|
readonly credentialKind: string;
|
|
55
56
|
readonly status: string;
|
|
56
57
|
readonly staticToken: boolean;
|
|
58
|
+
readonly lastErrorCategory: string | null;
|
|
57
59
|
readonly refreshCiphertext: Buffer | null;
|
|
58
60
|
readonly expiresAt: Date | null;
|
|
59
61
|
}
|
|
@@ -64,6 +66,7 @@ async function loadAccount(
|
|
|
64
66
|
): Promise<LoadedAccount | undefined> {
|
|
65
67
|
const loaded = await loadAccountWithOauthState(db, accountId, {
|
|
66
68
|
includeStatus: true,
|
|
69
|
+
includeLastErrorCategory: true,
|
|
67
70
|
includeExpiry: true,
|
|
68
71
|
});
|
|
69
72
|
if (!loaded || loaded.status === undefined || loaded.expiresAt === undefined) return undefined;
|
|
@@ -73,6 +76,7 @@ async function loadAccount(
|
|
|
73
76
|
credentialKind: loaded.credentialKind,
|
|
74
77
|
status: loaded.status,
|
|
75
78
|
staticToken: loaded.staticToken,
|
|
79
|
+
lastErrorCategory: loaded.lastErrorCategory ?? null,
|
|
76
80
|
refreshCiphertext: loaded.refreshCiphertext,
|
|
77
81
|
expiresAt: loaded.expiresAt,
|
|
78
82
|
};
|
|
@@ -137,6 +141,16 @@ export async function refreshAccountStatus(
|
|
|
137
141
|
}
|
|
138
142
|
const statusBefore = account.status;
|
|
139
143
|
|
|
144
|
+
if (account.status === "disabled" && account.lastErrorCategory === "auth_invalidated") {
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
tokenRefreshed: false,
|
|
148
|
+
statusAfter: statusBefore,
|
|
149
|
+
code: "auth_invalidated",
|
|
150
|
+
error: "auth_invalidated",
|
|
151
|
+
category: "This account was rejected by the provider and requires re-authentication; automatic refresh is disabled.",
|
|
152
|
+
};
|
|
153
|
+
}
|
|
140
154
|
if (account.credentialKind !== "oauth") {
|
|
141
155
|
return {
|
|
142
156
|
ok: false,
|