cartethyia 2.8.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -3
- package/dist/dashboard/assets/{BannedPage-Cc0vKpMG.js → BannedPage-Dq530awD.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-Bqj2aa1T.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-CXsaOAO2.js → CliToolsPage-DaZZ3cqP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-BeLpJ4ma.js → CombosPage-BlC_xdkX.js} +1 -1
- package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-DnV0uZ3m.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-CBxAjo63.js → CustomizationPage-7xT5yg2E.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-B5yEE0k6.js → HealthEventsModal-Clq8E9cW.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-BWFLECmz.js → InjectSystemPromptPanel-6Teoq9Se.js} +1 -1
- package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CgoPc5B9.js → LoginPage-CZuI0MAR.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-D9bFQern.js → ModelPicker-C1hNTlkr.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
- package/dist/dashboard/assets/{OverviewPage-B_p4tL8k.js → OverviewPage-0yfhSI1C.js} +1 -1
- package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderIcon-D_0PiZtg.js → ProviderIcon-Ddhm1InL.js} +1 -1
- package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-CLI2bJTK.js → ProvidersPage-C3fYuu6i.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
- package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-DA-a1iSN.js → QuotaPage-D1RV_2BX.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-CctTga2C.js → SettingsPage-BzZAvYSX.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-febLU4r1.js → SetupPage--s-EfEIL.js} +1 -1
- package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-M6fvR5Wz.js → StudioPage-BjXFGSK4.js} +1 -1
- package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-nyeuRqz9.js → UsagePage-CP8F8BN7.js} +1 -1
- package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BFOlvrJC.js → api-keys-2hc12Uz2.js} +1 -1
- package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
- package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
- package/dist/dashboard/assets/{assert-CqTLw5e7.js → assert-BMcj1xZE.js} +1 -1
- package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
- package/dist/dashboard/assets/{badge-C83EqLB0.js → badge-DkRUuVfz.js} +1 -1
- package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
- package/dist/dashboard/assets/{banner-D1xn7pIe.js → banner-CDjW841Q.js} +1 -1
- package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
- package/dist/dashboard/assets/{card-DU3Lq5Lm.js → card-Bto5UlL9.js} +1 -1
- package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-Dw1U_drK.js → cli-tools-DaH6g9hL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-CEL5Sg_J.js → clipboard-button-BYKBCzjk.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BjFR5UHy.js → dialog-DL0Zftwv.js} +1 -1
- package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-HvBW0AjI.js → drawer-Dpx_UXaS.js} +1 -1
- package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CECVELyy.js → entry-BV7-1NoM.js} +1 -1
- package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-DYYofQ7W.js → entry-CGvdNU6r.js} +1 -1
- package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSu3gFlt.js → entry-DScKYvZj.js} +3 -3
- package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DLW4i8zK.js → formatters-BS3DZlZj.js} +1 -1
- package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
- package/dist/dashboard/assets/{index-1-fCqe64.js → index-SQnvvTWX.js} +2 -2
- package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DGvU2oLK.js → inline-Dl-cuLK0.js} +1 -1
- package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
- package/dist/dashboard/assets/{input-iNnO1X2K.js → input-Bfx0EzRc.js} +1 -1
- package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-0q8UGypb.js → layout-BxhbQ_JS.js} +1 -1
- package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-C0w2bQjJ.js → list-row-D49Y4ptn.js} +1 -1
- package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
- package/dist/dashboard/assets/{live-M5aJ_xCa.js → live-CbVTdX9V.js} +1 -1
- package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
- package/dist/dashboard/assets/{network-BKeQGT3K.js → network-JGvDveof.js} +1 -1
- package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-CivAk3da.js → numbers-Dw6kiew-.js} +1 -1
- package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-CpzvI5ep.js → pagination-iUoI8GeE.js} +1 -1
- package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
- package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
- package/dist/dashboard/assets/providers/sensenova.png +0 -0
- package/dist/dashboard/assets/{routing-BFQX2VBc.js → routing-8jZr-3WE.js} +1 -1
- package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
- package/dist/dashboard/assets/{select-CXbck0jG.js → select-oO1FxMVb.js} +1 -1
- package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
- package/dist/dashboard/assets/{settings-C_XvMHh9.js → settings-CLr3kdIx.js} +1 -1
- package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DggRiCxE.js → stack-Y3pDteZr.js} +1 -1
- package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
- package/dist/dashboard/assets/{state-ClFzfbYp.js → state-CArX_Iak.js} +1 -1
- package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
- package/dist/dashboard/assets/{switch-CTIFxKqS.js → switch-DwlwmDO-.js} +1 -1
- package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BClG3yWj.js → useMutation-DJ9GYEgf.js} +1 -1
- package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +51 -51
- package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
- package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
- package/package.json +1 -1
- package/src/boot/app.ts +1 -1
- package/src/boot/dependencies.ts +4 -6
- package/src/config/providers.ts +6 -5
- package/src/config/spec.ts +8 -8
- package/src/console/backup/nine-router.ts +71 -10
- package/src/console/backup/service.ts +8 -1
- package/src/console/console-router.ts +1 -1
- package/src/console/domain-registration.ts +7 -2
- package/src/console/inferhub/client.ts +1 -1
- package/src/console/observability/live.ts +2 -2
- package/src/console/providers/catalog/contracts.ts +9 -3
- package/src/console/providers/catalog/model-operations.ts +2 -3
- package/src/console/providers/catalog/provider-operations.ts +1 -1
- package/src/console/providers/catalog/routes.ts +2 -2
- package/src/console/providers/catalog/store.ts +1914 -1907
- package/src/console/providers/detail/routes.ts +1 -0
- package/src/console/providers/detail/store.ts +4 -0
- package/src/console/providers/oauth/callback-listener.ts +30 -11
- package/src/console/providers/oauth/device-egress.ts +123 -0
- package/src/console/providers/oauth/routes.ts +123 -16
- package/src/console/quota/account-quota-tenant.ts +5 -5
- package/src/console/quota/account-test-egress.ts +2 -2
- package/src/console/quota/daily-growth-job.ts +1 -1
- package/src/console/routing/pools/contracts.ts +1 -1
- package/src/console/routing/pools/operations.ts +1 -1
- package/src/console/routing/pools/probe-verdict.ts +2 -2
- package/src/console/routing/pools/relay-deploy.ts +1 -1
- package/src/console/routing/pools/store.ts +4 -4
- package/src/network/client.ts +67 -0
- package/src/network/egress/bidi-session.ts +322 -0
- package/src/network/egress/dial.ts +201 -0
- package/src/network/egress/factory.ts +191 -0
- package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
- package/src/network/egress/tls-profile.ts +123 -0
- package/src/network/egress/ws.ts +175 -0
- package/src/network/{types.ts → pool/agent-config.ts} +1 -1
- package/src/network/pool/agent.ts +2 -2
- package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +7 -7
- package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
- package/src/network/pool/resolver.ts +10 -849
- package/src/network/pool/selector.ts +2 -2
- package/src/network/ssrf.ts +1 -1
- package/src/network/{retry.ts → util/retry.ts} +1 -1
- package/src/observability/telemetry-buffer.ts +1 -1
- package/src/persistence/schema.ts +9 -0
- package/src/persistence/ttl-cache.ts +1 -1
- package/src/protocol/codecs.ts +58 -1
- package/src/protocol/request/messages.ts +31 -18
- package/src/protocol/response/messages.ts +34 -7
- package/src/protocol/translation/quirks.ts +15 -0
- package/src/protocol/upstream/send-claude-messages.ts +2 -2
- package/src/providers/adapters/compatible-adapter.ts +5 -0
- package/src/providers/authentication/oauth-client.ts +40 -6
- package/src/providers/authentication/oauth-device-flow.ts +7 -3
- package/src/providers/authentication/oauth-flow-store.ts +82 -1
- package/src/providers/authentication/oauth-refresh-service.ts +766 -739
- package/src/providers/default-registry.ts +76 -0
- package/src/providers/discovery/discovery-types.ts +7 -0
- package/src/providers/discovery/probe-phases.ts +6 -2
- package/src/providers/discovery/probing-service.ts +7 -0
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +11 -0
- package/src/providers/integrations/buddy/account.ts +969 -0
- package/src/providers/integrations/buddy/capabilities.ts +10 -10
- package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
- package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +5 -5
- package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +4 -4
- package/src/providers/integrations/buddy/{buddy-identity.ts → headers.ts} +138 -140
- package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
- package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
- package/src/providers/integrations/cline/cline-oauth.ts +10 -5
- package/src/providers/integrations/cline/cline.ts +3 -4
- package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
- package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
- package/src/providers/integrations/clixad/provider.ts +145 -0
- package/src/providers/integrations/codex/codex-oauth.ts +8 -5
- package/src/providers/integrations/cursor/cursor-auth.ts +1 -1
- package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
- package/src/providers/integrations/cursor/cursor-shared.ts +1 -1
- package/src/providers/integrations/cursor/cursor.ts +485 -70
- package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
- package/src/providers/integrations/deepai/deepai-common.ts +145 -0
- package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
- package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
- package/src/providers/integrations/deepai/provider.ts +42 -0
- package/src/providers/integrations/devin/devin-auth.ts +7 -0
- package/src/providers/integrations/factory/factory-oauth.ts +16 -7
- package/src/providers/integrations/freebuff/freebuff.ts +2 -2
- package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
- package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
- package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
- package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
- package/src/providers/integrations/freepi/freepi-session.ts +158 -0
- package/src/providers/integrations/freepi/freepi.ts +80 -54
- package/src/providers/integrations/github/github-discovery.ts +30 -13
- package/src/providers/integrations/github/github-oauth.ts +217 -44
- package/src/providers/integrations/github/github-quota.ts +22 -5
- package/src/providers/integrations/github/github.ts +40 -32
- package/src/providers/integrations/grok/grok-oauth.ts +4 -4
- package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
- package/src/providers/integrations/hermes/hermes.ts +34 -5
- package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
- package/src/providers/integrations/kilo/kilo.ts +1 -1
- package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
- package/src/providers/integrations/muse/muse-oauth.ts +5 -5
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/openrouter/provider.ts +1 -1
- package/src/providers/integrations/perch/perch-protocol.ts +0 -3
- package/src/providers/integrations/perch/perch.ts +3 -3
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
- package/src/providers/integrations/qoder/qoder-adapter.ts +19 -113
- package/src/providers/integrations/qoder/qoder-auth.ts +8 -1
- package/src/providers/integrations/qoder/qoder-catalog.ts +1 -1
- package/src/providers/integrations/qoder/qoder-chat.ts +25 -8
- package/src/providers/integrations/qoder/qoder-checkin.ts +1 -1
- package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
- package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
- package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
- package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
- package/src/providers/integrations/qoder/qoder-types.ts +9 -0
- package/src/providers/integrations/qoder/qoder.ts +3 -25
- package/src/providers/integrations/sensenova/provider.ts +144 -0
- package/src/providers/integrations/trae/trae-quota.ts +15 -1
- package/src/providers/integrations/vercel/provider.ts +117 -0
- package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
- package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
- package/src/providers/integrations/zro/zro.ts +2 -1
- package/src/providers/operations/account-refresh-status.ts +14 -0
- package/src/providers/operations/client-versions.ts +95 -30
- package/src/providers/operations/oauth-refresh-lead.ts +46 -22
- package/src/providers/operations/provider-caches.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +22 -25
- package/src/providers/operations/session-resolution.ts +17 -1
- package/src/providers/provider-contracts.ts +2 -2
- package/src/providers/provider-metadata.ts +30 -0
- package/src/providers/quota/quota-contracts.ts +2 -0
- package/src/providers/quota/refresh.ts +25 -3
- package/src/security/ip-boundary.ts +1 -1
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/attempt-loop.ts +3 -3
- package/src/transport/dispatch/handler-deps.ts +1 -1
- package/src/transport/dispatch/leases.ts +1 -1
- package/src/transport/dispatch/retry-policy.ts +1 -1
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +1 -1
- package/src/transport/dispatch/upstream.ts +1 -1
- package/src/transport/shutdown-notice.ts +1 -1
- package/src/workers/buddy-growth-tasks.ts +8 -8
- package/src/workers/daily-checkin.ts +4 -4
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/zcode-gift-claim.ts +1 -1
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +0 -8
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js +0 -9
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +0 -2
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/src/console/providers/catalog/discover-constants.ts +0 -6
- package/src/network/pool-health.ts +0 -198
- package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
- package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
- package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -188
- package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
- package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -179
- package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
- package/src/providers/integrations/qoder/chat-proto.ts +0 -328
- package/src/providers/integrations/qoder/qoder-grpc.ts +0 -870
- package/src/providers/integrations/qoder/qoder-ide.ts +0 -481
- /package/dist/dashboard/assets/{app-DIXLjojg.js → app-C0gTXEoN.js} +0 -0
- /package/dist/dashboard/assets/{app-DIXLjojg.js.gz → app-C0gTXEoN.js.gz} +0 -0
- /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
- /package/src/network/pool/{byte-accounting.ts → accounting.ts} +0 -0
- /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
- /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
- /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
- /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
- /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
- /package/src/network/{rate-limit-verdict.ts → verdict.ts} +0 -0
|
@@ -2,32 +2,13 @@ import type { ProviderDispatchContext } from "../../provider-contracts";
|
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { decodeJwtPayload } from "../../authentication/oauth-flow-store";
|
|
5
|
-
import { buddyAccountUid } from "./
|
|
5
|
+
import { buddyAccountUid } from "./account";
|
|
6
6
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
*
|
|
11
|
-
* `desktop` is what every buddy provider sends today and stays the default for
|
|
12
|
-
* all four. `cli` is the identity the reference gateways use for CLI traffic: a
|
|
13
|
-
* different header set, a different User-Agent formula, and a different CN
|
|
14
|
-
* upstream.
|
|
15
|
-
*
|
|
16
|
-
* Nothing flips to `cli` implicitly. Being wrong here is what gets an account
|
|
17
|
-
* blocked upstream, so a provider changes identity only when an operator or an
|
|
18
|
-
* account says so.
|
|
19
|
-
*/
|
|
8
|
+
// ── buddy-identity ──────────────────────────────────────────
|
|
9
|
+
|
|
20
10
|
export type BuddyIdentity = "desktop" | "cli";
|
|
21
11
|
|
|
22
|
-
/**
|
|
23
|
-
* Resolves the identity one buddy dispatch presents.
|
|
24
|
-
*
|
|
25
|
-
* Precedence is account then provider: an account authorized as a CLI keeps
|
|
26
|
-
* that identity even when the provider default changes, because the upstream
|
|
27
|
-
* recorded it at login. The provider-level flag is
|
|
28
|
-
* `compatibilityProfile.cli_identity`, already declared, validated, and
|
|
29
|
-
* defaulted — it just never reached these adapters before.
|
|
30
|
-
*/
|
|
31
12
|
export function resolveBuddyIdentity(
|
|
32
13
|
context: ProviderDispatchContext | undefined,
|
|
33
14
|
profileIdentity?: boolean | undefined,
|
|
@@ -38,18 +19,6 @@ export function resolveBuddyIdentity(
|
|
|
38
19
|
return profileIdentity === true ? "cli" : "desktop";
|
|
39
20
|
}
|
|
40
21
|
|
|
41
|
-
/**
|
|
42
|
-
* The upstream's `X-User-Id` for a buddy dispatch.
|
|
43
|
-
*
|
|
44
|
-
* The reference CLI sends the literal `anonymous` when it has no uid rather
|
|
45
|
-
* than omitting the header, so an unauthenticated dispatch still looks like a
|
|
46
|
-
* client rather than like a caller that forgot a header.
|
|
47
|
-
*
|
|
48
|
-
* When the credential carries a JWT, the `sub` claim is the upstream uid and
|
|
49
|
-
* wins over the gateway's internal account id — the two can differ after an
|
|
50
|
-
* import, and the channel check keys on the upstream identity. Opaque API keys
|
|
51
|
-
* carry no identity, so the internal account id is the fallback.
|
|
52
|
-
*/
|
|
53
22
|
export function buddyUserId(context?: ProviderDispatchContext): string {
|
|
54
23
|
const secret = context?.credential?.secret;
|
|
55
24
|
const token = secret ? new TextDecoder().decode(secret).trim() : "";
|
|
@@ -59,15 +28,6 @@ export function buddyUserId(context?: ProviderDispatchContext): string {
|
|
|
59
28
|
return accountId !== undefined && accountId.length > 0 ? accountId : "anonymous";
|
|
60
29
|
}
|
|
61
30
|
|
|
62
|
-
/**
|
|
63
|
-
* Claim names a buddy access token may carry the enterprise id under.
|
|
64
|
-
*
|
|
65
|
-
* A list of candidates rather than one name because the upstream's token shape
|
|
66
|
-
* is not pinned anywhere this codebase can verify, and guessing one name would
|
|
67
|
-
* silently report "personal" for every account whose token spells it another
|
|
68
|
-
* way. Every candidate is a plausible spelling of the same fact; the first that
|
|
69
|
-
* holds a non-empty string wins, and a token carrying none yields no enterprise.
|
|
70
|
-
*/
|
|
71
31
|
const ENTERPRISE_CLAIMS: readonly string[] = [
|
|
72
32
|
"enterprise_id",
|
|
73
33
|
"enterpriseId",
|
|
@@ -78,24 +38,6 @@ const ENTERPRISE_CLAIMS: readonly string[] = [
|
|
|
78
38
|
"organization_id",
|
|
79
39
|
];
|
|
80
40
|
|
|
81
|
-
/**
|
|
82
|
-
* The enterprise this buddy account belongs to, or `undefined` for a personal
|
|
83
|
-
* one.
|
|
84
|
-
*
|
|
85
|
-
* Two sources, in this order:
|
|
86
|
-
*
|
|
87
|
-
* 1. **`auth_state.enterpriseId`** — written when the account was authorized, or
|
|
88
|
-
* set by an operator for an account whose token does not carry the fact.
|
|
89
|
-
* Wins because it is the one a human can correct.
|
|
90
|
-
* 2. **A claim on the access token** — for accounts authorized before this
|
|
91
|
-
* existed, whose `auth_state` was never populated.
|
|
92
|
-
*
|
|
93
|
-
* Deliberately conservative: no enterprise id means *personal*, and personal is
|
|
94
|
-
* what the gateway already sends. An unknown account is therefore unchanged
|
|
95
|
-
* rather than being given an enterprise it may not have — claiming one the
|
|
96
|
-
* upstream does not recognise is the kind of mismatch that draws a channel
|
|
97
|
-
* check.
|
|
98
|
-
*/
|
|
99
41
|
export function buddyEnterprise(context?: ProviderDispatchContext): string | undefined {
|
|
100
42
|
const stored = context?.credential.auth_state?.["enterpriseId"];
|
|
101
43
|
if (typeof stored === "string" && stored.trim().length > 0) return stored.trim();
|
|
@@ -110,29 +52,6 @@ export function buddyEnterprise(context?: ProviderDispatchContext): string | und
|
|
|
110
52
|
return undefined;
|
|
111
53
|
}
|
|
112
54
|
|
|
113
|
-
/**
|
|
114
|
-
* Per-account device binding (`qimei36`) for the buddy providers.
|
|
115
|
-
*
|
|
116
|
-
* The desktop auth state sends `X-Device-Id-List: {"qimei36":"…"}` alongside
|
|
117
|
-
* the Turing token — a second, independent device identity. Pinning it per
|
|
118
|
-
* account makes every account in a pool present a distinct device to the
|
|
119
|
-
* upstream risk control instead of sharing the machine's single fingerprint.
|
|
120
|
-
*
|
|
121
|
-
* Resolution order:
|
|
122
|
-
* 1. `auth_state.qimei36` — explicit operator-set binding (imported or edited).
|
|
123
|
-
* 2. Derived deterministically from the internal account id (sha256 → 32 hex).
|
|
124
|
-
* This keeps the binding stable across restarts without a database write,
|
|
125
|
-
* and gives each freshly-added account its own id automatically.
|
|
126
|
-
*
|
|
127
|
-
* IMPORTANT — the derived fallback is **not portable across instances**:
|
|
128
|
-
* export/import mints a NEW account id, so the derived binding changes and the
|
|
129
|
-
* upstream channel check (11128) rejects the re-imported account. The export
|
|
130
|
-
* path therefore materializes the raw result of this resolver into
|
|
131
|
-
* `auth_state.qimei36` whenever an account relies on the derivation, so a
|
|
132
|
-
* re-import carries the exact same device identity.
|
|
133
|
-
*
|
|
134
|
-
* Returns `undefined` only when no account id is available (unauthenticated).
|
|
135
|
-
*/
|
|
136
55
|
export function resolveBuddyDeviceBinding(context?: ProviderDispatchContext): string | undefined {
|
|
137
56
|
const explicit = context?.credential.auth_state?.["qimei36"];
|
|
138
57
|
if (typeof explicit === "string" && explicit.trim().length > 0) return explicit.trim();
|
|
@@ -141,9 +60,6 @@ export function resolveBuddyDeviceBinding(context?: ProviderDispatchContext): st
|
|
|
141
60
|
return createHash("sha256").update(`wb2a:qimei36:${accountId}`).digest("hex").slice(0, 32);
|
|
142
61
|
}
|
|
143
62
|
|
|
144
|
-
/** Materializes the portable binding for an account into a stored auth-state
|
|
145
|
-
* map, when the account does not already pin one explicitly. Used by the
|
|
146
|
-
* export path so a re-import keeps the exact qimei36 device identity. */
|
|
147
63
|
export function materializeBuddyDeviceBinding(
|
|
148
64
|
accountId: string,
|
|
149
65
|
authState: Readonly<Record<string, unknown>> | undefined,
|
|
@@ -155,19 +71,6 @@ export function materializeBuddyDeviceBinding(
|
|
|
155
71
|
return { ...(authState ?? {}), qimei36: derived };
|
|
156
72
|
}
|
|
157
73
|
|
|
158
|
-
/**
|
|
159
|
-
* The OAuth identity header family the reference ships on every cloud API call
|
|
160
|
-
* (`runIdentityHeaders`): `X-User-Id` plus the base64 `X-Userinfo` envelope and
|
|
161
|
-
* the auth-method / id-source markers.
|
|
162
|
-
*
|
|
163
|
-
* The JWT `sub` is the uid; the base64 envelope mirrors the reference exactly:
|
|
164
|
-
* `{ uin, owner_uin?, id_source?, token_source? }` — one leg per identity
|
|
165
|
-
* field that exists, so a personal account sends `{uin}` while an enterprise
|
|
166
|
-
* account adds `owner_uin`. `X-Auth-Method` / `X-Id-Source` are only sent when
|
|
167
|
-
* the operator pinned them in `auth_state` (there is no reliable source to
|
|
168
|
-
* invent them from). An opaque API key carries no uid and yields nothing.
|
|
169
|
-
*/
|
|
170
|
-
/** A short printable identity claim from a JWT payload, or `undefined`. */
|
|
171
74
|
function identityClaim(claims: Record<string, unknown> | undefined, name: string): string | undefined {
|
|
172
75
|
if (claims === undefined) return undefined;
|
|
173
76
|
const value = claims[name];
|
|
@@ -210,25 +113,10 @@ export function buddyOAuthIdentityHeaders(
|
|
|
210
113
|
return headers;
|
|
211
114
|
}
|
|
212
115
|
|
|
213
|
-
/**
|
|
214
|
-
* Whether this dispatch is in the reference's private-data mode. The CLI only
|
|
215
|
-
* sends `X-Private-Data: true` while the session is private; otherwise the
|
|
216
|
-
* header is deleted, never sent as `false`. The gateway has no session-level
|
|
217
|
-
* private flag, so the operator pins one per account in `auth_state.privateData`.
|
|
218
|
-
*/
|
|
219
116
|
export function buddyPrivateData(context?: ProviderDispatchContext): boolean {
|
|
220
117
|
return context?.credential.auth_state?.["privateData"] === true;
|
|
221
118
|
}
|
|
222
119
|
|
|
223
|
-
/**
|
|
224
|
-
* The effective agent purpose for one dispatch, matching the reference's
|
|
225
|
-
* `getEffectiveAgentPurpose` behavior as closely as the gateway can:
|
|
226
|
-
*
|
|
227
|
-
* - `PERSONAL_AGENT_ROLE` set → `person_agent` (same env the CLI reads);
|
|
228
|
-
* - otherwise an inbound `x-agent-purpose` header is preserved (the caller
|
|
229
|
-
* already stated a purpose — same shape the reference passes through);
|
|
230
|
-
* - otherwise the header is omitted. The reference does not invent `conversation`.
|
|
231
|
-
*/
|
|
232
120
|
export function buddyAgentPurpose(
|
|
233
121
|
context?: ProviderDispatchContext,
|
|
234
122
|
request?: CanonicalRequest,
|
|
@@ -243,17 +131,10 @@ export function buddyAgentPurpose(
|
|
|
243
131
|
return undefined;
|
|
244
132
|
}
|
|
245
133
|
|
|
246
|
-
/**
|
|
247
|
-
* Desktop risk token, sent only when the account actually has one.
|
|
248
|
-
*
|
|
249
|
-
* The account's own `auth_state` wins. When it carries none, a file the
|
|
250
|
-
* desktop client writes (`CARTETHYIA_DEVICE_TOKEN_FILE`, default
|
|
251
|
-
* `/app/data/device_token`) is read instead — cached for five minutes, and
|
|
252
|
-
* ignored when it is larger than 1 KB, because a token file that size is not
|
|
253
|
-
* a token. A missing file is the normal case and reads as "no token".
|
|
254
|
-
*/
|
|
255
134
|
const DEVICE_TOKEN_FILE_MAX_BYTES = 1024;
|
|
135
|
+
|
|
256
136
|
const DEVICE_TOKEN_FILE_TTL_MS = 5 * 60_000;
|
|
137
|
+
|
|
257
138
|
let deviceTokenFileCache: { readonly value: string | undefined; readonly readAt: number } | undefined;
|
|
258
139
|
|
|
259
140
|
export function readBuddyDeviceToken(context?: ProviderDispatchContext): string | undefined {
|
|
@@ -263,22 +144,6 @@ export function readBuddyDeviceToken(context?: ProviderDispatchContext): string
|
|
|
263
144
|
return readDeviceTokenFile();
|
|
264
145
|
}
|
|
265
146
|
|
|
266
|
-
/**
|
|
267
|
-
* The reference `X-Device-Token` pair, per the official desktop app.
|
|
268
|
-
*
|
|
269
|
-
* The desktop client always presents one of the
|
|
270
|
-
* two on chat traffic — a real token from the TuringShield SDK, or an
|
|
271
|
-
* `X-Device-Token-Error` when the SDK cannot produce one. It never omits both,
|
|
272
|
-
* and it sends the header on every realm (Intl and CN alike).
|
|
273
|
-
*
|
|
274
|
-
* The TuringShield SDK was a proprietary native addon shipped under
|
|
275
|
-
* `vendor/turing-sdk/`; it has been removed. The fallback path below is the
|
|
276
|
-
* captured token (auth_state / `CARTETHYIA_DEVICE_TOKEN_FILE`) and then the
|
|
277
|
-
* official failure state.
|
|
278
|
-
*
|
|
279
|
-
* - Legacy token (auth_state/file) → used when no SDK is available.
|
|
280
|
-
* - CLI identity never carries a device token (the CLI has no device).
|
|
281
|
-
*/
|
|
282
147
|
export async function buddyDeviceTokenHeaders(args: {
|
|
283
148
|
realm: "intl" | "cn";
|
|
284
149
|
context: ProviderDispatchContext | undefined;
|
|
@@ -311,3 +176,136 @@ function readDeviceTokenFile(): string | undefined {
|
|
|
311
176
|
deviceTokenFileCache = { value, readAt: now };
|
|
312
177
|
return value;
|
|
313
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
|
+
}
|