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
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Real credit deductions for the Tencent "buddy" family (`cb`, `cbcn`). *
|
|
3
|
-
* Every provider in the family reads the same usage-detail endpoint —
|
|
4
|
-
* `POST {billingHost}/billing/meter/get-user-request-usage` — which answers the
|
|
5
|
-
* actual per-request deductions the billing meter recorded: when the request
|
|
6
|
-
* happened, which model served it, and how many credits it cost. That is the
|
|
7
|
-
* figure the reference gateways show as *real usage*, and until now we had no
|
|
8
|
-
* upstream usage-detail read at all: the console's usage view was built from
|
|
9
|
-
* synthetic activity events we report ourselves.
|
|
10
|
-
*
|
|
11
|
-
* This module is read-only and never throws. A usage read is a display
|
|
12
|
-
* concern, and a failure to read it must never take an account out of
|
|
13
|
-
* rotation or fail a request — so an unreachable, malformed, or empty response
|
|
14
|
-
* yields whatever was collected plus `partial: true`, and an account with no
|
|
15
|
-
* usage at all yields empty rows rather than an error.
|
|
16
|
-
*/
|
|
17
|
-
import type { FetchLike } from "../../quota/quota-contracts";
|
|
18
|
-
import { record as asRecord, text as asText } from "../../quota/quota-contracts";
|
|
19
|
-
import { resolveBearerToken } from "./buddy-quota-shared";
|
|
20
|
-
|
|
21
|
-
/** One aggregated (day, model) credit deduction. */
|
|
22
|
-
export interface BuddyUsageRow {
|
|
23
|
-
/** Calendar day the request was metered on, `YYYY-MM-DD`. */
|
|
24
|
-
readonly day: string;
|
|
25
|
-
/** The model id the upstream metered it against. */
|
|
26
|
-
readonly model: string;
|
|
27
|
-
/** Credits deducted for every request on that (day, model). */
|
|
28
|
-
readonly credit: number;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface BuddyUsageResult {
|
|
32
|
-
readonly rows: readonly BuddyUsageRow[];
|
|
33
|
-
/** Sum of every row's credits. */
|
|
34
|
-
readonly totalCredits: number;
|
|
35
|
-
/**
|
|
36
|
-
* True when the read stopped short: a page failed, the page cap was reached,
|
|
37
|
-
* or the payload was not the expected shape. The rows are what was collected
|
|
38
|
-
* and are still worth showing — they are just not guaranteed to be all of it.
|
|
39
|
-
*/
|
|
40
|
-
readonly partial: boolean;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export interface BuddyUsageFetchOptions {
|
|
44
|
-
/** `{billingHost}/billing/meter/get-user-request-usage` for this provider. */
|
|
45
|
-
readonly url: string;
|
|
46
|
-
/** Provider transport/identity headers; `Authorization` is added here. */
|
|
47
|
-
readonly headers: Record<string, string>;
|
|
48
|
-
readonly credential: string;
|
|
49
|
-
readonly fetcher: FetchLike;
|
|
50
|
-
/** Window width in days, clamped to the upstream's 30-day maximum. */
|
|
51
|
-
readonly days: number;
|
|
52
|
-
/** Account UID for the `X-User-Id` billing identity header. */
|
|
53
|
-
readonly uid?: string | undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** The upstream answers empty totals beyond its own window. */
|
|
57
|
-
const USAGE_MAX_DAYS = 30;
|
|
58
|
-
const USAGE_PAGE_SIZE = 200;
|
|
59
|
-
const USAGE_MAX_PAGES = 30;
|
|
60
|
-
const TIMEOUT_MS = 15_000;
|
|
61
|
-
|
|
62
|
-
/** `YYYY-MM-DD HH:MM:SS` in local time, the stamp format the endpoint takes. */
|
|
63
|
-
function localStamp(at: Date): string {
|
|
64
|
-
const pad = (value: number): string => String(value).padStart(2, "0");
|
|
65
|
-
return (
|
|
66
|
-
`${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())} ` +
|
|
67
|
-
`${pad(at.getHours())}:${pad(at.getMinutes())}:${pad(at.getSeconds())}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Reads one provider's usage detail over the last `days` days.
|
|
73
|
-
*
|
|
74
|
-
* Paginated, because the endpoint answers at most {@link USAGE_PAGE_SIZE} rows
|
|
75
|
-
* per call and an active account exceeds that quickly. The loop stops as soon
|
|
76
|
-
* as a page comes back short or the upstream's own `total` is accounted for;
|
|
77
|
-
* running into the page cap instead sets `partial`, so the console can say so
|
|
78
|
-
* rather than presenting a truncated figure as the whole one.
|
|
79
|
-
*
|
|
80
|
-
* `days` is sent alongside the time window: the reference gateway sends
|
|
81
|
-
* `startTime`/`endTime`, and the day count is what our own callers think in, so
|
|
82
|
-
* both go on the wire rather than making one side convert.
|
|
83
|
-
*/
|
|
84
|
-
export async function fetchBuddyRequestUsage(
|
|
85
|
-
options: BuddyUsageFetchOptions,
|
|
86
|
-
): Promise<BuddyUsageResult> {
|
|
87
|
-
const { url, headers, credential, fetcher, uid } = options;
|
|
88
|
-
const bearer = resolveBearerToken(credential);
|
|
89
|
-
if (bearer === null) return { rows: [], totalCredits: 0, partial: true };
|
|
90
|
-
|
|
91
|
-
const days = Math.max(1, Math.min(Math.floor(options.days) || USAGE_MAX_DAYS, USAGE_MAX_DAYS));
|
|
92
|
-
const now = Date.now();
|
|
93
|
-
const window = {
|
|
94
|
-
days,
|
|
95
|
-
startTime: localStamp(new Date(now - days * 86_400_000)),
|
|
96
|
-
endTime: localStamp(new Date(now)),
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
const rows: BuddyUsageRow[] = [];
|
|
100
|
-
// (day, model) → index into `rows`, so a model seen on two pages aggregates
|
|
101
|
-
// into one row instead of being listed twice.
|
|
102
|
-
const index = new Map<string, number>();
|
|
103
|
-
let totalCredits = 0;
|
|
104
|
-
let partial = false;
|
|
105
|
-
// Raw request rows seen, which is what the upstream's `total` counts — not
|
|
106
|
-
// the aggregated (day, model) rows above.
|
|
107
|
-
let requests = 0;
|
|
108
|
-
|
|
109
|
-
for (let page = 1; page <= USAGE_MAX_PAGES; page += 1) {
|
|
110
|
-
const pageResult = await fetchUsagePage({
|
|
111
|
-
url,
|
|
112
|
-
headers,
|
|
113
|
-
bearer,
|
|
114
|
-
fetcher,
|
|
115
|
-
uid,
|
|
116
|
-
body: { ...window, pageNum: page, pageSize: USAGE_PAGE_SIZE },
|
|
117
|
-
});
|
|
118
|
-
// A page that could not be read ends the walk with what is already
|
|
119
|
-
// collected: the rows are real, there are just fewer of them.
|
|
120
|
-
if (pageResult === null) {
|
|
121
|
-
partial = true;
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
const { pageRows, total } = pageResult;
|
|
125
|
-
for (const row of pageRows) {
|
|
126
|
-
const key = `${row.day}\u0000${row.model}`;
|
|
127
|
-
const at = index.get(key);
|
|
128
|
-
if (at === undefined) {
|
|
129
|
-
index.set(key, rows.length);
|
|
130
|
-
rows.push(row);
|
|
131
|
-
} else {
|
|
132
|
-
rows[at] = { ...row, credit: round6(rows[at]!.credit + row.credit) };
|
|
133
|
-
}
|
|
134
|
-
totalCredits += row.credit;
|
|
135
|
-
}
|
|
136
|
-
// An empty page means the end of the data, however many the upstream said
|
|
137
|
-
// it had; carrying on would only re-request it.
|
|
138
|
-
if (pageRows.length === 0) break;
|
|
139
|
-
requests += pageRows.length;
|
|
140
|
-
if (total !== undefined && requests >= total) break;
|
|
141
|
-
// A short page has no more to give, and the upstream's `total` is not
|
|
142
|
-
// always present: stopping here avoids one pointless round trip per read.
|
|
143
|
-
if (pageRows.length < USAGE_PAGE_SIZE) break;
|
|
144
|
-
// Only reaching the page cap means more may exist than we collected.
|
|
145
|
-
if (page === USAGE_MAX_PAGES) partial = true;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return { rows, totalCredits: Math.round(totalCredits * 100) / 100, partial };
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
interface UsagePage {
|
|
152
|
-
readonly pageRows: readonly BuddyUsageRow[];
|
|
153
|
-
/** The upstream's stated request total, when it stated one. */
|
|
154
|
-
readonly total: number | undefined;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/** One page of the usage-detail endpoint, or `null` when it could not be read. */
|
|
158
|
-
async function fetchUsagePage(args: {
|
|
159
|
-
readonly url: string;
|
|
160
|
-
readonly headers: Record<string, string>;
|
|
161
|
-
readonly bearer: string;
|
|
162
|
-
readonly fetcher: FetchLike;
|
|
163
|
-
readonly uid: string | undefined;
|
|
164
|
-
readonly body: Record<string, unknown>;
|
|
165
|
-
}): Promise<UsagePage | null> {
|
|
166
|
-
let response: Response;
|
|
167
|
-
try {
|
|
168
|
-
response = await args.fetcher(args.url, {
|
|
169
|
-
method: "POST",
|
|
170
|
-
headers: {
|
|
171
|
-
...args.headers,
|
|
172
|
-
...(args.uid === undefined || args.uid.length === 0 ? {} : { "X-User-Id": args.uid }),
|
|
173
|
-
Authorization: `Bearer ${args.bearer}`,
|
|
174
|
-
"Content-Type": "application/json",
|
|
175
|
-
Accept: "application/json",
|
|
176
|
-
},
|
|
177
|
-
body: JSON.stringify(args.body),
|
|
178
|
-
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
179
|
-
});
|
|
180
|
-
} catch {
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
|
-
if (!response.ok) return null;
|
|
184
|
-
|
|
185
|
-
let parsed: unknown;
|
|
186
|
-
try {
|
|
187
|
-
parsed = JSON.parse(await response.text());
|
|
188
|
-
} catch {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
const envelope = asRecord(parsed);
|
|
192
|
-
// A non-zero `code` is a provider-side error even on HTTP 200.
|
|
193
|
-
if (envelope !== null && "code" in envelope) {
|
|
194
|
-
const code = Number(envelope["code"]);
|
|
195
|
-
if (Number.isFinite(code) && code !== 0) return null;
|
|
196
|
-
}
|
|
197
|
-
const data = asRecord(envelope?.["data"]) ?? envelope;
|
|
198
|
-
const list = data?.["data"];
|
|
199
|
-
// Missing business data must not read as "zero usage": an account that has
|
|
200
|
-
// spent nothing and an account whose payload we could not parse must not
|
|
201
|
-
// look the same.
|
|
202
|
-
if (!Array.isArray(list)) return null;
|
|
203
|
-
|
|
204
|
-
const pageRows: BuddyUsageRow[] = [];
|
|
205
|
-
for (const entry of list) {
|
|
206
|
-
const row = asRecord(entry);
|
|
207
|
-
if (row === null) continue;
|
|
208
|
-
const day = (asText(row["requestTime"]) ?? "").slice(0, 10);
|
|
209
|
-
if (day.length === 0) continue;
|
|
210
|
-
const model = asText(row["model"]) ?? "unknown";
|
|
211
|
-
const credit = Number(row["credit"] ?? 0);
|
|
212
|
-
pageRows.push({ day, model, credit: Number.isFinite(credit) ? round6(credit) : 0 });
|
|
213
|
-
}
|
|
214
|
-
const rawTotal = data?.["total"];
|
|
215
|
-
const total = typeof rawTotal === "number" && Number.isFinite(rawTotal) ? rawTotal : undefined;
|
|
216
|
-
return { pageRows, total };
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function round6(value: number): number {
|
|
220
|
-
return Math.round(value * 1e6) / 1e6;
|
|
221
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where the buddy usage-detail read is stored and read back.
|
|
3
|
-
*
|
|
4
|
-
* The upstream billing meter is the source of truth and answers a whole window
|
|
5
|
-
* on every call, so rows are *snapshots*: upserted, never appended. What that
|
|
6
|
-
* buys the console is a stored figure — without it, every page open would
|
|
7
|
-
* re-hit the billing endpoint once per account, and a read that failed would
|
|
8
|
-
* render as "no usage at all" instead of the last number obtained.
|
|
9
|
-
*
|
|
10
|
-
* Deliberately not a request-path store: this is written by a maintenance pass
|
|
11
|
-
* and read by the console. Nothing here can fail a dispatch.
|
|
12
|
-
*/
|
|
13
|
-
import { and, desc, eq, gte, inArray, sql } from "drizzle-orm";
|
|
14
|
-
import type { CartethyiaDatabase } from "../../../persistence/db-handle";
|
|
15
|
-
import { buddyUsageSnapshots } from "../../../persistence/schema";
|
|
16
|
-
import type { BuddyUsageRow } from "./buddy-usage-shared";
|
|
17
|
-
|
|
18
|
-
/** One stored (day, model) bucket, as the console renders it. */
|
|
19
|
-
export interface BuddyUsageSnapshotRow extends BuddyUsageRow {
|
|
20
|
-
readonly syncedAt: string | null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Days of usage retained. The upstream's own window is 30. */
|
|
24
|
-
const RETENTION_DAYS = 30;
|
|
25
|
-
|
|
26
|
-
/** Oldest day a stored bucket can hold, as the `YYYY-MM-DD` key the table uses. */
|
|
27
|
-
function retentionCutoff(now: Date = new Date()): string {
|
|
28
|
-
return new Date(now.getTime() - RETENTION_DAYS * 86_400_000).toISOString().slice(0, 10);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Upserts one account's usage buckets.
|
|
33
|
-
*
|
|
34
|
-
* One statement for every row rather than one per row: a 30-day window on an
|
|
35
|
-
* active account is a few hundred buckets, and the sweep walks accounts.
|
|
36
|
-
* `credit` is replaced, not accumulated — the upstream's number for a bucket is
|
|
37
|
-
* authoritative, so re-reading a partial window must not double-count it.
|
|
38
|
-
*
|
|
39
|
-
* Returns the number of rows written; a failure returns 0 rather than throwing,
|
|
40
|
-
* because a snapshot that could not be stored is a stale display, not an error
|
|
41
|
-
* the caller must handle.
|
|
42
|
-
*/
|
|
43
|
-
export async function saveBuddyUsageSnapshots(
|
|
44
|
-
db: CartethyiaDatabase,
|
|
45
|
-
accountId: string,
|
|
46
|
-
rows: readonly BuddyUsageRow[],
|
|
47
|
-
): Promise<number> {
|
|
48
|
-
if (rows.length === 0) return 0;
|
|
49
|
-
const now = new Date();
|
|
50
|
-
try {
|
|
51
|
-
await db
|
|
52
|
-
.insert(buddyUsageSnapshots)
|
|
53
|
-
.values(
|
|
54
|
-
rows.map((row) => ({
|
|
55
|
-
accountId,
|
|
56
|
-
dayKey: row.day,
|
|
57
|
-
model: row.model,
|
|
58
|
-
credit: String(row.credit),
|
|
59
|
-
syncedAt: now,
|
|
60
|
-
})),
|
|
61
|
-
)
|
|
62
|
-
.onConflictDoUpdate({
|
|
63
|
-
target: [
|
|
64
|
-
buddyUsageSnapshots.accountId,
|
|
65
|
-
buddyUsageSnapshots.dayKey,
|
|
66
|
-
buddyUsageSnapshots.model,
|
|
67
|
-
],
|
|
68
|
-
set: {
|
|
69
|
-
credit: sql`excluded."credit"`,
|
|
70
|
-
syncedAt: sql`excluded."synced_at"`,
|
|
71
|
-
},
|
|
72
|
-
});
|
|
73
|
-
return rows.length;
|
|
74
|
-
} catch {
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Most (day, model) buckets one day can hold, used only to bound the read.
|
|
81
|
-
*
|
|
82
|
-
* The renderer keeps {@link DEFAULT_LIMIT_PER_ACCOUNT} entries per account plus
|
|
83
|
-
* every bucket of the newest day, so this is a ceiling on a pathological table
|
|
84
|
-
* rather than a number the page depends on. Set well above any real model count
|
|
85
|
-
* so the cap can only ever trigger on a table that grew without pruning.
|
|
86
|
-
*/
|
|
87
|
-
const MODELS_PER_DAY_CEILING = 64;
|
|
88
|
-
|
|
89
|
-
/** Buckets per account the console renders. */
|
|
90
|
-
const DEFAULT_LIMIT_PER_ACCOUNT = 30;
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Reads each account's stored usage, newest day first.
|
|
94
|
-
*
|
|
95
|
-
* Bounded on both axes: with no day filter and no `LIMIT`, an account would
|
|
96
|
-
* fetch every bucket it had ever stored (~1500 rows for a 30-day window) to
|
|
97
|
-
* render 30 of them, on the route the dashboard polls.
|
|
98
|
-
*
|
|
99
|
-
* - The day window is semantic, not a truncation: {@link pruneBuddyUsageSnapshots}
|
|
100
|
-
* already drops everything older, so no row it excludes could have been
|
|
101
|
-
* rendered anyway.
|
|
102
|
-
* - The row ceiling is the backstop. It is sized per account, so one large
|
|
103
|
-
* account cannot starve the others in a shared `LIMIT`.
|
|
104
|
-
*
|
|
105
|
-
* `numeric` comes back from the driver as a string, so the credit is parsed
|
|
106
|
-
* rather than trusted; an unparseable row is reported as 0 instead of being
|
|
107
|
-
* dropped, because a bucket that exists is a bucket that was billed.
|
|
108
|
-
*/
|
|
109
|
-
export async function readBuddyUsageSnapshots(
|
|
110
|
-
db: CartethyiaDatabase,
|
|
111
|
-
accountIds: readonly string[],
|
|
112
|
-
limitPerAccount = DEFAULT_LIMIT_PER_ACCOUNT,
|
|
113
|
-
): Promise<Map<string, readonly BuddyUsageSnapshotRow[]>> {
|
|
114
|
-
const result = new Map<string, BuddyUsageSnapshotRow[]>();
|
|
115
|
-
if (accountIds.length === 0) return result;
|
|
116
|
-
let rows: {
|
|
117
|
-
accountId: string;
|
|
118
|
-
dayKey: string;
|
|
119
|
-
model: string;
|
|
120
|
-
credit: string | number | null;
|
|
121
|
-
syncedAt: Date | string | null;
|
|
122
|
-
}[];
|
|
123
|
-
try {
|
|
124
|
-
rows = await db
|
|
125
|
-
.select({
|
|
126
|
-
accountId: buddyUsageSnapshots.accountId,
|
|
127
|
-
dayKey: buddyUsageSnapshots.dayKey,
|
|
128
|
-
model: buddyUsageSnapshots.model,
|
|
129
|
-
credit: buddyUsageSnapshots.credit,
|
|
130
|
-
syncedAt: buddyUsageSnapshots.syncedAt,
|
|
131
|
-
})
|
|
132
|
-
.from(buddyUsageSnapshots)
|
|
133
|
-
.where(
|
|
134
|
-
and(
|
|
135
|
-
inArray(buddyUsageSnapshots.accountId, [...accountIds]),
|
|
136
|
-
gte(buddyUsageSnapshots.dayKey, retentionCutoff()),
|
|
137
|
-
),
|
|
138
|
-
)
|
|
139
|
-
.orderBy(desc(buddyUsageSnapshots.dayKey))
|
|
140
|
-
.limit(accountIds.length * limitPerAccount * MODELS_PER_DAY_CEILING);
|
|
141
|
-
} catch {
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
for (const row of rows) {
|
|
145
|
-
const bucket = result.get(row.accountId) ?? [];
|
|
146
|
-
// Ordered by day, so the first `limitPerAccount` distinct days win and a
|
|
147
|
-
// model that ran every day does not crowd out the rest of the window.
|
|
148
|
-
if (bucket.length >= limitPerAccount && bucket[bucket.length - 1]?.day !== row.dayKey) continue;
|
|
149
|
-
bucket.push({
|
|
150
|
-
day: row.dayKey,
|
|
151
|
-
model: row.model,
|
|
152
|
-
credit: Number(row.credit ?? 0) || 0,
|
|
153
|
-
syncedAt: row.syncedAt instanceof Date ? row.syncedAt.toISOString() : (row.syncedAt ?? null),
|
|
154
|
-
});
|
|
155
|
-
result.set(row.accountId, bucket);
|
|
156
|
-
}
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** Drops buckets older than the upstream's own window. Best-effort. */
|
|
161
|
-
export async function pruneBuddyUsageSnapshots(
|
|
162
|
-
db: CartethyiaDatabase,
|
|
163
|
-
now: Date = new Date(),
|
|
164
|
-
): Promise<number> {
|
|
165
|
-
const cutoff = new Date(now.getTime() - RETENTION_DAYS * 86_400_000)
|
|
166
|
-
.toISOString()
|
|
167
|
-
.slice(0, 10);
|
|
168
|
-
try {
|
|
169
|
-
const deleted = await db
|
|
170
|
-
.delete(buddyUsageSnapshots)
|
|
171
|
-
.where(and(eq(buddyUsageSnapshots.dayKey, cutoff)))
|
|
172
|
-
.returning({ accountId: buddyUsageSnapshots.accountId });
|
|
173
|
-
// Days strictly older than the cutoff, which a single equality cannot reach.
|
|
174
|
-
await db
|
|
175
|
-
.delete(buddyUsageSnapshots)
|
|
176
|
-
.where(sql`${buddyUsageSnapshots.dayKey} < ${cutoff}`);
|
|
177
|
-
return deleted.length;
|
|
178
|
-
} catch {
|
|
179
|
-
return 0;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CodeBuddy CN model roster, isolated in a leaf module.
|
|
3
|
-
*
|
|
4
|
-
* `buddy-chat-shared` needs the raw table to answer output-limit lookups for
|
|
5
|
-
* CN-only ids, and `cn-provider` builds its catalog from it. Keeping the table
|
|
6
|
-
* here — instead of inside `cn-provider` — removes the load-time import cycle
|
|
7
|
-
* between `buddy-chat-shared` ⇄ `cn-provider` (and its buddy-media/provider
|
|
8
|
-
* variants): both sides import this module, and this module imports nothing
|
|
9
|
-
* back.
|
|
10
|
-
*/
|
|
11
|
-
import type { BuddyRawEntry } from "../buddy-catalog-shared";
|
|
12
|
-
|
|
13
|
-
export const CODEBUDDY_CN_RAW: readonly BuddyRawEntry[] = [
|
|
14
|
-
["glm-5.1", "GLM 5.1", true, true, 200_000, 48_000],
|
|
15
|
-
["glm-5.2", "GLM 5.2", true, true, 1_000_000, 64_000],
|
|
16
|
-
["glm-5.3", "GLM 5.3", true, true, 1_000_000, 64_000],
|
|
17
|
-
["glm-5.3-flash", "GLM 5.3 Flash", true, true, 1_000_000, 131_072],
|
|
18
|
-
["glm-5v-turbo", "GLM 5v Turbo", true, true, 200_000, 64_000],
|
|
19
|
-
["minimax-m3", "MiniMax M3", true, true, 512_000, 64_000],
|
|
20
|
-
// 1M context, reasoning always on (upstream states both); vision inherited
|
|
21
|
-
// from the M3 row, which is the same family.
|
|
22
|
-
["minimax-m3.1-flash", "MiniMax M3.1 Flash", true, true, 1_000_000, 128_000],
|
|
23
|
-
["mimo-v2.6-pro", "MiMo V2.6 Pro", true, true, 1_000_000, 128_000],
|
|
24
|
-
["kimi-k2.8-preview", "Kimi K2.8 Preview", true, true, 1_000_000, 64_000],
|
|
25
|
-
["kimi-k3.1-pro", "Kimi K3.1 Pro", true, true, 1_000_000, 32_000],
|
|
26
|
-
["hy3", "Hy3", true, true, 192_000, 64_000],
|
|
27
|
-
["hy4", "Hy4", true, true, 960_000, 64_000],
|
|
28
|
-
["hy4free", "Hy4 Free", true, true, 960_000, 64_000],
|
|
29
|
-
["space-bunny", "Space Bunny", true, true, 1_000_000, 128_000],
|
|
30
|
-
["step-5-preview", "Step 5 Preview", true, true, 1_000_000, 64_000],
|
|
31
|
-
["deepseek-v4-pro", "DeepSeek V4 Pro", true, true, 1_000_000, 128_000],
|
|
32
|
-
["deepseek-v4.1-flash", "DeepSeek V4.1 Flash", true, true, 1_000_000, 128_000],
|
|
33
|
-
// Live on the CN roster but absent here, so a request for it resolved to
|
|
34
|
-
// nothing. Limits as published by /v3/config.
|
|
35
|
-
["kimi-k3-1", "Kimi K3-1", true, true, 1_000_000, 32_000],
|
|
36
|
-
["minimax-m2.7", "MiniMax M2.7", true, true, 200_000, 48_000],
|
|
37
|
-
];
|
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
// CodeBuddy CN adapter — exact provider contract.
|
|
2
|
-
// Canonical provider ID: cbcn
|
|
3
|
-
// Base (manifest-owned CODEBUDDY_CN_BASE_URL) → Chat: base + /chat/completions
|
|
4
|
-
// Auth: Authorization Bearer for both api_key and oauth
|
|
5
|
-
// Stream: force stream=true upstream, factory reaggregates for non-stream callers
|
|
6
|
-
// Headers: per-provider CodeBuddy headers (CLI identity for CN)
|
|
7
|
-
// Payload: neutralize CN agent prompts, reasoning_summary auto only when reasoning_effort
|
|
8
|
-
|
|
9
|
-
import { BuddyMediaAdapter } from "../buddy-media";
|
|
10
|
-
import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderAdapter } from "../../../provider-contracts";
|
|
11
|
-
import type { ModelDefinition } from "../../../provider-model-definition";
|
|
12
|
-
import type { DiscoveryInput } from "../../../discovery/discovery-types";
|
|
13
|
-
import type { CanonicalRequest } from "../../../../protocol/canonical-model";
|
|
14
|
-
import { ensurePayloadModel } from "../../../configured-provider";
|
|
15
|
-
import { providerBaseUrl } from "../../../provider-metadata";
|
|
16
|
-
import {
|
|
17
|
-
codebuddyAdapterConfig,
|
|
18
|
-
} from "./shared";
|
|
19
|
-
import { CODEBUDDY_CN_RAW } from "./cn-catalog";
|
|
20
|
-
import { CODEBUDDY_SYSTEM_PROMPT } from "./provider";
|
|
21
|
-
import {
|
|
22
|
-
BUDDY_CN_IMAGE_MODEL_ID_SET,
|
|
23
|
-
BUDDY_CN_VIDEO_MODEL_ID_SET,
|
|
24
|
-
makeBuddyCnImageModels,
|
|
25
|
-
makeBuddyCnVideoModels,
|
|
26
|
-
makeBuddyModel,
|
|
27
|
-
} from "../buddy-catalog-shared";
|
|
28
|
-
import { BUDDY_CN_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
|
|
29
|
-
import {
|
|
30
|
-
buddyPrePayloadCommon,
|
|
31
|
-
finalizeBuddyMessages,
|
|
32
|
-
injectBuddyParallelToolCalls,
|
|
33
|
-
normalizeBuddyToolNames,
|
|
34
|
-
} from "../buddy-chat-shared";
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// Constants — public contract
|
|
39
|
-
|
|
40
|
-
export const CODEBUDDY_CN_PROVIDER_ID = "cbcn" as const;
|
|
41
|
-
export const CODEBUDDY_CN_BASE_URL = providerBaseUrl("cbcn");
|
|
42
|
-
// Payload hook — provider CN semantics
|
|
43
|
-
// - force stream=true
|
|
44
|
-
// - reasoning_summary auto only when reasoning_effort
|
|
45
|
-
// - neutralize CN agent prompts (remove system agent instructions)
|
|
46
|
-
|
|
47
|
-
function isAgentPromptText(text: string): boolean {
|
|
48
|
-
return /you are claude code|claude.?code.+official.+cli|anthropic.+official.+cli|anxthxropic.+official.+cli|you are (?:cursor|windsurf|cline|aider|continue|copilot|cody)|you are an? (?:ai )?(?:coding |code )?agent|cc_entrypoint\s*=\s*(?:cli|vscode|jetbrains|gui)|claude.?code.+issues|give feedback.+claude.?code|you are .{0,30}(?:powerful )?ai agent|orchestration capabilities|OhMyOpenCode|<agent-identity>|<Role>|<Behavior_Instructions>/i.test(
|
|
49
|
-
text,
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const CODEBUDDY_CN_NEUTRAL_PROMPT = "You are a helpful assistant.";
|
|
54
|
-
|
|
55
|
-
function flattenContent(content: unknown): string {
|
|
56
|
-
if (typeof content === "string") return content;
|
|
57
|
-
if (!Array.isArray(content)) return "";
|
|
58
|
-
return content
|
|
59
|
-
.map((part) =>
|
|
60
|
-
part !== null && typeof part === "object" && "text" in part
|
|
61
|
-
? String((part as Record<string, unknown>)["text"] ?? "")
|
|
62
|
-
: "",
|
|
63
|
-
)
|
|
64
|
-
.join("\n");
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function neutralizeCnMessages(messages: Array<Record<string, unknown>>): void {
|
|
68
|
-
for (let index = 0; index < messages.length; index += 1) {
|
|
69
|
-
const message = messages[index];
|
|
70
|
-
if (!message || message["role"] !== "system") continue;
|
|
71
|
-
const content = message["content"];
|
|
72
|
-
const text = flattenContent(content);
|
|
73
|
-
if (text.length <= 2_000 && !isAgentPromptText(text)) continue;
|
|
74
|
-
messages[index] =
|
|
75
|
-
typeof content === "string"
|
|
76
|
-
? { ...message, content: CODEBUDDY_CN_NEUTRAL_PROMPT }
|
|
77
|
-
: {
|
|
78
|
-
...message,
|
|
79
|
-
content: [{ type: "text", text: CODEBUDDY_CN_NEUTRAL_PROMPT }],
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function codeBuddyCnPrePayload(
|
|
85
|
-
payload: Record<string, unknown>,
|
|
86
|
-
request: CanonicalRequest,
|
|
87
|
-
candidate: ProviderDispatchTarget,
|
|
88
|
-
context?: ProviderDispatchContext,
|
|
89
|
-
): void {
|
|
90
|
-
// CN ladder: the CN backend serves `low`/`max` levels the international one
|
|
91
|
-
// rejects, so the realm must be named rather than left to default to intl.
|
|
92
|
-
buddyPrePayloadCommon(payload, request, "cn", context);
|
|
93
|
-
if (Array.isArray(payload["messages"])) {
|
|
94
|
-
const messages = payload["messages"] as Array<Record<string, unknown>>;
|
|
95
|
-
neutralizeCnMessages(messages);
|
|
96
|
-
finalizeBuddyMessages(messages, { leadPrompt: CODEBUDDY_CN_NEUTRAL_PROMPT });
|
|
97
|
-
}
|
|
98
|
-
ensurePayloadModel(payload, candidate, "CodeBuddy CN");
|
|
99
|
-
normalizeBuddyToolNames(payload);
|
|
100
|
-
injectBuddyParallelToolCalls(payload, request);
|
|
101
|
-
void request;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Model catalog — CodeBuddy CN console and CLI catalog.
|
|
105
|
-
// Exported because `buddyModelOutputLimit` searches every buddy raw table, and
|
|
106
|
-
// a CN-only id would otherwise never get an output limit.
|
|
107
|
-
export { CODEBUDDY_CN_RAW };
|
|
108
|
-
/**
|
|
109
|
-
* CN's image-generation rows (`hunyuan-image-alpha`).
|
|
110
|
-
*
|
|
111
|
-
* Reached through `/images/generations` like the international rows. The image
|
|
112
|
-
* ids are filtered out of the chat pass so one id never appears under two
|
|
113
|
-
* service kinds, matching how the intl catalog does it.
|
|
114
|
-
*/
|
|
115
|
-
export const CODEBUDDY_CN_IMAGE_MODELS: readonly ModelDefinition[] = makeBuddyCnImageModels(
|
|
116
|
-
CODEBUDDY_CN_PROVIDER_ID,
|
|
117
|
-
"/images/generations",
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* CN's video-generation rows (`kling-video-v3`, `minimax-video-h3`).
|
|
122
|
-
*
|
|
123
|
-
* Reached through the native video route like the intl rows. The video ids
|
|
124
|
-
* are filtered out of the chat pass so one id never appears under two service
|
|
125
|
-
* kinds.
|
|
126
|
-
*/
|
|
127
|
-
export const CODEBUDDY_CN_VIDEO_MODELS: readonly ModelDefinition[] = makeBuddyCnVideoModels(
|
|
128
|
-
CODEBUDDY_CN_PROVIDER_ID,
|
|
129
|
-
"/videos/generations",
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
export const CODEBUDDY_CN_MODELS: readonly ModelDefinition[] = [
|
|
133
|
-
...CODEBUDDY_CN_RAW.filter(
|
|
134
|
-
(entry) =>
|
|
135
|
-
!BUDDY_CN_IMAGE_MODEL_ID_SET.has(entry[0]) &&
|
|
136
|
-
!BUDDY_CN_VIDEO_MODEL_ID_SET.has(entry[0]),
|
|
137
|
-
).map((entry) =>
|
|
138
|
-
makeBuddyModel(entry, CODEBUDDY_CN_PROVIDER_ID, undefined, "cn"),
|
|
139
|
-
),
|
|
140
|
-
...CODEBUDDY_CN_IMAGE_MODELS,
|
|
141
|
-
...CODEBUDDY_CN_VIDEO_MODELS,
|
|
142
|
-
];
|
|
143
|
-
|
|
144
|
-
/** Reads the CodeBuddy CN console directory (same envelope as the intl site). */
|
|
145
|
-
export async function discoverCodeBuddyCnModels(
|
|
146
|
-
input: DiscoveryInput,
|
|
147
|
-
): Promise<readonly ModelDefinition[] | null> {
|
|
148
|
-
return fetchBuddyDirectoryModels({
|
|
149
|
-
siteUrl: CODEBUDDY_CN_BASE_URL,
|
|
150
|
-
providerId: CODEBUDDY_CN_PROVIDER_ID,
|
|
151
|
-
credential: input.credential,
|
|
152
|
-
modelsPath: BUDDY_CN_MODELS_PATH,
|
|
153
|
-
endpoint: undefined,
|
|
154
|
-
...(input.signal ? { signal: input.signal } : {}),
|
|
155
|
-
...(input.fetcher ? { fetcher: input.fetcher } : {}),
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Public factory
|
|
160
|
-
|
|
161
|
-
export function createCodeBuddyCnAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
|
|
162
|
-
// BuddyMediaAdapter, not OpenAICompatibleAdapter: the CN realm publishes an
|
|
163
|
-
// image-generation row, and the plain compatible adapter has no image path,
|
|
164
|
-
// so `hunyuan-image-alpha` would route to /chat/completions and fail.
|
|
165
|
-
return new BuddyMediaAdapter(
|
|
166
|
-
codebuddyAdapterConfig({
|
|
167
|
-
providerId: CODEBUDDY_CN_PROVIDER_ID,
|
|
168
|
-
baseUrl: CODEBUDDY_CN_BASE_URL,
|
|
169
|
-
variant: "CLI",
|
|
170
|
-
prePayload: codeBuddyCnPrePayload,
|
|
171
|
-
// The CN CLI profile gzips the chat body (donor behavior). The console
|
|
172
|
-
// channel fallback is an intl-only recovery; CN has no second endpoint.
|
|
173
|
-
requestCompression: "gzip",
|
|
174
|
-
...(fetchImpl ? { fetchImpl } : {}),
|
|
175
|
-
}),
|
|
176
|
-
{
|
|
177
|
-
variant: "CLI",
|
|
178
|
-
// The CN realm has no separate system prompt of its own; the neutral CN
|
|
179
|
-
// prompt is applied by `codeBuddyCnPrePayload`, so the media config
|
|
180
|
-
// reuses the intl one purely to satisfy the required field. Image
|
|
181
|
-
// generation sends a prompt, not a conversation, so this turn is
|
|
182
|
-
// discarded by the image path in every case.
|
|
183
|
-
systemPrompt: CODEBUDDY_SYSTEM_PROMPT,
|
|
184
|
-
baseUrl: CODEBUDDY_CN_BASE_URL,
|
|
185
|
-
imageGenerationPath: "/images/generations",
|
|
186
|
-
},
|
|
187
|
-
);
|
|
188
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// CodeBuddy OAuth — browser-assisted state polling (non-PKCE) plus bespoke refresh.
|
|
2
|
-
// Canonical provider IDs: cb and cbcn.
|
|
3
|
-
import { providerBaseUrl } from "../../../provider-metadata";
|
|
4
|
-
import { buildCodeBuddyUserAgent } from "../../../operations/client-versions";
|
|
5
|
-
import {
|
|
6
|
-
BuddyOAuthClient,
|
|
7
|
-
strictResponseCode,
|
|
8
|
-
type BuddyOAuthVariant,
|
|
9
|
-
} from "../buddy-oauth-shared";
|
|
10
|
-
|
|
11
|
-
const CODEBUDDY_INTL_DEVICE_START_URL = `${providerBaseUrl("cb")}/plugin/auth/state`;
|
|
12
|
-
const CODEBUDDY_INTL_DEVICE_POLL_URL = `${providerBaseUrl("cb")}/plugin/auth/token`;
|
|
13
|
-
const CODEBUDDY_INTL_REFRESH_URL = `${providerBaseUrl("cb")}/plugin/auth/token/refresh`;
|
|
14
|
-
const CODEBUDDY_CN_DEVICE_START_URL = `${providerBaseUrl("cbcn")}/plugin/auth/state`;
|
|
15
|
-
const CODEBUDDY_CN_DEVICE_POLL_URL = `${providerBaseUrl("cbcn")}/plugin/auth/token`;
|
|
16
|
-
const CODEBUDDY_CN_REFRESH_URL = `${providerBaseUrl("cbcn")}/plugin/auth/token/refresh`;
|
|
17
|
-
|
|
18
|
-
export const CODEBUDDY_INTL_VARIANT: BuddyOAuthVariant = {
|
|
19
|
-
providerId: "cb",
|
|
20
|
-
providerLabel: "CodeBuddy",
|
|
21
|
-
domain: "www.codebuddy.ai",
|
|
22
|
-
platform: "ide",
|
|
23
|
-
userAgent: async () => {
|
|
24
|
-
return buildCodeBuddyUserAgent("IDE");
|
|
25
|
-
},
|
|
26
|
-
deviceStartUrl: CODEBUDDY_INTL_DEVICE_START_URL,
|
|
27
|
-
devicePollUrl: CODEBUDDY_INTL_DEVICE_POLL_URL,
|
|
28
|
-
refreshUrl: CODEBUDDY_INTL_REFRESH_URL,
|
|
29
|
-
responseCode: strictResponseCode,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const CODEBUDDY_CN_VARIANT: BuddyOAuthVariant = {
|
|
33
|
-
providerId: "cbcn",
|
|
34
|
-
providerLabel: "CodeBuddy",
|
|
35
|
-
domain: "copilot.tencent.com",
|
|
36
|
-
platform: "CLI",
|
|
37
|
-
userAgent: async () => {
|
|
38
|
-
return buildCodeBuddyUserAgent("CLI");
|
|
39
|
-
},
|
|
40
|
-
deviceStartUrl: CODEBUDDY_CN_DEVICE_START_URL,
|
|
41
|
-
devicePollUrl: CODEBUDDY_CN_DEVICE_POLL_URL,
|
|
42
|
-
refreshUrl: CODEBUDDY_CN_REFRESH_URL,
|
|
43
|
-
responseCode: strictResponseCode,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export const codeBuddyOAuthClient = new BuddyOAuthClient(CODEBUDDY_INTL_VARIANT);
|
|
47
|
-
export const codeBuddyCnOAuthClient = new BuddyOAuthClient(CODEBUDDY_CN_VARIANT);
|