cartethyia 2.7.9 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +6 -5
- package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BE3qwwfC.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CRZdmMIX.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-BE40s3u5.js → OverviewPage-0yfhSI1C.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CFNcATJJ.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BTlkq_Uk.js → api-keys-2hc12Uz2.js} +1 -1
- package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js +1 -0
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-A1-v8-03.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CJ4Zty89.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-DkjUouAj.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-B-LVLV6o.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2aDLyyg.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DNcAdMK-.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-DgrIH0hw.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-ecPvG_8g.js → pagination-iUoI8GeE.js} +1 -1
- package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
- package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
- package/dist/dashboard/assets/providers/sensenova.png +0 -0
- package/dist/dashboard/assets/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-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
- package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +11 -14
- package/src/boot/dependencies.ts +5 -7
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/providers.ts +6 -5
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +28 -8
- 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/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -4
- package/src/console/inferhub/client.ts +1 -1
- 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/live.ts +2 -2
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/contracts.ts +9 -3
- package/src/console/providers/catalog/model-operations.ts +2 -3
- package/src/console/providers/catalog/provider-operations.ts +1 -1
- package/src/console/providers/catalog/routes.ts +3 -2
- package/src/console/providers/catalog/store.ts +1914 -1902
- package/src/console/providers/detail/routes.ts +1 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/providers/oauth/callback-listener.ts +30 -11
- package/src/console/providers/oauth/device-egress.ts +123 -0
- package/src/console/providers/oauth/routes.ts +123 -16
- package/src/console/quota/account-quota-global.ts +14 -24
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +11 -23
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +32 -47
- package/src/console/routing/pools/probe-verdict.ts +2 -2
- package/src/console/routing/pools/relay-deploy.ts +1 -1
- package/src/console/routing/pools/store.ts +4 -4
- package/src/console/shared/errors.ts +33 -6
- package/src/main.ts +2 -3
- package/src/network/client.ts +67 -0
- package/src/network/egress/bidi-session.ts +322 -0
- package/src/network/egress/dial.ts +201 -0
- package/src/network/egress/factory.ts +191 -0
- package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
- package/src/network/egress/tls-profile.ts +123 -0
- package/src/network/egress/ws.ts +175 -0
- package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
- package/src/network/{types.ts → pool/agent-config.ts} +1 -1
- package/src/network/pool/agent.ts +2 -2
- package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
- package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
- package/src/network/pool/resolver.ts +10 -849
- package/src/network/pool/selector.ts +184 -41
- package/src/network/ssrf.ts +7 -7
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
- 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 +16 -26
- 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 +17 -0
- package/src/persistence/ttl-cache.ts +21 -3
- package/src/protocol/codecs.ts +59 -2
- 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 +34 -22
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/messages.ts +34 -7
- 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/protocol/translation/quirks.ts +15 -0
- package/src/protocol/upstream/send-claude-messages.ts +2 -2
- package/src/providers/adapters/compatible-adapter.ts +76 -12
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +105 -11
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -758
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +137 -36
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +20 -6
- package/src/providers/discovery/probing-service.ts +22 -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 +16 -1
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +12 -12
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
- package/src/providers/integrations/buddy/headers.ts +311 -0
- package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
- package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +5 -6
- package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
- package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
- package/src/providers/integrations/clixad/provider.ts +145 -0
- package/src/providers/integrations/codex/codex-oauth.ts +8 -5
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
- package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
- package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
- package/src/providers/integrations/cursor/cursor-request.ts +26 -12
- package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
- package/src/providers/integrations/cursor/cursor.ts +574 -110
- 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/deepai/deepai-catalog.ts +149 -0
- package/src/providers/integrations/deepai/deepai-common.ts +145 -0
- package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
- package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
- package/src/providers/integrations/deepai/provider.ts +42 -0
- package/src/providers/integrations/devin/devin-auth.ts +7 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
- package/src/providers/integrations/factory/factory-oauth.ts +33 -51
- 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/freepi/freepi-catalog.ts +5 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
- package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
- package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
- package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
- package/src/providers/integrations/freepi/freepi-session.ts +158 -0
- package/src/providers/integrations/freepi/freepi.ts +80 -54
- package/src/providers/integrations/github/github-discovery.ts +30 -13
- package/src/providers/integrations/github/github-oauth.ts +217 -44
- package/src/providers/integrations/github/github-quota.ts +22 -5
- package/src/providers/integrations/github/github.ts +40 -32
- package/src/providers/integrations/grok/grok-oauth.ts +52 -49
- 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/hermes-oauth.ts +3 -3
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
- package/src/providers/integrations/kilo/kilo.ts +1 -1
- package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- 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/fingerprint.ts +1 -1
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-protocol.ts +0 -6
- package/src/providers/integrations/perch/perch-quota.ts +2 -16
- package/src/providers/integrations/perch/perch.ts +6 -16
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
- package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
- package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
- package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
- package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
- package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
- package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
- package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
- package/src/providers/integrations/qoder/qoder-types.ts +9 -0
- package/src/providers/integrations/qoder/qoder.ts +3 -26
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-protocol.ts +9 -5
- package/src/providers/integrations/trae/trae-quota.ts +21 -29
- package/src/providers/integrations/trae/trae-realm.ts +38 -0
- package/src/providers/integrations/trae/trae.ts +7 -24
- package/src/providers/integrations/vercel/provider.ts +117 -0
- package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
- package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
- package/src/providers/integrations/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 +205 -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 +36 -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 +100 -81
- package/src/providers/operations/cooldown-rules.ts +11 -16
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- 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 +118 -51
- 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/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +6 -4
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +70 -10
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-contracts.ts +2 -0
- 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 +100 -21
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +15 -14
- package/src/transport/dispatch/attempt-loop.ts +73 -19
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- 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/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +10 -7
- package/src/transport/dispatch/streaming/stream.ts +9 -37
- 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/shutdown-notice.ts +1 -1
- 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/src/workers/buddy-growth-tasks.ts +8 -8
- package/src/workers/daily-checkin.ts +4 -4
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/zcode-gift-claim.ts +1 -1
- package/dist/dashboard/assets/BannedPage-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 +0 -9
- 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/network/pool-health.ts +0 -210
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
- package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
- package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
- package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
- package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
- package/src/providers/integrations/qoder/chat-proto.ts +0 -328
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
- 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-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
- /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
- /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
- /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
- /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
|
@@ -2,7 +2,7 @@ import { withBearerAuthentication, type OpenAICompatibleAdapterConfig } from "..
|
|
|
2
2
|
import type { CanonicalRequest } from "../../../../protocol/canonical-model";
|
|
3
3
|
import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
|
|
4
4
|
import { resolveInboundSessionId } from "../../../operations/session-resolution";
|
|
5
|
-
import { buddyConversationHeaders } from "../
|
|
5
|
+
import { buddyConversationHeaders } from "../headers";
|
|
6
6
|
import {
|
|
7
7
|
buddyAgentPurpose,
|
|
8
8
|
buddyEnterprise,
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
buddyUserId,
|
|
12
12
|
resolveBuddyDeviceBinding,
|
|
13
13
|
resolveBuddyIdentity,
|
|
14
|
-
} from "../
|
|
14
|
+
} from "../headers";
|
|
15
15
|
import { buildCodeBuddyUserAgent, getCodeBuddyCnVersion, getCodeBuddyVersion } from "../../../operations/client-versions";
|
|
16
|
-
import { buddyDeviceTokenHeaders } from "../
|
|
17
|
-
import { buddyCliHeaders, buddyCliTraceHeaders } from "../
|
|
16
|
+
import { buddyDeviceTokenHeaders } from "../headers";
|
|
17
|
+
import { buddyCliHeaders, buddyCliTraceHeaders } from "../headers";
|
|
18
18
|
|
|
19
19
|
/** Client identity variant behind the per-request CodeBuddy headers. */
|
|
20
20
|
export type CodeBuddyVariant = "IDE" | "CLI";
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
import type { ProviderDispatchContext } from "../../provider-contracts";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
4
|
+
import { decodeJwtPayload } from "../../authentication/oauth-flow-store";
|
|
5
|
+
import { buddyAccountUid } from "./account";
|
|
6
|
+
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
7
|
+
|
|
8
|
+
// ── buddy-identity ──────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
export type BuddyIdentity = "desktop" | "cli";
|
|
11
|
+
|
|
12
|
+
export function resolveBuddyIdentity(
|
|
13
|
+
context: ProviderDispatchContext | undefined,
|
|
14
|
+
profileIdentity?: boolean | undefined,
|
|
15
|
+
): BuddyIdentity {
|
|
16
|
+
const accountRaw = context?.credential.auth_state?.["cliIdentity"];
|
|
17
|
+
if (accountRaw === true) return "cli";
|
|
18
|
+
if (accountRaw === false) return "desktop";
|
|
19
|
+
return profileIdentity === true ? "cli" : "desktop";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function buddyUserId(context?: ProviderDispatchContext): string {
|
|
23
|
+
const secret = context?.credential?.secret;
|
|
24
|
+
const token = secret ? new TextDecoder().decode(secret).trim() : "";
|
|
25
|
+
const uid = buddyAccountUid(token);
|
|
26
|
+
if (uid !== undefined) return uid;
|
|
27
|
+
const accountId = context?.credential.account_id;
|
|
28
|
+
return accountId !== undefined && accountId.length > 0 ? accountId : "anonymous";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const ENTERPRISE_CLAIMS: readonly string[] = [
|
|
32
|
+
"enterprise_id",
|
|
33
|
+
"enterpriseId",
|
|
34
|
+
"enterprise",
|
|
35
|
+
"tenant_id",
|
|
36
|
+
"tenantId",
|
|
37
|
+
"org_id",
|
|
38
|
+
"organization_id",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export function buddyEnterprise(context?: ProviderDispatchContext): string | undefined {
|
|
42
|
+
const stored = context?.credential.auth_state?.["enterpriseId"];
|
|
43
|
+
if (typeof stored === "string" && stored.trim().length > 0) return stored.trim();
|
|
44
|
+
const token = context?.credential.secret;
|
|
45
|
+
if (token === undefined || token.length === 0) return undefined;
|
|
46
|
+
const claims = decodeJwtPayload(new TextDecoder().decode(token).trim());
|
|
47
|
+
if (claims === undefined) return undefined;
|
|
48
|
+
for (const claim of ENTERPRISE_CLAIMS) {
|
|
49
|
+
const value = claims[claim];
|
|
50
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function resolveBuddyDeviceBinding(context?: ProviderDispatchContext): string | undefined {
|
|
56
|
+
const explicit = context?.credential.auth_state?.["qimei36"];
|
|
57
|
+
if (typeof explicit === "string" && explicit.trim().length > 0) return explicit.trim();
|
|
58
|
+
const accountId = context?.credential.account_id;
|
|
59
|
+
if (accountId === undefined || accountId.length === 0) return undefined;
|
|
60
|
+
return createHash("sha256").update(`wb2a:qimei36:${accountId}`).digest("hex").slice(0, 32);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function materializeBuddyDeviceBinding(
|
|
64
|
+
accountId: string,
|
|
65
|
+
authState: Readonly<Record<string, unknown>> | undefined,
|
|
66
|
+
): Record<string, unknown> | undefined {
|
|
67
|
+
const existing = authState?.["qimei36"];
|
|
68
|
+
if (typeof existing === "string" && existing.trim().length > 0) return undefined;
|
|
69
|
+
if (accountId.length === 0) return undefined;
|
|
70
|
+
const derived = createHash("sha256").update(`wb2a:qimei36:${accountId}`).digest("hex").slice(0, 32);
|
|
71
|
+
return { ...(authState ?? {}), qimei36: derived };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function identityClaim(claims: Record<string, unknown> | undefined, name: string): string | undefined {
|
|
75
|
+
if (claims === undefined) return undefined;
|
|
76
|
+
const value = claims[name];
|
|
77
|
+
if (typeof value === "string" && value.trim().length > 0 && value.trim().length <= 128) return value.trim();
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function buddyOAuthIdentityHeaders(
|
|
82
|
+
context?: ProviderDispatchContext,
|
|
83
|
+
): Record<string, string> {
|
|
84
|
+
const secret = context?.credential?.secret;
|
|
85
|
+
const token = secret ? new TextDecoder().decode(secret).trim() : "";
|
|
86
|
+
const uid = buddyAccountUid(token) ?? context?.credential.account_id ?? "";
|
|
87
|
+
if (uid.length === 0) return {};
|
|
88
|
+
const enterpriseId = buddyEnterprise(context);
|
|
89
|
+
// The reference gateway reads `id_source` / `token_source` from the JWT
|
|
90
|
+
// payload and the account record, not from stored auth state — an account
|
|
91
|
+
// authorized before either was persisted still carries them on the wire.
|
|
92
|
+
// Precedence matches the donor (`client_profiles._identity_claim_headers`):
|
|
93
|
+
// account fields first, then JWT claims, then legacy `auth_state`.
|
|
94
|
+
const claims = token.length > 0 ? decodeJwtPayload(token) : undefined;
|
|
95
|
+
const state = context?.credential.auth_state;
|
|
96
|
+
const idSource =
|
|
97
|
+
identityClaim(claims, "id_source") ??
|
|
98
|
+
identityClaim(claims, "idSource") ??
|
|
99
|
+
identityClaim(state as Record<string, unknown> | undefined, "idSource");
|
|
100
|
+
const method =
|
|
101
|
+
identityClaim(claims, "token_source") ??
|
|
102
|
+
identityClaim(state as Record<string, unknown> | undefined, "authMethod");
|
|
103
|
+
const headers: Record<string, string> = { "X-User-Id": uid };
|
|
104
|
+
if (method !== undefined) headers["X-Auth-Method"] = method;
|
|
105
|
+
if (idSource !== undefined) headers["X-Id-Source"] = idSource;
|
|
106
|
+
if (enterpriseId !== undefined || idSource !== undefined || method !== undefined) {
|
|
107
|
+
const info: Record<string, string> = { uin: uid };
|
|
108
|
+
if (enterpriseId !== undefined) info["owner_uin"] = enterpriseId;
|
|
109
|
+
if (idSource !== undefined) info["id_source"] = idSource;
|
|
110
|
+
if (method !== undefined) info["token_source"] = method;
|
|
111
|
+
headers["X-Userinfo"] = Buffer.from(JSON.stringify(info), "utf-8").toString("base64");
|
|
112
|
+
}
|
|
113
|
+
return headers;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function buddyPrivateData(context?: ProviderDispatchContext): boolean {
|
|
117
|
+
return context?.credential.auth_state?.["privateData"] === true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function buddyAgentPurpose(
|
|
121
|
+
context?: ProviderDispatchContext,
|
|
122
|
+
request?: CanonicalRequest,
|
|
123
|
+
): string | undefined {
|
|
124
|
+
if (process.env.PERSONAL_AGENT_ROLE && process.env.PERSONAL_AGENT_ROLE.trim().length > 0) {
|
|
125
|
+
return "person_agent";
|
|
126
|
+
}
|
|
127
|
+
const inbound = context?.request_headers?.["x-agent-purpose"]?.trim();
|
|
128
|
+
if (inbound !== undefined && inbound.length > 0) return inbound;
|
|
129
|
+
const fromRequest = request?.metadata?.["agent_purpose"];
|
|
130
|
+
if (typeof fromRequest === "string" && fromRequest.trim().length > 0) return fromRequest.trim();
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const DEVICE_TOKEN_FILE_MAX_BYTES = 1024;
|
|
135
|
+
|
|
136
|
+
const DEVICE_TOKEN_FILE_TTL_MS = 5 * 60_000;
|
|
137
|
+
|
|
138
|
+
let deviceTokenFileCache: { readonly value: string | undefined; readonly readAt: number } | undefined;
|
|
139
|
+
|
|
140
|
+
export function readBuddyDeviceToken(context?: ProviderDispatchContext): string | undefined {
|
|
141
|
+
const state = context?.credential.auth_state;
|
|
142
|
+
const value = state?.["deviceToken"] ?? state?.["device_token"];
|
|
143
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
144
|
+
return readDeviceTokenFile();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function buddyDeviceTokenHeaders(args: {
|
|
148
|
+
realm: "intl" | "cn";
|
|
149
|
+
context: ProviderDispatchContext | undefined;
|
|
150
|
+
cliIdentity: boolean | undefined;
|
|
151
|
+
}): Promise<Record<string, string>> {
|
|
152
|
+
const { context, cliIdentity } = args;
|
|
153
|
+
void args.realm; // the desktop client sends the token on both realms
|
|
154
|
+
if (resolveBuddyIdentity(context, cliIdentity) === "cli") return {};
|
|
155
|
+
const token = readBuddyDeviceToken(context);
|
|
156
|
+
if (token !== undefined) return { "x-device-token": token };
|
|
157
|
+
return { "x-device-token-error": "sdk_not_initialized" };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function readDeviceTokenFile(): string | undefined {
|
|
161
|
+
const now = Date.now();
|
|
162
|
+
if (deviceTokenFileCache !== undefined && now - deviceTokenFileCache.readAt < DEVICE_TOKEN_FILE_TTL_MS) {
|
|
163
|
+
return deviceTokenFileCache.value;
|
|
164
|
+
}
|
|
165
|
+
const path = process.env["CARTETHYIA_DEVICE_TOKEN_FILE"] ?? "/app/data/device_token";
|
|
166
|
+
let value: string | undefined;
|
|
167
|
+
try {
|
|
168
|
+
const raw = readFileSync(path);
|
|
169
|
+
if (raw.byteLength > 0 && raw.byteLength <= DEVICE_TOKEN_FILE_MAX_BYTES) {
|
|
170
|
+
const text = raw.toString("utf8").trim();
|
|
171
|
+
if (text.length > 0) value = text;
|
|
172
|
+
}
|
|
173
|
+
} catch {
|
|
174
|
+
value = undefined;
|
|
175
|
+
}
|
|
176
|
+
deviceTokenFileCache = { value, readAt: now };
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ── buddy-cli-headers ──────────────────────────────────────────
|
|
181
|
+
|
|
182
|
+
export function buddyCliTraceHeaders(
|
|
183
|
+
conversation: Readonly<Record<string, string>>,
|
|
184
|
+
): Record<string, string> {
|
|
185
|
+
const traceId = conversation["x-trace-id"] ?? conversation["x-b3-traceid"];
|
|
186
|
+
const spanId = conversation["x-b3-spanid"];
|
|
187
|
+
if (traceId === undefined) return {};
|
|
188
|
+
const b3 = `${traceId}-${spanId ?? traceId.slice(0, 16)}-1-${traceId.slice(0, 16)}`;
|
|
189
|
+
return { ...(spanId === undefined ? {} : { "X-B3-ParentSpanId": spanId }), b3 };
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function buddyCliHeaders(args: {
|
|
193
|
+
readonly userId: string;
|
|
194
|
+
readonly enterpriseId?: string | undefined;
|
|
195
|
+
readonly privateData?: boolean;
|
|
196
|
+
}): Record<string, string> {
|
|
197
|
+
const enterpriseId =
|
|
198
|
+
args.enterpriseId !== undefined && args.enterpriseId.trim().length > 0
|
|
199
|
+
? args.enterpriseId.trim()
|
|
200
|
+
: undefined;
|
|
201
|
+
return {
|
|
202
|
+
"X-Agent-Intent": "craft",
|
|
203
|
+
"X-Agent-Type": "main",
|
|
204
|
+
// The reference enum is local-agent / cloud-agent / agent-agent, and its
|
|
205
|
+
// parser returns "other" for anything unknown or absent. A gateway is none
|
|
206
|
+
// of the three, so "other" is the honest value rather than a guess.
|
|
207
|
+
"X-Agent-Runtime": "other",
|
|
208
|
+
"X-User-Id": args.userId,
|
|
209
|
+
...(args.privateData === true ? { "X-Private-Data": "true" } : {}),
|
|
210
|
+
...(enterpriseId === undefined
|
|
211
|
+
? {}
|
|
212
|
+
: {
|
|
213
|
+
"X-Enterprise-Id": enterpriseId,
|
|
214
|
+
// The tenant falls back to the enterprise: the two are the same value
|
|
215
|
+
// for an account that belongs to one enterprise, and the upstream
|
|
216
|
+
// reads both.
|
|
217
|
+
"X-Tenant-Id": enterpriseId,
|
|
218
|
+
}),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ── buddy-conversation-headers ──────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
function newMessageId(): string {
|
|
225
|
+
return crypto.randomUUID().replaceAll("-", "");
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function toUuidHex(hex: string): string {
|
|
229
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function isValidTraceId(value: string): boolean {
|
|
233
|
+
if (value.length !== 16 && value.length !== 32) return false;
|
|
234
|
+
return /^[0-9a-fA-F]+$/.test(value);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface BuddyConversationIds {
|
|
238
|
+
/**
|
|
239
|
+
* Conversation-scoped id, stable across turns. `undefined` means the client
|
|
240
|
+
* sent none, and the header is then omitted rather than fabricated.
|
|
241
|
+
*/
|
|
242
|
+
readonly conversationId?: string | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Turn-scoped aggregation key. When absent a fresh one is generated, because
|
|
245
|
+
* the header is mandatory and a call without it is what drew `11128`.
|
|
246
|
+
*/
|
|
247
|
+
readonly conversationRequestId?: string | undefined;
|
|
248
|
+
/** Inbound trace id to pass through; falls back to the conversation request id. */
|
|
249
|
+
readonly traceId?: string | undefined;
|
|
250
|
+
/**
|
|
251
|
+
* Wire format for the two message-scoped ids (`x-conversation-message-id`,
|
|
252
|
+
* `x-request-id`).
|
|
253
|
+
*
|
|
254
|
+
* The reference emits these as dashed UUIDs on the desktop product
|
|
255
|
+
* and as 32-hex on CLI traffic (`build_attempt_headers` converts only the
|
|
256
|
+
* message/request ids, and only for the desktop profiles). The turn
|
|
257
|
+
* aggregation key (`x-conversation-request-id` / `x-root-request-id`) and the
|
|
258
|
+
* B3/W3C trace ids stay hex in both styles, because B3's spec accepts only
|
|
259
|
+
* hex. Default `"hex"`.
|
|
260
|
+
*/
|
|
261
|
+
readonly messageIdStyle?: "hex" | "uuid" | undefined;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function buddyConversationHeaders(
|
|
265
|
+
ids: BuddyConversationIds = {},
|
|
266
|
+
): Record<string, string> {
|
|
267
|
+
const conversationRequestId =
|
|
268
|
+
ids.conversationRequestId && ids.conversationRequestId.trim().length > 0
|
|
269
|
+
? ids.conversationRequestId.trim()
|
|
270
|
+
: newMessageId();
|
|
271
|
+
const messageId = newMessageId();
|
|
272
|
+
// The message-scoped ids may render as a dashed UUID (WorkBuddy desktop) or
|
|
273
|
+
// as 32-hex (CLI); the raw hex is still what the B3/W3C trace ids derive from.
|
|
274
|
+
const messageHeaderValue = ids.messageIdStyle === "uuid" ? toUuidHex(messageId) : messageId;
|
|
275
|
+
const traceId =
|
|
276
|
+
ids.traceId && ids.traceId.trim().length > 0 ? ids.traceId.trim() : conversationRequestId;
|
|
277
|
+
const b3TraceId = isValidTraceId(conversationRequestId) ? conversationRequestId : messageId;
|
|
278
|
+
|
|
279
|
+
const headers: Record<string, string> = {
|
|
280
|
+
"x-conversation-request-id": conversationRequestId,
|
|
281
|
+
"x-conversation-message-id": messageHeaderValue,
|
|
282
|
+
"x-request-id": messageHeaderValue,
|
|
283
|
+
"x-root-request-id": conversationRequestId,
|
|
284
|
+
"x-trace-id": traceId,
|
|
285
|
+
// W3C trace context alongside the B3 set below: the upstream reads both,
|
|
286
|
+
// and every reference request carries `traceparent`, so sending only the
|
|
287
|
+
// B3 half leaves a header the channel check expects absent.
|
|
288
|
+
traceparent: `00-${b3TraceId}-${messageId.slice(0, 16)}-01`,
|
|
289
|
+
"x-b3-traceid": b3TraceId,
|
|
290
|
+
"x-b3-spanid": messageId.slice(0, 16),
|
|
291
|
+
"x-b3-sampled": "1",
|
|
292
|
+
};
|
|
293
|
+
// Always sent, invented when the caller gave none.
|
|
294
|
+
//
|
|
295
|
+
// `x-conversation-id` is mandatory, and a chat request without it is refused
|
|
296
|
+
// with `400 · 11-128 "request illegal"` — an error that names neither the
|
|
297
|
+
// header nor the channel, and which reads like a block rather than a missing
|
|
298
|
+
// field. Isolated against the live API by removing one header at a time:
|
|
299
|
+
// only `x-conversation-id`, `x-conversation-request-id` and
|
|
300
|
+
// `x-conversation-message-id` are required; the B3/W3C trace set, the
|
|
301
|
+
// stainless set, the agent block and the IDE block are all optional.
|
|
302
|
+
//
|
|
303
|
+
// Inventing one when the caller has none is still the right default: the id
|
|
304
|
+
// is per-dispatch here, so a caller with no session is not claiming a session
|
|
305
|
+
// it never had — and withholding the header only guarantees a refusal.
|
|
306
|
+
headers["x-conversation-id"] =
|
|
307
|
+
ids.conversationId !== undefined && ids.conversationId.trim().length > 0
|
|
308
|
+
? ids.conversationId.trim()
|
|
309
|
+
: newMessageId();
|
|
310
|
+
return headers;
|
|
311
|
+
}
|