cartethyia 2.7.9 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -2
- package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Cc0vKpMG.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BmttNV3U.js → CliToolsPage-CXsaOAO2.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BE3qwwfC.js → CombosPage-BeLpJ4ma.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CRZdmMIX.js → ConsoleLogPage-DnV0uZ3m.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-Dv_FJ6Er.js → CustomizationPage-CBxAjo63.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CgoPc5B9.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-D9bFQern.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-BE40s3u5.js → OverviewPage-B_p4tL8k.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-CQ6bPUf_.js → ProviderIcon-D_0PiZtg.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-BJ87Pp0U.js → ProxyPage-BwNC_-Cx.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-CctTga2C.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CFNcATJJ.js → SetupPage-febLU4r1.js} +1 -1
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-YoD4tY5l.js → StudioPage-M6fvR5Wz.js} +1 -1
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-nyeuRqz9.js} +1 -1
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BTlkq_Uk.js → api-keys-BFOlvrJC.js} +1 -1
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/assert-CqTLw5e7.js +1 -0
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-C83EqLB0.js} +1 -1
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-D1xn7pIe.js} +1 -1
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-DU3Lq5Lm.js} +1 -1
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-A1-v8-03.js → cli-tools-Dw1U_drK.js} +1 -1
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CJ4Zty89.js → clipboard-button-CEL5Sg_J.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-B5L2jPQ_.js → dialog-BjFR5UHy.js} +1 -1
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-DkjUouAj.js → drawer-HvBW0AjI.js} +1 -1
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/{entry-B-LVLV6o.js → entry-CECVELyy.js} +1 -1
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CAhdYl3B.js → entry-DYYofQ7W.js} +1 -1
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-DLW4i8zK.js} +1 -1
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/{index-BU64Lqvp.js → index-1-fCqe64.js} +2 -2
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2aDLyyg.js → inline-DGvU2oLK.js} +1 -1
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/{input-BCVkdR9d.js → input-iNnO1X2K.js} +1 -1
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DNcAdMK-.js → layout-0q8UGypb.js} +1 -1
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DgrIH0hw.js → list-row-C0w2bQjJ.js} +1 -1
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/{live-Cae01iu8.js → live-M5aJ_xCa.js} +1 -1
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/{network-CRib7H_2.js → network-BKeQGT3K.js} +1 -1
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-CivAk3da.js} +1 -1
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-ecPvG_8g.js → pagination-CpzvI5ep.js} +1 -1
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/providers/zro.svg +3 -0
- package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
- package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-BFQX2VBc.js} +1 -1
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/{select-ChoFWyKz.js → select-CXbck0jG.js} +2 -2
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-C_XvMHh9.js} +1 -1
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-DggRiCxE.js} +1 -1
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-ClFzfbYp.js} +1 -1
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/{switch-Db70BMix.js → switch-CTIFxKqS.js} +1 -1
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-BClG3yWj.js} +1 -1
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/package.json +1 -1
- package/src/boot/app.ts +10 -13
- package/src/boot/dependencies.ts +1 -1
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +20 -0
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +40 -28
- package/src/console/auth/account-reset.ts +7 -9
- package/src/console/backup/contracts.ts +4 -0
- package/src/console/backup/export-endpoint.ts +7 -5
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/domain-registration.ts +0 -2
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +7 -13
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/contracts.ts +2 -2
- package/src/console/providers/catalog/discover-constants.ts +6 -0
- package/src/console/providers/catalog/routes.ts +1 -0
- package/src/console/providers/catalog/store.ts +21 -16
- package/src/console/quota/account-quota-global.ts +14 -24
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +6 -18
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/operations.ts +31 -46
- package/src/console/shared/errors.ts +33 -6
- package/src/main.ts +2 -3
- package/src/network/pool/byte-accounting.ts +3 -2
- package/src/network/pool/selector.ts +182 -39
- package/src/network/pool-cooldown-store.ts +89 -14
- package/src/network/pool-health.ts +49 -61
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/ssrf.ts +6 -6
- package/src/observability/event-log.ts +7 -361
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +15 -25
- package/src/observability/telemetry-reconciliation.ts +9 -37
- package/src/observability/telemetry-row.ts +125 -0
- package/src/persistence/db-mode.ts +4 -1
- package/src/persistence/dialect.ts +18 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +8 -0
- package/src/persistence/ttl-cache.ts +20 -2
- package/src/protocol/codecs.ts +1 -1
- package/src/protocol/dsml.ts +34 -86
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/request/chat.ts +10 -10
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +3 -4
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/providers/adapters/compatible-adapter.ts +71 -12
- package/src/providers/authentication/oauth-client.ts +1 -1
- package/src/providers/authentication/oauth-device-flow.ts +98 -8
- package/src/providers/authentication/oauth-refresh-service.ts +30 -49
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +61 -36
- package/src/providers/discovery/probe-phases.ts +14 -4
- package/src/providers/discovery/probing-service.ts +15 -2
- package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
- package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +5 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +173 -17
- package/src/providers/integrations/buddy/buddy-identity.ts +19 -6
- package/src/providers/integrations/buddy/capabilities.ts +2 -2
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +3 -0
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +37 -22
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
- package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
- package/src/providers/integrations/cursor/cursor-request.ts +26 -12
- package/src/providers/integrations/cursor/cursor-shared.ts +7 -4
- package/src/providers/integrations/cursor/cursor.ts +89 -40
- package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
- package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
- package/src/providers/integrations/factory/factory-oauth.ts +17 -44
- package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
- package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
- package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
- package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
- package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
- package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
- package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
- package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
- package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
- package/src/providers/integrations/freebuff/freebuff.ts +682 -0
- package/src/providers/integrations/grok/grok-oauth.ts +48 -45
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
- package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +9 -9
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/ollamacloud/index.ts +2 -0
- package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
- package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-protocol.ts +0 -3
- package/src/providers/integrations/perch/perch-quota.ts +2 -16
- package/src/providers/integrations/perch/perch.ts +3 -13
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +18 -59
- package/src/providers/integrations/qoder/qoder-adapter.ts +1 -12
- package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
- package/src/providers/integrations/qoder/qoder-catalog.ts +20 -5
- package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
- package/src/providers/integrations/qoder/qoder-checkin.ts +4 -4
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -1
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -107
- package/src/providers/integrations/qoder/qoder.ts +0 -1
- package/src/providers/integrations/trae/trae-protocol.ts +9 -5
- package/src/providers/integrations/trae/trae-quota.ts +6 -28
- package/src/providers/integrations/trae/trae-realm.ts +38 -0
- package/src/providers/integrations/trae/trae.ts +7 -24
- package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
- package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
- package/src/providers/integrations/zro/zro.ts +204 -0
- package/src/providers/operations/account-error-classification.ts +199 -307
- package/src/providers/operations/account-health-service.ts +82 -1
- package/src/providers/operations/account-refresh-status.ts +22 -37
- package/src/providers/operations/account-tier.ts +15 -16
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +5 -51
- package/src/providers/operations/cooldown-rules.ts +11 -16
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +102 -32
- package/src/providers/operations/provider-rules/github.ts +48 -0
- package/src/providers/operations/provider-rules/grok.ts +33 -0
- package/src/providers/operations/provider-rules/inception.ts +49 -0
- package/src/providers/operations/provider-rules/index.ts +32 -0
- package/src/providers/operations/provider-rules/perch.ts +37 -0
- package/src/providers/operations/provider-rules/qoder.ts +70 -0
- package/src/providers/operations/provider-rules/trae.ts +81 -0
- package/src/providers/provider-contracts.ts +4 -2
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +40 -10
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-limit-windows.ts +16 -5
- package/src/providers/quota/quota-support.ts +1 -1
- package/src/providers/quota/quota-window-parser.ts +90 -18
- package/src/providers/quota/refresh.ts +75 -18
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/transport/dispatch/attempt-finalize.ts +14 -13
- package/src/transport/dispatch/attempt-loop.ts +71 -17
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +8 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/streaming/finalize.ts +9 -6
- package/src/transport/dispatch/streaming/stream.ts +8 -36
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +63 -0
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +16 -30
- package/src/transport/guards/body-policy.ts +7 -1
- package/src/transport/guards/error-lifecycle.ts +13 -1
- package/src/transport/guards/request-context.ts +22 -14
- package/src/transport/request/preparer.ts +81 -71
- package/src/transport/routing/bounded-lru.ts +14 -0
- package/src/transport/routing/drain-reserve.ts +129 -0
- package/src/transport/routing/plan-gate.ts +7 -1
- package/src/transport/routing/round-robin.ts +60 -0
- package/src/transport/routing/route-catalog.ts +123 -111
- package/src/transport/routing/route-model.ts +51 -9
- package/src/transport/routing/router.ts +393 -32
- package/src/transport/surface/adapters.ts +11 -2
- package/src/transport/surface/chat/adapter.ts +2 -2
- package/src/transport/surface/chat/encode.ts +47 -4
- package/src/transport/surface/chat/parse.ts +2 -12
- package/src/transport/surface/completion.ts +44 -33
- package/src/transport/surface/content-parts.ts +21 -0
- package/src/transport/surface/messages/adapter.ts +7 -1
- package/src/transport/surface/messages/encode.ts +11 -3
- package/src/transport/surface/messages/parse.ts +2 -1
- package/src/transport/surface/messages/stream.ts +33 -17
- package/src/transport/surface/responses/encode.ts +22 -5
- package/src/transport/surface/responses/parse.ts +3 -11
- package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
- package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
- package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
- package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
- package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
- package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
- package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
- package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
- package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
- package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
- package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
- package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
- package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
- package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
- package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
- package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
- package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
- package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
- package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
- package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
- package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
- package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
- package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
- package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
- package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/operations/model-discovery-cache.ts +0 -34
- package/src/providers/operations/probe-fetch.ts +0 -15
- package/src/providers/operations/provider-version-cache.ts +0 -30
- package/src/providers/provider-capabilities.ts +0 -33
- package/src/providers/provider-credential-envelope.ts +0 -43
- /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-DIXLjojg.js} +0 -0
- /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-DIXLjojg.js.gz} +0 -0
|
@@ -40,10 +40,9 @@ import { log } from "../../../observability/logger";
|
|
|
40
40
|
import {
|
|
41
41
|
TRAE_ENT_USAGE_PATH,
|
|
42
42
|
TRAE_ENT_USAGE_PATH_V2,
|
|
43
|
-
TRAE_REGION_CORE_HOSTS,
|
|
44
|
-
TRAE_REGION_PAY_HOSTS,
|
|
45
|
-
TRAE_REALMS,
|
|
46
43
|
TRAE_SESSION_USAGE_PATH,
|
|
44
|
+
traeCoreForAccount,
|
|
45
|
+
traePayHostForAccount,
|
|
47
46
|
type TraeRealm,
|
|
48
47
|
} from "./trae-realm";
|
|
49
48
|
|
|
@@ -326,27 +325,6 @@ function logTraeQuotaMiss(errors: readonly string[]): void {
|
|
|
326
325
|
* whose pay host is unreachable still has a readable meter, and reporting
|
|
327
326
|
* "no quota" for it would park an account that can still serve.
|
|
328
327
|
*/
|
|
329
|
-
/**
|
|
330
|
-
* The core host for this account.
|
|
331
|
-
*
|
|
332
|
-
* A provisioned region overrides the realm default: an `sg` account sent to the
|
|
333
|
-
* US core is answered 401 code 1001, which looks exactly like a dead token.
|
|
334
|
-
*/
|
|
335
|
-
function coreHost(region: string, config: (typeof TRAE_REALMS)[TraeRealm]): string {
|
|
336
|
-
return (region !== "" ? TRAE_REGION_CORE_HOSTS[region] : undefined) ?? config.core;
|
|
337
|
-
}
|
|
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
|
-
|
|
350
328
|
export async function fetchTraeQuota(
|
|
351
329
|
credential: string,
|
|
352
330
|
fetcher: FetchLike,
|
|
@@ -412,13 +390,13 @@ export async function fetchTraeQuota(
|
|
|
412
390
|
* realm is tried: one of them accepts, and that is the answer.
|
|
413
391
|
*/
|
|
414
392
|
const tryRealms = async (
|
|
415
|
-
path: (
|
|
393
|
+
path: (realm: TraeRealm) => string,
|
|
416
394
|
surface: string,
|
|
417
395
|
parse: (payload: unknown) => { readonly windows: readonly ProviderQuotaWindow[]; readonly plan: string | null },
|
|
418
396
|
): Promise<{ readonly windows: readonly ProviderQuotaWindow[]; readonly plan: string | null } | null> => {
|
|
419
397
|
for (const candidate of realm === "cn" ? (["cn", "intl"] as const) : (["intl", "cn"] as const)) {
|
|
420
398
|
try {
|
|
421
|
-
const payload = await call(candidate, path(
|
|
399
|
+
const payload = await call(candidate, path(candidate), surface);
|
|
422
400
|
return parse(payload);
|
|
423
401
|
} catch (error) {
|
|
424
402
|
errors.push(`${candidate} ${surface}: ${cleanError(error)}`);
|
|
@@ -427,11 +405,11 @@ export async function fetchTraeQuota(
|
|
|
427
405
|
return null;
|
|
428
406
|
};
|
|
429
407
|
|
|
430
|
-
const session = await tryRealms((
|
|
408
|
+
const session = await tryRealms((r) => traeCoreForAccount(r, region) + TRAE_SESSION_USAGE_PATH, "session usage", parseSessionUsage);
|
|
431
409
|
// The entitlement path differs by realm: the CN realm answers v2 (v1 lacks
|
|
432
410
|
// `usage_summary` there), the intl realm answers v1 (v2 is a 404).
|
|
433
411
|
const entPath = realm === "cn" ? TRAE_ENT_USAGE_PATH_V2 : TRAE_ENT_USAGE_PATH;
|
|
434
|
-
const entitlement = await tryRealms((
|
|
412
|
+
const entitlement = await tryRealms((r) => traePayHostForAccount(r, region) + entPath, "entitlement", parseEntitlement);
|
|
435
413
|
|
|
436
414
|
const windows = [...(session?.windows ?? []), ...(entitlement?.windows ?? [])];
|
|
437
415
|
if (!session && !entitlement) {
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
/** One Trae deployment. */
|
|
13
13
|
export type TraeRealm = "intl" | "cn";
|
|
14
14
|
|
|
15
|
+
/** Provider ids served by the Trae integration (intl + CN). */
|
|
16
|
+
export const TRAE_PROVIDER_IDS: ReadonlySet<string> = new Set(["trae", "traecn"]);
|
|
17
|
+
|
|
15
18
|
/** Per-realm upstream addresses, client identity, and auth scheme. */
|
|
16
19
|
export interface TraeRealmConfig {
|
|
17
20
|
/** Data-plane host: chat + model list (`/api/ide/v1/*`). */
|
|
@@ -245,3 +248,38 @@ export function traeAccountCandidates(realm: TraeRealm): readonly string[] {
|
|
|
245
248
|
const config = TRAE_REALMS[realm];
|
|
246
249
|
return [config.account, ...config.accountFallbacks];
|
|
247
250
|
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* The core host for this account.
|
|
254
|
+
*
|
|
255
|
+
* A provisioned region overrides the realm default: an `sg` account sent to the
|
|
256
|
+
* US core is answered 401 code 1001 (which looks exactly like a dead token), so
|
|
257
|
+
* the region lookup must win when it is known. Falling back to the realm keeps
|
|
258
|
+
* older accounts (stored before the region was captured) working exactly as
|
|
259
|
+
* before.
|
|
260
|
+
*/
|
|
261
|
+
export function traeCoreForAccount(
|
|
262
|
+
realm: TraeRealm,
|
|
263
|
+
region: string,
|
|
264
|
+
): string {
|
|
265
|
+
const regional = TRAE_REGION_CORE_HOSTS[region];
|
|
266
|
+
if (regional !== undefined) return regional;
|
|
267
|
+
return traeCoreCandidates(realm)[0] ?? "";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The pay host for this account.
|
|
272
|
+
*
|
|
273
|
+
* The pay surface correlates the credential against its region, too: an `sg`
|
|
274
|
+
* account sent to the US pay host is answered 401 code 1001, while the SG pay
|
|
275
|
+
* host accepts the same token (verified live 2026-11-06). Falls back to the
|
|
276
|
+
* realm default host when no region is provisioned.
|
|
277
|
+
*/
|
|
278
|
+
export function traePayHostForAccount(
|
|
279
|
+
realm: TraeRealm,
|
|
280
|
+
region: string,
|
|
281
|
+
): string {
|
|
282
|
+
const regional = TRAE_REGION_PAY_HOSTS[region];
|
|
283
|
+
if (regional !== undefined) return regional;
|
|
284
|
+
return TRAE_REALMS[realm].pay;
|
|
285
|
+
}
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
TRAE_AGENT_ENDPOINT,
|
|
32
32
|
TRAE_CHAT_ENDPOINT,
|
|
33
33
|
} from "./trae-protocol";
|
|
34
|
-
import {
|
|
34
|
+
import { traeCoreForAccount, TRAE_MODEL_LIST_PATH, TRAE_AGENT_FUNCTION, type TraeRealm } from "./trae-realm";
|
|
35
35
|
|
|
36
36
|
export interface TraeAdapterOptions {
|
|
37
37
|
readonly providerId?: string;
|
|
@@ -269,7 +269,11 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
269
269
|
trafficType: agentSurface ? "agent" : "chat",
|
|
270
270
|
});
|
|
271
271
|
|
|
272
|
-
const
|
|
272
|
+
const region =
|
|
273
|
+
typeof context.credential.auth_state?.["region"] === "string"
|
|
274
|
+
? context.credential.auth_state["region"].toLowerCase()
|
|
275
|
+
: "";
|
|
276
|
+
const primary = traeCoreForAccount(this.realm, region);
|
|
273
277
|
const path = agentSurface ? TRAE_AGENT_ENDPOINT : TRAE_CHAT_ENDPOINT;
|
|
274
278
|
const url =
|
|
275
279
|
candidate.endpoint_path && candidate.endpoint_path.startsWith("http")
|
|
@@ -572,10 +576,7 @@ export async function discoverTraeModels(input: {
|
|
|
572
576
|
uid: input.uid,
|
|
573
577
|
appVersion: getTraeVersion(),
|
|
574
578
|
});
|
|
575
|
-
const core = traeCoreForAccount(
|
|
576
|
-
input.realm,
|
|
577
|
-
input.region === undefined ? undefined : { region: input.region },
|
|
578
|
-
);
|
|
579
|
+
const core = traeCoreForAccount(input.realm, (input.region ?? "").toLowerCase());
|
|
579
580
|
|
|
580
581
|
if (input.realm === "intl") {
|
|
581
582
|
// The agent picker: the only surface that lists the intl roster's configs.
|
|
@@ -649,21 +650,3 @@ export async function discoverTraeModels(input: {
|
|
|
649
650
|
}
|
|
650
651
|
|
|
651
652
|
export { TRAE_CN_MODELS, TRAE_INTL_MODELS };
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Core host for one account.
|
|
655
|
-
*
|
|
656
|
-
* An intl account is provisioned into a region and its token only authenticates
|
|
657
|
-
* against that region's host, so the account's own `region` wins over the
|
|
658
|
-
* realm default. Falling back to the realm keeps older accounts (stored before
|
|
659
|
-
* the region was captured) working exactly as before.
|
|
660
|
-
*/
|
|
661
|
-
function traeCoreForAccount(
|
|
662
|
-
realm: TraeRealm,
|
|
663
|
-
authState: Readonly<Record<string, unknown>> | undefined,
|
|
664
|
-
): string {
|
|
665
|
-
const region = typeof authState?.["region"] === "string" ? authState["region"].toLowerCase() : "";
|
|
666
|
-
const regional = TRAE_REGION_CORE_HOSTS[region];
|
|
667
|
-
if (regional !== undefined) return regional;
|
|
668
|
-
return traeCoreCandidates(realm)[0] ?? "";
|
|
669
|
-
}
|
|
@@ -1,16 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ZCode Start Plan
|
|
3
|
-
*
|
|
4
|
-
* The
|
|
5
|
-
*
|
|
2
|
+
* ZCode Start Plan provider integration.
|
|
3
|
+
*
|
|
4
|
+
* The plan lane is an Anthropic Messages endpoint that only accepts the
|
|
5
|
+
* dressed ZCode client request (see `dress`): the gateway content-inspects the
|
|
6
|
+
* `system` field and refuses a request without the exact three-block identity
|
|
7
|
+
* fingerprint with `405 {code:3012}`. The credential is a ZCode login JWT —
|
|
8
|
+
* pasted, or minted by the sign-in flow (`oauth.ts`).
|
|
9
|
+
*
|
|
10
|
+
* Wire facts mirrored from the donor gateway (verified live 2026-10-30):
|
|
11
|
+
* - `anthropic-beta: mid-conversation-system-2026-04-07` rides every request.
|
|
12
|
+
* - `metadata.user_id` is a JSON string `{"device_id","account_uuid","session_id"}`
|
|
13
|
+
* the gateway reads for attribution; it lives in the body, not a header.
|
|
14
|
+
* - The LLM identity face carries per-request correlation ids: `x-session-id`,
|
|
15
|
+
* `x-request-id`, `x-zcode-trace-id`, `x-query-id`, `x-zcode-query-source`.
|
|
16
|
+
* - Errors inside an HTTP 200 response come as a `{code,msg,logid}` envelope
|
|
17
|
+
* (`1113` grant spent, `3009` model concurrency, `3012` identity gate) and
|
|
18
|
+
* are mapped through the shared `classifyUpstreamError`.
|
|
6
19
|
*/
|
|
7
20
|
import { randomUUID } from "node:crypto";
|
|
8
21
|
import { release as osRelease } from "node:os";
|
|
9
22
|
|
|
10
|
-
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
11
23
|
import { defineModel } from "../../provider-model-definition";
|
|
12
24
|
import type { ModelDefinition } from "../../provider-model-definition";
|
|
13
25
|
import { getOrCreateInstallId } from "../shared/install-id";
|
|
26
|
+
import { resolveInboundSessionId } from "../../operations/session-resolution";
|
|
27
|
+
import { assertCredentialKind, assertWireFamily } from "../../provider-contracts";
|
|
28
|
+
import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
|
|
29
|
+
import { GatewayError } from "../../../protocol/gateway-error";
|
|
30
|
+
import { applyParamQuirks } from "../../../protocol/translation/quirks";
|
|
31
|
+
import { buildClaudeMessagesRequest, filterClaudeCustomHeaders } from "../shared/claude-messages";
|
|
32
|
+
import { mapClaudeHttpError } from "../../../protocol/messages-errors";
|
|
33
|
+
import { isRecord } from "../../../protocol/codecs";
|
|
34
|
+
import { classifyUpstreamError, upstreamErrorIdentifier, upstreamMessageAsIs } from "../../../transport/failure-policy";
|
|
35
|
+
import { parseClaudeSseStream, claudeResponseToEvents } from "../../../protocol/response/messages";
|
|
36
|
+
import { createUpstreamDeadlineLifecycle } from "../../operations/upstream-deadline";
|
|
37
|
+
import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
|
|
38
|
+
import { parseJwt } from "../../authentication/jwt-validator";
|
|
14
39
|
import prompt from "./zcode_prompt.json";
|
|
15
40
|
|
|
16
41
|
const CLI_PREFIX: string = prompt.cliPrefix;
|
|
@@ -21,8 +46,18 @@ export const ZCODE_START_PLAN_PROVIDER_ID = "zcode-start" as const;
|
|
|
21
46
|
export const ZCODE_START_PLAN_ENDPOINT_PATH = "/v1/messages" as const;
|
|
22
47
|
export const ZCODE_START_PLAN_BASE_URL = "https://zcode.z.ai/api/v1/zcode-plan/anthropic" as const;
|
|
23
48
|
|
|
24
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Client version the plan endpoint expects in the identity headers. This is
|
|
51
|
+
* kept in step with the bundled prompt asset (`zcode_prompt.json`, 3.14.5):
|
|
52
|
+
* the gateway content-inspects the system blocks, and a version/prompt split
|
|
53
|
+
* (e.g. 3.16.3 headers over 3.14.5 blocks) risks the 3012 identity gate. Bump
|
|
54
|
+
* both together only after re-capturing the live blocks and re-verifying.
|
|
55
|
+
*/
|
|
25
56
|
const APP_VERSION = "3.14.5";
|
|
57
|
+
/** Anthropic beta the desktop client sends on the plan lane (captured live). */
|
|
58
|
+
const ANTHROPIC_BETA = "mid-conversation-system-2026-04-07";
|
|
59
|
+
/** The plan gateway enforces a serial per-account in-flight limit; 8192 is the desktop default. */
|
|
60
|
+
const DEFAULT_MAX_TOKENS = 8192;
|
|
26
61
|
|
|
27
62
|
type Loose = Record<string, unknown>;
|
|
28
63
|
type TextBlock = { type: "text"; text: string; cache_control?: { type: "ephemeral" } };
|
|
@@ -40,26 +75,47 @@ function environmentBlock(provider: string, model: string): string {
|
|
|
40
75
|
.replace("{model}", model);
|
|
41
76
|
}
|
|
42
77
|
|
|
78
|
+
/** The account uuid carried by the plan JWT, for metadata attribution. */
|
|
79
|
+
function jwtUserId(credential: { secret?: Uint8Array | undefined } | undefined): string {
|
|
80
|
+
if (!credential?.secret || credential.secret.length === 0) return "";
|
|
81
|
+
try {
|
|
82
|
+
const token = new TextDecoder().decode(credential.secret);
|
|
83
|
+
const parsed = parseJwt(token);
|
|
84
|
+
const userId = parsed?.payload?.["user_id"];
|
|
85
|
+
return typeof userId === "string" ? userId : "";
|
|
86
|
+
} catch {
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
43
91
|
/** Identity headers every dispatch carries; the adapter adds Authorization. */
|
|
44
|
-
async function identityHeaders(): Promise<Record<string, string>> {
|
|
92
|
+
async function identityHeaders(context: ProviderDispatchContext): Promise<Record<string, string>> {
|
|
93
|
+
const sessionId = resolveInboundSessionId(context) ?? `session_${randomUUID().replace(/-/g, "").slice(0, 32)}`;
|
|
94
|
+
const requestId = randomUUID();
|
|
95
|
+
const traceId = randomUUID();
|
|
96
|
+
const queryId = `01a1${requestId.slice(4).replace(/-/g, "").slice(0, 28)}`;
|
|
97
|
+
const deviceMid = await getOrCreateInstallId("zcode-start-plan");
|
|
45
98
|
return {
|
|
46
99
|
"user-agent": `ZCode/${APP_VERSION} ai-sdk/anthropic/3.0.81`,
|
|
47
100
|
"http-referer": "https://zcode.z.ai",
|
|
48
|
-
"x-title": "Z Code@
|
|
101
|
+
"x-title": "Z Code@electron",
|
|
49
102
|
"x-zcode-app-version": APP_VERSION,
|
|
50
103
|
"x-zcode-agent": "glm",
|
|
51
104
|
"x-release-channel": "production",
|
|
52
105
|
"x-client-language": "en-US",
|
|
53
106
|
"x-client-timezone": "Asia/Jakarta",
|
|
54
|
-
"x-platform": "linux",
|
|
107
|
+
"x-platform": "linux-x64",
|
|
55
108
|
"x-os-category": "linux",
|
|
56
109
|
"x-os-version": osRelease(),
|
|
57
|
-
"x-request-id":
|
|
110
|
+
"x-request-id": requestId,
|
|
111
|
+
"x-query-id": queryId,
|
|
112
|
+
"x-zcode-trace-id": traceId,
|
|
58
113
|
"x-zcode-session-type": "main",
|
|
59
|
-
"x-zcode-
|
|
60
|
-
|
|
61
|
-
"x-device-mid":
|
|
114
|
+
"x-zcode-query-source": "main_turn",
|
|
115
|
+
"x-session-id": sessionId,
|
|
116
|
+
"x-device-mid": deviceMid,
|
|
62
117
|
"anthropic-version": "2023-06-01",
|
|
118
|
+
"anthropic-beta": ANTHROPIC_BETA,
|
|
63
119
|
};
|
|
64
120
|
}
|
|
65
121
|
|
|
@@ -119,13 +175,160 @@ export const ZCODE_START_PLAN_MODELS: readonly ModelDefinition[] = [
|
|
|
119
175
|
}),
|
|
120
176
|
];
|
|
121
177
|
|
|
122
|
-
/**
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
178
|
+
/** True when the body is the ZCode `{code,msg,logid}` business-error envelope. */
|
|
179
|
+
function isZcodeEnvelopeError(body: Record<string, unknown>): boolean {
|
|
180
|
+
if (body["success"] === false) return true;
|
|
181
|
+
const code = body["code"];
|
|
182
|
+
return code !== undefined && ![0, 200, "0", "200"].includes(code as string | number);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Plan-lane Messages adapter. Unlike the plain Anthropic adapter it must (a)
|
|
187
|
+
* dress the three-block system fingerprint, (b) inject `metadata.user_id`, and
|
|
188
|
+
* (c) treat a `{code,msg}` envelope inside an HTTP 200 as a refusal — the
|
|
189
|
+
* gateway reports business errors on success statuses.
|
|
190
|
+
*/
|
|
191
|
+
export class ZcodeStartPlanAdapter implements ProviderAdapter {
|
|
192
|
+
readonly provider_id = ZCODE_START_PLAN_PROVIDER_ID;
|
|
193
|
+
private readonly fetchFn: typeof fetch;
|
|
194
|
+
private readonly baseUrl: string;
|
|
195
|
+
|
|
196
|
+
constructor(fetchImpl?: typeof fetch, baseUrl?: string) {
|
|
197
|
+
this.fetchFn = fetchImpl ?? globalThis.fetch;
|
|
198
|
+
this.baseUrl = (baseUrl ?? ZCODE_START_PLAN_BASE_URL).replace(/\/+$/, "");
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async *dispatch(
|
|
202
|
+
request: CanonicalRequest,
|
|
203
|
+
candidate: ProviderDispatchTarget,
|
|
204
|
+
context: ProviderDispatchContext,
|
|
205
|
+
): AsyncIterable<CanonicalEvent> {
|
|
206
|
+
if (candidate.wire_family !== "messages") {
|
|
207
|
+
assertWireFamily(candidate, "messages", "zcode-start messages leg");
|
|
208
|
+
}
|
|
209
|
+
if (context.credential.credential_kind !== "api_key") {
|
|
210
|
+
assertCredentialKind(context.credential, "api_key", "zcode-start");
|
|
211
|
+
}
|
|
212
|
+
if (context.credential.secret === undefined || context.credential.secret.length === 0) {
|
|
213
|
+
throw new GatewayError(
|
|
214
|
+
"invalid_request",
|
|
215
|
+
400,
|
|
216
|
+
"zcode-start: plan JWT is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑",
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const planJwt = new TextDecoder().decode(context.credential.secret);
|
|
220
|
+
const sessionId = resolveInboundSessionId(context, request) ?? `session_${randomUUID().replace(/-/g, "").slice(0, 32)}`;
|
|
221
|
+
const deviceMid = await getOrCreateInstallId("zcode-start-plan");
|
|
222
|
+
const accountUuid = jwtUserId(context.credential);
|
|
223
|
+
const customHeaders = filterClaudeCustomHeaders({
|
|
224
|
+
...context.credential.custom_headers,
|
|
225
|
+
});
|
|
226
|
+
const outbound = buildClaudeMessagesRequest({
|
|
227
|
+
request: applyParamQuirks(request, candidate.provider_id),
|
|
228
|
+
authHeader: "bearer",
|
|
229
|
+
credential: { secret: planJwt, customHeaders },
|
|
230
|
+
baseUrl: this.baseUrl,
|
|
231
|
+
endpointPath: candidate.endpoint_path,
|
|
232
|
+
mutatePayload: (payload) => {
|
|
233
|
+
dress(payload);
|
|
234
|
+
const metadata = (isRecord(payload["metadata"]) ? payload["metadata"] : {}) as Loose;
|
|
235
|
+
metadata["user_id"] = JSON.stringify({
|
|
236
|
+
device_id: deviceMid,
|
|
237
|
+
account_uuid: accountUuid,
|
|
238
|
+
session_id: sessionId,
|
|
239
|
+
});
|
|
240
|
+
payload.metadata = metadata;
|
|
241
|
+
if (payload["max_tokens"] == null) payload["max_tokens"] = DEFAULT_MAX_TOKENS;
|
|
242
|
+
return payload;
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
Object.assign(outbound.headers, await identityHeaders(context));
|
|
246
|
+
|
|
247
|
+
const outboundFetch = context.outbound_fetch ?? this.fetchFn;
|
|
248
|
+
const lifecycle = createUpstreamDeadlineLifecycle(context);
|
|
249
|
+
let response: Response;
|
|
250
|
+
try {
|
|
251
|
+
response = await outboundFetch(outbound.url, {
|
|
252
|
+
method: "POST",
|
|
253
|
+
headers: outbound.headers,
|
|
254
|
+
body: outbound.body,
|
|
255
|
+
signal: lifecycle.signal,
|
|
256
|
+
});
|
|
257
|
+
} catch (error: unknown) {
|
|
258
|
+
lifecycle.release();
|
|
259
|
+
if (error instanceof GatewayError) throw error;
|
|
260
|
+
throw new GatewayError(
|
|
261
|
+
"transport_unavailable",
|
|
262
|
+
502,
|
|
263
|
+
`zcode-start upstream fetch failed: ${(error as Error)?.message ?? String(error)}`,
|
|
264
|
+
{},
|
|
265
|
+
"network",
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
lifecycle.release();
|
|
269
|
+
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
const bodyText = await response.text().catch(() => "");
|
|
272
|
+
throw mapClaudeHttpError(response.status, bodyText, response.headers);
|
|
273
|
+
}
|
|
274
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
275
|
+
if (contentType.toLowerCase().includes("text/event-stream") || request.stream) {
|
|
276
|
+
if (response.body === null) {
|
|
277
|
+
throw new GatewayError(
|
|
278
|
+
"platform_unavailable",
|
|
279
|
+
502,
|
|
280
|
+
"zcode-start returned no stream body (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
281
|
+
{},
|
|
282
|
+
"upstream",
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
yield* parseClaudeSseStream(response.body, context.abort_signal, false);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
const bodyText = await response.text().catch(() => "");
|
|
289
|
+
let json: unknown;
|
|
290
|
+
try {
|
|
291
|
+
json = JSON.parse(bodyText) as unknown;
|
|
292
|
+
} catch {
|
|
293
|
+
const upstreamText = upstreamMessageAsIs(bodyText, "");
|
|
294
|
+
throw new GatewayError(
|
|
295
|
+
"platform_unavailable",
|
|
296
|
+
502,
|
|
297
|
+
upstreamText.message || "zcode-start response is not valid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
298
|
+
{ raw: bodyText.slice(0, 4096) },
|
|
299
|
+
"upstream",
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
if (!isRecord(json)) {
|
|
303
|
+
throw new GatewayError(
|
|
304
|
+
"platform_unavailable",
|
|
305
|
+
502,
|
|
306
|
+
"zcode-start response must be an object (request {requestId}). The upstream came back empty-handed — retry 🌙",
|
|
307
|
+
{},
|
|
308
|
+
"upstream",
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
if (isZcodeEnvelopeError(json)) {
|
|
312
|
+
const identifier = upstreamErrorIdentifier(json);
|
|
313
|
+
const classification = classifyUpstreamError(undefined, identifier);
|
|
314
|
+
const upstreamText = upstreamMessageAsIs(json, "");
|
|
315
|
+
throw new GatewayError(
|
|
316
|
+
classification.code,
|
|
317
|
+
classification.status,
|
|
318
|
+
upstreamText.message || "zcode-start reported an upstream error",
|
|
319
|
+
{
|
|
320
|
+
providerId: this.provider_id,
|
|
321
|
+
...(identifier === undefined ? {} : { providerCode: identifier }),
|
|
322
|
+
...(upstreamText.hadUpstreamText ? { upstreamMessageAsIs: true } : {}),
|
|
323
|
+
raw: bodyText.slice(0, 4096),
|
|
324
|
+
},
|
|
325
|
+
classification.origin,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
yield* claudeResponseToEvents(json, request, false);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function createZcodeStartPlanAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
|
|
333
|
+
return new ZcodeStartPlanAdapter(fetchImpl);
|
|
334
|
+
}
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { asCoercedNumber, asRecord, asTrimmedString } from "../../../shared/coerce";
|
|
2
3
|
import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
|
|
3
4
|
|
|
4
5
|
const BALANCE_URL = "https://zcode.z.ai/api/v1/zcode-plan/billing/balance?app_version=3.16.3";
|
|
5
|
-
const DEVICE_MID = "9f1b0d4e-3c2a-4e7b-9f1d-6a2c8b5e0d31";
|
|
6
6
|
const APP_VERSION = "3.16.3";
|
|
7
|
+
const PLATFORM = "linux-x64";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Stable per-account device mid. The gateway validates `X-Device-Mid` as a
|
|
11
|
+
* UUID (billing answers `3001 parameter error` without it) and attributes
|
|
12
|
+
* usage to it; a hardcoded shared UUID would lump every account into one
|
|
13
|
+
* billing identity. Derivation matches the gift-claim device id, so quota and
|
|
14
|
+
* claim present the same device per account.
|
|
15
|
+
*/
|
|
16
|
+
function deviceMid(accountId: string): string {
|
|
17
|
+
const hash = createHash("sha256").update(`zcode-device\0${accountId}`).digest("hex");
|
|
18
|
+
const variant = ((parseInt(hash[16] as string, 16) & 3) | 8).toString(16);
|
|
19
|
+
return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-4${hash.slice(13, 16)}-${variant}${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
|
|
20
|
+
}
|
|
7
21
|
|
|
8
22
|
function instant(value: unknown): string | null {
|
|
9
23
|
const seconds = asCoercedNumber(value);
|
|
@@ -57,16 +71,19 @@ function samePlan(bucket: Record<string, unknown>, plan: Record<string, unknown>
|
|
|
57
71
|
export async function fetchZcodeStartPlanQuota(
|
|
58
72
|
credential: string,
|
|
59
73
|
fetcher: FetchLike,
|
|
74
|
+
context?: { accountId?: string },
|
|
60
75
|
): Promise<ProviderQuotaResult> {
|
|
61
76
|
const source = "zcode-start";
|
|
62
77
|
try {
|
|
78
|
+
const accountId = context?.accountId ?? credential.trim();
|
|
63
79
|
const response = await fetcher(BALANCE_URL, {
|
|
64
80
|
headers: {
|
|
65
81
|
authorization: `Bearer ${credential}`,
|
|
66
82
|
accept: "application/json",
|
|
67
|
-
"x-device-mid":
|
|
83
|
+
"x-device-mid": deviceMid(accountId),
|
|
68
84
|
"x-zcode-app-version": APP_VERSION,
|
|
69
85
|
"x-client-language": "en-US",
|
|
86
|
+
"x-platform": PLATFORM,
|
|
70
87
|
},
|
|
71
88
|
signal: AbortSignal.timeout(15_000),
|
|
72
89
|
});
|