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
|
@@ -167,6 +167,14 @@ export function materializeBuddyDeviceBinding(
|
|
|
167
167
|
* the operator pinned them in `auth_state` (there is no reliable source to
|
|
168
168
|
* invent them from). An opaque API key carries no uid and yields nothing.
|
|
169
169
|
*/
|
|
170
|
+
/** A short printable identity claim from a JWT payload, or `undefined`. */
|
|
171
|
+
function identityClaim(claims: Record<string, unknown> | undefined, name: string): string | undefined {
|
|
172
|
+
if (claims === undefined) return undefined;
|
|
173
|
+
const value = claims[name];
|
|
174
|
+
if (typeof value === "string" && value.trim().length > 0 && value.trim().length <= 128) return value.trim();
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
170
178
|
export function buddyOAuthIdentityHeaders(
|
|
171
179
|
context?: ProviderDispatchContext,
|
|
172
180
|
): Record<string, string> {
|
|
@@ -175,15 +183,20 @@ export function buddyOAuthIdentityHeaders(
|
|
|
175
183
|
const uid = buddyAccountUid(token) ?? context?.credential.account_id ?? "";
|
|
176
184
|
if (uid.length === 0) return {};
|
|
177
185
|
const enterpriseId = buddyEnterprise(context);
|
|
186
|
+
// The reference gateway reads `id_source` / `token_source` from the JWT
|
|
187
|
+
// payload and the account record, not from stored auth state — an account
|
|
188
|
+
// authorized before either was persisted still carries them on the wire.
|
|
189
|
+
// Precedence matches the donor (`client_profiles._identity_claim_headers`):
|
|
190
|
+
// account fields first, then JWT claims, then legacy `auth_state`.
|
|
191
|
+
const claims = token.length > 0 ? decodeJwtPayload(token) : undefined;
|
|
178
192
|
const state = context?.credential.auth_state;
|
|
179
193
|
const idSource =
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
identityClaim(claims, "id_source") ??
|
|
195
|
+
identityClaim(claims, "idSource") ??
|
|
196
|
+
identityClaim(state as Record<string, unknown> | undefined, "idSource");
|
|
183
197
|
const method =
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
: undefined;
|
|
198
|
+
identityClaim(claims, "token_source") ??
|
|
199
|
+
identityClaim(state as Record<string, unknown> | undefined, "authMethod");
|
|
187
200
|
const headers: Record<string, string> = { "X-User-Id": uid };
|
|
188
201
|
if (method !== undefined) headers["X-Auth-Method"] = method;
|
|
189
202
|
if (idSource !== undefined) headers["X-Id-Source"] = idSource;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// dynamic-import-ok: lazy per-realm capability map. Each buddy regional
|
|
2
2
|
// product (cb/cbcn) imports its adapter + oauth + discovery on first use so a
|
|
3
3
|
// deployment that only serves one realm never drags the others into memory.
|
|
4
|
-
import type { ProviderModuleCapabilities } from "../../provider-
|
|
5
|
-
import { oauthCapability, quotaCapability } from "../../provider-
|
|
4
|
+
import type { ProviderModuleCapabilities } from "../../provider-registry";
|
|
5
|
+
import { oauthCapability, quotaCapability } from "../../provider-registry";
|
|
6
6
|
|
|
7
7
|
type BuddyProviderId = "cb" | "cbcn";
|
|
8
8
|
|
|
@@ -168,6 +168,9 @@ export function createCodeBuddyCnAdapter(fetchImpl?: typeof fetch): ProviderAdap
|
|
|
168
168
|
baseUrl: CODEBUDDY_CN_BASE_URL,
|
|
169
169
|
variant: "CLI",
|
|
170
170
|
prePayload: codeBuddyCnPrePayload,
|
|
171
|
+
// The CN CLI profile gzips the chat body (donor behavior). The console
|
|
172
|
+
// channel fallback is an intl-only recovery; CN has no second endpoint.
|
|
173
|
+
requestCompression: "gzip",
|
|
171
174
|
...(fetchImpl ? { fetchImpl } : {}),
|
|
172
175
|
}),
|
|
173
176
|
{
|
|
@@ -160,6 +160,10 @@ export function createCodeBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapte
|
|
|
160
160
|
variant: "IDE",
|
|
161
161
|
cliIdentity: true,
|
|
162
162
|
prePayload: codeBuddyIntlPrePayload,
|
|
163
|
+
// The intl CLI profile gzips the chat body and recovers a channel-check
|
|
164
|
+
// 400 by retrying once on the console chat endpoint (donor behavior).
|
|
165
|
+
requestCompression: "gzip",
|
|
166
|
+
channelFallbackPath: "/console/chat/completions",
|
|
163
167
|
...(fetchImpl ? { fetchImpl } : {}),
|
|
164
168
|
}),
|
|
165
169
|
{
|
|
@@ -87,7 +87,7 @@ export async function codebuddyHeaders(
|
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
89
|
const purpose = buddyAgentPurpose(context, request);
|
|
90
|
-
|
|
90
|
+
const headers: Record<string, string> = {
|
|
91
91
|
accept: "text/event-stream",
|
|
92
92
|
"User-Agent": ua,
|
|
93
93
|
"X-Product": "SaaS",
|
|
@@ -100,28 +100,29 @@ export async function codebuddyHeaders(
|
|
|
100
100
|
"X-Domain": codebuddyDomain(variant),
|
|
101
101
|
"x-requested-with": "XMLHttpRequest",
|
|
102
102
|
"x-codebuddy-request": "1",
|
|
103
|
-
// The effective agent purpose, matching the reference's dynamic value.
|
|
104
|
-
// The reference does not invent `conversation`; it sends the purpose only
|
|
105
|
-
// when one exists.
|
|
106
|
-
...(purpose === undefined ? {} : { "X-Agent-Purpose": purpose }),
|
|
107
|
-
// The upstream's channel check reads the turn-level aggregation key, and a
|
|
108
|
-
// chat request without it is refused for a missing conversation id.
|
|
109
|
-
...conversation,
|
|
110
|
-
// Per-account device binding (qimei36) — distinct device per account.
|
|
111
|
-
...(() => {
|
|
112
|
-
const binding = resolveBuddyDeviceBinding(context);
|
|
113
|
-
return binding === undefined ? {} : { "X-Device-Id-List": JSON.stringify({ qimei36: binding }) };
|
|
114
|
-
})(),
|
|
115
|
-
// The desktop client sends the device-token pair on both realms. Captured
|
|
116
|
-
// token (auth_state / device-token file) when present, otherwise the
|
|
117
|
-
// official failure placeholder. (CLI branch above already returned without
|
|
118
|
-
// device headers.)
|
|
119
|
-
...(await buddyDeviceTokenHeaders({
|
|
120
|
-
realm: identity === "IDE" ? "intl" : "cn",
|
|
121
|
-
context,
|
|
122
|
-
cliIdentity,
|
|
123
|
-
})),
|
|
124
103
|
};
|
|
104
|
+
// The effective agent purpose, matching the reference's dynamic value.
|
|
105
|
+
// The reference does not invent `conversation`; it sends the purpose only
|
|
106
|
+
// when one exists.
|
|
107
|
+
if (purpose !== undefined) headers["X-Agent-Purpose"] = purpose;
|
|
108
|
+
// The upstream's channel check reads the turn-level aggregation key, and a
|
|
109
|
+
// chat request without it is refused for a missing conversation id.
|
|
110
|
+
Object.assign(headers, conversation);
|
|
111
|
+
// Per-account device binding (qimei36) — distinct device per account.
|
|
112
|
+
const binding = resolveBuddyDeviceBinding(context);
|
|
113
|
+
if (binding !== undefined) {
|
|
114
|
+
headers["X-Device-Id-List"] = JSON.stringify({ qimei36: binding });
|
|
115
|
+
}
|
|
116
|
+
// The desktop client sends the device-token pair on both realms. Captured
|
|
117
|
+
// token (auth_state / device-token file) when present, otherwise the
|
|
118
|
+
// official failure placeholder. (CLI branch above already returned without
|
|
119
|
+
// device headers.)
|
|
120
|
+
Object.assign(headers, await buddyDeviceTokenHeaders({
|
|
121
|
+
realm: identity === "IDE" ? "intl" : "cn",
|
|
122
|
+
context,
|
|
123
|
+
cliIdentity,
|
|
124
|
+
}));
|
|
125
|
+
return headers;
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
/**
|
|
@@ -140,6 +141,14 @@ export function codebuddyAdapterConfig(args: {
|
|
|
140
141
|
) => void;
|
|
141
142
|
fetchImpl?: typeof fetch;
|
|
142
143
|
cliIdentity?: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Body compression for chat dispatches. The CodeBuddy CLI contract (donor
|
|
146
|
+
* `codebuddy2api`) gzips the JSON body for the CLI profiles and sends
|
|
147
|
+
* `Accept-Encoding: identity`. `"json"` (default) keeps plain JSON.
|
|
148
|
+
*/
|
|
149
|
+
requestCompression?: "json" | "gzip";
|
|
150
|
+
/** When set, retry a channel-check 400 against this path (console fallback). */
|
|
151
|
+
channelFallbackPath?: string;
|
|
143
152
|
}): OpenAICompatibleAdapterConfig {
|
|
144
153
|
return withBearerAuthentication({
|
|
145
154
|
provider_id: args.providerId,
|
|
@@ -147,6 +156,12 @@ export function codebuddyAdapterConfig(args: {
|
|
|
147
156
|
buildExtraHeaders: (context, request) =>
|
|
148
157
|
codebuddyHeaders(args.variant, context, request, args.cliIdentity),
|
|
149
158
|
prePayload: args.prePayload,
|
|
159
|
+
...(args.requestCompression === undefined
|
|
160
|
+
? {}
|
|
161
|
+
: { request_compression: args.requestCompression }),
|
|
162
|
+
...(args.channelFallbackPath === undefined
|
|
163
|
+
? {}
|
|
164
|
+
: { channel_fallback_path: args.channelFallbackPath }),
|
|
150
165
|
...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
|
|
151
166
|
});
|
|
152
167
|
}
|
|
@@ -102,9 +102,13 @@ export async function fetchClaudeQuota(
|
|
|
102
102
|
credential: string,
|
|
103
103
|
fetcher: FetchLike,
|
|
104
104
|
): Promise<ProviderQuotaResult> {
|
|
105
|
+
// No module-local quota cache: the shared two-tier quota cache owns
|
|
106
|
+
// cross-call dedup, and a local tier keyed by credential only is never
|
|
107
|
+
// invalidated by `debitCachedQuota`, so a sweep within its TTL could
|
|
108
|
+
// resurrect a spent balance over the shared cache. Every call here is a
|
|
109
|
+
// fresh upstream read; the shared cache's in-flight dedup prevents
|
|
110
|
+
// duplicate traffic.
|
|
105
111
|
const key = sha256Hex(credential);
|
|
106
|
-
const cached = quotaCache.get(key);
|
|
107
|
-
if (cached !== undefined) return cached;
|
|
108
112
|
if (quotaCooldown.get(key) !== undefined) {
|
|
109
113
|
throw new Error("Quota endpoint rejected request: rate limited (cooled down)");
|
|
110
114
|
}
|
|
@@ -131,9 +135,7 @@ export async function fetchClaudeQuota(
|
|
|
131
135
|
},
|
|
132
136
|
observing,
|
|
133
137
|
);
|
|
134
|
-
|
|
135
|
-
quotaCache.set(key, result);
|
|
136
|
-
return result;
|
|
138
|
+
return parseClaudeQuota(body);
|
|
137
139
|
} catch (error: unknown) {
|
|
138
140
|
// Hammering the usage endpoint on every call is its own rate-limit
|
|
139
141
|
// risk: back off briefly after a 429 instead of retrying into it.
|
|
@@ -143,21 +145,16 @@ export async function fetchClaudeQuota(
|
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
/**
|
|
146
|
-
*
|
|
147
|
-
* (3 min). Keys are credential hashes, never raw secrets; both caches are
|
|
148
|
+
* Short 429 cooldown (3 min). Keys are credential hashes, never raw secrets;
|
|
148
149
|
* capped so credential fan-out cannot pin memory.
|
|
150
|
+
*
|
|
151
|
+
* The cooldown is an absolute window (`until = now + QUOTA_COOLDOWN_MS`), not a
|
|
152
|
+
* TTL from read time, so it is a sentinel whose own TTL *is* that window: the
|
|
153
|
+
* entry lives for exactly the cooldown and is gone the moment it closes.
|
|
149
154
|
*/
|
|
150
|
-
const QUOTA_CACHE_TTL_MS = 5 * 60_000;
|
|
151
155
|
const QUOTA_COOLDOWN_MS = 3 * 60_000;
|
|
152
|
-
const
|
|
153
|
-
const quotaCache = new TtlCache<ProviderQuotaResult>({
|
|
154
|
-
ttlMs: QUOTA_CACHE_TTL_MS,
|
|
155
|
-
maxEntries: QUOTA_CACHE_MAX_ENTRIES,
|
|
156
|
-
});
|
|
157
|
-
// The cooldown is an absolute window (`until = now + QUOTA_COOLDOWN_MS`), not a
|
|
158
|
-
// TTL from read time, so it is a sentinel whose own TTL *is* that window: the
|
|
159
|
-
// entry lives for exactly the cooldown and is gone the moment it closes.
|
|
156
|
+
const QUOTA_COOLDOWN_MAX_ENTRIES = 256;
|
|
160
157
|
const quotaCooldown = new TtlCache<true>({
|
|
161
158
|
ttlMs: QUOTA_COOLDOWN_MS,
|
|
162
|
-
maxEntries:
|
|
159
|
+
maxEntries: QUOTA_COOLDOWN_MAX_ENTRIES,
|
|
163
160
|
});
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createApiKeyAdapter } from "../../configured-provider";
|
|
2
2
|
import type { ProviderDispatchTarget, ProviderAdapter, ProviderDispatchContext } from "../../provider-contracts";
|
|
3
3
|
import type { ModelDefinition } from "../../provider-model-definition";
|
|
4
|
-
import { unwrapProviderToken } from "../../provider-
|
|
4
|
+
import { unwrapProviderToken } from "../../provider-credentials";
|
|
5
5
|
import { GatewayError } from "../../../protocol/gateway-error";
|
|
6
6
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
7
7
|
import { completeRequiredSchema, isRecord } from "../../../protocol/codecs";
|
|
8
8
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
9
|
-
import { getCachedModelDiscovery } from "../../operations/
|
|
9
|
+
import { getCachedModelDiscovery } from "../../operations/provider-caches";
|
|
10
10
|
import { defineModel } from "../../provider-model-definition";
|
|
11
11
|
import { clineReasoningReplayPrepares } from "../buddy/buddy-chat-shared";
|
|
12
12
|
import { clinePlatform, clinePlatformVersion } from "../../operations/cli-platform";
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
* independent: retain the balance or subscription when the other is unavailable.
|
|
16
16
|
*/
|
|
17
17
|
import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
|
|
18
|
+
import { isoDate } from "../../quota/quota-contracts";
|
|
19
|
+
import { asCoercedNumber, asRecord } from "../../../shared/coerce";
|
|
18
20
|
|
|
19
21
|
const COMMANDCODE_API_BASE = "https://api.commandcode.ai" as const;
|
|
20
22
|
const REQUEST_TIMEOUT_MS = 15_000;
|
|
@@ -73,29 +75,21 @@ async function readJson(
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
|
-
|
|
77
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
78
|
-
? (value as Record<string, unknown>)
|
|
79
|
-
: undefined;
|
|
80
|
-
}
|
|
81
|
-
|
|
78
|
+
/** Numeric value coerced via the shared helper, or `null` (shared sentinel). */
|
|
82
79
|
function numberOrNull(value: unknown): number | null {
|
|
83
|
-
|
|
84
|
-
if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) {
|
|
85
|
-
return Number(value);
|
|
86
|
-
}
|
|
87
|
-
return null;
|
|
80
|
+
return asCoercedNumber(value) ?? null;
|
|
88
81
|
}
|
|
89
82
|
|
|
83
|
+
/**
|
|
84
|
+
* ISO timestamp from a numeric epoch (seconds vs ms via the 1e12 boundary) or
|
|
85
|
+
* a parseable date string, else `null` — the shared `isoDate` semantics. The
|
|
86
|
+
* one local delta kept: a non-positive numeric is `null` (no deadline) rather
|
|
87
|
+
* than an epoch 0/negative instant.
|
|
88
|
+
*/
|
|
90
89
|
function isoTimestamp(value: unknown): string | null {
|
|
91
90
|
const numeric = numberOrNull(value);
|
|
92
|
-
if (numeric !== null)
|
|
93
|
-
|
|
94
|
-
const date = new Date(numeric > 1_000_000_000_000 ? numeric : numeric * 1000);
|
|
95
|
-
return Number.isFinite(date.getTime()) ? date.toISOString() : null;
|
|
96
|
-
}
|
|
97
|
-
if (typeof value !== "string" || !Number.isFinite(Date.parse(value))) return null;
|
|
98
|
-
return new Date(value).toISOString();
|
|
91
|
+
if (numeric !== null && numeric <= 0) return null;
|
|
92
|
+
return isoDate(value);
|
|
99
93
|
}
|
|
100
94
|
|
|
101
95
|
function withQuery(path: string, params: Readonly<Record<string, string | null>>): string {
|
|
@@ -149,8 +143,8 @@ function windowLimits(
|
|
|
149
143
|
limits: Record<string, unknown>,
|
|
150
144
|
): readonly ProviderQuotaWindow[] {
|
|
151
145
|
const out: ProviderQuotaWindow[] = [];
|
|
152
|
-
const fiveHour =
|
|
153
|
-
const weekly =
|
|
146
|
+
const fiveHour = asRecord(limits["fiveHour"]);
|
|
147
|
+
const weekly = asRecord(limits["weekly"]);
|
|
154
148
|
const push = (source: Record<string, unknown> | undefined, kind: string, label: string) => {
|
|
155
149
|
if (source === undefined) return;
|
|
156
150
|
const used = numberOrNull(source["used"]) ?? 0;
|
|
@@ -191,9 +185,9 @@ export async function fetchCommandCodeQuota(
|
|
|
191
185
|
};
|
|
192
186
|
}
|
|
193
187
|
|
|
194
|
-
const whoamiBody = whoami.ok ?
|
|
195
|
-
const user =
|
|
196
|
-
const organization =
|
|
188
|
+
const whoamiBody = whoami.ok ? asRecord(whoami.value) : undefined;
|
|
189
|
+
const user = asRecord(whoamiBody?.["user"]);
|
|
190
|
+
const organization = asRecord(whoamiBody?.["org"]);
|
|
197
191
|
const orgId = typeof organization?.["id"] === "string" ? organization["id"] : null;
|
|
198
192
|
const accountLabel =
|
|
199
193
|
(typeof user?.["email"] === "string" && user["email"]) ||
|
|
@@ -215,8 +209,8 @@ export async function fetchCommandCodeQuota(
|
|
|
215
209
|
};
|
|
216
210
|
}
|
|
217
211
|
|
|
218
|
-
const subscriptionBody = subscriptionRaw.ok ?
|
|
219
|
-
const planRecord =
|
|
212
|
+
const subscriptionBody = subscriptionRaw.ok ? asRecord(subscriptionRaw.value) : undefined;
|
|
213
|
+
const planRecord = asRecord(subscriptionBody?.["data"]);
|
|
220
214
|
const planId = typeof planRecord?.["planId"] === "string" ? planRecord["planId"] : null;
|
|
221
215
|
const parsedPlan = planId === null ? null : commandCodePlan(planId);
|
|
222
216
|
const plan =
|
|
@@ -225,12 +219,12 @@ export async function fetchCommandCodeQuota(
|
|
|
225
219
|
(creditsRaw.ok ? "Credits" : null);
|
|
226
220
|
const periodEnd = isoTimestamp(planRecord?.["currentPeriodEnd"]);
|
|
227
221
|
|
|
228
|
-
const creditsBody = creditsRaw.ok ?
|
|
222
|
+
const creditsBody = creditsRaw.ok ? asRecord(creditsRaw.value) : undefined;
|
|
229
223
|
const windows: ProviderQuotaWindow[] = [];
|
|
230
224
|
if (creditsBody !== undefined) {
|
|
231
|
-
const credits =
|
|
225
|
+
const credits = asRecord(creditsBody["credits"]);
|
|
232
226
|
if (credits !== undefined) windows.push(...creditWindows(credits, parsedPlan?.cap ?? null, periodEnd));
|
|
233
|
-
const limits =
|
|
227
|
+
const limits = asRecord(creditsBody["windowLimits"]);
|
|
234
228
|
if (limits !== undefined) windows.push(...windowLimits(limits));
|
|
235
229
|
}
|
|
236
230
|
|
|
@@ -41,7 +41,6 @@ import {
|
|
|
41
41
|
CURSOR_WEBSITE_URL,
|
|
42
42
|
SESSION_REFRESH_TIMEOUT_MS,
|
|
43
43
|
SIGN_IN_POLICY_VIOLATION,
|
|
44
|
-
TOKEN_EXPIRY_THRESHOLD_S,
|
|
45
44
|
isExchangeableApiKey,
|
|
46
45
|
} from "./cursor-shared";
|
|
47
46
|
|
|
@@ -92,13 +91,6 @@ export function decodeJwtExpiryMs(token: string): number | undefined {
|
|
|
92
91
|
return exp * 1000;
|
|
93
92
|
}
|
|
94
93
|
|
|
95
|
-
/** True when a JWT expires within the refresh threshold. */
|
|
96
|
-
export function isExpiringSoon(token: string, thresholdSeconds = TOKEN_EXPIRY_THRESHOLD_S): boolean {
|
|
97
|
-
const expiry = decodeJwtExpiryMs(token);
|
|
98
|
-
if (expiry === undefined) return false;
|
|
99
|
-
return expiry - Date.now() < thresholdSeconds * 1000;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
94
|
/**
|
|
103
95
|
* The account identity Cursor itself asserts, from the access token's `sub`.
|
|
104
96
|
*
|
|
@@ -389,15 +389,22 @@ function globFiles(args: Record<string, unknown>, root: string): Record<string,
|
|
|
389
389
|
return { files: out };
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
/**
|
|
392
|
+
/**
|
|
393
|
+
* Minimal glob matcher: `*` (within a segment), `**` (any depth), `?`.
|
|
394
|
+
* The value is normalized to forward slashes first, so a Windows `\` path
|
|
395
|
+
* matches exactly like a POSIX `/` path — otherwise `*.ts` matches
|
|
396
|
+
* `src\a.ts` on Windows but not `src/a.ts`, and the same pattern behaves
|
|
397
|
+
* differently depending on which separator `relative()` happened to emit.
|
|
398
|
+
*/
|
|
393
399
|
function simpleGlobMatch(pattern: string, value: string): boolean {
|
|
400
|
+
const normalized = value.replace(/\\/g, "/");
|
|
394
401
|
const re = pattern
|
|
395
402
|
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
396
403
|
.replace(/\*\*/g, "__GLOBSTAR__")
|
|
397
404
|
.replace(/\*/g, "[^/]*")
|
|
398
405
|
.replace(/__GLOBSTAR__/g, ".*")
|
|
399
406
|
.replace(/\?/g, ".");
|
|
400
|
-
return new RegExp(`^${re}$`).test(
|
|
407
|
+
return new RegExp(`^${re}$`).test(normalized);
|
|
401
408
|
}
|
|
402
409
|
|
|
403
410
|
function grepFiles(args: Record<string, unknown>, root: string, pi: boolean): Record<string, unknown> {
|
|
@@ -219,7 +219,9 @@ export function systemPromptFrom(request: CanonicalRequest): string | undefined
|
|
|
219
219
|
*/
|
|
220
220
|
export function historyFromRequest(request: CanonicalRequest): CursorHistoryEntry[] {
|
|
221
221
|
const entries: CursorHistoryEntry[] = [];
|
|
222
|
-
|
|
222
|
+
const liveIndex = lastLiveUserMessageIndex(request);
|
|
223
|
+
for (const [index, message] of request.messages.entries()) {
|
|
224
|
+
if (index === liveIndex) continue;
|
|
223
225
|
const text = messageText(message);
|
|
224
226
|
if (text.trim().length === 0) continue;
|
|
225
227
|
if (message.role === "assistant") entries.push({ role: "assistant", content: text });
|
|
@@ -235,9 +237,6 @@ export function buildRunRequest(input: {
|
|
|
235
237
|
readonly text: string;
|
|
236
238
|
readonly modelId: string;
|
|
237
239
|
readonly conversationId: string;
|
|
238
|
-
/** Stable parent group; unlike the conversation id it survives a rebase. */
|
|
239
|
-
readonly conversationGroupId?: string;
|
|
240
|
-
readonly runId?: string;
|
|
241
240
|
readonly messageId?: string;
|
|
242
241
|
readonly history?: readonly CursorHistoryEntry[];
|
|
243
242
|
/** Cursor-declared parameter tuple (effort/context/fast) for this model. */
|
|
@@ -277,12 +276,17 @@ export function buildRunRequest(input: {
|
|
|
277
276
|
userMessageAction["request_context"] = requestContext;
|
|
278
277
|
const runRequest: Record<string, unknown> = {
|
|
279
278
|
conversation_id: input.conversationId,
|
|
280
|
-
conversation_group_id: input.conversationGroupId ?? input.conversationId,
|
|
281
|
-
run_id: input.runId ?? messageId,
|
|
282
279
|
action:
|
|
283
280
|
input.action === "resume"
|
|
284
281
|
? { resume_action: { request_context: requestContext } }
|
|
285
282
|
: { user_message_action: userMessageAction },
|
|
283
|
+
// `model_details` (#3) carries the safe wire id; `requested_model` (#9)
|
|
284
|
+
// carries the parameter tuple. Matches `agent.proto` exactly — the old
|
|
285
|
+
// schema invented extra fields that have no wire meaning.
|
|
286
|
+
model_details: {
|
|
287
|
+
model_id: input.modelId,
|
|
288
|
+
max_mode: input.maxMode ?? false,
|
|
289
|
+
},
|
|
286
290
|
requested_model: {
|
|
287
291
|
model_id: input.modelId,
|
|
288
292
|
max_mode: input.maxMode ?? false,
|
|
@@ -290,8 +294,6 @@ export function buildRunRequest(input: {
|
|
|
290
294
|
},
|
|
291
295
|
conversation_state: seeded ? buildSeedConversationState() : input.conversationState,
|
|
292
296
|
mcp_tools: { mcp_tools: [] },
|
|
293
|
-
unknown_flag: 0,
|
|
294
|
-
field_12: 0,
|
|
295
297
|
};
|
|
296
298
|
return encodeMessage("AgentClientMessage", { run_request: runRequest });
|
|
297
299
|
}
|
|
@@ -309,9 +311,12 @@ export function buildExecStreamClose(execId: number, execIdString?: string): Uin
|
|
|
309
311
|
}
|
|
310
312
|
|
|
311
313
|
/** Stops the live Run, as Cursor CLI does before closing the stream. */
|
|
312
|
-
export function buildCancelAction(
|
|
314
|
+
export function buildCancelAction(_reason: string): Uint8Array {
|
|
315
|
+
// `agent.proto` CancelAction is empty — the oneof presence is the signal,
|
|
316
|
+
// and the reason travels out-of-band (stream close). Sending a `reason`
|
|
317
|
+
// field would encode bytes the server does not expect.
|
|
313
318
|
return encodeMessage("AgentClientMessage", {
|
|
314
|
-
conversation_action: { cancel_action: {
|
|
319
|
+
conversation_action: { cancel_action: {} },
|
|
315
320
|
});
|
|
316
321
|
}
|
|
317
322
|
|
|
@@ -530,12 +535,21 @@ function toolResultText(part: Extract<ContentPart, { kind: "toolResult" }>): str
|
|
|
530
535
|
* only the current prompt.
|
|
531
536
|
*/
|
|
532
537
|
export function liveUserText(request: CanonicalRequest): string {
|
|
538
|
+
const index = lastLiveUserMessageIndex(request);
|
|
539
|
+
if (index === -1) return "";
|
|
540
|
+
const message = request.messages[index];
|
|
541
|
+
if (message === undefined) return "";
|
|
542
|
+
return messageText(message);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** Index of the current user/tool turn Cursor should send as the live prompt. */
|
|
546
|
+
function lastLiveUserMessageIndex(request: CanonicalRequest): number {
|
|
533
547
|
for (let index = request.messages.length - 1; index >= 0; index -= 1) {
|
|
534
548
|
const message = request.messages[index];
|
|
535
549
|
if (message === undefined) continue;
|
|
536
550
|
if (message.role !== "user" && message.role !== "tool") continue;
|
|
537
551
|
const text = messageText(message);
|
|
538
|
-
if (text.trim().length > 0) return
|
|
552
|
+
if (text.trim().length > 0) return index;
|
|
539
553
|
}
|
|
540
|
-
return
|
|
554
|
+
return -1;
|
|
541
555
|
}
|
|
@@ -83,11 +83,14 @@ export const SESSION_REFRESH_TIMEOUT_MS = 20_000;
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* How long a live Cursor Run is held open waiting for the client's next
|
|
86
|
-
* tool-result request. Matches the donor's
|
|
87
|
-
*
|
|
88
|
-
* a pool slot for the life
|
|
86
|
+
* tool-result request. Matches the donor's relay hold (`CURSOR_RELAY_IDLE_
|
|
87
|
+
* TIMEOUT_MS` in oh-my-pi: 30 minutes): a tool round the client never answers
|
|
88
|
+
* must not hold an HTTP/2 stream, an account lease, or a pool slot for the life
|
|
89
|
+
* of the process, but a human-approved tool round often takes longer than ten
|
|
90
|
+
* minutes — a shorter TTL expired the Run mid-approval and forced the client to
|
|
91
|
+
* resend the whole conversation.
|
|
89
92
|
*/
|
|
90
|
-
export const RUN_IDLE_TTL_MS =
|
|
93
|
+
export const RUN_IDLE_TTL_MS = 30 * 60_000;
|
|
91
94
|
|
|
92
95
|
/**
|
|
93
96
|
* Any HTTPS subdomain of `cursor.sh` is an acceptable Run host: the region
|