cartethyia 2.7.0 → 2.7.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 +107 -106
- package/README.md +25 -2
- package/dist/dashboard/assets/{BannedPage-P76QLGJA.js → BannedPage-D-J75hBM.js} +1 -1
- package/dist/dashboard/assets/BannedPage-D-J75hBM.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-DdBggJS9.js → CliToolDetailPage-CVe6RaBH.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-CVe6RaBH.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-aN1iXhhP.js → CliToolsPage-Dd8ZSamp.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-Dd8ZSamp.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-DE-F1nxZ.js → CombosPage-QoJ6foxo.js} +1 -1
- package/dist/dashboard/assets/CombosPage-QoJ6foxo.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-3CUxMy2X.js → CustomizationPage-CKUFTcW4.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-CKUFTcW4.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DubdQcvX.js +1 -0
- package/dist/dashboard/assets/LoginPage-DubdQcvX.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-DKVslqG3.js → ModelPicker-BH8Tehdi.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BH8Tehdi.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js +4 -0
- package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js +9 -0
- package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-BjldQwIU.js → QuotaPage-ATpaxrbl.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-ATpaxrbl.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-DUIoLRxk.js → SettingsPage-CETophpx.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-CETophpx.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-BdgECjqq.js +1 -0
- package/dist/dashboard/assets/SetupPage-BdgECjqq.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-fI7JkdIB.js → SortableList-CAK-EN9z.js} +1 -1
- package/dist/dashboard/assets/SortableList-CAK-EN9z.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CHVZqskZ.js → StudioPage-B7W2_RhT.js} +3 -3
- package/dist/dashboard/assets/StudioPage-B7W2_RhT.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-6T4EFDjW.js +56 -0
- package/dist/dashboard/assets/UsagePage-6T4EFDjW.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-DFY_fZU4.js → api-keys-CUi6UXsR.js} +1 -1
- package/dist/dashboard/assets/api-keys-CUi6UXsR.js.gz +0 -0
- package/dist/dashboard/assets/app-KvsUJUMF.css +2 -0
- package/dist/dashboard/assets/app-KvsUJUMF.css.gz +0 -0
- package/dist/dashboard/assets/{assert-CwdnZARt.js → assert-67xXH5rf.js} +1 -1
- package/dist/dashboard/assets/assert-67xXH5rf.js.gz +0 -0
- package/dist/dashboard/assets/{badge-Dr-uf0Au.js → badge-DC2L43Mj.js} +1 -1
- package/dist/dashboard/assets/badge-DC2L43Mj.js.gz +0 -0
- package/dist/dashboard/assets/{banner-BddmMdoS.js → banner-BBVcb0J3.js} +1 -1
- package/dist/dashboard/assets/banner-BBVcb0J3.js.gz +0 -0
- package/dist/dashboard/assets/{card-CK0PXWlX.js → card-Cca1XC6G.js} +1 -1
- package/dist/dashboard/assets/card-Cca1XC6G.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-CcB6mGh2.js → cli-tools-KvsWa1Jl.js} +1 -1
- package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DGb2P9Yx.js → clipboard-button-DUzEbynq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DUzEbynq.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-LkfuL50u.js → dialog-DFvWhwTa.js} +1 -1
- package/dist/dashboard/assets/dialog-DFvWhwTa.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-ZbEZ_84c.js → drawer-CFM2sMX1.js} +1 -1
- package/dist/dashboard/assets/drawer-CFM2sMX1.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CWBY5A0f.js → entry-BLBLxX0h.js} +3 -3
- package/dist/dashboard/assets/entry-BLBLxX0h.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BJfsVMvA.js → entry-Bqy8RFvM.js} +1 -1
- package/dist/dashboard/assets/entry-Bqy8RFvM.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CvC1-Zqx.js → entry-_xHo5x6r.js} +1 -1
- package/dist/dashboard/assets/entry-_xHo5x6r.js.gz +0 -0
- package/dist/dashboard/assets/formatters-mpBPqAQ8.js +1 -0
- package/dist/dashboard/assets/formatters-mpBPqAQ8.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-BxpznFLt.js → github-badge-C9e8Ts7e.js} +1 -1
- package/dist/dashboard/assets/github-badge-C9e8Ts7e.js.gz +0 -0
- package/dist/dashboard/assets/{index-CDzP3ovJ.js → index-D6QzEC_n.js} +2 -2
- package/dist/dashboard/assets/index-D6QzEC_n.js.gz +0 -0
- package/dist/dashboard/assets/{inline-Ae13MQ5w.js → inline-BFUcvllj.js} +1 -1
- package/dist/dashboard/assets/inline-BFUcvllj.js.gz +0 -0
- package/dist/dashboard/assets/{input-D23fo7cp.js → input-C_ILAvBb.js} +1 -1
- package/dist/dashboard/assets/input-C_ILAvBb.js.gz +0 -0
- package/dist/dashboard/assets/{layout-CSsxjj5P.js → layout-CBIyT6Rt.js} +1 -1
- package/dist/dashboard/assets/layout-CBIyT6Rt.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-dmbwZMDY.js → list-row-ebJ_-Nsb.js} +1 -1
- package/dist/dashboard/assets/list-row-ebJ_-Nsb.js.gz +0 -0
- package/dist/dashboard/assets/{live-BG1oUsZZ.js → live-D0mm--ME.js} +1 -1
- package/dist/dashboard/assets/live-D0mm--ME.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-DSF-e4ho.js → mutation-sMD965oO.js} +1 -1
- package/dist/dashboard/assets/mutation-sMD965oO.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-Bm_aECY7.js → numbers-BO9dKaFr.js} +1 -1
- package/dist/dashboard/assets/numbers-BO9dKaFr.js.gz +0 -0
- package/dist/dashboard/assets/providers/inception.svg +5 -0
- package/dist/dashboard/assets/providers/inception.svg.gz +0 -0
- package/dist/dashboard/assets/{query-keys-CF56nYIV.js → query-keys-CfL_Zdoh.js} +1 -1
- package/dist/dashboard/assets/query-keys-CfL_Zdoh.js.gz +0 -0
- package/dist/dashboard/assets/{routing-CeA71n7G.js → routing-BnIpi1IJ.js} +1 -1
- package/dist/dashboard/assets/routing-BnIpi1IJ.js.gz +0 -0
- package/dist/dashboard/assets/{select-KIT0rC6G.js → select-Cj5Nw43g.js} +1 -1
- package/dist/dashboard/assets/select-Cj5Nw43g.js.gz +0 -0
- package/dist/dashboard/assets/{settings-B_2gkePf.js → settings-BAFhDgX8.js} +1 -1
- package/dist/dashboard/assets/settings-BAFhDgX8.js.gz +0 -0
- package/dist/dashboard/assets/{stack-D7WOSzcX.js → stack-EMrOMt4I.js} +1 -1
- package/dist/dashboard/assets/stack-EMrOMt4I.js.gz +0 -0
- package/dist/dashboard/assets/{state-BBxtKZOQ.js → state-CWoo7ty5.js} +1 -1
- package/dist/dashboard/assets/state-CWoo7ty5.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DNS_D5Ea.js → switch-CCjT6IkF.js} +1 -1
- package/dist/dashboard/assets/switch-CCjT6IkF.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BgoxdoMk.js → useMutation-DjkLHUcE.js} +1 -1
- package/dist/dashboard/assets/useMutation-DjkLHUcE.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -53
- package/migrations/full-postgres/0024_add_pool_provider_cooldowns.sql +12 -0
- package/migrations/full-postgres/0025_add_pool_random_strategy.sql +3 -0
- package/migrations/lite-sqlite3/0024_add_pool_provider_cooldowns.sql +12 -0
- package/migrations/lite-sqlite3/0025_add_pool_random_strategy.sql +20 -0
- package/package.json +96 -96
- package/scripts/cli/console-menu.ts +5 -2
- package/scripts/cli/tray.ts +21 -6
- package/src/boot/app.ts +684 -714
- package/src/boot/dependencies.ts +65 -62
- package/src/config/cooldowns.ts +16 -0
- package/src/config/providers.ts +13 -1
- package/src/config/resources.ts +70 -70
- package/src/config/security.ts +37 -37
- package/src/config/spec.ts +371 -358
- package/src/console/console-router.ts +233 -225
- package/src/console/domain-registration.ts +398 -381
- package/src/console/providers/catalog/catalog-projections.ts +2 -6
- package/src/console/providers/catalog/contracts.ts +19 -0
- package/src/console/providers/catalog/provider-operations.ts +38 -0
- package/src/console/providers/catalog/routes.ts +14 -0
- package/src/console/providers/catalog/store-helpers.ts +326 -0
- package/src/console/providers/catalog/store.ts +1292 -1563
- package/src/console/quota/account-quota-global.ts +2 -2
- package/src/console/quota/account-quota-shared.ts +1 -1
- package/src/console/quota/account-quota-tenant.ts +35 -12
- package/src/console/quota/quota-view.ts +2 -2
- package/src/console/routing/pools/contracts.ts +41 -1
- package/src/console/routing/pools/operations.ts +183 -4
- package/src/console/routing/pools/relay-deploy.ts +17 -4
- package/src/console/routing/pools/routes.ts +30 -0
- package/src/console/routing/pools/store.ts +98 -8
- package/src/main.ts +183 -167
- package/src/network/outbound-fetch.ts +226 -365
- package/src/network/pool/agent.ts +8 -0
- package/src/network/pool/pool-state.ts +7 -0
- package/src/network/pool/selector.ts +110 -2
- package/src/network/pool-cooldown-store.ts +252 -0
- package/src/network/pool-health-machine.ts +5 -3
- package/src/network/pool-health.ts +36 -9
- package/src/observability/event-query.ts +57 -0
- package/src/observability/metrics.ts +467 -467
- package/src/observability/runtime-metrics.ts +269 -269
- package/src/persistence/health-event-flush.ts +2 -0
- package/src/persistence/schema.ts +19 -0
- package/src/persistence/usage-flush.ts +8 -3
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/dsml.ts +377 -0
- package/src/protocol/gateway-error.ts +232 -232
- package/src/{providers/provider-reasoning.ts → protocol/reasoning.ts} +10 -9
- package/src/protocol/request/chat.ts +7 -7
- package/src/protocol/request/codex.ts +2 -2
- package/src/protocol/request/gemini.ts +1 -1
- package/src/protocol/request/messages.ts +6 -6
- package/src/protocol/request/responses.ts +7 -7
- package/src/protocol/response/dsml.ts +12 -133
- package/src/{transport → protocol}/translation/attachment-integrity.ts +2 -2
- package/src/{transport → protocol}/translation/cache-controls.ts +1 -1
- package/src/{transport → protocol}/translation/capabilities.ts +2 -2
- package/src/{transport → protocol}/translation/normalize.ts +1 -1
- package/src/{transport → protocol}/translation/quirks.ts +1 -1
- package/src/{transport → protocol}/translation/search.ts +1 -1
- package/src/{transport → protocol}/translation/thinking.ts +23 -1
- package/src/{transport → protocol}/translation/tool-id.ts +1 -1
- package/src/{transport → protocol}/translation/tool-repair.ts +2 -2
- package/src/protocol/upstream-parsing.ts +176 -0
- package/src/providers/adapters/compatible-adapter.ts +11 -2
- package/src/providers/authentication/oauth-refresh-service.ts +9 -5
- package/src/providers/default-registry.ts +21 -5
- package/src/providers/discovery/probe-phases.ts +16 -3
- package/src/providers/discovery/probing-service.ts +4 -1
- package/src/providers/integrations/anthropic.ts +1 -1
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -4
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +141 -8
- package/src/providers/integrations/buddy/buddy-checkin.ts +5 -1
- package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -82
- package/src/providers/integrations/buddy/buddy-identity.ts +25 -0
- package/src/providers/integrations/buddy/buddy-server-tools.ts +240 -0
- package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +36 -0
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +6 -31
- package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -0
- package/src/providers/integrations/buddy/codebuddy/shared.ts +19 -4
- package/src/providers/integrations/buddy/turing-device-token.ts +262 -0
- package/src/providers/integrations/buddy/workbuddy/provider.ts +2 -0
- package/src/providers/integrations/buddy/workbuddy/shared.ts +56 -3
- package/src/providers/integrations/claude/claude.ts +1 -1
- package/src/providers/integrations/cloudflareai/cloudflareai.ts +1 -1
- package/src/providers/integrations/codex/codex-errors.ts +1 -1
- package/src/providers/integrations/codex/codex.ts +1 -1
- package/src/providers/integrations/factory/factory.ts +1 -1
- package/src/providers/integrations/github/github.ts +1 -1
- package/src/providers/integrations/grok/grok.ts +1 -1
- package/src/providers/integrations/inception/provider.ts +91 -0
- package/src/providers/integrations/inferhub.ts +1 -1
- package/src/providers/integrations/kiro/kiro-request.ts +1 -1
- package/src/providers/integrations/mistral.ts +193 -19
- package/src/providers/integrations/opencode/fingerprint.ts +19 -2
- package/src/providers/integrations/opencode/prompt.ts +111 -0
- package/src/providers/integrations/opencode/provider.ts +101 -23
- package/src/providers/integrations/opencode/tool-definitions.ts +4 -4
- package/src/providers/integrations/qoder/qoder-checkin.ts +303 -0
- package/src/providers/integrations/qoder/qoder.ts +1641 -1458
- package/src/providers/integrations/shared/install-id.ts +2 -1
- package/src/providers/integrations/trae/trae-cache.ts +110 -0
- package/src/providers/integrations/trae/trae-oauth.ts +29 -4
- package/src/providers/integrations/trae/trae-protocol.ts +2 -1
- package/src/providers/integrations/trae/trae.ts +106 -23
- package/src/providers/operations/account-error-classification.ts +1660 -0
- package/src/providers/operations/account-health-service.ts +621 -2097
- package/src/providers/operations/account-reset-service.ts +2 -0
- package/src/providers/provider-contracts.ts +0 -2
- package/src/providers/provider-metadata.ts +25 -4
- package/src/providers/provider-probe.ts +2 -2
- package/src/{console → providers}/quota/cache.ts +1 -1
- package/src/{console → providers}/quota/refresh.ts +5 -5
- package/src/transport/dispatch/attempt-finalize.ts +114 -12
- package/src/transport/dispatch/attempt-loop.ts +3 -0
- package/src/transport/dispatch/empty-stream.ts +224 -217
- package/src/transport/dispatch/generation.ts +37 -55
- package/src/transport/dispatch/handler-deps.ts +32 -0
- package/src/transport/dispatch/leases.ts +9 -4
- package/src/transport/dispatch/proxy-request.ts +6 -30
- package/src/transport/dispatch/responses-compact.ts +22 -43
- package/src/transport/dispatch/streaming/finalize.ts +3 -0
- package/src/transport/dispatch/streaming/stream.ts +0 -8
- package/src/transport/dispatch/systemone.ts +22 -42
- package/src/transport/dispatch/token-count.ts +23 -39
- package/src/transport/dispatch/upstream.ts +1 -3
- package/src/transport/dispatch/websearch.ts +22 -41
- package/src/transport/failure-policy.ts +59 -178
- package/src/transport/guards/abuse-guard.ts +10 -0
- package/src/transport/guards/auth-guard.ts +109 -109
- package/src/transport/guards/error-lifecycle.ts +1 -1
- package/src/transport/guards/pipeline.ts +220 -220
- package/src/transport/guards/request-context.ts +245 -238
- package/src/transport/request/degradation.ts +20 -1
- package/src/transport/request/inflight.ts +4 -114
- package/src/transport/request/preparer.ts +6 -6
- package/src/transport/request/state.ts +66 -38
- package/src/transport/request/tenant-preferences.ts +1 -1
- package/src/transport/routing/route-catalog.ts +41 -31
- package/src/transport/routing/router.ts +2 -2
- package/src/transport/surface/messages/parse.ts +1 -1
- package/src/workers/buddy-growth-tasks.ts +346 -425
- package/src/workers/daily-checkin.ts +17 -6
- package/src/workers/quota-refresh-sweep.ts +2 -2
- package/src/workers/scheduler.ts +17 -1
- package/dist/dashboard/assets/BannedPage-P76QLGJA.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DdBggJS9.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-aN1iXhhP.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DE-F1nxZ.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-5SpmfLyw.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-5SpmfLyw.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-3CUxMy2X.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BkmJQKC0.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-BkmJQKC0.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-B_0FUKWc.js +0 -1
- package/dist/dashboard/assets/LoginPage-B_0FUKWc.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-DKVslqG3.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D-H4MEiT.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D-H4MEiT.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CEJw6Guo.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-CEJw6Guo.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CEplAR-i.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-CEplAR-i.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CAN7hy0f.js +0 -7
- package/dist/dashboard/assets/ProxyPage-CAN7hy0f.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BjldQwIU.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DUIoLRxk.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-_bCaTM0v.js +0 -1
- package/dist/dashboard/assets/SetupPage-_bCaTM0v.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-fI7JkdIB.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-CHVZqskZ.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DiFBymHj.js +0 -56
- package/dist/dashboard/assets/UsagePage-DiFBymHj.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-DFY_fZU4.js.gz +0 -0
- package/dist/dashboard/assets/app-BOJ1_xUB.css +0 -2
- package/dist/dashboard/assets/app-BOJ1_xUB.css.gz +0 -0
- package/dist/dashboard/assets/assert-CwdnZARt.js.gz +0 -0
- package/dist/dashboard/assets/badge-Dr-uf0Au.js.gz +0 -0
- package/dist/dashboard/assets/banner-BddmMdoS.js.gz +0 -0
- package/dist/dashboard/assets/card-CK0PXWlX.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CcB6mGh2.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DGb2P9Yx.js.gz +0 -0
- package/dist/dashboard/assets/cog-CdWhsajs.js +0 -1
- package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
- package/dist/dashboard/assets/dialog-LkfuL50u.js.gz +0 -0
- package/dist/dashboard/assets/drawer-ZbEZ_84c.js.gz +0 -0
- package/dist/dashboard/assets/entry-BJfsVMvA.js.gz +0 -0
- package/dist/dashboard/assets/entry-CWBY5A0f.js.gz +0 -0
- package/dist/dashboard/assets/entry-CvC1-Zqx.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-BxpznFLt.js.gz +0 -0
- package/dist/dashboard/assets/index-CDzP3ovJ.js.gz +0 -0
- package/dist/dashboard/assets/inline-Ae13MQ5w.js.gz +0 -0
- package/dist/dashboard/assets/input-D23fo7cp.js.gz +0 -0
- package/dist/dashboard/assets/layout-CSsxjj5P.js.gz +0 -0
- package/dist/dashboard/assets/list-row-dmbwZMDY.js.gz +0 -0
- package/dist/dashboard/assets/live-BG1oUsZZ.js.gz +0 -0
- package/dist/dashboard/assets/mutation-DSF-e4ho.js.gz +0 -0
- package/dist/dashboard/assets/numbers-Bm_aECY7.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-CF56nYIV.js.gz +0 -0
- package/dist/dashboard/assets/routing-CeA71n7G.js.gz +0 -0
- package/dist/dashboard/assets/select-KIT0rC6G.js.gz +0 -0
- package/dist/dashboard/assets/settings-B_2gkePf.js.gz +0 -0
- package/dist/dashboard/assets/stack-D7WOSzcX.js.gz +0 -0
- package/dist/dashboard/assets/state-BBxtKZOQ.js.gz +0 -0
- package/dist/dashboard/assets/switch-DNS_D5Ea.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BgoxdoMk.js.gz +0 -0
- /package/dist/dashboard/assets/{app-CaXZ9SCn.js → app-BaWd0puM.js} +0 -0
- /package/dist/dashboard/assets/{app-CaXZ9SCn.js.gz → app-BaWd0puM.js.gz} +0 -0
|
@@ -25,6 +25,7 @@ import { mkdir, open, readFile } from "node:fs/promises";
|
|
|
25
25
|
import { dirname, join } from "node:path";
|
|
26
26
|
import { randomUUID } from "node:crypto";
|
|
27
27
|
import { log } from "../../../observability/logger";
|
|
28
|
+
import { resolveInstallIdDir } from "../../../config/providers";
|
|
28
29
|
|
|
29
30
|
/** Overrides the directory the install ids are persisted in. */
|
|
30
31
|
const INSTALL_ID_DIR_ENV = "CARTETHYIA_INSTALL_ID_DIR";
|
|
@@ -40,7 +41,7 @@ const INSTALL_ID_DIR_ENV = "CARTETHYIA_INSTALL_ID_DIR";
|
|
|
40
41
|
*/
|
|
41
42
|
function installIdDirectories(): readonly string[] {
|
|
42
43
|
const candidates: string[] = [];
|
|
43
|
-
const configured =
|
|
44
|
+
const configured = resolveInstallIdDir()?.trim();
|
|
44
45
|
if (configured && configured.length > 0) candidates.push(configured);
|
|
45
46
|
const home = (process.env["HOME"] ?? process.env["USERPROFILE"])?.trim();
|
|
46
47
|
if (home && home.length > 0) candidates.push(join(home, ".cartethyia"));
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Trae session-cache estimation.
|
|
2
|
+
//
|
|
3
|
+
// Trae's agent surface does not report prompt-cache hits: the upstream metadata
|
|
4
|
+
// carries `prompt_cache_pool_record: null` and every cache counter
|
|
5
|
+
// (`cache_read_input_tokens`, `cached_tokens`) stays 0 even for byte-identical
|
|
6
|
+
// prefixes. The underlying models do cache those prefixes, so for the same
|
|
7
|
+
// conversation we ESTIMATE the hit locally. This only fills the gap when
|
|
8
|
+
// upstream reports nothing (0 or unavailable); a genuine upstream report (>0)
|
|
9
|
+
// is trusted and left untouched.
|
|
10
|
+
|
|
11
|
+
import { createHash } from "node:crypto";
|
|
12
|
+
import type { CanonicalMessage, UsageRecord } from "../../../protocol/canonical-model";
|
|
13
|
+
|
|
14
|
+
/** Bounded in-memory tracker: one entry per session, oldest evicted first. */
|
|
15
|
+
const MAX_SESSIONS = 512;
|
|
16
|
+
|
|
17
|
+
interface TraeSessionCacheEntry {
|
|
18
|
+
/** hash(full messages) -> reported input tokens for that exact list. */
|
|
19
|
+
readonly seen: Map<string, number>;
|
|
20
|
+
/** Insertion order for bounded eviction. */
|
|
21
|
+
readonly order: string[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sessions = new Map<string, TraeSessionCacheEntry>();
|
|
25
|
+
|
|
26
|
+
function hashOf(messages: readonly CanonicalMessage[]): string {
|
|
27
|
+
return createHash("sha256").update(JSON.stringify(messages)).digest("hex");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function sessionFor(sessionId: string): TraeSessionCacheEntry {
|
|
31
|
+
let entry = sessions.get(sessionId);
|
|
32
|
+
if (!entry) {
|
|
33
|
+
entry = { seen: new Map(), order: [] };
|
|
34
|
+
sessions.set(sessionId, entry);
|
|
35
|
+
}
|
|
36
|
+
return entry;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function remember(sessionId: string, fullHash: string, inputTokens: number): void {
|
|
40
|
+
const entry = sessionFor(sessionId);
|
|
41
|
+
if (!entry.seen.has(fullHash)) {
|
|
42
|
+
entry.order.push(fullHash);
|
|
43
|
+
if (entry.order.length > MAX_SESSIONS) {
|
|
44
|
+
const oldest = entry.order.shift();
|
|
45
|
+
if (oldest !== undefined) entry.seen.delete(oldest);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
entry.seen.set(fullHash, inputTokens);
|
|
49
|
+
if (sessions.size > MAX_SESSIONS) {
|
|
50
|
+
const oldestSession = sessions.keys().next().value;
|
|
51
|
+
if (oldestSession !== undefined) sessions.delete(oldestSession);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Estimates how much of this request's input was served from cache.
|
|
57
|
+
*
|
|
58
|
+
* The longest prefix of `messages` that was ever sent as a complete request in
|
|
59
|
+
* this session is considered cached, and its recorded token count is the
|
|
60
|
+
* cached portion — if that prefix is the whole request, everything was cached.
|
|
61
|
+
* This models how upstream prompt caching actually behaves (byte-identical
|
|
62
|
+
* prefix reuse) without trusting a counter the upstream never reports.
|
|
63
|
+
*
|
|
64
|
+
* Returns the record unchanged when there is nothing to estimate (no session,
|
|
65
|
+
* no history, or upstream already reported a real hit).
|
|
66
|
+
*/
|
|
67
|
+
export function estimateTraeSessionCache(
|
|
68
|
+
record: UsageRecord,
|
|
69
|
+
sessionId: string | undefined,
|
|
70
|
+
messages: readonly CanonicalMessage[] | undefined,
|
|
71
|
+
): UsageRecord {
|
|
72
|
+
if (!sessionId || !messages || messages.length === 0) return record;
|
|
73
|
+
const upstreamReported =
|
|
74
|
+
typeof record.cached_input_tokens === "number" && record.cached_input_tokens > 0;
|
|
75
|
+
if (upstreamReported) return record;
|
|
76
|
+
|
|
77
|
+
const fullHash = hashOf(messages);
|
|
78
|
+
const entry = sessions.get(sessionId);
|
|
79
|
+
|
|
80
|
+
if (entry) {
|
|
81
|
+
// Longest prefix that matches a previously sent complete request.
|
|
82
|
+
for (let len = messages.length; len >= 1; len -= 1) {
|
|
83
|
+
const prefix = messages.slice(0, len);
|
|
84
|
+
const tokens = entry.seen.get(hashOf(prefix));
|
|
85
|
+
if (tokens === undefined) continue;
|
|
86
|
+
if (len === messages.length) {
|
|
87
|
+
// Byte-identical request: the whole input came from cache.
|
|
88
|
+
return {
|
|
89
|
+
...record,
|
|
90
|
+
cached_input_tokens: record.input_tokens,
|
|
91
|
+
uncached_input_tokens: 0,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const cached = Math.min(tokens, record.input_tokens);
|
|
95
|
+
return {
|
|
96
|
+
...record,
|
|
97
|
+
cached_input_tokens: cached,
|
|
98
|
+
uncached_input_tokens: Math.max(0, record.input_tokens - cached),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
remember(sessionId, fullHash, record.input_tokens);
|
|
104
|
+
return record;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Drops all tracked sessions. Test-only. */
|
|
108
|
+
export function resetTraeSessionCacheForTesting(): void {
|
|
109
|
+
sessions.clear();
|
|
110
|
+
}
|
|
@@ -505,9 +505,15 @@ export class TraeOAuthClient extends OAuthClient {
|
|
|
505
505
|
override async refresh(
|
|
506
506
|
refreshToken: string,
|
|
507
507
|
signal?: AbortSignal,
|
|
508
|
-
context?: { readonly account_id?: string },
|
|
508
|
+
context?: { readonly account_id?: string; readonly auth_state?: Readonly<Record<string, unknown>> },
|
|
509
509
|
): Promise<OAuthTokenRefreshResult> {
|
|
510
|
-
|
|
510
|
+
// The exchange is addressed per Trae account, not per gateway account row:
|
|
511
|
+
// `UserID` must be the upstream user id. The login flow stores it in
|
|
512
|
+
// `auth_state.userId`, and re-imports carry it the same way — preferring it
|
|
513
|
+
// over `account_id` keeps refresh working for accounts whose row id is not
|
|
514
|
+
// the upstream user id (any account created before the id was persisted).
|
|
515
|
+
const upstreamUserId = firstString(context?.auth_state ?? {}, ["userId", "user_id", "uid"]);
|
|
516
|
+
return this.refreshWithUser(refreshToken, upstreamUserId ?? context?.account_id ?? "", signal);
|
|
511
517
|
}
|
|
512
518
|
|
|
513
519
|
async #exchange(
|
|
@@ -577,12 +583,15 @@ function parsedResult(
|
|
|
577
583
|
refresh: string,
|
|
578
584
|
isStatic: boolean,
|
|
579
585
|
): OAuthExchangeResult {
|
|
586
|
+
const state: Record<string, unknown> = {};
|
|
587
|
+
if (isStatic) state["staticToken"] = true;
|
|
588
|
+
if (parsed.userId !== undefined) state["userId"] = parsed.userId;
|
|
580
589
|
return {
|
|
581
590
|
access,
|
|
582
591
|
refresh,
|
|
583
592
|
expiresAt:
|
|
584
593
|
parsed.expiresAtMs === undefined ? new Date(Date.now() + 3600_000) : new Date(parsed.expiresAtMs),
|
|
585
|
-
...(
|
|
594
|
+
...(Object.keys(state).length === 0 ? {} : { auth_state: state }),
|
|
586
595
|
...(parsed.email === undefined ? {} : { accountLabel: parsed.email }),
|
|
587
596
|
};
|
|
588
597
|
}
|
|
@@ -619,7 +628,12 @@ function parseExport(credential: string): TraeExport | undefined {
|
|
|
619
628
|
const refresh = firstString(parsed, ["refreshToken", "refresh_token", "refresh"]);
|
|
620
629
|
const expiresAtMs = firstNumber(parsed, ["expiredAt", "expiresAt", "TokenExpireAt", "tokenExpireAt"]);
|
|
621
630
|
const email = firstString(parsed, ["email", "userEmail", "accountLabel"]);
|
|
622
|
-
|
|
631
|
+
// The exporter nests the user id under `authState`; a hand-built export may
|
|
632
|
+
// carry it at the top level instead.
|
|
633
|
+
const authState = firstRecord(parsed, ["authState", "auth_state"]);
|
|
634
|
+
const userId =
|
|
635
|
+
firstString(authState ?? {}, ["userId", "user_id", "uid", "UserID"]) ??
|
|
636
|
+
firstString(parsed, ["userId", "user_id", "uid", "UserID"]);
|
|
623
637
|
return {
|
|
624
638
|
access,
|
|
625
639
|
...(refresh === undefined ? {} : { refresh }),
|
|
@@ -629,6 +643,17 @@ function parseExport(credential: string): TraeExport | undefined {
|
|
|
629
643
|
};
|
|
630
644
|
}
|
|
631
645
|
|
|
646
|
+
/** First object value present under any of `keys`, or undefined. */
|
|
647
|
+
function firstRecord(record: Record<string, unknown>, keys: readonly string[]): Record<string, unknown> | undefined {
|
|
648
|
+
for (const key of keys) {
|
|
649
|
+
const value = record[key];
|
|
650
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
|
651
|
+
return value as Record<string, unknown>;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return undefined;
|
|
655
|
+
}
|
|
656
|
+
|
|
632
657
|
function firstNumber(record: Record<string, unknown>, keys: readonly string[]): number | undefined {
|
|
633
658
|
for (const key of keys) {
|
|
634
659
|
const value = record[key];
|
|
@@ -160,6 +160,7 @@ export function buildTraeChatBody(
|
|
|
160
160
|
modelId: string,
|
|
161
161
|
request: CanonicalRequest,
|
|
162
162
|
realm: TraeRealm,
|
|
163
|
+
sessionId?: string,
|
|
163
164
|
): TraeChatBody {
|
|
164
165
|
if (modelId.length === 0) throw new Error("trae model name is required");
|
|
165
166
|
|
|
@@ -235,7 +236,7 @@ export function buildTraeChatBody(
|
|
|
235
236
|
stream: request.stream,
|
|
236
237
|
region: config.region,
|
|
237
238
|
ai_region: config.region,
|
|
238
|
-
...(request.session_id ? { session_id: request.session_id } : {}),
|
|
239
|
+
...(request.session_id ?? sessionId ? { session_id: request.session_id ?? sessionId } : {}),
|
|
239
240
|
};
|
|
240
241
|
/**
|
|
241
242
|
* Tool declarations, with `parameters` serialized to a string.
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
// `Authorization: Cloud-IDE-JWT <token>` per the Trae 1.107.1 bundle.
|
|
6
6
|
|
|
7
7
|
import { GatewayError } from "../../../protocol/gateway-error";
|
|
8
|
-
import type { CanonicalEvent, CanonicalRequest, CanonicalStopReason } from "../../../protocol/canonical-model";
|
|
8
|
+
import type { CanonicalEvent, CanonicalMessage, CanonicalRequest, CanonicalStopReason } from "../../../protocol/canonical-model";
|
|
9
|
+
import type { UsageRecord } from "../../../protocol/canonical-model";
|
|
9
10
|
import { usageFromProvider } from "../../provider-usage";
|
|
10
11
|
import {
|
|
11
12
|
readCredentialSecret,
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
} from "../../provider-contracts";
|
|
17
18
|
import { mapUpstreamHttpError } from "../../../transport/failure-policy";
|
|
18
19
|
import { abortGatewayError, createUpstreamDeadlineLifecycle } from "../../operations/upstream-deadline";
|
|
20
|
+
import { resolvePromptCacheKey } from "../../operations/session-resolution";
|
|
21
|
+
import { estimateTraeSessionCache } from "./trae-cache";
|
|
19
22
|
import { TRAE_CN_MODELS, TRAE_INTL_MODELS, traeMaxContextWindow } from "./trae-catalog";
|
|
20
23
|
import { buildTraeHeaders } from "./trae-headers";
|
|
21
24
|
import {
|
|
@@ -86,6 +89,53 @@ function extractToken(secret: string): string | undefined {
|
|
|
86
89
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
87
90
|
}
|
|
88
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Maps a Trae upstream error (a named `error` SSE event, or an error object
|
|
94
|
+
* in a frame body) to the canonical GatewayError.
|
|
95
|
+
*
|
|
96
|
+
* The mapping mirrors the reference bridge's `TRAE_ERROR_MAP`:
|
|
97
|
+
* - `1001` — "we are not able to authenticate you" — is a credential verdict.
|
|
98
|
+
* It must surface as account-scoped `authentication_failed` so the account
|
|
99
|
+
* is parked for re-login and failover tries a sibling — never the proxy
|
|
100
|
+
* pool.
|
|
101
|
+
* - `4008` / "exceeded the quota" — free-tier quota exhausted. That is a
|
|
102
|
+
* `quota_exceeded` 429, not a platform fault.
|
|
103
|
+
* - Everything else is a platform fault (`platform_unavailable`).
|
|
104
|
+
*/
|
|
105
|
+
function throwTraeUpstreamError(codeRaw: unknown, messageRaw: unknown): never {
|
|
106
|
+
const code =
|
|
107
|
+
typeof codeRaw === "number" || typeof codeRaw === "string" ? String(codeRaw) : undefined;
|
|
108
|
+
const message =
|
|
109
|
+
typeof messageRaw === "string" && messageRaw.trim().length > 0
|
|
110
|
+
? messageRaw.trim()
|
|
111
|
+
: code !== undefined
|
|
112
|
+
? `Trae stream error (upstream code ${code})`
|
|
113
|
+
: "Trae stream error";
|
|
114
|
+
|
|
115
|
+
if (code === "1001") {
|
|
116
|
+
throw new GatewayError(
|
|
117
|
+
"authentication_failed",
|
|
118
|
+
401,
|
|
119
|
+
`Trae could not authenticate the account (upstream code 1001): ${message}`,
|
|
120
|
+
{ providerCode: "1001", providerStatus: 1001, credentialEvidence: true },
|
|
121
|
+
"upstream",
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const lower = message.toLowerCase();
|
|
126
|
+
if (code === "4008" || lower.includes("exceeded the quota") || lower.includes("quota")) {
|
|
127
|
+
throw new GatewayError(
|
|
128
|
+
"quota_exceeded",
|
|
129
|
+
429,
|
|
130
|
+
`Trae quota exceeded (upstream code ${code ?? "unknown"}): ${message}`,
|
|
131
|
+
{ providerCode: code ?? "4008", providerStatus: code === "4008" ? 4008 : 429 },
|
|
132
|
+
"upstream",
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
|
|
137
|
+
}
|
|
138
|
+
|
|
89
139
|
class TraeAdapter implements ProviderAdapter {
|
|
90
140
|
readonly provider_id: ProviderId;
|
|
91
141
|
private readonly realm: TraeRealm;
|
|
@@ -115,7 +165,21 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
115
165
|
(context.outbound_fetch as unknown as typeof fetch | undefined) ?? this.fetchFn;
|
|
116
166
|
|
|
117
167
|
const auth = traeAuth(secret, context.credential.account_id);
|
|
118
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Trae keeps upstream prompt-cache state keyed by the request's
|
|
170
|
+
* `session_id`. The canonical request rarely carries one (surfaces do not
|
|
171
|
+
* populate it), so without this the body always omitted `session_id` and
|
|
172
|
+
* upstream treated every turn as a fresh context — `cached_tokens: 0`
|
|
173
|
+
* even for byte-identical prefixes. Resolve the same session/cache key the
|
|
174
|
+
* other adapters use (caller key → inbound session headers → opening-turn
|
|
175
|
+
* hash) and thread it through.
|
|
176
|
+
*/
|
|
177
|
+
const sessionId = request.session_id ?? resolvePromptCacheKey(request, context);
|
|
178
|
+
const body = buildTraeChatBody(modelId, request, this.realm, sessionId);
|
|
179
|
+
// The cache estimator is scoped per (session, model): upstream cache keys
|
|
180
|
+
// are model-specific, so two models sharing a conversation id must not
|
|
181
|
+
// treat each other's identical prefixes as hits.
|
|
182
|
+
const cacheSessionKey = sessionId === undefined ? undefined : `${modelId}:${sessionId}`;
|
|
119
183
|
/**
|
|
120
184
|
* The endpoint follows the model, not the provider.
|
|
121
185
|
*
|
|
@@ -159,6 +223,8 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
159
223
|
response.body as ReadableStream<Uint8Array>,
|
|
160
224
|
lifecycle.signal,
|
|
161
225
|
request.model,
|
|
226
|
+
cacheSessionKey,
|
|
227
|
+
request.messages,
|
|
162
228
|
);
|
|
163
229
|
} catch (err: unknown) {
|
|
164
230
|
const abortError = abortGatewayError(lifecycle, err, context.abort_signal);
|
|
@@ -173,6 +239,8 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
173
239
|
body: ReadableStream<Uint8Array>,
|
|
174
240
|
_signal: AbortSignal,
|
|
175
241
|
requestModel: string,
|
|
242
|
+
sessionId?: string,
|
|
243
|
+
messages?: readonly CanonicalMessage[],
|
|
176
244
|
): AsyncIterable<CanonicalEvent> {
|
|
177
245
|
let seq = 1;
|
|
178
246
|
yield { type: "response_start", sequence_number: seq++, model: requestModel } as CanonicalEvent;
|
|
@@ -202,15 +270,21 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
202
270
|
}
|
|
203
271
|
if (frame.event === "error") {
|
|
204
272
|
const data = frame.data as { message?: unknown; code?: unknown };
|
|
205
|
-
|
|
206
|
-
? data.message
|
|
207
|
-
: typeof data.code === "number" || typeof data.code === "string"
|
|
208
|
-
? `Trae stream error (upstream code ${data.code})`
|
|
209
|
-
: "Trae stream error";
|
|
210
|
-
throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
|
|
273
|
+
throwTraeUpstreamError(data.code, data.message);
|
|
211
274
|
}
|
|
212
275
|
if (typeof frame.data !== "object" || frame.data === null) continue;
|
|
213
276
|
const record = frame.data as Record<string, unknown>;
|
|
277
|
+
// The upstream can answer with an error object in the frame body rather
|
|
278
|
+
// than a named `error` event — e.g. HTTP 200 carrying `{"code":1001,
|
|
279
|
+
// "message":"…"}` (sometimes nested under an `error` key). Detect both
|
|
280
|
+
// spellings so a rejected turn surfaces as the real error instead of an
|
|
281
|
+
// empty stream that ends with a normal `stop`.
|
|
282
|
+
if (record["code"] !== undefined || (typeof record["error"] === "object" && record["error"] !== null)) {
|
|
283
|
+
const nested = record["error"] as Record<string, unknown> | undefined;
|
|
284
|
+
const code = record["code"] ?? nested?.["code"];
|
|
285
|
+
const message = record["message"] ?? nested?.["message"];
|
|
286
|
+
throwTraeUpstreamError(code, message);
|
|
287
|
+
}
|
|
214
288
|
/**
|
|
215
289
|
* Two frame layouts reach here and both are live.
|
|
216
290
|
*
|
|
@@ -278,16 +352,25 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
278
352
|
}
|
|
279
353
|
}
|
|
280
354
|
|
|
281
|
-
|
|
282
|
-
|
|
355
|
+
// Assess the raw usage exactly once per request, then reuse the result for
|
|
356
|
+
// both the `usage` event and the terminal. Assessing twice would let the
|
|
357
|
+
// terminal see the `usage` event's own history entry and misreport a cache
|
|
358
|
+
// hit on the very first request.
|
|
359
|
+
const assessed = usage === undefined ? undefined : this.#assessUsage(usage, sessionId, messages);
|
|
360
|
+
if (assessed !== undefined) {
|
|
361
|
+
yield { type: "usage", sequence_number: seq++, usage: assessed } as unknown as CanonicalEvent;
|
|
283
362
|
}
|
|
284
363
|
// The canonical terminal is `terminal`; a stream that ends without one is
|
|
285
|
-
// read as "the upstream never reported a result".
|
|
364
|
+
// read as "the upstream never reported a result". The assessed usage is
|
|
365
|
+
// carried on the terminal itself (matching the other adapters) so the
|
|
366
|
+
// non-streaming path records the real token counts instead of falling back
|
|
367
|
+
// to the request estimate.
|
|
286
368
|
yield {
|
|
287
369
|
type: "terminal",
|
|
288
370
|
sequence_number: seq,
|
|
289
371
|
state: "complete",
|
|
290
372
|
stop_reason: stopReason,
|
|
373
|
+
...(assessed === undefined ? {} : { usage: assessed }),
|
|
291
374
|
} as unknown as CanonicalEvent;
|
|
292
375
|
}
|
|
293
376
|
|
|
@@ -348,20 +431,20 @@ class TraeAdapter implements ProviderAdapter {
|
|
|
348
431
|
}
|
|
349
432
|
}
|
|
350
433
|
|
|
351
|
-
/**
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
* request that cost nothing.
|
|
359
|
-
*/
|
|
360
|
-
async *#usageEvent(usage: Record<string, unknown>, seq: number): AsyncIterable<CanonicalEvent> {
|
|
434
|
+
/** Normalizes + cache-assesses one raw upstream usage frame, if any. */
|
|
435
|
+
#assessUsage(
|
|
436
|
+
usage: Record<string, unknown> | undefined,
|
|
437
|
+
sessionId?: string,
|
|
438
|
+
messages?: readonly CanonicalMessage[],
|
|
439
|
+
): UsageRecord | undefined {
|
|
440
|
+
if (usage === undefined) return undefined;
|
|
361
441
|
const record = usageFromProvider(usage);
|
|
362
|
-
if (record === undefined) return;
|
|
363
|
-
|
|
442
|
+
if (record === undefined) return undefined;
|
|
443
|
+
// Trae's agent surface never reports prompt-cache hits; for repeated
|
|
444
|
+
// prefixes we estimate them locally (see trae-cache.ts).
|
|
445
|
+
return estimateTraeSessionCache(record, sessionId, messages);
|
|
364
446
|
}
|
|
447
|
+
|
|
365
448
|
}
|
|
366
449
|
|
|
367
450
|
export function createTraeAdapter(options: TraeAdapterOptions = {}): ProviderAdapter {
|