cartethyia 2.7.7 → 2.7.9
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 +0 -1
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js +1 -0
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-CLUhmjUy.js → CliToolDetailPage-ixwgKk53.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-CQmrqqrk.js → CliToolsPage-BmttNV3U.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js +1 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-C-e2AMz6.js → InjectSystemPromptPanel-BOoO8rpz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-J8wPbmfT.js → LoginPage-ChJuNNVN.js} +1 -1
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-C6WlpU5E.js → ModelPicker-BZAJtPg1.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-BBTRBAQ3.js → ProxyPage-BJ87Pp0U.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-B2WqMSG1.js → QuotaPage-gkSyRAKa.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js +1 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-LND6_Ss7.js → SetupPage-CFNcATJJ.js} +1 -1
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-BzNnm6Bi.js → StudioPage-YoD4tY5l.js} +1 -1
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js +56 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js +1 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +2 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +1 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/{badge-BaX2GTrn.js → badge-DdbT_7Am.js} +1 -1
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DFH4Bkte.js → banner-CsGN-nbm.js} +1 -1
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/favicon.webp +0 -0
- package/dist/dashboard/assets/brand/login_register.webp +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
- package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/og_image.webp +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
- package/dist/dashboard/assets/{card-CxDw0lK6.js → card-mgZ_TLLZ.js} +1 -1
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js +1 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DfS1ntiq.js → clipboard-button-CJ4Zty89.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BK-NRr5u.js → dialog-B5L2jPQ_.js} +1 -1
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-QqPul6sC.js → drawer-DkjUouAj.js} +1 -1
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BMlYJVFj.js → entry-B-LVLV6o.js} +1 -1
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js +1 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +4 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DP-5E01-.js → formatters-CrsdLVsn.js} +1 -1
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/{index-D36vCZht.js → index-BU64Lqvp.js} +2 -2
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/{inline-CHJQwxLa.js → inline-B2aDLyyg.js} +1 -1
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/{input-BlmlizVV.js → input-BCVkdR9d.js} +1 -1
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/{layout-Bz93I-yE.js → layout-DNcAdMK-.js} +1 -1
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Ml16KCfu.js → list-row-DgrIH0hw.js} +1 -1
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/{live-7_QpnYGu.js → live-Cae01iu8.js} +1 -1
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
- package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
- package/dist/dashboard/assets/{network-CuMDaTzT.js → network-CRib7H_2.js} +1 -1
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-CoqpaDMx.js → numbers-BKQE8Xpz.js} +1 -1
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-B5aOoweZ.js → pagination-ecPvG_8g.js} +1 -1
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/providers/devin.svg +9 -0
- package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
- package/dist/dashboard/assets/providers/windsurf.svg +10 -0
- package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
- package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
- package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js +1 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/{select-C9Ssle9b.js → select-ChoFWyKz.js} +1 -1
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js +1 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/{stack-j7cXjgYX.js → stack-DWCwU3fh.js} +1 -1
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/{state-DHmEnLa2.js → state-Cg3VL5J_.js} +1 -1
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/story/25817331.webp +0 -0
- package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
- package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
- package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
- package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
- package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
- package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
- package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
- package/dist/dashboard/assets/{switch-DmZcyTIC.js → switch-Db70BMix.js} +1 -1
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BqdE0LuM.js} +1 -1
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.webp +0 -0
- package/dist/dashboard/console-backgrounds_initial.webp +0 -0
- package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
- package/dist/dashboard/index.html +3 -3
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +57 -55
- package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
- package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/package.json +1 -1
- package/src/boot/dependencies.ts +11 -3
- package/src/config/cooldowns.ts +1 -1
- package/src/config/spec.ts +0 -6
- package/src/console/api-keys/routes.ts +11 -4
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -0
- package/src/console/ip-bans/routes.ts +99 -0
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -0
- package/src/console/providers/catalog/model-operations.ts +122 -10
- package/src/console/providers/catalog/provider-operations.ts +116 -8
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +64 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +243 -3
- package/src/console/quota/account-quota-global.ts +89 -1
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +1 -0
- package/src/observability/event-query.ts +18 -4
- package/src/persistence/dialect.ts +12 -0
- package/src/persistence/schema.ts +20 -2
- package/src/protocol/dsml.ts +1 -1
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +4 -4
- package/src/protocol/request/messages.ts +1 -1
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stream-error-frames.ts +13 -3
- package/src/protocol/translation/quirks.ts +1 -1
- package/src/protocol/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream/send-claude-messages.ts +15 -4
- package/src/protocol/upstream-parsing.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +7 -5
- package/src/providers/authentication/oauth-refresh-service.ts +149 -36
- package/src/providers/default-registry.ts +68 -3
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +61 -30
- package/src/providers/discovery/probing-service.ts +279 -164
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +117 -2
- package/src/providers/integrations/antigravity/antigravity.ts +13 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +18 -18
- package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
- package/src/providers/integrations/buddy/buddy-identity.ts +70 -0
- package/src/providers/integrations/buddy/buddy-media.ts +4 -5
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
- package/src/providers/integrations/buddy/capabilities.ts +4 -41
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +20 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +6 -10
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +738 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +9 -8
- package/src/providers/integrations/cursor/cursor-shared.ts +19 -1
- package/src/providers/integrations/cursor/cursor.ts +50 -30
- package/src/providers/integrations/cursor/protocol/tool-canonical.ts +26 -100
- package/src/providers/integrations/devin/devin-auth.ts +353 -0
- package/src/providers/integrations/devin/devin-catalog.ts +207 -0
- package/src/providers/integrations/devin/devin-http.ts +91 -0
- package/src/providers/integrations/devin/devin-quota.ts +214 -0
- package/src/providers/integrations/devin/devin-shared.ts +111 -0
- package/src/providers/integrations/devin/devin.ts +539 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +584 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory.ts +2 -2
- package/src/providers/integrations/freepi/freepi-catalog.ts +60 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
- package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
- package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
- package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
- package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
- package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
- package/src/providers/integrations/freepi/freepi.ts +292 -0
- package/src/providers/integrations/gemini.ts +2 -2
- package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
- package/src/providers/integrations/hermes.ts +4 -12
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +211 -0
- package/src/providers/integrations/perch/perch-quota.ts +137 -0
- package/src/providers/integrations/perch/perch-realm.ts +82 -0
- package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
- package/src/providers/integrations/perch/perch.ts +315 -0
- package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
- package/src/providers/integrations/qoder/chat-proto.ts +328 -328
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +89 -28
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +6 -1
- package/src/providers/integrations/qoder/qoder-checkin.ts +2 -2
- package/src/providers/integrations/qoder/qoder-grpc.ts +209 -5
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -1
- package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
- package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
- package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
- package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
- package/src/providers/integrations/qoder/qoder.ts +3 -6
- package/src/providers/integrations/trae/trae-catalog.ts +9 -14
- package/src/providers/integrations/trae/trae-headers.ts +36 -11
- package/src/providers/integrations/trae/trae-oauth.ts +14 -17
- package/src/providers/integrations/trae/trae-protocol.ts +3 -6
- package/src/providers/integrations/trae/trae-quota.ts +103 -21
- package/src/providers/integrations/trae/trae-realm.ts +36 -15
- package/src/providers/integrations/trae/trae.ts +97 -7
- package/src/providers/operations/account-error-classification.ts +66 -1
- package/src/providers/operations/account-health-service.ts +192 -26
- package/src/providers/operations/account-refresh-status.ts +284 -0
- package/src/providers/operations/account-tier.ts +67 -0
- package/src/providers/operations/byok-wire-profile.ts +9 -12
- package/src/providers/operations/client-versions.ts +37 -99
- package/src/providers/operations/cooldown-rules.ts +61 -0
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/provider-contracts.ts +29 -0
- package/src/providers/provider-metadata.ts +59 -4
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/quota/refresh.ts +21 -0
- package/src/security/abuse.ts +71 -0
- package/src/transport/dispatch/proxy-request.ts +1 -0
- package/src/transport/dispatch/streaming/stream.ts +1 -0
- package/src/transport/dispatch/upstream.ts +4 -1
- package/src/transport/failure-policy.ts +113 -7
- package/src/transport/routing/router.ts +25 -1
- package/src/transport/surface/messages/adapter.ts +2 -1
- package/src/transport/surface/responses/encode.ts +12 -1
- package/src/workers/daily-checkin.ts +1 -1
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/scheduler.ts +22 -4
- package/dist/dashboard/assets/BannedPage-B05aF8Dg.js +0 -1
- package/dist/dashboard/assets/BannedPage-B05aF8Dg.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-CLUhmjUy.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CQmrqqrk.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js +0 -1
- package/dist/dashboard/assets/CombosPage-CHG_1Wr3.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DPgbklad.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-DPgbklad.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-pnfAqr_-.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-pnfAqr_-.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DGJuU2A6.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-C-e2AMz6.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-J8wPbmfT.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js +0 -1
- package/dist/dashboard/assets/OverviewPage-BSQnF2Lp.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js +0 -7
- package/dist/dashboard/assets/ProviderDetailPage-DK_e0FJz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-D_a3r6Gc.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BBTRBAQ3.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-B2WqMSG1.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-D7xp5Ij_.js +0 -1
- package/dist/dashboard/assets/SettingsPage-D7xp5Ij_.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-LND6_Ss7.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BzNnm6Bi.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-C1TbL24N.js +0 -56
- package/dist/dashboard/assets/UsagePage-C1TbL24N.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +0 -2
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +0 -1
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/banner-DFH4Bkte.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.png +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/favicon.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
- package/dist/dashboard/assets/card-CxDw0lK6.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +0 -1
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/entry-vqGb8yVz.js +0 -4
- package/dist/dashboard/assets/entry-vqGb8yVz.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DP-5E01-.js.gz +0 -0
- package/dist/dashboard/assets/index-D36vCZht.js.gz +0 -0
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-YSoQOUh6.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +0 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/select-C9Ssle9b.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
- package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
- package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
- package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
- package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
- /package/dist/dashboard/assets/{app-DRnQLhsc.js → app-B7kIWFm5.js} +0 -0
- /package/dist/dashboard/assets/{app-DRnQLhsc.js.gz → app-B7kIWFm5.js.gz} +0 -0
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// X-Device-Type, X-Os-Version (all encodeURIComponent'd)
|
|
9
9
|
// - User-Agent: TraeClient/TTNet
|
|
10
10
|
//
|
|
11
|
-
// The
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// The native Agent transport also sends x-ide-token alongside Authorization.
|
|
12
|
+
// Version headers remain separate: they are not universally required by Agent
|
|
13
|
+
// and commercial requests.
|
|
14
14
|
|
|
15
15
|
import { createHash } from "node:crypto";
|
|
16
16
|
import {
|
|
@@ -32,9 +32,9 @@ export interface TraeDeviceIdentity {
|
|
|
32
32
|
* Derives the device pair the upstream client sends.
|
|
33
33
|
*
|
|
34
34
|
* Both are pure one-way derivations from the account id, so one account always
|
|
35
|
-
* presents one device and two accounts never share one —
|
|
36
|
-
*
|
|
37
|
-
*
|
|
35
|
+
* presents one device and two accounts never share one — this is the
|
|
36
|
+
* risk-control correlation surface, so a per-process random id would look like
|
|
37
|
+
* many devices behind one account and a shared id would link them.
|
|
38
38
|
*/
|
|
39
39
|
export function traeDeviceIdentity(uid: string): TraeDeviceIdentity {
|
|
40
40
|
const seed = String(uid ?? "").trim() || "anonymous";
|
|
@@ -52,9 +52,9 @@ export function traeDeviceIdentity(uid: string): TraeDeviceIdentity {
|
|
|
52
52
|
/**
|
|
53
53
|
* OS string reported as `X-Os-Version`.
|
|
54
54
|
*
|
|
55
|
-
*
|
|
56
|
-
* Windows build
|
|
57
|
-
*
|
|
55
|
+
* Upstream reads this from the host registry, which would leak the operator's
|
|
56
|
+
* real Windows build. This gateway is not the operator's desktop, so a fixed
|
|
57
|
+
* value of the same shape is both more private and more stable.
|
|
58
58
|
*/
|
|
59
59
|
export const TRAE_OS_VERSION = "Windows 11 Pro";
|
|
60
60
|
|
|
@@ -70,6 +70,13 @@ export interface TraeHeaderInput {
|
|
|
70
70
|
readonly uid: string;
|
|
71
71
|
/** Version code sent as `x-ide-version-code`. */
|
|
72
72
|
readonly versionCode?: string;
|
|
73
|
+
/** Client semver (e.g. `3.6.13`), sent as `X-App-Version`/`x-ide-version`. */
|
|
74
|
+
readonly appVersion?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Traffic class, sent as `request-traffic-type`. Defaults to `chat`;
|
|
77
|
+
* the agent surface overrides to `agent`.
|
|
78
|
+
*/
|
|
79
|
+
readonly trafficType?: string;
|
|
73
80
|
/** True for the streaming chat call, which overrides `Accept`. */
|
|
74
81
|
readonly stream?: boolean;
|
|
75
82
|
/** Extra/replacement headers, applied case-insensitively. */
|
|
@@ -79,7 +86,15 @@ export interface TraeHeaderInput {
|
|
|
79
86
|
/**
|
|
80
87
|
* Builds the header set for one Trae request.
|
|
81
88
|
*
|
|
82
|
-
* `null` in `extra` deletes the header
|
|
89
|
+
* `null` in `extra` deletes the header.
|
|
90
|
+
*
|
|
91
|
+
* Deliberately does NOT send:
|
|
92
|
+
* - `x-ide-token` — the canonical client (Trae 1.107.1 bundle, commit
|
|
93
|
+
* `b6786417`) does not send it on the chat/agent data plane; it is an
|
|
94
|
+
* OAuth/business-host header only. Sending it changed nothing for auth but
|
|
95
|
+
* diverges from the reference wire.
|
|
96
|
+
* - `store-country-code` — not sent on the data plane either. The pay/quota
|
|
97
|
+
* collector adds it explicitly where the commercial surface requires it.
|
|
83
98
|
*/
|
|
84
99
|
export function buildTraeHeaders(input: TraeHeaderInput): Record<string, string> {
|
|
85
100
|
const config = TRAE_REALMS[input.realm];
|
|
@@ -88,7 +103,6 @@ export function buildTraeHeaders(input: TraeHeaderInput): Record<string, string>
|
|
|
88
103
|
"X-App-Id": TRAE_APP_ID,
|
|
89
104
|
"x-plugin-channel": TRAE_PLUGIN_CHANNEL,
|
|
90
105
|
"x-ide-version-code": input.versionCode ?? config.versionCode,
|
|
91
|
-
"x-ide-token": input.token,
|
|
92
106
|
Authorization: `Cloud-IDE-JWT ${input.token}`,
|
|
93
107
|
"Content-Type": "application/json",
|
|
94
108
|
Accept: "application/json",
|
|
@@ -99,6 +113,17 @@ export function buildTraeHeaders(input: TraeHeaderInput): Record<string, string>
|
|
|
99
113
|
"X-Device-Brand": encodeURIComponent(TRAE_DEVICE_BRAND),
|
|
100
114
|
"X-Device-Type": encodeURIComponent("windows"),
|
|
101
115
|
"X-Os-Version": encodeURIComponent(TRAE_OS_VERSION),
|
|
116
|
+
// Semver + traffic-class headers the 3.6.13 harness sends; verified live
|
|
117
|
+
// (2026-11-06) that they are accepted and change nothing (A/B sweep
|
|
118
|
+
// identical). Only sent when the caller supplies a version.
|
|
119
|
+
...(input.appVersion === undefined
|
|
120
|
+
? {}
|
|
121
|
+
: {
|
|
122
|
+
"X-App-Version": input.appVersion,
|
|
123
|
+
"X-App-Version-Code": input.appVersion,
|
|
124
|
+
"x-ide-version": input.appVersion,
|
|
125
|
+
}),
|
|
126
|
+
"request-traffic-type": input.trafficType ?? "chat",
|
|
102
127
|
};
|
|
103
128
|
|
|
104
129
|
if (input.stream === true) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Trae credential login and refresh.
|
|
2
2
|
//
|
|
3
|
-
// Trae has a real browser authorization flow, just not a device-code one:
|
|
4
|
-
//
|
|
3
|
+
// Trae has a real browser authorization flow, just not a device-code one: an
|
|
4
|
+
// earlier probe of the device-authorization surface answered `unsupported`,
|
|
5
5
|
// which is what led to the earlier claim that Trae had no OAuth login at all.
|
|
6
6
|
// The browser path is `GetLoginGuidance` (discovers the login host) → the
|
|
7
7
|
// operator signs in at `/authorization` → the callback carries a refresh token
|
|
@@ -18,9 +18,6 @@
|
|
|
18
18
|
// NEW refresh token and invalidates the one sent. A refresh that persisted only
|
|
19
19
|
// the access token would leave the account holding a dead refresh token and
|
|
20
20
|
// unrecoverable on its next expiry.
|
|
21
|
-
//
|
|
22
|
-
// Sourced from the donor hub `Public/trae2api-hub` (`_refresh_account_request`
|
|
23
|
-
// in `trae_client.py`).
|
|
24
21
|
|
|
25
22
|
import { randomUUID } from "node:crypto";
|
|
26
23
|
import { firstNonEmptyString as firstString } from "../../../shared/coerce";
|
|
@@ -50,10 +47,9 @@ const TRAE_OAUTH_USER_AGENT = "Trae/1.0.0 antigravity-cockpit-tools";
|
|
|
50
47
|
/**
|
|
51
48
|
* Plugin version the desktop client reports.
|
|
52
49
|
*
|
|
53
|
-
* Observed in a real authorize URL as `2.3.93439`. The
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* is used here.
|
|
50
|
+
* Observed in a real authorize URL as `2.3.93439`. The web build reports
|
|
51
|
+
* `local`; the login page accepts it, but the value is part of the fingerprint
|
|
52
|
+
* upstream correlates, so the desktop shape is used here.
|
|
57
53
|
*/
|
|
58
54
|
const TRAE_PLUGIN_VERSION = "2.3.93439";
|
|
59
55
|
|
|
@@ -61,9 +57,9 @@ const TRAE_PLUGIN_VERSION = "2.3.93439";
|
|
|
61
57
|
* Device context for the login.
|
|
62
58
|
*
|
|
63
59
|
* Derived with the same function the data plane uses, so one account presents
|
|
64
|
-
* one device across login and requests. A per-process random pair
|
|
65
|
-
*
|
|
66
|
-
*
|
|
60
|
+
* one device across login and requests. A per-process random pair would make
|
|
61
|
+
* every gateway restart look like a brand new device to the risk-control
|
|
62
|
+
* surface that correlates them.
|
|
67
63
|
*
|
|
68
64
|
* The seed is the login trace id because no account identity exists yet: the
|
|
69
65
|
* authorize step is what produces the account.
|
|
@@ -102,10 +98,11 @@ interface TraeExchangeResponse extends TraeExchangeResult {
|
|
|
102
98
|
|
|
103
99
|
export class TraeOAuthClient extends OAuthClient {
|
|
104
100
|
/**
|
|
105
|
-
* Trae has no device-code flow —
|
|
106
|
-
* `unsupported` for it — but it does have a browser
|
|
107
|
-
* `GetLoginGuidance` discovers the login host, the
|
|
108
|
-
* and the callback carries a refresh token that
|
|
101
|
+
* Trae has no device-code flow — an earlier probe of the device-authorization
|
|
102
|
+
* surface answered `unsupported` for it — but it does have a browser
|
|
103
|
+
* authorization flow: `GetLoginGuidance` discovers the login host, the
|
|
104
|
+
* operator signs in there, and the callback carries a refresh token that
|
|
105
|
+
* `ExchangeToken` redeems.
|
|
109
106
|
*
|
|
110
107
|
* Declaring only the browser half is what keeps the console from offering a
|
|
111
108
|
* device login that cannot work.
|
|
@@ -691,7 +688,7 @@ interface TraeCallbackPayload {
|
|
|
691
688
|
* Upstream has two shapes and the page picks by how the login started:
|
|
692
689
|
*
|
|
693
690
|
* - `?isRedirect=true&refreshToken=…&refreshExpireAt=…` — the refresh-token
|
|
694
|
-
* flow
|
|
691
|
+
* flow.
|
|
695
692
|
* - `?isRedirect=true&scope=trae&authCodeInfo={"AuthCode":…}&host=…` — the PKCE
|
|
696
693
|
* flow, which is what the live page actually produces here. The code inside
|
|
697
694
|
* `authCodeInfo` is what `public/oauth/ExchangeToken` redeems against the
|
|
@@ -8,9 +8,6 @@
|
|
|
8
8
|
// 2. Message `content` must be an array of parts. A plain string is refused
|
|
9
9
|
// (400/4001), so every message is normalized to parts even when there is
|
|
10
10
|
// only text.
|
|
11
|
-
//
|
|
12
|
-
// Sourced from the donor hub `Public/trae2api-hub` (`build_chat_body` and
|
|
13
|
-
// `iter_events` in `trae_client.py`).
|
|
14
11
|
|
|
15
12
|
import type { CanonicalRequest, ContentPart } from "../../../protocol/canonical-model";
|
|
16
13
|
import { resolveWireMaxTokens } from "../../../protocol/translation/quirks";
|
|
@@ -79,9 +76,9 @@ export interface TraeToolCall {
|
|
|
79
76
|
/**
|
|
80
77
|
* Generation fields upstream accepts.
|
|
81
78
|
*
|
|
82
|
-
* Undeclared fields are deliberately omitted:
|
|
83
|
-
*
|
|
84
|
-
*
|
|
79
|
+
* Undeclared fields are deliberately omitted: sending anything outside this
|
|
80
|
+
* set risks a 4001, so `provider_options` is never spread into the body
|
|
81
|
+
* wholesale.
|
|
85
82
|
*/
|
|
86
83
|
const PASSTHROUGH_OPTIONS = ["temperature", "top_p", "max_tokens", "stop"] as const;
|
|
87
84
|
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
// - `ide_user_ent_usage` on the **pay** host is the entitlement: which package
|
|
10
10
|
// the account holds and when it lapses.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
12
|
+
// Both are read and either may fail without the other: entitlement is a *pay*
|
|
13
|
+
// host, which is the first thing a region-blocked or unpaid account loses.
|
|
14
|
+
// Letting a dead pay host fail the whole read would report "no quota" for an
|
|
15
|
+
// account whose session meter is perfectly readable — and "no quota" is what
|
|
16
|
+
// the router parks on.
|
|
17
17
|
//
|
|
18
18
|
// Headers come from `buildTraeHeaders` rather than being rebuilt here: the
|
|
19
19
|
// device fingerprint is derived from the uid, and an account that reports one
|
|
@@ -39,14 +39,16 @@ import { buildTraeHeaders } from "./trae-headers";
|
|
|
39
39
|
import { log } from "../../../observability/logger";
|
|
40
40
|
import {
|
|
41
41
|
TRAE_ENT_USAGE_PATH,
|
|
42
|
+
TRAE_ENT_USAGE_PATH_V2,
|
|
42
43
|
TRAE_REGION_CORE_HOSTS,
|
|
44
|
+
TRAE_REGION_PAY_HOSTS,
|
|
43
45
|
TRAE_REALMS,
|
|
44
46
|
TRAE_SESSION_USAGE_PATH,
|
|
45
47
|
type TraeRealm,
|
|
46
48
|
} from "./trae-realm";
|
|
47
49
|
|
|
48
50
|
/**
|
|
49
|
-
* The buckets `remain_usage` carries, in the order
|
|
51
|
+
* The buckets `remain_usage` carries, in the order they are read.
|
|
50
52
|
*
|
|
51
53
|
* `advanced_model` and `premium_model_*` are request counts; `dollar_basic` and
|
|
52
54
|
* `dollar_bonus` are spend balances. They are separate budgets and must never
|
|
@@ -210,30 +212,96 @@ function parseSessionUsage(payload: unknown): {
|
|
|
210
212
|
return { windows, plan };
|
|
211
213
|
}
|
|
212
214
|
|
|
213
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* The entitlement payload, from the pay host.
|
|
217
|
+
*
|
|
218
|
+
* Shape verified live (2026-11-06, intl Free plan):
|
|
219
|
+
*
|
|
220
|
+
* {
|
|
221
|
+
* "billing_version": 3,
|
|
222
|
+
* "is_dollar_usage_billing": true,
|
|
223
|
+
* "user_entitlement_pack_list": [{
|
|
224
|
+
* "display_desc": "Free plan",
|
|
225
|
+
* "entitlement_base_info": {
|
|
226
|
+
* "end_time": 1796083199,
|
|
227
|
+
* "quota": { "advanced_model_request_limit": 1000, ... }
|
|
228
|
+
* },
|
|
229
|
+
* "quota": { "advanced_model_request_limit": 1000, ... },
|
|
230
|
+
* "usage": { "basic_usage_amount": 0, ... },
|
|
231
|
+
* "status": 1,
|
|
232
|
+
* "expire_time": 0
|
|
233
|
+
* }]
|
|
234
|
+
* }
|
|
235
|
+
*
|
|
236
|
+
* The v2 surface (CN realm) instead carries a `usage_summary` block:
|
|
237
|
+
*
|
|
238
|
+
* { "total_amount": 900, "consumed_amount": 0.39, ... }
|
|
239
|
+
*
|
|
240
|
+
* Limits live in `entitlement_base_info.quota` (or the sibling `quota`)
|
|
241
|
+
* as `<bucket>_limit` fields. There is no consumed/remaining count in the
|
|
242
|
+
* v1 shape — `used` stays null, and the window reports just the cap.
|
|
243
|
+
*/
|
|
214
244
|
function parseEntitlement(payload: unknown): {
|
|
215
245
|
readonly windows: readonly ProviderQuotaWindow[];
|
|
216
246
|
readonly plan: string | null;
|
|
217
247
|
} {
|
|
218
248
|
const root = record(payload) ?? {};
|
|
219
249
|
const data = record(root["data"]) ?? root;
|
|
220
|
-
const
|
|
221
|
-
? data["
|
|
222
|
-
: Array.isArray(data["
|
|
223
|
-
? data["
|
|
250
|
+
const packs = Array.isArray(data["user_entitlement_pack_list"])
|
|
251
|
+
? data["user_entitlement_pack_list"]
|
|
252
|
+
: Array.isArray(data["entitlement_list"])
|
|
253
|
+
? data["entitlement_list"]
|
|
224
254
|
: [];
|
|
225
255
|
const windows: ProviderQuotaWindow[] = [];
|
|
226
256
|
let plan: string | null = null;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
257
|
+
|
|
258
|
+
// The pack's `quota` block names its fields `<bucket>_limit` — with the
|
|
259
|
+
// word `request` inside for the model buckets (`advanced_model_request_limit`),
|
|
260
|
+
// and `usage_limit` for the dollar buckets (`basic_usage_limit`). Mapping
|
|
261
|
+
// them explicitly beats string-concatenating the bucket id.
|
|
262
|
+
const LIMIT_FIELDS: Readonly<Record<string, string>> = {
|
|
263
|
+
advanced_model: "advanced_model_request_limit",
|
|
264
|
+
premium_model_fast_request: "premium_model_fast_request_limit",
|
|
265
|
+
premium_model_slow_request: "premium_model_slow_request_limit",
|
|
266
|
+
dollar_basic: "basic_usage_limit",
|
|
267
|
+
dollar_bonus: "bonus_usage_limit",
|
|
268
|
+
};
|
|
269
|
+
const LABELS = new Map<string, string>([...REQUEST_BUCKETS, ...DOLLAR_BUCKETS]);
|
|
270
|
+
|
|
271
|
+
for (const entry of packs) {
|
|
272
|
+
const pack = record(entry);
|
|
273
|
+
if (!pack) continue;
|
|
274
|
+
const base = record(pack["entitlement_base_info"]) ?? {};
|
|
275
|
+
const quota = record(base["quota"]) ?? record(pack["quota"]) ?? {};
|
|
276
|
+
const name = text(pack["display_desc"]) ?? text(pack["name"]) ?? text(pack["title"]);
|
|
231
277
|
if (!plan && name) plan = name;
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
278
|
+
const resetsAt = isoDate(
|
|
279
|
+
number(base["end_time"]) ?? number(pack["end_time"]) ?? number(pack["expire_time"]),
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
// v2 surface (CN realm): the summary carries the total and consumed
|
|
283
|
+
// amounts; use it as a single window when present.
|
|
284
|
+
const summary = record(record(data["usage_summary"]) ?? record(pack["usage_summary"]));
|
|
285
|
+
if (summary) {
|
|
286
|
+
const window = bucketWindow(
|
|
287
|
+
name ?? "Plan",
|
|
288
|
+
number(summary["consumed_amount"]),
|
|
289
|
+
number(summary["total_amount"]),
|
|
290
|
+
resetsAt,
|
|
291
|
+
);
|
|
292
|
+
if (window) windows.push(window);
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// v1 surface: `<bucket>_limit` fields, no consumption count — the cap
|
|
297
|
+
// is all this shape can report.
|
|
298
|
+
for (const [key, limitField] of Object.entries(LIMIT_FIELDS)) {
|
|
299
|
+
const limit = number(quota[limitField]);
|
|
300
|
+
if (limit === null) continue;
|
|
301
|
+
const label = LABELS.get(key) ?? key;
|
|
302
|
+
const window = percentWindow(`trae:${key}`, label, null, resetsAt, null, limit, "independent");
|
|
303
|
+
if (window) windows.push(window);
|
|
304
|
+
}
|
|
237
305
|
}
|
|
238
306
|
return { windows, plan };
|
|
239
307
|
}
|
|
@@ -268,6 +336,17 @@ function coreHost(region: string, config: (typeof TRAE_REALMS)[TraeRealm]): stri
|
|
|
268
336
|
return (region !== "" ? TRAE_REGION_CORE_HOSTS[region] : undefined) ?? config.core;
|
|
269
337
|
}
|
|
270
338
|
|
|
339
|
+
/**
|
|
340
|
+
* The pay host for this account.
|
|
341
|
+
*
|
|
342
|
+
* The pay surface correlates the credential against its region, too: an `sg`
|
|
343
|
+
* account sent to the US pay host is answered 401 code 1001, while the SG pay
|
|
344
|
+
* host accepts the same token (verified live 2026-11-06).
|
|
345
|
+
*/
|
|
346
|
+
function payHost(region: string, config: (typeof TRAE_REALMS)[TraeRealm]): string {
|
|
347
|
+
return (region !== "" ? TRAE_REGION_PAY_HOSTS[region] : undefined) ?? config.pay;
|
|
348
|
+
}
|
|
349
|
+
|
|
271
350
|
export async function fetchTraeQuota(
|
|
272
351
|
credential: string,
|
|
273
352
|
fetcher: FetchLike,
|
|
@@ -349,7 +428,10 @@ export async function fetchTraeQuota(
|
|
|
349
428
|
};
|
|
350
429
|
|
|
351
430
|
const session = await tryRealms((config) => coreHost(region, config) + TRAE_SESSION_USAGE_PATH, "session usage", parseSessionUsage);
|
|
352
|
-
|
|
431
|
+
// The entitlement path differs by realm: the CN realm answers v2 (v1 lacks
|
|
432
|
+
// `usage_summary` there), the intl realm answers v1 (v2 is a 404).
|
|
433
|
+
const entPath = realm === "cn" ? TRAE_ENT_USAGE_PATH_V2 : TRAE_ENT_USAGE_PATH;
|
|
434
|
+
const entitlement = await tryRealms((config) => payHost(region, config) + entPath, "entitlement", parseEntitlement);
|
|
353
435
|
|
|
354
436
|
const windows = [...(session?.windows ?? []), ...(entitlement?.windows ?? [])];
|
|
355
437
|
if (!session && !entitlement) {
|
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
// `
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// a CN account to `*.traeapi.us` and get it refused.
|
|
1
|
+
// Regions are per-realm constants: `trae` (global / intl) and `traecn`
|
|
2
|
+
// (China) share the wire protocol — an `x-ide-token` credential, a
|
|
3
|
+
// `model_name` body, an SSE stream — but nothing else about the address:
|
|
4
|
+
// different core host, different account/oauth host, different UA, a
|
|
5
|
+
// *different authorization scheme*, and a different model roster. Treating
|
|
6
|
+
// them as one provider with a region flag is what would send a CN account to
|
|
7
|
+
// `*.traeapi.us` and get it refused.
|
|
9
8
|
//
|
|
10
9
|
// Everything per-realm lives here so the adapter, the auth builder, and the
|
|
11
10
|
// discovery fetcher cannot drift apart on host, UA, or version code.
|
|
12
|
-
//
|
|
13
|
-
// Sourced from the donor hub `Public/trae2api-hub` (`REALMS` in
|
|
14
|
-
// `trae_client.py`, `TRAEREALMS`-shaped config in `trae_accounts.py`).
|
|
15
11
|
|
|
16
12
|
/** One Trae deployment. */
|
|
17
13
|
export type TraeRealm = "intl" | "cn";
|
|
@@ -43,7 +39,7 @@ export interface TraeRealmConfig {
|
|
|
43
39
|
/**
|
|
44
40
|
* Chat path, identical across realms.
|
|
45
41
|
*
|
|
46
|
-
* The list endpoint takes a body (`{"type":"chat"}`);
|
|
42
|
+
* The list endpoint takes a body (`{"type":"chat"}`); upstream posts it, so
|
|
47
43
|
* this is not a bare GET.
|
|
48
44
|
*/
|
|
49
45
|
export const TRAE_CHAT_PATH = "/api/ide/v1/llm_raw_chat";
|
|
@@ -101,8 +97,8 @@ export const TRAE_AUTHORIZATION_PATH = "/authorization";
|
|
|
101
97
|
* `/`, a trailing slash — is answered with "Login Failed" before the operator
|
|
102
98
|
* gets to sign in, so the gateway's own `/callback` default cannot be used.
|
|
103
99
|
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
100
|
+
* This gateway serves this on its own configured port and only the path is
|
|
101
|
+
* fixed.
|
|
106
102
|
*/
|
|
107
103
|
export const TRAE_CALLBACK_PATH = "/authorize";
|
|
108
104
|
|
|
@@ -123,6 +119,14 @@ export const TRAE_LOGIN_GUIDANCE_URLS: readonly string[] = [
|
|
|
123
119
|
/** Usage / entitlement paths, relative to the realm's `pay` host. */
|
|
124
120
|
export const TRAE_SESSION_USAGE_PATH = "/api/v1/commercial/get_session_usage";
|
|
125
121
|
export const TRAE_ENT_USAGE_PATH = "/trae/api/v1/pay/ide_user_ent_usage";
|
|
122
|
+
/**
|
|
123
|
+
* The v2 entitlement path, used by the CN realm.
|
|
124
|
+
*
|
|
125
|
+
* Verified live (2026-11-06): the CN realm answers v2 — v1 lacks the
|
|
126
|
+
* `usage_summary` block there — while the intl realm answers v1 (v2 is a
|
|
127
|
+
* 404 on the intl pay host).
|
|
128
|
+
*/
|
|
129
|
+
export const TRAE_ENT_USAGE_PATH_V2 = "/trae/api/v2/pay/ide_user_ent_usage";
|
|
126
130
|
|
|
127
131
|
/**
|
|
128
132
|
* Realm → deployment.
|
|
@@ -169,7 +173,10 @@ export const TRAE_REALMS: Readonly<Record<TraeRealm, TraeRealmConfig>> = {
|
|
|
169
173
|
coreFallbacks: ["https://core-normal.traeapi.us", "https://core-normal.trae.ai"],
|
|
170
174
|
account: "https://grow-normal.trae.ai",
|
|
171
175
|
accountFallbacks: ["https://grow-normal.traeapi.us"],
|
|
172
|
-
|
|
176
|
+
// SG default, like the core: the pay surface is region-correlated too, and
|
|
177
|
+
// the SG host answers an sg-provisioned (or region-unrecorded intl) account
|
|
178
|
+
// that the US host refuses with 401 code 1001 (verified live 2026-11-06).
|
|
179
|
+
pay: "https://grow-normal.trae.ai",
|
|
173
180
|
ug: "https://grow-normal.traeapi.us",
|
|
174
181
|
userAgent: "Trae/3.6.2",
|
|
175
182
|
versionCode: "20260212",
|
|
@@ -196,6 +203,20 @@ export const TRAE_REGION_CORE_HOSTS: Readonly<Record<string, string>> = {
|
|
|
196
203
|
us: "https://core-normal.traeapi.us",
|
|
197
204
|
};
|
|
198
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Pay host per account region, when the login reported one.
|
|
208
|
+
*
|
|
209
|
+
* Verified live (2026-11-06): an `sg` account's token is refused by the US
|
|
210
|
+
* pay host with `401 code 1001` ("we are not able to authenticate you"), and
|
|
211
|
+
* accepted by the SG pay host. Same region-routing rule as the core host —
|
|
212
|
+
* the pay surface correlates the credential against its region, so a
|
|
213
|
+
* provisioned region must pick its own pay host too.
|
|
214
|
+
*/
|
|
215
|
+
export const TRAE_REGION_PAY_HOSTS: Readonly<Record<string, string>> = {
|
|
216
|
+
sg: "https://grow-normal.trae.ai",
|
|
217
|
+
us: "https://grow-normal.traeapi.us",
|
|
218
|
+
};
|
|
219
|
+
|
|
199
220
|
/** The app id is constant across realms. */
|
|
200
221
|
export const TRAE_APP_ID = "6eefa01c-1036-4c7e-9ca5-d891f63bfcd8";
|
|
201
222
|
|
|
@@ -22,6 +22,7 @@ import { resolvePromptCacheKey } from "../../operations/session-resolution";
|
|
|
22
22
|
import { estimateTraeSessionCache } from "./trae-cache";
|
|
23
23
|
import { TRAE_CN_MODELS, TRAE_INTL_MODELS, traeMaxContextWindow } from "./trae-catalog";
|
|
24
24
|
import { buildTraeHeaders } from "./trae-headers";
|
|
25
|
+
import { getTraeVersion } from "../../operations/client-versions";
|
|
25
26
|
import {
|
|
26
27
|
buildTraeChatBody,
|
|
27
28
|
isTraeAgentEndpoint,
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
TRAE_AGENT_ENDPOINT,
|
|
31
32
|
TRAE_CHAT_ENDPOINT,
|
|
32
33
|
} from "./trae-protocol";
|
|
33
|
-
import { TRAE_REGION_CORE_HOSTS, traeCoreCandidates, type TraeRealm } from "./trae-realm";
|
|
34
|
+
import { TRAE_REGION_CORE_HOSTS, traeCoreCandidates, TRAE_MODEL_LIST_PATH, TRAE_AGENT_FUNCTION, type TraeRealm } from "./trae-realm";
|
|
34
35
|
|
|
35
36
|
export interface TraeAdapterOptions {
|
|
36
37
|
readonly providerId?: string;
|
|
@@ -94,13 +95,22 @@ function extractToken(secret: string): string | undefined {
|
|
|
94
95
|
* Maps a Trae upstream error (a named `error` SSE event, or an error object
|
|
95
96
|
* in a frame body) to the canonical GatewayError.
|
|
96
97
|
*
|
|
97
|
-
*
|
|
98
|
+
* Codes resolved from live probing (2026-11-06), not guessed:
|
|
98
99
|
* - `1001` — "we are not able to authenticate you" — is a credential verdict.
|
|
99
100
|
* It must surface as account-scoped `authentication_failed` so the account
|
|
100
101
|
* is parked for re-login and failover tries a sibling — never the proxy
|
|
101
|
-
* pool.
|
|
102
|
+
* pool. Note: the pay host answers it on *region mismatch* too (an sg
|
|
103
|
+
* account sent to the us pay host), which is not the same as an expired
|
|
104
|
+
* token — a token that answers `GetUserInfo` 200 is alive.
|
|
102
105
|
* - `4008` / "exceeded the quota" — free-tier quota exhausted. That is a
|
|
103
106
|
* `quota_exceeded` 429, not a platform fault.
|
|
107
|
+
* - `1005` (extra `{"plan":N}`) and `4015` — entitlement verdicts. Verified
|
|
108
|
+
* live: identical wire, a paid-capable account streams the same model fine
|
|
109
|
+
* while a Free account is refused with these codes, and the refused
|
|
110
|
+
* account's token still answers `GetUserInfo` 200. Neither auth nor
|
|
111
|
+
* platform fault: `quota_exceeded`.
|
|
112
|
+
* - `4013` / region message — durable regional unavailability, scoped by the
|
|
113
|
+
* classifier to the account (`trae-region-unavailable`).
|
|
104
114
|
* - Everything else is a platform fault (`platform_unavailable`).
|
|
105
115
|
*/
|
|
106
116
|
function throwTraeUpstreamError(
|
|
@@ -163,6 +173,27 @@ function throwTraeUpstreamError(
|
|
|
163
173
|
);
|
|
164
174
|
}
|
|
165
175
|
|
|
176
|
+
// `1005` and `4015` are entitlement verdicts, not auth failures and not
|
|
177
|
+
// platform faults. Verified live: the same wire streams fine on a
|
|
178
|
+
// paid-capable account while a Free account is refused with these codes,
|
|
179
|
+
// and the refused account's token still answers `GetUserInfo` 200. Treating
|
|
180
|
+
// them as auth would park the account for re-login pointlessly; treating
|
|
181
|
+
// them as platform faults would failover to another account that hits the
|
|
182
|
+
// same wall. They are `quota_exceeded` — the model/account cannot serve.
|
|
183
|
+
if (code === "1005" || code === "4015") {
|
|
184
|
+
throw new GatewayError(
|
|
185
|
+
"quota_exceeded",
|
|
186
|
+
429,
|
|
187
|
+
`Trae model not available on this account (upstream code ${code}): ${message} (request {requestId}). The model needs a plan or permission this account does not hold — pick another model or account ⏳`,
|
|
188
|
+
{
|
|
189
|
+
providerCode: code,
|
|
190
|
+
providerStatus: code === "1005" ? 1005 : 4015,
|
|
191
|
+
...(providerId ? { providerId } : {}),
|
|
192
|
+
},
|
|
193
|
+
"upstream",
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
166
197
|
throw new GatewayError(
|
|
167
198
|
"platform_unavailable",
|
|
168
199
|
502,
|
|
@@ -234,6 +265,8 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
234
265
|
token: auth.token,
|
|
235
266
|
uid: auth.uid,
|
|
236
267
|
stream: true,
|
|
268
|
+
appVersion: getTraeVersion(),
|
|
269
|
+
trafficType: agentSurface ? "agent" : "chat",
|
|
237
270
|
});
|
|
238
271
|
|
|
239
272
|
const primary = traeCoreForAccount(this.realm, context.credential.auth_state);
|
|
@@ -326,7 +359,7 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
326
359
|
/**
|
|
327
360
|
* Two frame layouts reach here and both are live.
|
|
328
361
|
*
|
|
329
|
-
*
|
|
362
|
+
* Upstream's client nests the answer under `chunk`; the region host this
|
|
330
363
|
* gateway talks to sends it flat — `event: output` with
|
|
331
364
|
* `{"response":"…"}` — and reports usage as a separate `token_usage`
|
|
332
365
|
* frame with the OpenAI spelling at the top level. Reading only `chunk`
|
|
@@ -503,6 +536,17 @@ export function createTraeCnAdapter(options: TraeAdapterOptions = {}): ProviderA
|
|
|
503
536
|
/**
|
|
504
537
|
* Live model discovery.
|
|
505
538
|
*
|
|
539
|
+
* The source follows the realm, not one endpoint:
|
|
540
|
+
*
|
|
541
|
+
* - **intl** — the agent picker (`batch_get_detail_param` with
|
|
542
|
+
* `function: solo_agent`), filtered to `usage == "chat_completion"` rows.
|
|
543
|
+
* The chat `model_list` is NOT the intl source: it lists only the legacy
|
|
544
|
+
* nine chat ids, and an agent roster row (`gpt-5-paygo`,
|
|
545
|
+
* `deepseek-v4.1-flash`, `search_agent_*`, …) is absent from it (verified
|
|
546
|
+
* live 2026-11-06). Reading it would replace the agent catalog with models
|
|
547
|
+
* the agent surface rejects (`4023 model is unknown`).
|
|
548
|
+
* - **CN** — the chat `model_list`, which is the surface that serves CN.
|
|
549
|
+
*
|
|
506
550
|
* The listing is per account region, not per realm: it answers on CN and on the
|
|
507
551
|
* intl region host that serves the account (`coresg-normal.trae.ai` verified),
|
|
508
552
|
* while the generic intl core answers `403 no schema found`. An empty result is
|
|
@@ -526,8 +570,54 @@ export async function discoverTraeModels(input: {
|
|
|
526
570
|
realm: input.realm,
|
|
527
571
|
token: input.token,
|
|
528
572
|
uid: input.uid,
|
|
573
|
+
appVersion: getTraeVersion(),
|
|
529
574
|
});
|
|
530
|
-
const
|
|
575
|
+
const core = traeCoreForAccount(
|
|
576
|
+
input.realm,
|
|
577
|
+
input.region === undefined ? undefined : { region: input.region },
|
|
578
|
+
);
|
|
579
|
+
|
|
580
|
+
if (input.realm === "intl") {
|
|
581
|
+
// The agent picker: the only surface that lists the intl roster's configs.
|
|
582
|
+
const url = `${core}/api/ide/v1/batch_get_detail_param`;
|
|
583
|
+
const response = await input.fetcher(url, {
|
|
584
|
+
method: "POST",
|
|
585
|
+
headers,
|
|
586
|
+
body: JSON.stringify({ functions: [TRAE_AGENT_FUNCTION], Request: {} }),
|
|
587
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
588
|
+
});
|
|
589
|
+
if (!response.ok) return [];
|
|
590
|
+
const parsed = (await response.json()) as { function_configs?: unknown };
|
|
591
|
+
const groups = Array.isArray(parsed.function_configs) ? parsed.function_configs : [];
|
|
592
|
+
const out: { id: string; ctx: number | undefined }[] = [];
|
|
593
|
+
for (const group of groups) {
|
|
594
|
+
if (typeof group !== "object" || group === null) continue;
|
|
595
|
+
const list = (group as Record<string, unknown>)["config_info_list"];
|
|
596
|
+
if (!Array.isArray(list)) continue;
|
|
597
|
+
for (const entry of list) {
|
|
598
|
+
if (typeof entry !== "object" || entry === null) continue;
|
|
599
|
+
const row = entry as Record<string, unknown>;
|
|
600
|
+
// Only chat-capable configs are dispatch targets; fast_apply,
|
|
601
|
+
// title_generation, etc. are not.
|
|
602
|
+
if (String(row["usage"] ?? "") !== "chat_completion") continue;
|
|
603
|
+
const id = String(row["config_name"] ?? "").trim();
|
|
604
|
+
if (id.length === 0) continue;
|
|
605
|
+
// Context: the picker row carries `model_detail_list` with the real
|
|
606
|
+
// upstream rows; prefer the widest selectable window among them.
|
|
607
|
+
let ctx: number | undefined;
|
|
608
|
+
const details = Array.isArray(row["model_detail_list"]) ? row["model_detail_list"] : [];
|
|
609
|
+
for (const detail of details) {
|
|
610
|
+
const w = traeMaxContextWindow(detail);
|
|
611
|
+
if (w !== undefined && (ctx === undefined || w > ctx)) ctx = w;
|
|
612
|
+
}
|
|
613
|
+
out.push({ id, ctx });
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
return out;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// CN: the chat roster surface.
|
|
620
|
+
const url = `${core}${TRAE_MODEL_LIST_PATH}`;
|
|
531
621
|
const response = await input.fetcher(url, {
|
|
532
622
|
method: "POST",
|
|
533
623
|
headers,
|
|
@@ -550,8 +640,8 @@ export async function discoverTraeModels(input: {
|
|
|
550
640
|
return rows
|
|
551
641
|
.filter((row): row is Record<string, unknown> => typeof row === "object" && row !== null)
|
|
552
642
|
.map((row) => ({
|
|
553
|
-
// `model_name` is the key upstream's listing uses;
|
|
554
|
-
// spellings
|
|
643
|
+
// `model_name` is the key upstream's listing uses; `name`/`id` are
|
|
644
|
+
// spellings older snapshots assumed.
|
|
555
645
|
id: String(row["model_name"] ?? row["name"] ?? row["id"] ?? "").trim(),
|
|
556
646
|
ctx: traeMaxContextWindow(row),
|
|
557
647
|
}))
|