cartethyia 2.7.8 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +3 -3
- package/README.md +29 -59
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js +1 -0
- package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-CXsaOAO2.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js +1 -0
- package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
- package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
- package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-CgoPc5B9.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-D9bFQern.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js +1 -0
- package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
- package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BwNC_-Cx.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
- package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-febLU4r1.js} +1 -1
- package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-M6fvR5Wz.js} +1 -1
- package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js +56 -0
- package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js +1 -0
- package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
- package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
- package/dist/dashboard/assets/{assert-CidQVoNo.js → assert-CqTLw5e7.js} +1 -1
- package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
- package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-C83EqLB0.js} +1 -1
- package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
- package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
- package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-D1xn7pIe.js} +1 -1
- package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/favicon.webp +0 -0
- package/dist/dashboard/assets/brand/login_register.webp +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
- package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
- package/dist/dashboard/assets/brand/og_image.webp +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
- package/dist/dashboard/assets/{card-_HwAEqFF.js → card-DU3Lq5Lm.js} +1 -1
- package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js +1 -0
- package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CEL5Sg_J.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-BjFR5UHy.js} +1 -1
- package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-HvBW0AjI.js} +1 -1
- package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
- package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
- package/dist/dashboard/assets/{entry-COaC-irN.js → entry-CECVELyy.js} +1 -1
- package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js +1 -0
- package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-DLW4i8zK.js} +1 -1
- package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
- package/dist/dashboard/assets/{index-CgKmFngv.js → index-1-fCqe64.js} +2 -2
- package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
- package/dist/dashboard/assets/{inline-B2BirKry.js → inline-DGvU2oLK.js} +1 -1
- package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
- package/dist/dashboard/assets/{input-D-qV9dKY.js → input-iNnO1X2K.js} +1 -1
- package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
- package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-0q8UGypb.js} +1 -1
- package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-C0w2bQjJ.js} +1 -1
- package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
- package/dist/dashboard/assets/{live-DGizF06-.js → live-M5aJ_xCa.js} +1 -1
- package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
- package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
- package/dist/dashboard/assets/{network-C9UE-bOr.js → network-BKeQGT3K.js} +1 -1
- package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-CivAk3da.js} +1 -1
- package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
- package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-CpzvI5ep.js} +1 -1
- package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
- package/dist/dashboard/assets/providers/devin.svg +9 -0
- package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
- package/dist/dashboard/assets/providers/windsurf.svg +10 -0
- package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
- package/dist/dashboard/assets/providers/zro.svg +3 -0
- package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
- package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
- package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
- package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js +1 -0
- package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
- package/dist/dashboard/assets/{select-BCOcv8WK.js → select-CXbck0jG.js} +2 -2
- package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js +1 -0
- package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
- package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DggRiCxE.js} +1 -1
- package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
- package/dist/dashboard/assets/{state-DXbGTx7N.js → state-ClFzfbYp.js} +1 -1
- package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
- package/dist/dashboard/assets/story/25817331.webp +0 -0
- package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
- package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
- package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
- package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
- package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
- package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
- package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
- package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-CTIFxKqS.js} +1 -1
- package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BClG3yWj.js} +1 -1
- package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.webp +0 -0
- package/dist/dashboard/console-backgrounds_initial.webp +0 -0
- package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
- package/dist/dashboard/index.html +3 -3
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +59 -56
- package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
- package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
- package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
- package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
- package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
- package/package.json +1 -1
- package/src/boot/app.ts +10 -13
- package/src/boot/dependencies.ts +12 -4
- package/src/boot/flush.ts +20 -0
- package/src/boot/lifecycle.ts +7 -5
- package/src/config/cooldowns.ts +1 -1
- package/src/config/routing.ts +26 -0
- package/src/config/spec-metadata.ts +72 -0
- package/src/config/spec.ts +20 -6
- package/src/console/api-keys/contracts.ts +12 -1
- package/src/console/api-keys/routes.ts +50 -31
- package/src/console/auth/account-reset.ts +7 -9
- package/src/console/backup/contracts.ts +4 -0
- package/src/console/backup/export-endpoint.ts +7 -5
- package/src/console/cli-tools/service.ts +6 -12
- package/src/console/console-router-guards.ts +23 -16
- package/src/console/console-router.ts +7 -0
- package/src/console/dashboard-assets.ts +5 -5
- package/src/console/domain-registration.ts +27 -2
- package/src/console/inferhub/normalize.ts +24 -28
- package/src/console/inferhub/types.ts +3 -0
- package/src/console/ip-bans/routes.ts +93 -0
- package/src/console/observability/store.ts +0 -53
- package/src/console/providers/catalog/catalog-projections.ts +5 -2
- package/src/console/providers/catalog/contracts.ts +123 -0
- package/src/console/providers/catalog/discover-constants.ts +6 -0
- package/src/console/providers/catalog/model-operations.ts +122 -10
- package/src/console/providers/catalog/provider-operations.ts +116 -8
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +65 -4
- package/src/console/providers/catalog/store-helpers.ts +30 -1
- package/src/console/providers/catalog/store.ts +249 -4
- package/src/console/quota/account-quota-global.ts +97 -19
- package/src/console/quota/account-quota-shared.ts +49 -0
- package/src/console/quota/account-quota-tenant.ts +6 -18
- package/src/console/quota/native-identity.ts +2 -0
- package/src/console/quota/quota-view.ts +19 -3
- package/src/console/routing/pools/operations.ts +31 -46
- package/src/console/settings/contracts.ts +18 -0
- package/src/console/settings/store.ts +32 -0
- package/src/console/shared/errors.ts +33 -6
- package/src/console/system-prompt/contracts.ts +0 -1
- package/src/main.ts +3 -3
- package/src/network/pool/byte-accounting.ts +3 -2
- package/src/network/pool/selector.ts +182 -39
- package/src/network/pool-cooldown-store.ts +89 -14
- package/src/network/pool-health.ts +49 -61
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/ssrf.ts +6 -6
- package/src/observability/event-log.ts +7 -361
- package/src/observability/event-query.ts +18 -4
- package/src/observability/performance-metrics.ts +9 -0
- package/src/observability/runtime-metrics.ts +14 -9
- package/src/observability/telemetry-buffer.ts +15 -25
- package/src/observability/telemetry-reconciliation.ts +9 -37
- package/src/observability/telemetry-row.ts +125 -0
- package/src/persistence/db-mode.ts +4 -1
- package/src/persistence/dialect.ts +30 -0
- package/src/persistence/migrate.ts +6 -3
- package/src/persistence/schema.ts +28 -2
- package/src/persistence/ttl-cache.ts +20 -2
- package/src/protocol/codecs.ts +1 -1
- package/src/protocol/dsml.ts +35 -87
- package/src/protocol/gateway-error.ts +1 -0
- package/src/protocol/markup-stream-parser.ts +195 -0
- package/src/protocol/reasoning-text.ts +19 -0
- package/src/protocol/reasoning.ts +1 -1
- package/src/protocol/request/chat.ts +14 -14
- package/src/protocol/request/gemini.ts +8 -2
- package/src/protocol/request/messages.ts +4 -5
- package/src/protocol/response/chat.ts +12 -20
- package/src/protocol/response/gemini.ts +6 -1
- package/src/protocol/response/omp-tool-call-markup.ts +43 -86
- package/src/protocol/response/responses.ts +18 -2
- package/src/protocol/sse-decoder.ts +25 -8
- package/src/protocol/stop-reason.ts +23 -1
- package/src/protocol/stream-error-frames.ts +13 -3
- package/src/protocol/think-split.ts +112 -0
- package/src/protocol/translation/dialect/qwen.ts +26 -58
- package/src/protocol/translation/quirks.ts +1 -1
- package/src/protocol/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream/send-claude-messages.ts +15 -4
- package/src/protocol/upstream-parsing.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +78 -17
- package/src/providers/authentication/oauth-client.ts +1 -1
- package/src/providers/authentication/oauth-device-flow.ts +98 -8
- package/src/providers/authentication/oauth-refresh-service.ts +153 -59
- package/src/providers/configured-provider.ts +148 -0
- package/src/providers/default-registry.ts +117 -27
- package/src/providers/discovery/discovery-types.ts +12 -0
- package/src/providers/discovery/probe-phases.ts +74 -33
- package/src/providers/discovery/probing-service.ts +293 -165
- 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 +121 -2
- package/src/providers/integrations/antigravity/antigravity.ts +13 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +191 -35
- package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
- package/src/providers/integrations/buddy/buddy-identity.ts +89 -6
- package/src/providers/integrations/buddy/buddy-media.ts +4 -5
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
- package/src/providers/integrations/buddy/capabilities.ts +6 -43
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +23 -1
- package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
- package/src/providers/integrations/buddy/codebuddy/shared.ts +38 -27
- package/src/providers/integrations/claude/claude-quota.ts +14 -17
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/commandcode/quota.ts +22 -28
- package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
- package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
- package/src/providers/integrations/cursor/cursor-exec.ts +745 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
- package/src/providers/integrations/cursor/cursor-request.ts +35 -20
- package/src/providers/integrations/cursor/cursor-shared.ts +26 -5
- package/src/providers/integrations/cursor/cursor.ts +139 -70
- 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/cursor/protocol/tool-canonical.ts +26 -100
- package/src/providers/integrations/devin/devin-auth.ts +353 -0
- package/src/providers/integrations/devin/devin-catalog.ts +207 -0
- package/src/providers/integrations/devin/devin-http.ts +91 -0
- package/src/providers/integrations/devin/devin-quota.ts +214 -0
- package/src/providers/integrations/devin/devin-shared.ts +111 -0
- package/src/providers/integrations/devin/devin.ts +539 -0
- package/src/providers/integrations/devin/protocol/devin-proto.ts +558 -0
- package/src/providers/integrations/devin/protocol/framing.ts +124 -0
- package/src/providers/integrations/factory/factory-oauth.ts +17 -44
- package/src/providers/integrations/factory/factory.ts +2 -2
- 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 +60 -0
- package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
- package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
- package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
- package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
- package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
- package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
- package/src/providers/integrations/freepi/freepi.ts +292 -0
- package/src/providers/integrations/gemini.ts +2 -2
- package/src/providers/integrations/grok/grok-oauth.ts +48 -45
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
- package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
- package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
- package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +13 -21
- package/src/providers/integrations/hermes/index.ts +2 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
- package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
- package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
- package/src/providers/integrations/kiro/kiro.ts +15 -19
- package/src/providers/integrations/ollamacloud/index.ts +2 -0
- package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
- package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
- package/src/providers/integrations/opencode/fingerprint.ts +1 -1
- package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
- package/src/providers/integrations/perch/perch-catalog.ts +105 -0
- package/src/providers/integrations/perch/perch-credential.ts +25 -0
- package/src/providers/integrations/perch/perch-oauth.ts +170 -0
- package/src/providers/integrations/perch/perch-protocol.ts +208 -0
- package/src/providers/integrations/perch/perch-quota.ts +123 -0
- package/src/providers/integrations/perch/perch-realm.ts +82 -0
- package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
- package/src/providers/integrations/perch/perch.ts +305 -0
- package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
- package/src/providers/integrations/qoder/chat-proto.ts +328 -328
- package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
- package/src/providers/integrations/qoder/qoder-adapter.ts +90 -40
- package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
- package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
- package/src/providers/integrations/qoder/qoder-catalog.ts +26 -6
- package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
- package/src/providers/integrations/qoder/qoder-checkin.ts +6 -6
- package/src/providers/integrations/qoder/qoder-grpc.ts +210 -7
- package/src/providers/integrations/qoder/qoder-ide.ts +5 -108
- package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
- package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
- package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
- package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
- package/src/providers/integrations/qoder/qoder.ts +3 -7
- package/src/providers/integrations/trae/trae-catalog.ts +9 -14
- package/src/providers/integrations/trae/trae-headers.ts +36 -11
- package/src/providers/integrations/trae/trae-oauth.ts +14 -17
- package/src/providers/integrations/trae/trae-protocol.ts +12 -11
- package/src/providers/integrations/trae/trae-quota.ts +96 -36
- package/src/providers/integrations/trae/trae-realm.ts +74 -15
- package/src/providers/integrations/trae/trae.ts +99 -26
- package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
- package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
- package/src/providers/integrations/zro/zro.ts +204 -0
- package/src/providers/operations/account-error-classification.ts +235 -278
- package/src/providers/operations/account-health-service.ts +273 -26
- package/src/providers/operations/account-refresh-status.ts +269 -0
- package/src/providers/operations/account-tier.ts +66 -0
- package/src/providers/operations/client-version-resolver.ts +1 -1
- package/src/providers/operations/client-versions.ts +42 -150
- package/src/providers/operations/cooldown-rules.ts +56 -0
- package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
- package/src/providers/operations/provider-catalog-seeder.ts +4 -0
- package/src/providers/operations/provider-catalog-service.ts +1 -1
- package/src/providers/operations/provider-credential-service.ts +102 -32
- package/src/providers/operations/provider-rules/github.ts +48 -0
- package/src/providers/operations/provider-rules/grok.ts +33 -0
- package/src/providers/operations/provider-rules/inception.ts +49 -0
- package/src/providers/operations/provider-rules/index.ts +32 -0
- package/src/providers/operations/provider-rules/perch.ts +37 -0
- package/src/providers/operations/provider-rules/qoder.ts +70 -0
- package/src/providers/operations/provider-rules/trae.ts +81 -0
- package/src/providers/provider-contracts.ts +33 -2
- package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
- package/src/providers/provider-metadata.ts +99 -14
- package/src/providers/provider-model-definition.ts +36 -0
- package/src/providers/provider-probe.ts +15 -1
- package/src/providers/provider-registry.ts +42 -33
- package/src/providers/quota/quota-limit-windows.ts +16 -5
- package/src/providers/quota/quota-support.ts +1 -1
- package/src/providers/quota/quota-window-parser.ts +90 -18
- package/src/providers/quota/refresh.ts +96 -18
- package/src/security/abuse.ts +71 -0
- package/src/security/api-key-auth-cache.ts +1 -1
- package/src/security/api-key-auth.ts +6 -2
- package/src/transport/dispatch/attempt-finalize.ts +14 -13
- package/src/transport/dispatch/attempt-loop.ts +71 -17
- package/src/transport/dispatch/generation.ts +2 -8
- package/src/transport/dispatch/native-shared.ts +25 -0
- package/src/transport/dispatch/proxy-request.ts +9 -46
- package/src/transport/dispatch/responses-compact.ts +2 -8
- package/src/transport/dispatch/streaming/finalize.ts +9 -6
- package/src/transport/dispatch/streaming/stream.ts +9 -36
- package/src/transport/dispatch/systemone.ts +2 -8
- package/src/transport/dispatch/token-count.ts +2 -6
- package/src/transport/dispatch/upstream.ts +67 -1
- package/src/transport/drain-endpoint.ts +31 -4
- package/src/transport/failure-policy.ts +129 -37
- 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 +418 -33
- 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 +9 -2
- 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 +34 -6
- package/src/transport/surface/responses/parse.ts +3 -11
- package/src/workers/daily-checkin.ts +1 -1
- package/src/workers/quota-refresh-sweep.ts +1 -1
- package/src/workers/scheduler.ts +22 -4
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
- package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
- package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
- package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js +0 -1
- package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
- package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
- package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
- package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
- package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
- package/dist/dashboard/assets/brand/bansos_page.png +0 -0
- package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/favicon.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register.jpg +0 -0
- package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
- package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
- package/dist/dashboard/assets/brand/og_image.jpg +0 -0
- package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
- package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
- package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
- package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
- package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
- package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
- package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
- package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
- package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
- package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
- package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
- package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
- package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
- package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-YSoQOUh6.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-fnCsxgNO.js +0 -1
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
- package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
- package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
- package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
- package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/src/providers/bundled-discovery-providers.ts +0 -98
- package/src/providers/configured-openai-providers.ts +0 -120
- package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
- package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
- package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
- package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
- package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
- package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
- package/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-CTxoqyYB.js → app-DIXLjojg.js} +0 -0
- /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-DIXLjojg.js.gz} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Chat-wire payload and message normalization shared by the Tencent "buddy"
|
|
3
|
-
* family providers — CodeBuddy International (`cb`)
|
|
4
|
-
*
|
|
3
|
+
* family providers — CodeBuddy International (`cb`) and CodeBuddy CN (`cbcn`).
|
|
4
|
+
* Both speak the same upstream contract for this part of
|
|
5
5
|
* the payload, so the rules live here once instead of being copied per
|
|
6
6
|
* variant:
|
|
7
7
|
*
|
|
@@ -21,6 +21,7 @@ import { createHash } from "node:crypto";
|
|
|
21
21
|
import { completeRequiredSchema } from "../../../protocol/codecs";
|
|
22
22
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
23
23
|
import { isRecord } from "../../../protocol/codecs";
|
|
24
|
+
import { GatewayError } from "../../../protocol/gateway-error";
|
|
24
25
|
import { applyDeepSeekReasoning, applyOpenAIReasoning, backfillDeepSeekReasoningContent, clampedEffortOutputFloor, ensureChatReasoningReplayPresence } from "../../../protocol/reasoning";
|
|
25
26
|
import { BUDDY_CN_EFFORTS, BUDDY_INTL_EFFORTS, BUDDY_SHARED_RAW } from "./buddy-catalog-shared";
|
|
26
27
|
// Imported for the CN roster only: a CN-only id has no row in the shared
|
|
@@ -55,6 +56,123 @@ function normalizedToolName(value: string, index: number, used: Set<string>): st
|
|
|
55
56
|
return uniqueToolName(base || `tool_${index + 1}`, used);
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Schema keywords whose values are schemas (recursed as schema objects).
|
|
61
|
+
* Mirrors the donor gateway's `upstream_compat._SCHEMA_MAPS/_ARRAYS/CHILDREN`.
|
|
62
|
+
*/
|
|
63
|
+
const RE2_SCHEMA_MAPS: ReadonlySet<string> = new Set([
|
|
64
|
+
"properties",
|
|
65
|
+
"patternProperties",
|
|
66
|
+
"$defs",
|
|
67
|
+
"definitions",
|
|
68
|
+
"dependentSchemas",
|
|
69
|
+
"dependencies",
|
|
70
|
+
]);
|
|
71
|
+
const RE2_SCHEMA_ARRAYS: ReadonlySet<string> = new Set([
|
|
72
|
+
"allOf",
|
|
73
|
+
"anyOf",
|
|
74
|
+
"oneOf",
|
|
75
|
+
"prefixItems",
|
|
76
|
+
"items",
|
|
77
|
+
]);
|
|
78
|
+
const RE2_SCHEMA_CHILDREN: ReadonlySet<string> = new Set([
|
|
79
|
+
"items",
|
|
80
|
+
"additionalItems",
|
|
81
|
+
"contains",
|
|
82
|
+
"unevaluatedItems",
|
|
83
|
+
"additionalProperties",
|
|
84
|
+
"unevaluatedProperties",
|
|
85
|
+
"propertyNames",
|
|
86
|
+
"not",
|
|
87
|
+
"if",
|
|
88
|
+
"then",
|
|
89
|
+
"else",
|
|
90
|
+
"contentSchema",
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Removes unescaped backslashes before underscores in one regex pattern. The
|
|
95
|
+
* CodeBuddy upstream validates tool schemas with RE2, which does not support
|
|
96
|
+
* `\_` escapes — a client schema that serializes `\_` (a common JSON
|
|
97
|
+
* representation of a literal underscore) is rejected with a 400. The donor
|
|
98
|
+
* gateway normalizes this before dispatch; a backslash that escapes a
|
|
99
|
+
* backslash is preserved.
|
|
100
|
+
*/
|
|
101
|
+
function normalizeRe2Pattern(value: string): string {
|
|
102
|
+
let out = "";
|
|
103
|
+
for (let i = 0; i < value.length; i++) {
|
|
104
|
+
const char = value[i];
|
|
105
|
+
if (char === "\\" && value[i + 1] === "\\") {
|
|
106
|
+
// Escaped backslash: keep the pair so a following `_` stays escaped.
|
|
107
|
+
out += "\\\\";
|
|
108
|
+
i += 1;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (char === "\\" && value[i + 1] === "_") {
|
|
112
|
+
// `\_` — the upstream's RE2 rejects it; drop the backslash.
|
|
113
|
+
out += "_";
|
|
114
|
+
i += 1;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
out += char;
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Normalizes RE2-incompatible underscore escapes in schema pattern positions. */
|
|
123
|
+
function normalizeRe2SchemaPatterns(schema: unknown): void {
|
|
124
|
+
if (!isRecord(schema)) return;
|
|
125
|
+
const pattern = schema["pattern"];
|
|
126
|
+
if (typeof pattern === "string") schema["pattern"] = normalizeRe2Pattern(pattern);
|
|
127
|
+
const patternProperties = schema["patternProperties"];
|
|
128
|
+
if (isRecord(patternProperties)) {
|
|
129
|
+
const normalized: Record<string, unknown> = {};
|
|
130
|
+
for (const [key, value] of Object.entries(patternProperties)) {
|
|
131
|
+
const key2 = normalizeRe2Pattern(key);
|
|
132
|
+
if (key2 in normalized) {
|
|
133
|
+
normalized[key2] = { allOf: [normalized[key2], value] };
|
|
134
|
+
} else {
|
|
135
|
+
normalized[key2] = value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
schema["patternProperties"] = normalized;
|
|
139
|
+
}
|
|
140
|
+
for (const key of RE2_SCHEMA_MAPS) {
|
|
141
|
+
const map = schema[key];
|
|
142
|
+
if (!isRecord(map)) continue;
|
|
143
|
+
for (const child of Object.values(map)) normalizeRe2SchemaPatterns(child);
|
|
144
|
+
}
|
|
145
|
+
for (const key of RE2_SCHEMA_ARRAYS) {
|
|
146
|
+
const list = schema[key];
|
|
147
|
+
if (!Array.isArray(list)) continue;
|
|
148
|
+
for (const child of list) normalizeRe2SchemaPatterns(child);
|
|
149
|
+
}
|
|
150
|
+
for (const key of RE2_SCHEMA_CHILDREN) {
|
|
151
|
+
normalizeRe2SchemaPatterns(schema[key]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** JSON-serializes a value to cheaply detect a backslash-before-underscore. */
|
|
156
|
+
function hasUnderscoreEscape(value: unknown): boolean {
|
|
157
|
+
try {
|
|
158
|
+
return JSON.stringify(value).includes("\\_");
|
|
159
|
+
} catch {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Returns the declaration with RE2-safe schema patterns, or the same object. */
|
|
165
|
+
function normalizeRe2Declaration(declaration: Record<string, unknown>): Record<string, unknown> {
|
|
166
|
+
const parameters = declaration["parameters"];
|
|
167
|
+
if (!hasUnderscoreEscape(parameters)) return declaration;
|
|
168
|
+
// Deep-copy only when a rewrite is needed; the shared object must not be
|
|
169
|
+
// mutated for every dispatch.
|
|
170
|
+
const out: Record<string, unknown> = { ...declaration };
|
|
171
|
+
out["parameters"] = structuredClone(parameters);
|
|
172
|
+
normalizeRe2SchemaPatterns(out["parameters"]);
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
58
176
|
/**
|
|
59
177
|
* Buddy's Chat Completions wire has no `web_search_preview` hosted tool; its
|
|
60
178
|
* search is an ordinary function named `web_search` with a `{query}` schema.
|
|
@@ -102,29 +220,28 @@ export function normalizeBuddyToolNames(payload: Record<string, unknown>): void
|
|
|
102
220
|
const name = normalizedToolName(sourceName, index, used);
|
|
103
221
|
used.add(name);
|
|
104
222
|
if (!replacements.has(sourceName)) replacements.set(sourceName, name);
|
|
105
|
-
if (fn !== undefined)
|
|
106
|
-
|
|
107
|
-
...
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
name,
|
|
111
|
-
...(fn["parameters"] === undefined ? {} : { parameters: completeRequiredSchema(fn["parameters"]) }),
|
|
112
|
-
},
|
|
223
|
+
if (fn !== undefined) {
|
|
224
|
+
const fnOut = {
|
|
225
|
+
...fn,
|
|
226
|
+
name,
|
|
227
|
+
...(fn["parameters"] === undefined ? {} : { parameters: completeRequiredSchema(fn["parameters"]) }),
|
|
113
228
|
};
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
},
|
|
229
|
+
return normalizeRe2Declaration(fnOut);
|
|
230
|
+
}
|
|
231
|
+
if (custom !== undefined) {
|
|
232
|
+
const customOut = {
|
|
233
|
+
...custom,
|
|
234
|
+
name,
|
|
235
|
+
...(custom["format"] === undefined ? {} : { format: completeRequiredSchema(custom["format"]) }),
|
|
122
236
|
};
|
|
123
|
-
|
|
237
|
+
return { ...rawTool, custom: normalizeRe2Declaration(customOut) };
|
|
238
|
+
}
|
|
239
|
+
const bareOut = {
|
|
124
240
|
...rawTool,
|
|
125
241
|
name,
|
|
126
242
|
...(rawTool["parameters"] === undefined ? {} : { parameters: completeRequiredSchema(rawTool["parameters"]) }),
|
|
127
243
|
};
|
|
244
|
+
return normalizeRe2Declaration(bareOut);
|
|
128
245
|
});
|
|
129
246
|
const messages = payload["messages"];
|
|
130
247
|
if (Array.isArray(messages)) {
|
|
@@ -138,6 +255,13 @@ export function normalizeBuddyToolNames(payload: Record<string, unknown>): void
|
|
|
138
255
|
}
|
|
139
256
|
}
|
|
140
257
|
}
|
|
258
|
+
const responseFormat = payload["response_format"];
|
|
259
|
+
if (isRecord(responseFormat) && hasUnderscoreEscape(responseFormat)) {
|
|
260
|
+
const copied = structuredClone(responseFormat) as Record<string, unknown>;
|
|
261
|
+
const jsonSchema = copied["json_schema"];
|
|
262
|
+
if (isRecord(jsonSchema)) normalizeRe2SchemaPatterns(jsonSchema["schema"]);
|
|
263
|
+
payload["response_format"] = copied;
|
|
264
|
+
}
|
|
141
265
|
const choice = payload["tool_choice"];
|
|
142
266
|
if (!isRecord(choice)) return;
|
|
143
267
|
if (choice["type"] === "allowed_tools" && Array.isArray(choice["tools"])) {
|
|
@@ -332,10 +456,10 @@ function buddyTemplatePattern(text: string): RegExp {
|
|
|
332
456
|
return new RegExp(`(?<!\\w)${buddyTemplateSource(text)}(?!\\w)`, "i");
|
|
333
457
|
}
|
|
334
458
|
|
|
335
|
-
// DeepSeek Harness (DSH) role identities. DSH is the harness behind
|
|
336
|
-
// a history that still carries its self-description reads to the
|
|
337
|
-
// foreign channel, so the hardened client rewrites it back to
|
|
338
|
-
// identity rather than forwarding a competing one.
|
|
459
|
+
// DeepSeek Harness (DSH) role identities. DSH is the harness behind the buddy
|
|
460
|
+
// family; a history that still carries its self-description reads to the
|
|
461
|
+
// upstream as a foreign channel, so the hardened client rewrites it back to
|
|
462
|
+
// the CodeBuddy identity rather than forwarding a competing one.
|
|
339
463
|
const DSH_CODING_PATTERN = new RegExp(
|
|
340
464
|
`(?<!\\w)${buddyTemplateSource("You are a coding agent powered by the")}` +
|
|
341
465
|
`[\\s${BUDDY_ZWSP}]+([^\\r\\n]{1,200}?)[\\s${BUDDY_ZWSP}]+` +
|
|
@@ -350,17 +474,17 @@ const DSH_DIRECT_PATTERN = buddyTemplatePattern("You are DeepSeek Harness");
|
|
|
350
474
|
const DSH_WEB_GUI_PATTERN = buddyTemplatePattern("DeepSeek Harness Web GUI");
|
|
351
475
|
|
|
352
476
|
/** The identity DSH role prompts are rewritten to; neutral and minimal. */
|
|
353
|
-
const
|
|
477
|
+
const DSH_CODEBUDDY_IDENTITY = "You are a helpful assistant";
|
|
354
478
|
|
|
355
479
|
/**
|
|
356
480
|
* Rewrites DeepSeek Harness role identities in one message's text back to the
|
|
357
|
-
*
|
|
481
|
+
* CodeBuddy identity. Port of the donor gateway's always-on
|
|
358
482
|
* `desensitize_channel_body`, scoped to text the wire actually carries.
|
|
359
483
|
*
|
|
360
484
|
* This normalizes a replayed history (or a surviving system turn) that still
|
|
361
|
-
* claims the DSH harness, so a
|
|
485
|
+
* claims the DSH harness, so a buddy request never advertises a competing
|
|
362
486
|
* channel identity upstream. The coding persona keeps the model it named:
|
|
363
|
-
* "You are a coding agent powered by the X model" becomes the
|
|
487
|
+
* "You are a coding agent powered by the X model" becomes the CodeBuddy
|
|
364
488
|
* identity plus "powered by the X model".
|
|
365
489
|
*/
|
|
366
490
|
export function scrubBuddyChannelIdentityText(text: string): string {
|
|
@@ -368,13 +492,13 @@ export function scrubBuddyChannelIdentityText(text: string): string {
|
|
|
368
492
|
const withCodingPersona = text.replace(
|
|
369
493
|
DSH_CODING_PATTERN,
|
|
370
494
|
(_match, model: string) =>
|
|
371
|
-
`${
|
|
495
|
+
`${DSH_CODEBUDDY_IDENTITY}. This conversation is powered by the ${model.trim()} model`,
|
|
372
496
|
);
|
|
373
497
|
return withCodingPersona
|
|
374
|
-
.replace(DSH_CHANNEL_IDENTITY_PATTERN,
|
|
375
|
-
.replace(DSH_MINIMAL_PATTERN,
|
|
376
|
-
.replace(DSH_DIRECT_PATTERN,
|
|
377
|
-
.replace(DSH_WEB_GUI_PATTERN, "
|
|
498
|
+
.replace(DSH_CHANNEL_IDENTITY_PATTERN, DSH_CODEBUDDY_IDENTITY)
|
|
499
|
+
.replace(DSH_MINIMAL_PATTERN, DSH_CODEBUDDY_IDENTITY)
|
|
500
|
+
.replace(DSH_DIRECT_PATTERN, DSH_CODEBUDDY_IDENTITY)
|
|
501
|
+
.replace(DSH_WEB_GUI_PATTERN, "CodeBuddy Web GUI");
|
|
378
502
|
}
|
|
379
503
|
|
|
380
504
|
function scrubBuddyMessageText(message: Record<string, unknown>, field: string): void {
|
|
@@ -477,6 +601,10 @@ export function buddyPrePayloadCommon(
|
|
|
477
601
|
normalizeBuddyImageUrl(payload);
|
|
478
602
|
// developer role → system (buddy whitelist rejects developer, 11128)
|
|
479
603
|
normalizeBuddyRoles(payload);
|
|
604
|
+
// Validate the *caller's* thinking controls before the DeepSeek contract may
|
|
605
|
+
// inject its own `thinking` (an injected `{type:"enabled"}` has no budget and
|
|
606
|
+
// must not be rejected as a malformed client shape).
|
|
607
|
+
validateBuddyThinking(payload);
|
|
480
608
|
applyOpenAIReasoning(payload, request);
|
|
481
609
|
applyDeepSeekReasoning(payload);
|
|
482
610
|
// sol family defaults to high reasoning like reference thinking.go defaultDeepSeekEffort — sol without effort gets 500/invoke error otherwise
|
|
@@ -504,8 +632,8 @@ export function buddyPrePayloadCommon(
|
|
|
504
632
|
cleanupBuddyOrphanToolPairs(arr);
|
|
505
633
|
coalesceConsecutiveAssistantMessages(arr);
|
|
506
634
|
// Normalize a replayed harness history before the blocked-code rewrite
|
|
507
|
-
// below: DSH role identities are replaced with the
|
|
508
|
-
// a
|
|
635
|
+
// below: DSH role identities are replaced with the CodeBuddy identity, so
|
|
636
|
+
// a buddy-family request never forwards a competing channel identity.
|
|
509
637
|
scrubBuddyChannelIdentity(arr);
|
|
510
638
|
// After every merge: a quoted `11128` in any surviving text blocks the
|
|
511
639
|
// whole request, and the merges above are what produce the final text.
|
|
@@ -516,6 +644,34 @@ export function buddyPrePayloadCommon(
|
|
|
516
644
|
delete payload["agent_prompt"];
|
|
517
645
|
}
|
|
518
646
|
|
|
647
|
+
/**
|
|
648
|
+
* Validates the reasoning controls the CodeBuddy Chat wire accepts, mirroring
|
|
649
|
+
* the donor gateway's `map_reasoning_controls`. The upstream rejects the whole
|
|
650
|
+
* request for shapes it does not model, so a client that sends an unsupported
|
|
651
|
+
* `thinking` shape is failed here with a 400 that names the field — instead of
|
|
652
|
+
* an opaque upstream error.
|
|
653
|
+
*/
|
|
654
|
+
function validateBuddyThinking(payload: Record<string, unknown>): void {
|
|
655
|
+
const thinking = isRecord(payload["thinking"]) ? payload["thinking"] : undefined;
|
|
656
|
+
if (thinking === undefined) return;
|
|
657
|
+
const mode = typeof thinking["type"] === "string" ? (thinking["type"] as string) : "";
|
|
658
|
+
if (mode !== "enabled" && mode !== "adaptive" && mode !== "disabled") {
|
|
659
|
+
throw new GatewayError("invalid_request", 400, `CodeBuddy thinking.type must be enabled, adaptive or disabled (got ${JSON.stringify(mode)}) (request {requestId}). Check the shape of what you sent — then resend 🪞`);
|
|
660
|
+
}
|
|
661
|
+
if (mode === "enabled") {
|
|
662
|
+
const budget = thinking["budget_tokens"];
|
|
663
|
+
if (typeof budget !== "number" || !Number.isInteger(budget) || budget < 1024) {
|
|
664
|
+
throw new GatewayError("invalid_request", 400, "CodeBuddy thinking.budget_tokens must be an integer >= 1024 (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
665
|
+
}
|
|
666
|
+
} else if (thinking["budget_tokens"] !== undefined) {
|
|
667
|
+
throw new GatewayError("invalid_request", 400, "CodeBuddy thinking.budget_tokens requires thinking.type=enabled (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
668
|
+
}
|
|
669
|
+
const display = thinking["display"];
|
|
670
|
+
if (display !== undefined && display !== null && display !== "summarized") {
|
|
671
|
+
throw new GatewayError("invalid_request", 400, "CodeBuddy thinking.display supports only summarized (request {requestId}). Check the shape of what you sent — then resend 🪞");
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
519
675
|
function injectSolReasoningDefault(payload: Record<string, unknown>): void {
|
|
520
676
|
const model = typeof payload["model"] === "string" ? (payload["model"] as string) : "";
|
|
521
677
|
const isSol = model.toLowerCase().includes("sol");
|
|
@@ -1138,7 +1294,7 @@ export interface BuddyMessageFinalizeOptions {
|
|
|
1138
1294
|
* The single authoritative buddy message-shape pipeline. Every variant runs
|
|
1139
1295
|
* the same sequence — coalesce, drop empty turns, guarantee the leading system
|
|
1140
1296
|
* turn, omit content on tool_calls-only assistant turns, then auto-cache — so
|
|
1141
|
-
* the wire shape cannot drift between CodeBuddy intl
|
|
1297
|
+
* the wire shape cannot drift between CodeBuddy intl and CN.
|
|
1142
1298
|
*/
|
|
1143
1299
|
export function finalizeBuddyMessages(
|
|
1144
1300
|
messages: Array<Record<string, unknown>>,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { asCoercedNumber as sharedAsNumber, asRecord as sharedAsRecord } from "../../../shared/coerce";
|
|
2
2
|
|
|
3
|
-
// Buddy-family daily check-in (daily login credit claim), shared by
|
|
4
|
-
// variants (`cb`, `cbcn
|
|
3
|
+
// Buddy-family daily check-in (daily login credit claim), shared by both
|
|
4
|
+
// variants (`cb`, `cbcn`): same Tencent billing facade, same
|
|
5
5
|
// status/claim contract — only the endpoint base and identity headers differ
|
|
6
6
|
// per variant, and those already live in each provider's own modules.
|
|
7
7
|
//
|
|
@@ -22,15 +22,8 @@ import { asCoercedNumber as sharedAsNumber, asRecord as sharedAsRecord } from ".
|
|
|
22
22
|
|
|
23
23
|
import { providerBaseUrl } from "../../provider-metadata";
|
|
24
24
|
import { sleep } from "../../../shared/sleep";
|
|
25
|
-
import { WORKBUDDY_DOMAIN } from "./workbuddy/shared";
|
|
26
25
|
import { BUDDY_PROVIDER_IDS } from "../../provider-metadata";
|
|
27
26
|
import { QODER_CHECKIN_PROVIDER_IDS } from "../qoder/qoder-checkin";
|
|
28
|
-
import {
|
|
29
|
-
buildWorkBuddyUserAgent,
|
|
30
|
-
getWorkBuddyClientVersion,
|
|
31
|
-
getWorkBuddyCnClientVersion,
|
|
32
|
-
getWorkBuddyCliVersion,
|
|
33
|
-
} from "../../operations/client-versions";
|
|
34
27
|
import { buildCodeBuddyUserAgent } from "../../operations/client-versions";
|
|
35
28
|
import { codebuddyDomain, type CodeBuddyVariant } from "./codebuddy/shared";
|
|
36
29
|
/** Providers whose billing facade exposes the daily check-in routes. */
|
|
@@ -186,8 +179,8 @@ export function buildActivityReportEvent(args: {
|
|
|
186
179
|
* chat send. A single event did not move the growth tasks; four events per
|
|
187
180
|
* batch, sent twice with a pause between the rounds, is what does. The pause
|
|
188
181
|
* is what keeps the two rounds from landing as one burst. Both numbers apply
|
|
189
|
-
* to every buddy variant — the request is built the same way for `cb
|
|
190
|
-
* `cbcn`,
|
|
182
|
+
* to every buddy variant — the request is built the same way for `cb` and
|
|
183
|
+
* `cbcn`, so neither can drift back to a single shot.
|
|
191
184
|
*/
|
|
192
185
|
export const ACTIVITY_REPORT_EVENTS_PER_BATCH = 4;
|
|
193
186
|
export const ACTIVITY_REPORT_ROUNDS = 2;
|
|
@@ -196,8 +189,8 @@ export const ACTIVITY_REPORT_ROUND_DELAY_MS = 1_500;
|
|
|
196
189
|
/**
|
|
197
190
|
* Sends the growth-activity report (`POST {base}/v2/report`, the versioned
|
|
198
191
|
* billing-meter path joined the same way as the status/claim routes:
|
|
199
|
-
* `VERSION_SEGMENT` supplies
|
|
200
|
-
*
|
|
192
|
+
* `VERSION_SEGMENT` supplies nothing for `cb`/`cbcn`, which already end in
|
|
193
|
+
* `/v2`).
|
|
201
194
|
*
|
|
202
195
|
* Two rounds of four events, paused between rounds. Each event carries its
|
|
203
196
|
* own conversation and request id: the facade drops a repeated id as a
|
|
@@ -290,13 +283,10 @@ const CLAIM_RETRY_DELAYS_MS = [1_000, 2_000] as const;
|
|
|
290
283
|
/**
|
|
291
284
|
* Check-in paths are joined onto the provider's manifest base URL, which does
|
|
292
285
|
* NOT carry a consistent version segment: `cb`/`cbcn` already end in `/v2`,
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
* gateways cannot drift apart.
|
|
286
|
+
* so no segment is prepended. This map keeps the join aligned with each
|
|
287
|
+
* provider's own quota collector, so the gateways cannot drift apart.
|
|
296
288
|
*/
|
|
297
289
|
const VERSION_SEGMENT: Readonly<Record<string, string>> = {
|
|
298
|
-
workbuddy: "/v2",
|
|
299
|
-
workbuddycn: "/v2",
|
|
300
290
|
cb: "",
|
|
301
291
|
cbcn: "",
|
|
302
292
|
};
|
|
@@ -311,10 +301,9 @@ function claimUrl(providerId: string): string {
|
|
|
311
301
|
|
|
312
302
|
/**
|
|
313
303
|
* Per-provider billing headers. The Buddy gateways share the Tencent billing
|
|
314
|
-
* facade but each risk-gates on its own client identity:
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* the chat surface does.
|
|
304
|
+
* facade but each risk-gates on its own client identity: CodeBuddy intl
|
|
305
|
+
* wants the `IDE` identity, and CN wants `CLI` (plus its own `X-Domain`).
|
|
306
|
+
* Sending the wrong one trips a 403 the same way the chat surface does.
|
|
318
307
|
*/
|
|
319
308
|
async function checkinHeaders(providerId: string): Promise<Record<string, string>> {
|
|
320
309
|
const common = {
|
|
@@ -324,24 +313,13 @@ async function checkinHeaders(providerId: string): Promise<Record<string, string
|
|
|
324
313
|
"Content-Type": "application/json",
|
|
325
314
|
Accept: "application/json",
|
|
326
315
|
};
|
|
327
|
-
|
|
328
|
-
const variant: CodeBuddyVariant = providerId === "cb" ? "IDE" : "CLI";
|
|
329
|
-
return {
|
|
330
|
-
...common,
|
|
331
|
-
"User-Agent": buildCodeBuddyUserAgent(variant),
|
|
332
|
-
"X-IDE-Type": variant,
|
|
333
|
-
"X-IDE-Name": variant,
|
|
334
|
-
"X-Domain": codebuddyDomain(variant),
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
const clientVersion = providerId === "workbuddycn"
|
|
338
|
-
? getWorkBuddyCnClientVersion()
|
|
339
|
-
: getWorkBuddyClientVersion();
|
|
316
|
+
const variant: CodeBuddyVariant = providerId === "cb" ? "IDE" : "CLI";
|
|
340
317
|
return {
|
|
341
318
|
...common,
|
|
342
|
-
"User-Agent":
|
|
343
|
-
"X-
|
|
344
|
-
"
|
|
319
|
+
"User-Agent": buildCodeBuddyUserAgent(variant),
|
|
320
|
+
"X-IDE-Type": variant,
|
|
321
|
+
"X-IDE-Name": variant,
|
|
322
|
+
"X-Domain": codebuddyDomain(variant),
|
|
345
323
|
};
|
|
346
324
|
}
|
|
347
325
|
|
|
@@ -392,7 +370,7 @@ function envelopeCode(payload: unknown): number | null {
|
|
|
392
370
|
}
|
|
393
371
|
|
|
394
372
|
/**
|
|
395
|
-
* Unwraps the check-in payload.
|
|
373
|
+
* Unwraps the check-in payload. The gateway returns a flat `{ code, data }`,
|
|
396
374
|
* while the CodeBuddy billing facade nests Tencent's `data.Response.Data`
|
|
397
375
|
* (the same double wrap its quota endpoint uses), so both shapes resolve.
|
|
398
376
|
*/
|
|
@@ -62,9 +62,9 @@ export interface BuddyConversationIds {
|
|
|
62
62
|
* Wire format for the two message-scoped ids (`x-conversation-message-id`,
|
|
63
63
|
* `x-request-id`).
|
|
64
64
|
*
|
|
65
|
-
* The reference emits these as dashed UUIDs on the
|
|
65
|
+
* The reference emits these as dashed UUIDs on the desktop product
|
|
66
66
|
* and as 32-hex on CLI traffic (`build_attempt_headers` converts only the
|
|
67
|
-
* message/request ids, and only for the
|
|
67
|
+
* message/request ids, and only for the desktop profiles). The turn
|
|
68
68
|
* aggregation key (`x-conversation-request-id` / `x-root-request-id`) and the
|
|
69
69
|
* B3/W3C trace ids stay hex in both styles, because B3's spec accepts only
|
|
70
70
|
* hex. Default `"hex"`.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { asNumber as sharedAsNumber, asRecord } from "../../../shared/coerce";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Model discovery for the buddy family (CodeBuddy intl / CN
|
|
4
|
+
* Model discovery for the buddy family (CodeBuddy intl / CN).
|
|
5
5
|
*
|
|
6
|
-
* The
|
|
7
|
-
* difference is load-bearing: the international
|
|
6
|
+
* The two sites are protocol-isomorphic but NOT path-isomorphic, and the
|
|
7
|
+
* difference is load-bearing: the international site answers
|
|
8
8
|
* `/v2/enterprises/personal/models`, while the CN site answers
|
|
9
9
|
* `/console/enterprises/personal/models`. Probing the CN path on an
|
|
10
10
|
* international host returns HTTP 500 from the edge (APISIX) rather than 404 —
|
|
@@ -34,8 +34,8 @@ import { buddyAccountUid } from "./buddy-oauth-shared";
|
|
|
34
34
|
export const BUDDY_CN_MODELS_PATH = "/console/enterprises/personal/models" as const;
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Console directory path on the international
|
|
38
|
-
*
|
|
37
|
+
* Console directory path on the international site (`codebuddy.ai`). The CN
|
|
38
|
+
* path above answers 500 on these hosts.
|
|
39
39
|
*/
|
|
40
40
|
export const BUDDY_INTL_MODELS_PATH = "/v2/enterprises/personal/models" as const;
|
|
41
41
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ProviderDispatchContext } from "../../provider-contracts";
|
|
2
2
|
import { createHash } from "node:crypto";
|
|
3
|
+
import { readFileSync } from "node:fs";
|
|
3
4
|
import { decodeJwtPayload } from "../../authentication/oauth-flow-store";
|
|
4
5
|
import { buddyAccountUid } from "./buddy-oauth-shared";
|
|
5
6
|
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
@@ -166,6 +167,14 @@ export function materializeBuddyDeviceBinding(
|
|
|
166
167
|
* the operator pinned them in `auth_state` (there is no reliable source to
|
|
167
168
|
* invent them from). An opaque API key carries no uid and yields nothing.
|
|
168
169
|
*/
|
|
170
|
+
/** A short printable identity claim from a JWT payload, or `undefined`. */
|
|
171
|
+
function identityClaim(claims: Record<string, unknown> | undefined, name: string): string | undefined {
|
|
172
|
+
if (claims === undefined) return undefined;
|
|
173
|
+
const value = claims[name];
|
|
174
|
+
if (typeof value === "string" && value.trim().length > 0 && value.trim().length <= 128) return value.trim();
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
169
178
|
export function buddyOAuthIdentityHeaders(
|
|
170
179
|
context?: ProviderDispatchContext,
|
|
171
180
|
): Record<string, string> {
|
|
@@ -174,15 +183,20 @@ export function buddyOAuthIdentityHeaders(
|
|
|
174
183
|
const uid = buddyAccountUid(token) ?? context?.credential.account_id ?? "";
|
|
175
184
|
if (uid.length === 0) return {};
|
|
176
185
|
const enterpriseId = buddyEnterprise(context);
|
|
186
|
+
// The reference gateway reads `id_source` / `token_source` from the JWT
|
|
187
|
+
// payload and the account record, not from stored auth state — an account
|
|
188
|
+
// authorized before either was persisted still carries them on the wire.
|
|
189
|
+
// Precedence matches the donor (`client_profiles._identity_claim_headers`):
|
|
190
|
+
// account fields first, then JWT claims, then legacy `auth_state`.
|
|
191
|
+
const claims = token.length > 0 ? decodeJwtPayload(token) : undefined;
|
|
177
192
|
const state = context?.credential.auth_state;
|
|
178
193
|
const idSource =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
194
|
+
identityClaim(claims, "id_source") ??
|
|
195
|
+
identityClaim(claims, "idSource") ??
|
|
196
|
+
identityClaim(state as Record<string, unknown> | undefined, "idSource");
|
|
182
197
|
const method =
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
: undefined;
|
|
198
|
+
identityClaim(claims, "token_source") ??
|
|
199
|
+
identityClaim(state as Record<string, unknown> | undefined, "authMethod");
|
|
186
200
|
const headers: Record<string, string> = { "X-User-Id": uid };
|
|
187
201
|
if (method !== undefined) headers["X-Auth-Method"] = method;
|
|
188
202
|
if (idSource !== undefined) headers["X-Id-Source"] = idSource;
|
|
@@ -228,3 +242,72 @@ export function buddyAgentPurpose(
|
|
|
228
242
|
if (typeof fromRequest === "string" && fromRequest.trim().length > 0) return fromRequest.trim();
|
|
229
243
|
return undefined;
|
|
230
244
|
}
|
|
245
|
+
|
|
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
|
+
const DEVICE_TOKEN_FILE_MAX_BYTES = 1024;
|
|
256
|
+
const DEVICE_TOKEN_FILE_TTL_MS = 5 * 60_000;
|
|
257
|
+
let deviceTokenFileCache: { readonly value: string | undefined; readonly readAt: number } | undefined;
|
|
258
|
+
|
|
259
|
+
export function readBuddyDeviceToken(context?: ProviderDispatchContext): string | undefined {
|
|
260
|
+
const state = context?.credential.auth_state;
|
|
261
|
+
const value = state?.["deviceToken"] ?? state?.["device_token"];
|
|
262
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
263
|
+
return readDeviceTokenFile();
|
|
264
|
+
}
|
|
265
|
+
|
|
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
|
+
export async function buddyDeviceTokenHeaders(args: {
|
|
283
|
+
realm: "intl" | "cn";
|
|
284
|
+
context: ProviderDispatchContext | undefined;
|
|
285
|
+
cliIdentity: boolean | undefined;
|
|
286
|
+
}): Promise<Record<string, string>> {
|
|
287
|
+
const { context, cliIdentity } = args;
|
|
288
|
+
void args.realm; // the desktop client sends the token on both realms
|
|
289
|
+
if (resolveBuddyIdentity(context, cliIdentity) === "cli") return {};
|
|
290
|
+
const token = readBuddyDeviceToken(context);
|
|
291
|
+
if (token !== undefined) return { "x-device-token": token };
|
|
292
|
+
return { "x-device-token-error": "sdk_not_initialized" };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function readDeviceTokenFile(): string | undefined {
|
|
296
|
+
const now = Date.now();
|
|
297
|
+
if (deviceTokenFileCache !== undefined && now - deviceTokenFileCache.readAt < DEVICE_TOKEN_FILE_TTL_MS) {
|
|
298
|
+
return deviceTokenFileCache.value;
|
|
299
|
+
}
|
|
300
|
+
const path = process.env["CARTETHYIA_DEVICE_TOKEN_FILE"] ?? "/app/data/device_token";
|
|
301
|
+
let value: string | undefined;
|
|
302
|
+
try {
|
|
303
|
+
const raw = readFileSync(path);
|
|
304
|
+
if (raw.byteLength > 0 && raw.byteLength <= DEVICE_TOKEN_FILE_MAX_BYTES) {
|
|
305
|
+
const text = raw.toString("utf8").trim();
|
|
306
|
+
if (text.length > 0) value = text;
|
|
307
|
+
}
|
|
308
|
+
} catch {
|
|
309
|
+
value = undefined;
|
|
310
|
+
}
|
|
311
|
+
deviceTokenFileCache = { value, readAt: now };
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Buddy-family media generation: image and video.
|
|
3
3
|
*
|
|
4
|
-
* CodeBuddy (intl
|
|
5
|
-
* request shaping lives here. Their image endpoint can differ by
|
|
4
|
+
* CodeBuddy (intl + CN) serves media through the same facade, so shared
|
|
5
|
+
* request shaping lives here. Their image endpoint can differ by realm;
|
|
6
6
|
* identity headers come from {@link codebuddyHeaders} keyed on the variant.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* path. The configured provider path selects the wire format.
|
|
8
|
+
* The image path is CodeBuddy's native `/images/generations` API. The
|
|
9
|
+
* configured provider path selects the wire format.
|
|
11
10
|
*
|
|
12
11
|
* - **Video** (`seedance-2.5`) is implemented as an async task: submission
|
|
13
12
|
* expects a task ID, then the adapter polls a sibling task URL until a clip
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The buddy-family device-login mechanism (`cb`, `cbcn
|
|
2
|
+
* The buddy-family device-login mechanism (`cb`, `cbcn`).
|
|
3
3
|
*
|
|
4
4
|
* All three complete device login against the same plugin auth endpoints: a
|
|
5
5
|
* state POST, a token poll that answers the pending code `11217` until the user
|
|
@@ -64,7 +64,7 @@ export function strictResponseCode(payload: unknown): number | undefined {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/**
|
|
67
|
-
* Reads the envelope `code` through `Number()`, which is how the
|
|
67
|
+
* Reads the envelope `code` through `Number()`, which is how the buddy
|
|
68
68
|
* gateway is read. Looser than `strictResponseCode` on a malformed payload: a
|
|
69
69
|
* `null` code coerces to `0`, i.e. success, and `true` to `1`. Kept verbatim
|
|
70
70
|
* rather than tightened because nothing here shows what that gateway sends for
|
|
@@ -2,7 +2,7 @@ import { asNumber as sharedAsNumber } from "../../../shared/coerce";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Shared Tencent billing-meter parsing for the CodeBuddy family
|
|
5
|
-
* (`cb`, `cbcn
|
|
5
|
+
* (`cb`, `cbcn`).
|
|
6
6
|
*
|
|
7
7
|
* All three read the same endpoint shape — POST
|
|
8
8
|
* `{base}/v2/billing/meter/get-user-resource` answering
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Real credit deductions for the Tencent "buddy" family (`cb`, `cbcn
|
|
3
|
-
* `workbuddy`, `workbuddycn`).
|
|
4
|
-
*
|
|
2
|
+
* Real credit deductions for the Tencent "buddy" family (`cb`, `cbcn`). *
|
|
5
3
|
* Every provider in the family reads the same usage-detail endpoint —
|
|
6
4
|
* `POST {billingHost}/billing/meter/get-user-request-usage` — which answers the
|
|
7
5
|
* actual per-request deductions the billing meter recorded: when the request
|