cartethyia 2.7.4 → 2.7.5
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 +2 -0
- package/README.md +17 -5
- package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
- package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
- package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
- package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
- package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
- package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
- package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
- package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
- package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
- package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
- package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
- package/dist/dashboard/assets/banner-BllT4LcF.js.gz +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/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
- package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
- package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
- package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
- package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
- package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
- package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
- package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
- package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
- package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
- package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
- package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
- package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
- package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
- package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
- package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
- package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +56 -55
- package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
- package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
- package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
- package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
- package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
- package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
- package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
- package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
- package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
- package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
- package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
- package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
- package/package.json +4 -6
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +58 -2
- package/src/boot/dependencies.ts +786 -732
- package/src/boot/lifecycle.ts +11 -12
- package/src/config/cooldowns.ts +34 -55
- package/src/config/network.ts +1 -1
- package/src/config/package-paths.ts +1 -1
- package/src/config/providers.ts +13 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +26 -6
- package/src/console/api-keys/ban-constants.ts +38 -0
- package/src/console/api-keys/contracts.ts +71 -62
- package/src/console/api-keys/routes.ts +48 -12
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +1 -1
- package/src/console/auth/audit-recorder.ts +1 -1
- package/src/console/auth/lockout.ts +7 -3
- package/src/console/auth/row-coercion.ts +57 -12
- package/src/console/auth/session-resolver.ts +1 -1
- package/src/console/auth/session-service.ts +8 -2
- package/src/console/auth/session.ts +37 -31
- package/src/console/auth/setup-service.ts +4 -3
- package/src/console/auth/user-store.ts +1 -1
- package/src/console/backup/9router-map.ts +0 -3
- package/src/console/backup/contracts.ts +9 -9
- package/src/console/backup/export-endpoint.ts +5 -6
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +29 -33
- package/src/console/backup/service.ts +468 -468
- package/src/console/backup/store.ts +47 -29
- package/src/console/backup/validate.ts +11 -1
- package/src/console/cli-tools/contracts.ts +7 -7
- package/src/console/cli-tools/injectors/cline.ts +110 -110
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/copilot.ts +108 -108
- package/src/console/cli-tools/injectors/driver.ts +247 -247
- package/src/console/cli-tools/injectors/jcode.ts +115 -115
- package/src/console/cli-tools/injectors/openclaw.ts +161 -161
- package/src/console/cli-tools/injectors/opencode.ts +153 -153
- package/src/console/cli-tools/routes.ts +1 -1
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router.ts +32 -0
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/domain-registration.ts +16 -2
- package/src/console/inferhub/client.ts +0 -7
- package/src/console/inferhub/key-store.ts +1 -1
- package/src/console/inferhub/normalize.ts +2 -2
- package/src/console/inferhub/routes.ts +1 -1
- package/src/console/inferhub/types.ts +1 -1
- package/src/console/observability/contracts.ts +1 -1
- package/src/console/observability/live.ts +31 -18
- package/src/console/observability/logs.ts +1 -1
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +20 -4
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +39 -0
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +95 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +27 -3
- package/src/console/providers/catalog/store.ts +147 -8
- package/src/console/providers/detail/routes.ts +1 -1
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +92 -13
- package/src/console/quota/account-quota-global.ts +41 -3
- package/src/console/quota/account-quota-shared.ts +10 -3
- package/src/console/quota/account-quota-tenant.ts +259 -66
- package/src/console/quota/daily-growth-job.ts +308 -0
- package/src/console/quota/native-identity.ts +2 -2
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/remote-support/routes.ts +1 -1
- package/src/console/remote-support/service.ts +2 -2
- package/src/console/routing/model/contracts.ts +1 -1
- package/src/console/routing/pools/contracts.ts +2 -2
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/relay-deploy.ts +3 -3
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +100 -32
- package/src/console/share/share-stats.ts +4 -4
- package/src/console/share/share-usage.ts +1 -1
- package/src/console/shared/errors.ts +2 -2
- package/src/console/shared/object.ts +18 -0
- package/src/console/shared/read-through-cache.ts +4 -4
- package/src/console/shared/transaction.ts +14 -0
- package/src/console/system-prompt/contracts.ts +89 -12
- package/src/console/system-prompt/routes.ts +98 -45
- package/src/console/updates/apply-update.ts +244 -0
- package/src/console/updates/routes.ts +252 -97
- package/src/main.ts +11 -5
- package/src/network/http2-bidi.ts +1 -1
- package/src/network/ip-utils.ts +298 -0
- package/src/network/outbound-fetch.ts +1 -1
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +16 -12
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-health-machine.ts +1 -1
- package/src/network/rate-limit-verdict.ts +1 -1
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +20 -71
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +59 -291
- package/src/observability/log-sanitize.ts +1 -1
- package/src/observability/metrics.ts +4 -4
- package/src/observability/payload-capture.ts +6 -5
- package/src/observability/payload-store.ts +1 -1
- package/src/observability/runtime-metrics.ts +1 -1
- package/src/observability/telemetry-buffer.ts +12 -3
- package/src/observability/telemetry-reconciliation.ts +3 -3
- package/src/observability/token-speed.ts +1 -1
- package/src/persistence/connection-url.ts +1 -1
- package/src/persistence/db-handle.ts +1 -1
- package/src/persistence/db-pg.ts +2 -2
- package/src/persistence/db-sqlite.ts +3 -3
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +113 -40
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +10 -1
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/system-prompt-store.ts +63 -18
- package/src/persistence/tenant-preferences.ts +1 -1
- package/src/persistence/ttl-cache.ts +3 -3
- package/src/persistence/usage-flush.ts +7 -2
- package/src/protocol/canonical-model.ts +1 -1
- package/src/protocol/codecs.ts +6 -10
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/reasoning-text.ts +1 -1
- package/src/protocol/reasoning.ts +7 -52
- package/src/protocol/registry.ts +50 -15
- package/src/protocol/request/chat.ts +46 -19
- package/src/protocol/request/codex.ts +1 -1
- package/src/protocol/request/messages.ts +46 -14
- package/src/protocol/request/responses.ts +19 -10
- package/src/protocol/response/chat.ts +25 -10
- package/src/protocol/response/codex.ts +1 -1
- package/src/protocol/response/messages.ts +1 -1
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +1 -1
- package/src/protocol/sse-decoder.ts +50 -1
- package/src/protocol/stop-reason.ts +2 -2
- package/src/protocol/think-split.ts +347 -0
- package/src/protocol/translation/attachment-integrity.ts +3 -3
- package/src/protocol/translation/cache-controls.ts +8 -20
- package/src/protocol/translation/capabilities.ts +6 -6
- package/src/protocol/translation/dialect/deepseek.ts +10 -0
- package/src/protocol/translation/dialect/inband.ts +39 -0
- package/src/protocol/translation/dialect/model-thinking.ts +89 -0
- package/src/protocol/translation/dialect/qwen.ts +114 -0
- package/src/protocol/translation/dialect/resolver.ts +83 -0
- package/src/protocol/translation/dialect/rules.ts +93 -0
- package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
- package/src/protocol/translation/dialect/types.ts +58 -0
- package/src/protocol/translation/quirks.ts +18 -4
- package/src/protocol/translation/thinking.ts +12 -252
- package/src/protocol/translation/tool-id.ts +3 -3
- package/src/protocol/translation/tool-repair.ts +1 -1
- package/src/protocol/upstream/post-json.ts +6 -1
- package/src/providers/adapters/compatible-adapter.ts +42 -3
- package/src/providers/authentication/jwt-validator.ts +0 -5
- package/src/providers/authentication/oauth-client.ts +254 -253
- package/src/providers/authentication/oauth-flow-store.ts +42 -7
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/default-registry.ts +23 -35
- package/src/providers/discovery/catalog/catalog-format.ts +13 -2
- package/src/providers/discovery/discovery-types.ts +0 -1
- package/src/providers/discovery/openai-model-discovery.ts +2 -2
- package/src/providers/discovery/probe-phases.ts +48 -13
- package/src/providers/discovery/probing-service.ts +6 -8
- package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
- package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
- package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
- package/src/providers/integrations/antigravity/antigravity.ts +2 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
- package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
- package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
- package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +1 -1
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/commandcode/commandcode.ts +75 -115
- package/src/providers/integrations/commandcode/quota.ts +131 -51
- package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
- package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
- package/src/providers/integrations/cursor/cursor-request.ts +0 -87
- package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
- package/src/providers/integrations/cursor/cursor.ts +38 -5
- package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
- package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
- package/src/providers/integrations/factory/factory.ts +9 -9
- package/src/providers/integrations/github/github-discovery.ts +55 -10
- package/src/providers/integrations/github/github-oauth.ts +6 -5
- package/src/providers/integrations/github/github.ts +41 -14
- package/src/providers/integrations/grok/grok-oauth.ts +261 -261
- package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
- package/src/providers/integrations/grok/grok-quota.ts +16 -7
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
- package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
- package/src/providers/integrations/grok/grok.ts +86 -36
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
- package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
- package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
- package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
- package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
- package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
- package/src/providers/integrations/kiro/kiro-request.ts +8 -11
- package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
- package/src/providers/integrations/kiro/kiro.ts +81 -68
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
- package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
- package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
- package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
- package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
- package/src/providers/integrations/qoder/qoder.ts +354 -62
- package/src/providers/integrations/shared/connect.ts +0 -54
- package/src/providers/integrations/shared/hash.ts +15 -0
- package/src/providers/integrations/shared/session-cache.ts +136 -0
- package/src/providers/integrations/trae/trae-cache.ts +7 -87
- package/src/providers/integrations/trae/trae-catalog.ts +1 -6
- package/src/providers/integrations/trae/trae-protocol.ts +17 -8
- package/src/providers/integrations/trae/trae-realm.ts +0 -7
- package/src/providers/integrations/trae/trae.ts +53 -10
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
- package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
- package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
- package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
- package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
- package/src/providers/operations/account-error-classification.ts +131 -116
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/cli-platform.ts +31 -5
- package/src/providers/operations/client-version-resolver.ts +4 -6
- package/src/providers/operations/client-versions.ts +10 -7
- package/src/providers/operations/provider-catalog-seeder.ts +2 -0
- package/src/providers/operations/provider-catalog-service.ts +18 -2
- package/src/providers/operations/provider-credential-service.ts +19 -2
- package/src/providers/provider-contracts.ts +18 -7
- package/src/providers/provider-metadata.ts +17 -2
- package/src/providers/provider-model-definition.ts +22 -1
- package/src/providers/provider-probe.ts +4 -2
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +4 -0
- package/src/providers/quota/refresh.ts +27 -4
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +1 -3
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +4 -4
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +16 -4
- package/src/security/client-router-fingerprint.ts +4 -4
- package/src/security/credential-codec.ts +3 -3
- package/src/security/csrf.ts +2 -2
- package/src/security/ip-boundary.ts +16 -189
- package/src/security/model-access-rule.ts +1 -1
- package/src/security/outbound-headers.ts +18 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +1 -1
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +23 -20
- package/src/transport/dispatch/generation.ts +25 -45
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +3 -1
- package/src/transport/dispatch/responses-compact.ts +25 -46
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +2 -2
- package/src/transport/dispatch/streaming/stream.ts +7 -3
- package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
- package/src/transport/dispatch/systemone.ts +20 -48
- package/src/transport/dispatch/token-count.ts +41 -38
- package/src/transport/dispatch/websearch.ts +19 -45
- package/src/transport/drain-endpoint.ts +1 -1
- package/src/transport/failure-policy.ts +6 -0
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/headroom-guard.ts +1 -1
- package/src/transport/guards/pipeline.ts +1 -1
- package/src/transport/guards/request-context.ts +12 -17
- package/src/transport/request/preparer.ts +286 -7
- package/src/transport/request/rtk/compress-request.ts +3 -3
- package/src/transport/request/rtk/rtk-constants.ts +2 -2
- package/src/transport/request/rtk/rtk-filters.ts +8 -8
- package/src/transport/request/state.ts +1 -13
- package/src/transport/request/system-prompt-injection.ts +74 -11
- package/src/transport/request/tenant-preferences.ts +22 -0
- package/src/transport/routing/candidate-index.ts +2 -2
- package/src/transport/routing/round-robin.ts +1 -1
- package/src/transport/routing/route-catalog.ts +17 -18
- package/src/transport/routing/route-model.ts +126 -33
- package/src/transport/routing/router.ts +152 -37
- package/src/transport/shutdown-notice.ts +2 -2
- package/src/transport/surface/adapters.ts +3 -3
- package/src/transport/surface/chat/encode.ts +7 -7
- package/src/transport/surface/chat/parse.ts +7 -7
- package/src/transport/surface/completion.ts +2 -2
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/parse.ts +3 -3
- package/src/transport/surface/responses/adapter.ts +1 -1
- package/src/transport/surface/responses/errors.ts +0 -9
- package/src/transport/vision-handoff-cache.ts +58 -0
- package/src/transport/vision-handoff.ts +376 -0
- package/src/workers/account-identity-sweep.ts +2 -2
- package/src/workers/buddy-growth-tasks.ts +392 -346
- package/src/workers/daily-checkin.ts +102 -49
- package/src/workers/maintenance-lease.ts +2 -35
- package/src/workers/oauth-refresh-sweep.ts +8 -1
- package/src/workers/quota-refresh-sweep.ts +120 -82
- package/src/workers/scheduler.ts +67 -4
- package/src/workers/sweep-runner.ts +24 -5
- package/src/workers/zcode-gift-claim.ts +108 -0
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
- package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
- package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
- package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
- package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
- package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
- package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
- package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
- package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
- package/dist/dashboard/assets/app-a159k0ub.css +0 -2
- package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
- package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
- package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
- package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
- package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
- package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
- package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
- package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
- package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
- package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
- package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
- package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
- package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
- package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
- package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
- package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
- package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
- package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
- package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
- package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
- package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
- package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
- package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
- package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
- package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
- package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
- package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
- package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
- package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
- package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
- package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
- package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
- package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
- package/src/network/response-headers.ts +0 -39
- package/src/protocol/response/dsml.ts +0 -38
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
- /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
- /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* - `isGatewayError()` semantics live in one shared SQL predicate.
|
|
19
19
|
*/
|
|
20
20
|
import { and, desc, eq, gte, inArray, isNotNull, or, sql, type SQL } from "drizzle-orm";
|
|
21
|
+
import { PgDialect } from "drizzle-orm/pg-core";
|
|
21
22
|
import type { CartethyiaDatabase } from "../persistence/db-handle";
|
|
22
23
|
import { apiKeys, telemetryEvents, telemetryUsageTotals } from "../persistence/schema";
|
|
23
24
|
import type { TelemetryEventRecord } from "./event-log";
|
|
@@ -33,6 +34,20 @@ import { gatewayErrorSql } from "./telemetry-status";
|
|
|
33
34
|
*/
|
|
34
35
|
export const IS_GATEWAY_ERROR_SQL = gatewayErrorSql(telemetryEvents.status, telemetryEvents.httpStatus);
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* The aggregate select fragments shared by every tenant-window read. The
|
|
39
|
+
* `errors` count uses the single shared gateway-error predicate (see
|
|
40
|
+
* {@link IS_GATEWAY_ERROR_SQL}) so the row-level rule and the SQL aggregate
|
|
41
|
+
* cannot drift; the sum fragments coalesce to 0 so an empty window reads as
|
|
42
|
+
* zero rather than null.
|
|
43
|
+
*/
|
|
44
|
+
const AGGREGATE_SELECT = {
|
|
45
|
+
errors: sql<number>`sum(case when ${IS_GATEWAY_ERROR_SQL} then 1 else 0 end)`,
|
|
46
|
+
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
47
|
+
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
48
|
+
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
36
51
|
/** One bounded page of events, newest first. */
|
|
37
52
|
export interface EventPage {
|
|
38
53
|
readonly events: TelemetryEventRecord[];
|
|
@@ -40,7 +55,7 @@ export interface EventPage {
|
|
|
40
55
|
readonly nextCursor?: string;
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
|
|
58
|
+
interface EventListQuery {
|
|
44
59
|
readonly tenantId: string;
|
|
45
60
|
/**
|
|
46
61
|
* Lower bound. Omitting it means "the whole retained window" — the SQL table
|
|
@@ -96,7 +111,7 @@ export interface UsageSummary {
|
|
|
96
111
|
readonly unpriced: number;
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
|
|
114
|
+
interface BreakdownGroup {
|
|
100
115
|
readonly key: string;
|
|
101
116
|
readonly requests: number;
|
|
102
117
|
readonly errors: number;
|
|
@@ -116,15 +131,8 @@ export interface ChartBucket {
|
|
|
116
131
|
readonly errors: number;
|
|
117
132
|
readonly inputTokens: number;
|
|
118
133
|
readonly outputTokens: number;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
export interface HealthTotals {
|
|
122
|
-
readonly requests: number;
|
|
123
|
-
readonly errors: number;
|
|
124
|
-
readonly inputTokens: number;
|
|
125
|
-
readonly outputTokens: number;
|
|
134
|
+
/** Cached-input share of the prompt, summed for the bucket. */
|
|
126
135
|
readonly cachedInputTokens: number;
|
|
127
|
-
readonly latencyAvgMs: number | null;
|
|
128
136
|
}
|
|
129
137
|
|
|
130
138
|
const DEFAULT_LIMIT = 50;
|
|
@@ -141,7 +149,7 @@ function numericNullable(value: unknown): number | null {
|
|
|
141
149
|
}
|
|
142
150
|
|
|
143
151
|
/** Maps one `telemetry_events` row to the console's record shape. */
|
|
144
|
-
|
|
152
|
+
function eventRecordFromRow(row: {
|
|
145
153
|
readonly id: string | null;
|
|
146
154
|
readonly createdAt: Date;
|
|
147
155
|
readonly tenantId: string;
|
|
@@ -225,11 +233,28 @@ export function eventRecordFromRow(row: {
|
|
|
225
233
|
* renders the SQL, so it is the only answer that cannot disagree with it.
|
|
226
234
|
*/
|
|
227
235
|
function isPostgres(db: CartethyiaDatabase): boolean {
|
|
228
|
-
const dialect = (db as unknown as { dialect?:
|
|
229
|
-
|
|
236
|
+
const dialect = (db as unknown as { dialect?: unknown }).dialect;
|
|
237
|
+
if (dialect instanceof PgDialect) return true;
|
|
238
|
+
const name = (dialect as { constructor?: { name?: string } } | undefined)?.constructor?.name;
|
|
230
239
|
return name === "PostgresDialect" || name === "PgDialect";
|
|
231
240
|
}
|
|
232
241
|
|
|
242
|
+
/**
|
|
243
|
+
* The epoch-bucket SQL expression for one time column.
|
|
244
|
+
*
|
|
245
|
+
* Inlined (not parameterised) so Postgres sees the SELECT and GROUP BY
|
|
246
|
+
* expressions as identical: parameter numbers differing between the two
|
|
247
|
+
* clauses made Postgres treat them as unrelated expressions referencing
|
|
248
|
+
* `created_at`, which 42803-rejected the query. The width is a raw SQL
|
|
249
|
+
* literal for the same reason.
|
|
250
|
+
*/
|
|
251
|
+
function bucketExpression(db: CartethyiaDatabase, column: typeof telemetryEvents.createdAt, widthSeconds: number): SQL {
|
|
252
|
+
const w = sql.raw(String(Math.max(1, Math.trunc(widthSeconds))));
|
|
253
|
+
return isPostgres(db)
|
|
254
|
+
? sql<number>`(cast(extract(epoch from ${column}) as bigint) / ${w}) * ${w}`
|
|
255
|
+
: sql<number>`(cast(strftime('%s', ${column}) as integer) / ${w}) * ${w}`;
|
|
256
|
+
}
|
|
257
|
+
|
|
233
258
|
/**
|
|
234
259
|
* The tenant predicate — the scope every read shares — plus the window when
|
|
235
260
|
* one is given.
|
|
@@ -400,90 +425,9 @@ export async function queryTelemetryEvents(
|
|
|
400
425
|
};
|
|
401
426
|
}
|
|
402
427
|
|
|
403
|
-
/** One event by request id — a single indexed row, never a window scan. */
|
|
404
|
-
export async function eventByRequestId(
|
|
405
|
-
db: CartethyiaDatabase,
|
|
406
|
-
tenantId: string,
|
|
407
|
-
requestId: string,
|
|
408
|
-
): Promise<TelemetryEventRecord | undefined> {
|
|
409
|
-
const [row] = await db
|
|
410
|
-
.select()
|
|
411
|
-
.from(telemetryEvents)
|
|
412
|
-
.where(and(eq(telemetryEvents.tenantId, tenantId), eq(telemetryEvents.requestId, requestId)))
|
|
413
|
-
.limit(1);
|
|
414
|
-
if (!row) return undefined;
|
|
415
|
-
return eventRecordFromRow(row as Parameters<typeof eventRecordFromRow>[0]);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
428
|
/**
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
* Percentiles are computed by the database. Postgres uses `percentile_cont`;
|
|
422
|
-
* SQLite (no ordered-set aggregates) computes nearest-rank percentiles from
|
|
423
|
-
* the ordered latency column via OFFSET/LIMIT. Either way, latency values are
|
|
424
|
-
* never returned to JavaScript — the array that the old raw reader built to
|
|
425
|
-
* sort in JS was the memory cost this replaces.
|
|
429
|
+
* The SQL column one breakdown dimension groups by.
|
|
426
430
|
*/
|
|
427
|
-
export async function summarizeTelemetry(
|
|
428
|
-
db: CartethyiaDatabase,
|
|
429
|
-
tenantId: string,
|
|
430
|
-
since: Date,
|
|
431
|
-
): Promise<UsageSummary> {
|
|
432
|
-
const condition = scoped(tenantId, since);
|
|
433
|
-
const [row] = await db
|
|
434
|
-
.select({
|
|
435
|
-
requests: sql<number>`count(*)`,
|
|
436
|
-
errors: sql<number>`sum(case when ${IS_GATEWAY_ERROR_SQL} then 1 else 0 end)`,
|
|
437
|
-
cancelled: sql<number>`sum(case when ${telemetryEvents.status} = 'cancelled' then 1 else 0 end)`,
|
|
438
|
-
truncated: sql<number>`sum(case when ${telemetryEvents.status} = 'truncated' then 1 else 0 end)`,
|
|
439
|
-
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
440
|
-
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
441
|
-
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
442
|
-
reasoningTokens: sql<number>`coalesce(sum(${telemetryEvents.reasoningTokens}), 0)`,
|
|
443
|
-
estimatedCostUsd: sql<number>`coalesce(sum(${telemetryEvents.estimatedCostUsd}), 0)`,
|
|
444
|
-
sampled: sql<number>`count(${telemetryEvents.latencyMs})`,
|
|
445
|
-
latencyAvg: sql<number>`avg(${telemetryEvents.latencyMs})`,
|
|
446
|
-
unpriced: sql<number>`sum(case when ${telemetryEvents.estimatedCostUsd} is null then 1 else 0 end)`,
|
|
447
|
-
})
|
|
448
|
-
.from(telemetryEvents)
|
|
449
|
-
.where(condition);
|
|
450
|
-
if (!row) {
|
|
451
|
-
return {
|
|
452
|
-
requests: 0,
|
|
453
|
-
errors: 0,
|
|
454
|
-
cancelled: 0,
|
|
455
|
-
truncated: 0,
|
|
456
|
-
inputTokens: 0,
|
|
457
|
-
outputTokens: 0,
|
|
458
|
-
cachedInputTokens: 0,
|
|
459
|
-
reasoningTokens: 0,
|
|
460
|
-
estimatedCostUsd: 0,
|
|
461
|
-
sampled: 0,
|
|
462
|
-
latencyMs: { avg: null, p50: null, p95: null, p99: null },
|
|
463
|
-
unpriced: 0,
|
|
464
|
-
};
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const sampled = numeric(row.sampled);
|
|
468
|
-
const percentiles = await latencyPercentiles(db, tenantId, since, sampled);
|
|
469
|
-
return {
|
|
470
|
-
requests: numeric(row.requests),
|
|
471
|
-
errors: numeric(row.errors),
|
|
472
|
-
cancelled: numeric(row.cancelled),
|
|
473
|
-
truncated: numeric(row.truncated),
|
|
474
|
-
inputTokens: numeric(row.inputTokens),
|
|
475
|
-
outputTokens: numeric(row.outputTokens),
|
|
476
|
-
cachedInputTokens: numeric(row.cachedInputTokens),
|
|
477
|
-
reasoningTokens: numeric(row.reasoningTokens),
|
|
478
|
-
estimatedCostUsd: numeric(row.estimatedCostUsd),
|
|
479
|
-
sampled,
|
|
480
|
-
latencyMs: {
|
|
481
|
-
avg: numericNullable(row.latencyAvg),
|
|
482
|
-
...percentiles,
|
|
483
|
-
},
|
|
484
|
-
unpriced: numeric(row.unpriced),
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
431
|
|
|
488
432
|
type Percentiles = { p50: number | null; p95: number | null; p99: number | null };
|
|
489
433
|
|
|
@@ -546,9 +490,6 @@ async function latencyPercentiles(
|
|
|
546
490
|
};
|
|
547
491
|
}
|
|
548
492
|
|
|
549
|
-
/**
|
|
550
|
-
* The SQL column one breakdown dimension groups by.
|
|
551
|
-
*/
|
|
552
493
|
function dimensionColumn(dimension: string) {
|
|
553
494
|
if (dimension === "model") return telemetryEvents.requestedModel;
|
|
554
495
|
if (dimension === "provider") return telemetryEvents.providerId;
|
|
@@ -587,9 +528,7 @@ export async function breakdownTelemetry(
|
|
|
587
528
|
.select({
|
|
588
529
|
key: column,
|
|
589
530
|
requests: sql<number>`count(*)`,
|
|
590
|
-
|
|
591
|
-
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
592
|
-
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
531
|
+
...AGGREGATE_SELECT,
|
|
593
532
|
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
594
533
|
costUsd: sql<number>`coalesce(sum(${telemetryEvents.estimatedCostUsd}), 0)`,
|
|
595
534
|
avgTokensPerSec: sql<number>`coalesce(avg(${telemetryEvents.tokensPerSec}), 0)`,
|
|
@@ -626,32 +565,23 @@ export async function chartTelemetry(
|
|
|
626
565
|
since: Date,
|
|
627
566
|
bucketSeconds: number,
|
|
628
567
|
): Promise<ChartBucket[]> {
|
|
629
|
-
const
|
|
630
|
-
// Inlined (not parameterised) so Postgres sees the SELECT and GROUP BY
|
|
631
|
-
// expressions as identical: parameter numbers differing between the two
|
|
632
|
-
// clauses made Postgres treat them as unrelated expressions referencing
|
|
633
|
-
// `created_at`, which 42803-rejected the query.
|
|
634
|
-
const w = sql.raw(String(width));
|
|
635
|
-
const bucketExpression = isPostgres(db)
|
|
636
|
-
? sql<number>`(cast(extract(epoch from ${telemetryEvents.createdAt}) as bigint) / ${w}) * ${w}`
|
|
637
|
-
: sql<number>`(cast(strftime('%s', ${telemetryEvents.createdAt}) as integer) / ${w}) * ${w}`;
|
|
568
|
+
const bucketExpr = bucketExpression(db, telemetryEvents.createdAt, bucketSeconds);
|
|
638
569
|
const rows = await db
|
|
639
570
|
.select({
|
|
640
|
-
at:
|
|
571
|
+
at: bucketExpr,
|
|
641
572
|
requests: sql<number>`count(*)`,
|
|
642
|
-
|
|
643
|
-
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
644
|
-
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
573
|
+
...AGGREGATE_SELECT,
|
|
645
574
|
})
|
|
646
575
|
.from(telemetryEvents)
|
|
647
576
|
.where(scoped(tenantId, since))
|
|
648
|
-
.groupBy(
|
|
577
|
+
.groupBy(bucketExpr);
|
|
649
578
|
return rows.map((row) => ({
|
|
650
579
|
at: numeric(row.at) * 1000,
|
|
651
580
|
requests: numeric(row.requests),
|
|
652
581
|
errors: numeric(row.errors),
|
|
653
582
|
inputTokens: numeric(row.inputTokens),
|
|
654
583
|
outputTokens: numeric(row.outputTokens),
|
|
584
|
+
cachedInputTokens: numeric(row.cachedInputTokens),
|
|
655
585
|
}));
|
|
656
586
|
}
|
|
657
587
|
|
|
@@ -681,20 +611,15 @@ export async function providerUsageMatrix(
|
|
|
681
611
|
providerId: string,
|
|
682
612
|
since: Date,
|
|
683
613
|
): Promise<ProviderUsageDayRow[]> {
|
|
684
|
-
|
|
685
|
-
// identical expression or Postgres 42803-rejects the grouped reference.
|
|
686
|
-
const w = sql.raw(String(86400));
|
|
687
|
-
const dayExpression = isPostgres(db)
|
|
688
|
-
? sql<number>`(cast(extract(epoch from ${telemetryEvents.createdAt}) as bigint) / ${w}) * ${w}`
|
|
689
|
-
: sql<number>`(cast(strftime('%s', ${telemetryEvents.createdAt}) as integer) / ${w}) * ${w}`;
|
|
614
|
+
const dayExpression = bucketExpression(db, telemetryEvents.createdAt, 86400);
|
|
690
615
|
const rows = await db
|
|
691
616
|
.select({
|
|
692
617
|
day: dayExpression,
|
|
693
618
|
model: telemetryEvents.requestedModel,
|
|
694
619
|
requests: sql<number>`count(*)`,
|
|
695
|
-
inputTokens:
|
|
620
|
+
inputTokens: AGGREGATE_SELECT.inputTokens,
|
|
696
621
|
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
697
|
-
outputTokens:
|
|
622
|
+
outputTokens: AGGREGATE_SELECT.outputTokens,
|
|
698
623
|
costUsd: sql<number>`coalesce(sum(${telemetryEvents.estimatedCostUsd}), 0)`,
|
|
699
624
|
})
|
|
700
625
|
.from(telemetryEvents)
|
|
@@ -712,43 +637,6 @@ export async function providerUsageMatrix(
|
|
|
712
637
|
}));
|
|
713
638
|
}
|
|
714
639
|
|
|
715
|
-
/** Overview/health totals for one tenant window. */
|
|
716
|
-
export async function healthTelemetry(
|
|
717
|
-
db: CartethyiaDatabase,
|
|
718
|
-
tenantId: string,
|
|
719
|
-
since: Date,
|
|
720
|
-
): Promise<HealthTotals> {
|
|
721
|
-
const [row] = await db
|
|
722
|
-
.select({
|
|
723
|
-
requests: sql<number>`count(*)`,
|
|
724
|
-
errors: sql<number>`sum(case when ${IS_GATEWAY_ERROR_SQL} then 1 else 0 end)`,
|
|
725
|
-
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
726
|
-
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
727
|
-
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
728
|
-
latencyAvg: sql<number>`avg(${telemetryEvents.latencyMs})`,
|
|
729
|
-
})
|
|
730
|
-
.from(telemetryEvents)
|
|
731
|
-
.where(scoped(tenantId, since));
|
|
732
|
-
if (!row) {
|
|
733
|
-
return {
|
|
734
|
-
requests: 0,
|
|
735
|
-
errors: 0,
|
|
736
|
-
inputTokens: 0,
|
|
737
|
-
outputTokens: 0,
|
|
738
|
-
cachedInputTokens: 0,
|
|
739
|
-
latencyAvgMs: null,
|
|
740
|
-
};
|
|
741
|
-
}
|
|
742
|
-
return {
|
|
743
|
-
requests: numeric(row.requests),
|
|
744
|
-
errors: numeric(row.errors),
|
|
745
|
-
inputTokens: numeric(row.inputTokens),
|
|
746
|
-
outputTokens: numeric(row.outputTokens),
|
|
747
|
-
cachedInputTokens: numeric(row.cachedInputTokens),
|
|
748
|
-
latencyAvgMs: numericNullable(row.latencyAvg),
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
|
|
752
640
|
/**
|
|
753
641
|
* Summed input+output tokens for a set of API keys over one window — the
|
|
754
642
|
* family bucket spend query.
|
|
@@ -783,9 +671,6 @@ export async function sumTelemetryTokens(
|
|
|
783
671
|
return numeric(row?.total ?? 0);
|
|
784
672
|
}
|
|
785
673
|
|
|
786
|
-
/** One hour, in milliseconds — the share page's hourly bucket width. */
|
|
787
|
-
const HOUR_MS = 3_600_000;
|
|
788
|
-
|
|
789
674
|
/**
|
|
790
675
|
* All-time family counts from the durable rollup, not from a scan of the
|
|
791
676
|
* retained telemetry window.
|
|
@@ -798,7 +683,7 @@ const HOUR_MS = 3_600_000;
|
|
|
798
683
|
* event on every tick. The rollup is the same definition as the read-side
|
|
799
684
|
* counts, so the two cannot drift.
|
|
800
685
|
*/
|
|
801
|
-
|
|
686
|
+
interface FamilyKpiTotals {
|
|
802
687
|
readonly requests: number;
|
|
803
688
|
readonly errors: number;
|
|
804
689
|
readonly tokens: number;
|
|
@@ -830,43 +715,6 @@ export async function familyKpiTotals(
|
|
|
830
715
|
};
|
|
831
716
|
}
|
|
832
717
|
|
|
833
|
-
/**
|
|
834
|
-
* All-time family counts: the numbers a share page's KPI card shows.
|
|
835
|
-
*
|
|
836
|
-
* These must be computed in SQL, not derived from the bounded page read — the
|
|
837
|
-
* page caps at {@link MAX_LIMIT}, so a busy family would freeze at 500
|
|
838
|
-
* requests/errors/last-hour regardless of real traffic.
|
|
839
|
-
*/
|
|
840
|
-
export interface FamilyUsageTotals {
|
|
841
|
-
readonly requests: number;
|
|
842
|
-
readonly errors: number;
|
|
843
|
-
readonly lastHourRequests: number;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/** Counts one share family's requests, errors, and last-hour traffic in SQL. */
|
|
847
|
-
export async function familyUsageTotals(
|
|
848
|
-
db: CartethyiaDatabase,
|
|
849
|
-
tenantId: string,
|
|
850
|
-
familyKeyId: string,
|
|
851
|
-
now: Date,
|
|
852
|
-
): Promise<FamilyUsageTotals> {
|
|
853
|
-
const lastHourStart = new Date(now.getTime() - HOUR_MS);
|
|
854
|
-
const conditions = [eq(telemetryEvents.tenantId, tenantId), familyKeyCondition(familyKeyId)];
|
|
855
|
-
const [row] = await db
|
|
856
|
-
.select({
|
|
857
|
-
requests: sql<number>`count(*)`,
|
|
858
|
-
errors: sql<number>`sum(case when ${IS_GATEWAY_ERROR_SQL} then 1 else 0 end)`,
|
|
859
|
-
lastHourRequests: sql<number>`sum(case when ${telemetryEvents.createdAt} >= ${lastHourStart} then 1 else 0 end)`,
|
|
860
|
-
})
|
|
861
|
-
.from(telemetryEvents)
|
|
862
|
-
.where(and(...conditions));
|
|
863
|
-
return {
|
|
864
|
-
requests: numeric(row?.requests ?? 0),
|
|
865
|
-
errors: numeric(row?.errors ?? 0),
|
|
866
|
-
lastHourRequests: numeric(row?.lastHourRequests ?? 0),
|
|
867
|
-
};
|
|
868
|
-
}
|
|
869
|
-
|
|
870
718
|
/** Counts one share family's requests in a bounded window — a range scan, not a full-window aggregate. */
|
|
871
719
|
export async function familyWindowRequests(
|
|
872
720
|
db: CartethyiaDatabase,
|
|
@@ -945,83 +793,36 @@ export async function familyHourlyTelemetry(
|
|
|
945
793
|
since: Date,
|
|
946
794
|
bucketSeconds: number,
|
|
947
795
|
): Promise<ChartBucket[]> {
|
|
948
|
-
const
|
|
949
|
-
// Inlined (not parameterised) so Postgres sees the SELECT and GROUP BY
|
|
950
|
-
// expressions as identical — see chartTelemetry for the failure this avoids.
|
|
951
|
-
const w = sql.raw(String(width));
|
|
952
|
-
const bucketExpression = isPostgres(db)
|
|
953
|
-
? sql<number>`(cast(extract(epoch from ${telemetryEvents.createdAt}) as bigint) / ${w}) * ${w}`
|
|
954
|
-
: sql<number>`(cast(strftime('%s', ${telemetryEvents.createdAt}) as integer) / ${w}) * ${w}`;
|
|
796
|
+
const bucketExpr = bucketExpression(db, telemetryEvents.createdAt, bucketSeconds);
|
|
955
797
|
const conditions = [scoped(tenantId, since), familyKeyCondition(familyKeyId)];
|
|
956
798
|
const rows = await db
|
|
957
799
|
.select({
|
|
958
|
-
at:
|
|
800
|
+
at: bucketExpr,
|
|
959
801
|
requests: sql<number>`count(*)`,
|
|
960
|
-
|
|
961
|
-
inputTokens: sql<number>`coalesce(sum(${telemetryEvents.inputTokens}), 0)`,
|
|
962
|
-
outputTokens: sql<number>`coalesce(sum(${telemetryEvents.outputTokens}), 0)`,
|
|
802
|
+
...AGGREGATE_SELECT,
|
|
963
803
|
})
|
|
964
804
|
.from(telemetryEvents)
|
|
965
805
|
.where(and(...conditions))
|
|
966
|
-
.groupBy(
|
|
806
|
+
.groupBy(bucketExpr);
|
|
967
807
|
return rows.map((row) => ({
|
|
968
808
|
at: numeric(row.at) * 1000,
|
|
969
809
|
requests: numeric(row.requests),
|
|
970
810
|
errors: numeric(row.errors),
|
|
971
811
|
inputTokens: numeric(row.inputTokens),
|
|
972
812
|
outputTokens: numeric(row.outputTokens),
|
|
813
|
+
cachedInputTokens: numeric(row.cachedInputTokens),
|
|
973
814
|
}));
|
|
974
815
|
}
|
|
975
816
|
|
|
976
|
-
/**
|
|
977
|
-
* The health card's latency and throughput figures for one window.
|
|
978
|
-
*
|
|
979
|
-
* Same principle as {@link summarizeTelemetry}: `avg(tokens_per_sec)` and the
|
|
980
|
-
* latency percentiles are computed by the database. The console's health card
|
|
981
|
-
* used to pull every retained event into an array to average `tokensPerSec`
|
|
982
|
-
* and sort latencies in JavaScript.
|
|
983
|
-
*/
|
|
984
|
-
export interface HealthPerformance {
|
|
985
|
-
readonly latencyAvgMs: number | null;
|
|
986
|
-
readonly latencyP50Ms: number | null;
|
|
987
|
-
readonly latencyP95Ms: number | null;
|
|
988
|
-
readonly latencyP99Ms: number | null;
|
|
989
|
-
readonly avgTokensPerSec: number;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
export async function summarizeHealthPerformance(
|
|
993
|
-
db: CartethyiaDatabase,
|
|
994
|
-
tenantId: string,
|
|
995
|
-
since: Date,
|
|
996
|
-
): Promise<HealthPerformance> {
|
|
997
|
-
const [row] = await db
|
|
998
|
-
.select({
|
|
999
|
-
latencyAvg: sql<number>`avg(${telemetryEvents.latencyMs})`,
|
|
1000
|
-
sampled: sql<number>`count(${telemetryEvents.latencyMs})`,
|
|
1001
|
-
avgTokensPerSec: sql<number>`coalesce(avg(${telemetryEvents.tokensPerSec}), 0)`,
|
|
1002
|
-
})
|
|
1003
|
-
.from(telemetryEvents)
|
|
1004
|
-
.where(scoped(tenantId, since));
|
|
1005
|
-
const sampled = numeric(row?.sampled ?? 0);
|
|
1006
|
-
const percentiles = await latencyPercentiles(db, tenantId, since, sampled);
|
|
1007
|
-
return {
|
|
1008
|
-
latencyAvgMs: numericNullable(row?.latencyAvg ?? null),
|
|
1009
|
-
latencyP50Ms: percentiles.p50,
|
|
1010
|
-
latencyP95Ms: percentiles.p95,
|
|
1011
|
-
latencyP99Ms: percentiles.p99,
|
|
1012
|
-
avgTokensPerSec: numeric(row?.avgTokensPerSec ?? 0),
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
817
|
/**
|
|
1017
818
|
* The Usage summary's performance block, computed in SQL.
|
|
1018
819
|
*
|
|
1019
820
|
* Replaces `summarizeUsagePerformance` (which sorted a latency array in
|
|
1020
821
|
* JavaScript): `avg(resolve_ms)` and `avg(tokens_per_sec)` are SQL averages,
|
|
1021
822
|
* and the latency percentiles come from the same database-side percentile
|
|
1022
|
-
* path {@link
|
|
823
|
+
* path {@link summarizeUsageWithPerformance} uses.
|
|
1023
824
|
*/
|
|
1024
|
-
|
|
825
|
+
interface UsagePerformanceTotals {
|
|
1025
826
|
readonly avgResolveMs: number;
|
|
1026
827
|
readonly avgDurationMs: number;
|
|
1027
828
|
/**
|
|
@@ -1038,42 +839,9 @@ export interface UsagePerformanceTotals {
|
|
|
1038
839
|
readonly avgTokensPerSec: number;
|
|
1039
840
|
}
|
|
1040
841
|
|
|
1041
|
-
export async function summarizeUsagePerformanceSql(
|
|
1042
|
-
db: CartethyiaDatabase,
|
|
1043
|
-
tenantId: string,
|
|
1044
|
-
since: Date,
|
|
1045
|
-
): Promise<UsagePerformanceTotals> {
|
|
1046
|
-
const [row] = await db
|
|
1047
|
-
.select({
|
|
1048
|
-
sampled: sql<number>`count(${telemetryEvents.latencyMs})`,
|
|
1049
|
-
latencyAvg: sql<number>`avg(${telemetryEvents.latencyMs})`,
|
|
1050
|
-
resolveSum: sql<number>`coalesce(sum(${telemetryEvents.resolveMs}), 0)`,
|
|
1051
|
-
resolveCount: sql<number>`count(${telemetryEvents.resolveMs})`,
|
|
1052
|
-
avgTokensPerSec: sql<number>`coalesce(avg(${telemetryEvents.tokensPerSec}), 0)`,
|
|
1053
|
-
})
|
|
1054
|
-
.from(telemetryEvents)
|
|
1055
|
-
.where(scoped(tenantId, since));
|
|
1056
|
-
const sampled = numeric(row?.sampled ?? 0);
|
|
1057
|
-
const resolveCount = numeric(row?.resolveCount ?? 0);
|
|
1058
|
-
const percentiles = await latencyPercentiles(db, tenantId, since, sampled);
|
|
1059
|
-
return {
|
|
1060
|
-
avgResolveMs: resolveCount > 0 ? numeric(row?.resolveSum ?? 0) / resolveCount : 0,
|
|
1061
|
-
avgDurationMs: numericNullable(row?.latencyAvg ?? null) ?? 0,
|
|
1062
|
-
latencyP50Ms: percentiles.p50 ?? 0,
|
|
1063
|
-
latencyP95Ms: percentiles.p95 ?? 0,
|
|
1064
|
-
latencyP99Ms: percentiles.p99 ?? 0,
|
|
1065
|
-
latencySampleCount: sampled,
|
|
1066
|
-
resolveSampleCount: resolveCount,
|
|
1067
|
-
avgTokensPerSec: numeric(row?.avgTokensPerSec ?? 0),
|
|
1068
|
-
};
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
842
|
/**
|
|
1072
843
|
* Combined usage totals + performance in ONE window scan.
|
|
1073
844
|
*
|
|
1074
|
-
* `summarizeTelemetry` and `summarizeUsagePerformanceSql` both scan the same
|
|
1075
|
-
* tenant window and each additionally run the percentile path, so the Usage
|
|
1076
|
-
* summary endpoint paid two scans plus two percentile passes for one response.
|
|
1077
845
|
* This runs the combined SELECT once and one percentile pass, returning both
|
|
1078
846
|
* shapes so the caller needs no second query.
|
|
1079
847
|
*/
|
|
@@ -1086,11 +854,11 @@ export async function summarizeUsageWithPerformance(
|
|
|
1086
854
|
const [row] = await db
|
|
1087
855
|
.select({
|
|
1088
856
|
requests: sql<number>`count(*)`,
|
|
1089
|
-
errors:
|
|
857
|
+
errors: AGGREGATE_SELECT.errors,
|
|
1090
858
|
cancelled: sql<number>`sum(case when ${telemetryEvents.status} = 'cancelled' then 1 else 0 end)`,
|
|
1091
859
|
truncated: sql<number>`sum(case when ${telemetryEvents.status} = 'truncated' then 1 else 0 end)`,
|
|
1092
|
-
inputTokens:
|
|
1093
|
-
outputTokens:
|
|
860
|
+
inputTokens: AGGREGATE_SELECT.inputTokens,
|
|
861
|
+
outputTokens: AGGREGATE_SELECT.outputTokens,
|
|
1094
862
|
cachedInputTokens: sql<number>`coalesce(sum(${telemetryEvents.cachedInputTokens}), 0)`,
|
|
1095
863
|
reasoningTokens: sql<number>`coalesce(sum(${telemetryEvents.reasoningTokens}), 0)`,
|
|
1096
864
|
estimatedCostUsd: sql<number>`coalesce(sum(${telemetryEvents.estimatedCostUsd}), 0)`,
|
|
@@ -36,7 +36,7 @@ export const LOG_RING_MAX_CODE_UNITS = 8_192;
|
|
|
36
36
|
|
|
37
37
|
/** Marker appended wherever content was dropped. */
|
|
38
38
|
export const LOG_TRUNCATED_MARKER = "[truncated]";
|
|
39
|
-
|
|
39
|
+
const LOG_CIRCULAR_MARKER = "[circular]";
|
|
40
40
|
|
|
41
41
|
function isHighSurrogate(code: number): boolean {
|
|
42
42
|
return code >= 0xd800 && code <= 0xdbff;
|
|
@@ -5,18 +5,18 @@
|
|
|
5
5
|
* `render()` emits the Prometheus exposition format on demand.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
type MetricLabels = Readonly<Record<string, string | number>>;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
interface CounterMetric {
|
|
11
11
|
inc(value?: number, labels?: MetricLabels): void;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
interface GaugeMetric extends CounterMetric {
|
|
15
15
|
set(value: number, labels?: MetricLabels): void;
|
|
16
16
|
dec(value?: number, labels?: MetricLabels): void;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
interface HistogramMetric {
|
|
20
20
|
observe(value: number, labels?: MetricLabels): void;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -8,7 +8,7 @@ import type {
|
|
|
8
8
|
TelemetryPayloadDepth,
|
|
9
9
|
TelemetryPayloadMode,
|
|
10
10
|
} from "../console/settings/contracts";
|
|
11
|
-
|
|
11
|
+
type CaptureScope = "tenant" | "debug_session" | "operator_flag";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* How long a captured payload frame lives when the deployment has not chosen.
|
|
@@ -203,13 +203,13 @@ export interface PayloadCaptureInput {
|
|
|
203
203
|
operatorFlagOptIn?: boolean;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
|
|
206
|
+
interface PayloadSignals {
|
|
207
207
|
readonly toolCalls: number;
|
|
208
208
|
readonly images: number;
|
|
209
209
|
readonly attachments: number;
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
interface StoredPayload {
|
|
213
213
|
id: string;
|
|
214
214
|
/**
|
|
215
215
|
* JSON text of the five body surfaces, in drawer order, built while the
|
|
@@ -412,8 +412,9 @@ export function buildPayloadRecord(
|
|
|
412
412
|
|
|
413
413
|
/**
|
|
414
414
|
* Postgres-backed redacted request/response payload capture. Payloads live for
|
|
415
|
-
* the tenant's chosen retention —
|
|
416
|
-
*
|
|
415
|
+
* the tenant's chosen retention — an hour by default (see
|
|
416
|
+
* {@link payloadRetentionMs} / `DEFAULT_PAYLOAD_RETENTION_MS`) — and are pruned
|
|
417
|
+
* by the sweep.
|
|
417
418
|
|
|
418
419
|
*/
|
|
419
420
|
export class TelemetryPayloadCapture {
|
|
@@ -22,7 +22,7 @@ interface PayloadFrame {
|
|
|
22
22
|
readonly payload: unknown;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
function isPayloadFileReference(value: unknown): value is PayloadFileReference {
|
|
26
26
|
if (typeof value !== "object" || value === null) return false;
|
|
27
27
|
const record = value as Record<string, unknown>;
|
|
28
28
|
return (
|
|
@@ -32,7 +32,7 @@ export interface RuntimeMemorySnapshot {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/** Live collection sizes sampled alongside process memory. */
|
|
35
|
-
|
|
35
|
+
interface RuntimeMetricSources {
|
|
36
36
|
readonly routingRoundRobinEntries: () => { readonly combo: number; readonly provider: number };
|
|
37
37
|
/**
|
|
38
38
|
* Tracked keys in the in-memory IP abuse store, or 0 when the store is
|
|
@@ -158,7 +158,7 @@ function telemetryEventRow(event: TelemetryEventInput) {
|
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
interface TelemetryBatchBufferOptions {
|
|
162
162
|
readonly flushIntervalMs?: number;
|
|
163
163
|
readonly maxBatch?: number;
|
|
164
164
|
readonly maxItems?: number;
|
|
@@ -184,8 +184,17 @@ function drainRetryDelayMs(attempt: number, baseDelayMs = DRAIN_RETRY_BASE_MS):
|
|
|
184
184
|
return exponentialBackoff(attempt, options);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
/**
|
|
188
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Floor for the adaptive active interval so a full queue still drains promptly.
|
|
189
|
+
*
|
|
190
|
+
* Raised to 200ms (from 50ms) so a flush does not collide with console reads:
|
|
191
|
+
* under load the queue saturates `maxBatch`, the interval fell to 50ms, and a
|
|
192
|
+
* drain landed in the middle of the console's own telemetry reads — the GROUP BY
|
|
193
|
+
* behind the Usage/ConsoleLog pages — making the page's queries wait on the
|
|
194
|
+
* drain's insert lock. 200ms still drains a 500-row batch ~5x/sec, which is a
|
|
195
|
+
* steady 2500 rows/sec ceiling; the adaptive curve otherwise keeps its shape.
|
|
196
|
+
*/
|
|
197
|
+
const ADAPTIVE_FLUSH_MIN_MS = 200;
|
|
189
198
|
/** Multiplier applied to the base interval while the queue is empty. */
|
|
190
199
|
const ADAPTIVE_IDLE_MULTIPLIER = 4;
|
|
191
200
|
|
|
@@ -66,13 +66,13 @@ const MAX_FILES_PER_RUN = 64;
|
|
|
66
66
|
*/
|
|
67
67
|
const HOURS_TO_SKIP = 2;
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
interface ReconcileOptions {
|
|
70
70
|
/** Report only: count the gap without writing anything. */
|
|
71
71
|
readonly verify?: boolean;
|
|
72
72
|
readonly now?: Date;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
interface ReconcileReport {
|
|
76
76
|
readonly ran: boolean;
|
|
77
77
|
/** Why the run did nothing, when it did nothing. */
|
|
78
78
|
readonly skippedReason?: "lease_held" | "no_files" | "uptodate";
|
|
@@ -393,7 +393,7 @@ async function insertChunk(
|
|
|
393
393
|
.set({
|
|
394
394
|
fileName,
|
|
395
395
|
byteOffset,
|
|
396
|
-
filesCompleted: sql`${telemetryReconciliationState.filesCompleted} +
|
|
396
|
+
filesCompleted: sql`${telemetryReconciliationState.filesCompleted} + 1`,
|
|
397
397
|
eventsExamined: sql`${telemetryReconciliationState.eventsExamined} + ${events.length}`,
|
|
398
398
|
eventsInserted: sql`${telemetryReconciliationState.eventsInserted} + ${rows.length}`,
|
|
399
399
|
conflicts: sql`${telemetryReconciliationState.conflicts} + ${events.length - rows.length}`,
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* but those spans measure local response processing, not decode. Only a
|
|
32
32
|
* client-visible stream window counts as decode time.
|
|
33
33
|
*/
|
|
34
|
-
|
|
34
|
+
interface TokenSpeedInput {
|
|
35
35
|
/** Completion/output tokens reported for the request. */
|
|
36
36
|
readonly outputTokens?: number | undefined;
|
|
37
37
|
/** End-to-end gateway latency in milliseconds. */
|