cartethyia 2.7.3 → 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-2TJD37Hb.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-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.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-BKj_r0rp.js +1 -0
- 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-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BtPcAfot.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-5SnUSy3j.js +9 -0
- 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-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
- package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-TP7voAQ0.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-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
- package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
- package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DMrMPmth.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-Be5Uzamx.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-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-BQqBQd2n.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
- package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-Bm8WKaGY.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-q5HwZ8nN.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-BTScrQpe.js → formatters-BAACA727.js} +1 -1
- package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-YSCE4UC2.js} +1 -1
- package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
- package/dist/dashboard/assets/{index-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
- package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
- package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
- package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
- package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-BHHX_Tmm.js} +1 -1
- package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
- package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
- package/dist/dashboard/assets/{list-row-CzFvogbj.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/minimize-2-BTmMTK4o.js +1 -0
- package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
- package/dist/dashboard/assets/mutation-Rr0TIvcj.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/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
- package/dist/dashboard/assets/query-keys-BloKtaXJ.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-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
- package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
- package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
- 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-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
- package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
- package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
- package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
- package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
- package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.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 +59 -57
- package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
- package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
- package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
- package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
- 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/0027_qoder_identity_genuine_seed.sql +9 -10
- package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
- package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
- package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
- package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -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 -5
- package/scripts/cli/update.ts +15 -41
- package/src/boot/app.ts +67 -10
- 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 +8 -4
- 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 +92 -31
- package/src/console/api-keys/routes.ts +131 -6
- package/src/console/audit/routes.ts +3 -3
- package/src/console/auth/access.ts +4 -4
- package/src/console/auth/account-reset.ts +5 -5
- 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 +40 -34
- 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 +11 -9
- package/src/console/backup/export-endpoint.ts +11 -12
- package/src/console/backup/nine-router.ts +1 -7
- package/src/console/backup/routes.ts +32 -36
- 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 +4 -4
- package/src/console/cli-tools/service.ts +1 -1
- package/src/console/cli-tools/store.ts +2 -2
- package/src/console/console-router-guards.ts +2 -2
- package/src/console/console-router.ts +36 -4
- package/src/console/dashboard-assets.ts +9 -9
- package/src/console/data-management/routes.ts +3 -3
- package/src/console/domain-registration.ts +18 -4
- 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 +5 -1
- package/src/console/observability/live.ts +34 -21
- package/src/console/observability/logs.ts +4 -4
- package/src/console/observability/performance.ts +3 -3
- package/src/console/observability/routes.ts +3 -3
- package/src/console/observability/sse.ts +62 -8
- package/src/console/observability/store.ts +36 -20
- package/src/console/providers/catalog/catalog-projections.ts +1 -1
- package/src/console/providers/catalog/contracts.ts +82 -22
- package/src/console/providers/catalog/model-operations.ts +1 -1
- package/src/console/providers/catalog/provider-operations.ts +110 -17
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/routes.ts +30 -6
- package/src/console/providers/catalog/store-helpers.ts +349 -326
- package/src/console/providers/catalog/store.ts +1662 -1292
- package/src/console/providers/detail/routes.ts +4 -4
- package/src/console/providers/oauth/callback-listener.ts +100 -18
- package/src/console/providers/oauth/routes.ts +95 -16
- 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 +285 -67
- package/src/console/quota/account-test-egress.ts +4 -4
- 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/model/routes.ts +3 -3
- package/src/console/routing/pools/contracts.ts +13 -10
- package/src/console/routing/pools/import-parse.ts +3 -3
- package/src/console/routing/pools/operations.ts +14 -7
- package/src/console/routing/pools/probe-verdict.ts +8 -3
- package/src/console/routing/pools/relay-deploy.ts +12 -12
- package/src/console/routing/pools/routes.ts +3 -3
- package/src/console/routing/pools/store.ts +21 -1
- package/src/console/settings/contracts.ts +29 -2
- package/src/console/settings/routes.ts +3 -3
- package/src/console/settings/store.ts +20 -0
- package/src/console/share/share-router.ts +112 -44
- package/src/console/share/share-stats.ts +109 -39
- 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 +42 -6
- 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 +256 -98
- 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 +76 -5
- package/src/network/pool/agent.ts +7 -6
- package/src/network/pool/byte-accounting.ts +1 -1
- package/src/network/pool/resolver.ts +55 -51
- package/src/network/pool/selector.ts +150 -136
- package/src/network/pool-cooldown-store.ts +71 -16
- package/src/network/pool-health-machine.ts +22 -2
- package/src/network/rate-limit-verdict.ts +68 -0
- package/src/network/retry.ts +1 -1
- package/src/network/ssrf.ts +24 -75
- package/src/observability/event-log.ts +2 -2
- package/src/observability/event-query.ts +286 -214
- 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/telemetry-status.ts +1 -1
- 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 +10 -5
- package/src/persistence/dialect.ts +5 -1
- package/src/persistence/readiness.ts +19 -7
- package/src/persistence/redis.ts +1 -1
- package/src/persistence/schema.ts +177 -45
- package/src/persistence/shared-cache.ts +2 -2
- package/src/persistence/sort-order.ts +1 -1
- package/src/persistence/stores/api-key-store.ts +109 -4
- package/src/persistence/stores/share-store.ts +20 -8
- package/src/persistence/stores/telemetry-store.ts +1 -1
- 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 +12 -16
- package/src/protocol/dsml.ts +3 -49
- package/src/protocol/gateway-error.ts +6 -3
- package/src/protocol/image-clamp.ts +2 -2
- package/src/protocol/image-generation.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 +27 -12
- package/src/protocol/response/codex.ts +2 -2
- package/src/protocol/response/gemini.ts +1 -1
- package/src/protocol/response/messages.ts +6 -6
- package/src/protocol/response/omp-tool-call-markup.ts +1 -1
- package/src/protocol/response/responses.ts +3 -3
- package/src/protocol/sse-decoder.ts +64 -4
- 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 +8 -8
- 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/protocol/upstream/send-claude-messages.ts +3 -3
- package/src/providers/adapters/base-adapter.ts +1 -1
- package/src/providers/adapters/compatible-adapter.ts +44 -5
- 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/authentication/oauth-refresh-service.ts +2 -2
- package/src/providers/bundled-discovery-providers.ts +6 -30
- package/src/providers/configured-openai-providers.ts +82 -97
- package/src/providers/configured-provider.ts +1 -1
- 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 +50 -15
- package/src/providers/discovery/probing-service.ts +18 -20
- package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
- package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
- package/src/providers/integrations/anthropic.ts +4 -11
- 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 +15 -26
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
- 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-discovery-shared.ts +37 -6
- package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
- package/src/providers/integrations/buddy/buddy-media.ts +16 -16
- 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 +5 -16
- package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
- package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
- package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
- package/src/providers/integrations/claude/claude-betas.ts +1 -1
- package/src/providers/integrations/claude/claude-cch.ts +148 -148
- package/src/providers/integrations/claude/claude-credentials.ts +1 -1
- package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
- package/src/providers/integrations/claude/claude.ts +3 -10
- package/src/providers/integrations/claude/fallback-credit.ts +3 -7
- package/src/providers/integrations/cline/cline.ts +2 -2
- package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
- package/src/providers/integrations/codex/codex-device-code.ts +101 -101
- package/src/providers/integrations/codex/codex-errors.ts +1 -1
- package/src/providers/integrations/codex/codex-oauth.ts +0 -1
- package/src/providers/integrations/codex/codex.ts +14 -15
- package/src/providers/integrations/commandcode/commandcode.ts +76 -116
- package/src/providers/integrations/commandcode/quota.ts +132 -48
- package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
- 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 +53 -20
- 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 +13 -13
- package/src/providers/integrations/gemini.ts +11 -11
- 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 +47 -20
- 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 +88 -42
- package/src/providers/integrations/inferhub.ts +4 -11
- package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
- package/src/providers/integrations/kimi/kimi.ts +4 -11
- 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 +91 -78
- package/src/providers/integrations/muse/muse-oauth.ts +0 -1
- package/src/providers/integrations/muse/muse-quota.ts +0 -4
- package/src/providers/integrations/muse/muse.ts +6 -9
- package/src/providers/integrations/opencode/fingerprint.ts +7 -5
- package/src/providers/integrations/opencode/provider.ts +17 -24
- package/src/providers/integrations/perplexity.ts +2 -2
- package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
- package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
- package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -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 +22 -28
- package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
- package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
- package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
- package/src/providers/integrations/qoder/qoder.ts +521 -63
- 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/tokenharbor.ts +2 -2
- 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 +59 -19
- package/src/providers/integrations/xai/xai-oauth.ts +5 -5
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- 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 +22 -6
- package/src/providers/operations/provider-credential-service.ts +35 -6
- package/src/providers/operations/upstream-deadline.ts +3 -3
- package/src/providers/provider-contracts.ts +65 -10
- package/src/providers/provider-credential-resolver.ts +1 -1
- 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-registry.ts +4 -4
- package/src/providers/provider-usage.ts +81 -16
- package/src/providers/quota/cache.ts +29 -0
- package/src/providers/quota/quota-contracts.ts +28 -10
- package/src/providers/quota/refresh.ts +29 -6
- package/src/providers/quota/snapshot.ts +94 -0
- package/src/providers/search/search-provider.ts +6 -8
- package/src/providers/search/search-providers.ts +2 -1
- package/src/security/abuse.ts +8 -8
- package/src/security/admission/reasons.ts +17 -17
- package/src/security/admission/service.ts +2 -2
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +20 -8
- 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/coerce.ts +19 -0
- package/src/shared/invoke-guard.ts +47 -0
- package/src/transport/contracts.ts +13 -4
- package/src/transport/dispatch/attempt-finalize.ts +5 -4
- package/src/transport/dispatch/attempt-loop.ts +10 -7
- package/src/transport/dispatch/capture-policy.ts +34 -37
- package/src/transport/dispatch/empty-stream.ts +28 -25
- package/src/transport/dispatch/generation.ts +33 -53
- package/src/transport/dispatch/leases.ts +8 -8
- package/src/transport/dispatch/native-shared.ts +127 -0
- package/src/transport/dispatch/proxy-request.ts +10 -8
- package/src/transport/dispatch/responses-compact.ts +35 -56
- package/src/transport/dispatch/retry-policy.ts +4 -67
- package/src/transport/dispatch/stream-bridge.ts +1 -1
- package/src/transport/dispatch/streaming/encoder.ts +18 -72
- package/src/transport/dispatch/streaming/finalize.ts +11 -10
- 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 +27 -55
- package/src/transport/dispatch/token-count.ts +49 -46
- package/src/transport/dispatch/websearch.ts +24 -50
- package/src/transport/drain-endpoint.ts +3 -3
- package/src/transport/failure-policy.ts +19 -6
- package/src/transport/guards/auth-guard.ts +6 -11
- package/src/transport/guards/body-policy.ts +7 -7
- package/src/transport/guards/error-lifecycle.ts +18 -3
- package/src/transport/guards/guard-errors.ts +7 -3
- package/src/transport/guards/headroom-guard.ts +2 -2
- package/src/transport/guards/pipeline.ts +7 -7
- package/src/transport/guards/readiness-guard.ts +16 -2
- package/src/transport/guards/request-context.ts +15 -20
- package/src/transport/request/preparer.ts +306 -27
- 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 +5 -20
- 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 +113 -19
- package/src/transport/routing/route-model.ts +131 -38
- package/src/transport/routing/router.ts +154 -39
- package/src/transport/shutdown-notice.ts +21 -9
- 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 +3 -3
- package/src/transport/surface/content-parts.ts +1 -1
- package/src/transport/surface/dialects.ts +2 -2
- package/src/transport/surface/messages/encode.ts +1 -1
- 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-2TJD37Hb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
- package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
- package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
- package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
- package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.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-0OsXRGXe.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
- package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
- package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
- package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
- package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
- package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
- package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
- package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
- package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
- package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
- package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
- package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
- package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
- package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
- package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
- package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
- package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
- package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
- package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
- package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
- package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
- package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
- package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
- package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
- package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
- package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
- package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
- package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
- package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
- package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
- package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
- package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
- package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
- package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
- package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
- package/dist/dashboard/assets/state-DLS7IDMy.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-42ItvbAs.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dmnfh1Ue.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-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
- /package/dist/dashboard/assets/{app-wvwCi4Eh.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
|
@@ -26,7 +26,7 @@ import type {
|
|
|
26
26
|
/** Ask buckets are keyed to this many decimals so float noise cannot split one price into two tiers. */
|
|
27
27
|
const PRICE_PRECISION = 6;
|
|
28
28
|
/** Default number of live providers a capacity-weighted price must have behind it. */
|
|
29
|
-
|
|
29
|
+
const DEFAULT_MIN_CAPACITY = 2;
|
|
30
30
|
|
|
31
31
|
const FAMILY_STATES: readonly FamilyState[] = [
|
|
32
32
|
"operational",
|
|
@@ -114,7 +114,7 @@ export function groupTiers(
|
|
|
114
114
|
* provider count would make `providersLive` wrong, and a wrong availability
|
|
115
115
|
* number is worse than an absent one.
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
function pricePointsToTiers(
|
|
118
118
|
points: unknown,
|
|
119
119
|
official: number | null,
|
|
120
120
|
): readonly Tier[] {
|
|
@@ -57,7 +57,7 @@ import type {
|
|
|
57
57
|
/** Success rate below which a model is not routed to, when one is reported. */
|
|
58
58
|
const MIN_SUCCESS_RATE_PCT = 80;
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
interface InferhubRoutesConfig {
|
|
61
61
|
readonly accessResolver: (request: Request) => AccessDecision | undefined;
|
|
62
62
|
/** Resolves the `config_read` key. Absent means the catalog cannot be read. */
|
|
63
63
|
readonly resolveConfigKey?: () => Promise<string | undefined> | string | undefined;
|
|
@@ -34,7 +34,7 @@ export interface ModelHealth {
|
|
|
34
34
|
readonly familyState: FamilyState | null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
interface ModelCapabilities {
|
|
38
38
|
readonly contextWindow: number | null;
|
|
39
39
|
readonly maxOutputTokens: number | null;
|
|
40
40
|
readonly modalities: readonly string[];
|
|
@@ -173,7 +173,7 @@ export interface UsageCacheResponse {
|
|
|
173
173
|
cacheWriteTokens: number;
|
|
174
174
|
hitRate: number;
|
|
175
175
|
}
|
|
176
|
-
|
|
176
|
+
type UsageRequestMode = "stream" | "non_stream";
|
|
177
177
|
export interface UsageRequestItem {
|
|
178
178
|
requestId: string;
|
|
179
179
|
surface?: string;
|
|
@@ -191,6 +191,10 @@ export interface UsageRequestItem {
|
|
|
191
191
|
apiKeyId?: string;
|
|
192
192
|
userAgent?: string;
|
|
193
193
|
clientName?: string;
|
|
194
|
+
/** The proxy pool that carried this request, when one was used. */
|
|
195
|
+
networkPoolId?: string;
|
|
196
|
+
/** Operator-facing label of the pool; absent when the pool is gone. */
|
|
197
|
+
networkPoolLabel?: string;
|
|
194
198
|
estimatedCost?: number;
|
|
195
199
|
/** Provider-billed credits; absent when the upstream reported no credit field. */
|
|
196
200
|
creditUsed?: number;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
// Every endpoint requires `dashboard:read`. The global request count is
|
|
8
8
|
// process-level; pool usage and health are filtered to the caller's tenant.
|
|
9
9
|
|
|
10
|
-
import { Elysia } from "elysia";
|
|
10
|
+
import { Elysia, type AnyElysia } from "elysia";
|
|
11
11
|
import { errorResponse, requireScope } from "../shared/errors";
|
|
12
12
|
import type { ConsoleAccessResolver } from "../auth/access";
|
|
13
13
|
/**
|
|
@@ -34,7 +34,7 @@ import { poolByteSnapshot } from "../../network/pool/byte-accounting";
|
|
|
34
34
|
import { consoleSseResponse, createConsoleSseStream } from "./sse";
|
|
35
35
|
import { subscribeRequestCompleted } from "../../observability/request-notify";
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
interface LiveConfig {
|
|
38
38
|
readonly accessResolver: ConsoleAccessResolver;
|
|
39
39
|
readonly poolSelector?: NetworkPoolSelector;
|
|
40
40
|
readonly db?: CartethyiaDatabase;
|
|
@@ -86,7 +86,7 @@ function withPoolBytes<T extends { poolId: string; currentInflight?: number }>(
|
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
export function createLiveRoutes(config: LiveConfig):
|
|
89
|
+
export function createLiveRoutes(config: LiveConfig): AnyElysia {
|
|
90
90
|
return new Elysia()
|
|
91
91
|
.get("/live/requests/stream", ({ request, set }) => {
|
|
92
92
|
try {
|
|
@@ -94,10 +94,9 @@ export function createLiveRoutes(config: LiveConfig): Elysia {
|
|
|
94
94
|
requireScope(access, "dashboard:read");
|
|
95
95
|
const tenantId = access?.tenantId;
|
|
96
96
|
if (!tenantId) return errorResponse(new Error("Tenant required"), set, "Live operation failed");
|
|
97
|
-
set.headers
|
|
98
|
-
set
|
|
99
|
-
|
|
100
|
-
set.headers["x-accel-buffering"] = "no";
|
|
97
|
+
// No `set.headers` writes here: this handler returns a `Response`, so
|
|
98
|
+
// Elysia discards `set` and `consoleSseResponse` below owns the SSE
|
|
99
|
+
// headers (content-type, cache-control, connection, buffering).
|
|
101
100
|
return consoleSseResponse(
|
|
102
101
|
createConsoleSseStream(request.signal, ({ send }) => {
|
|
103
102
|
return subscribeRequestCompleted((notice) => {
|
|
@@ -119,22 +118,36 @@ export function createLiveRoutes(config: LiveConfig): Elysia {
|
|
|
119
118
|
})
|
|
120
119
|
.get("/live/in-flight/stream", ({ request, set }) => {
|
|
121
120
|
try {
|
|
122
|
-
requireScope(config.accessResolver(request), "dashboard:read");
|
|
121
|
+
const access = requireScope(config.accessResolver(request), "dashboard:read");
|
|
122
|
+
const tenantId = access?.tenantId;
|
|
123
|
+
return consoleSseResponse(
|
|
124
|
+
createConsoleSseStream(request.signal, ({ send }) => {
|
|
125
|
+
const store = config.stateStore;
|
|
126
|
+
if (!store) {
|
|
127
|
+
send("count", EMPTY_IN_FLIGHT);
|
|
128
|
+
return () => {};
|
|
129
|
+
}
|
|
130
|
+
// The Usage page keeps one stream open for both the in-flight gauge
|
|
131
|
+
// and request-table invalidation, so this route also fans out
|
|
132
|
+
// `request_completed` events (tagged by kind) for the tenant,
|
|
133
|
+
// mirroring `/live/requests/stream`.
|
|
134
|
+
const unsubscribe = store.subscribeInFlight((snapshot) => send("count", snapshot));
|
|
135
|
+
let unsubscribeCompleted: (() => void) | undefined;
|
|
136
|
+
if (tenantId) {
|
|
137
|
+
unsubscribeCompleted = subscribeRequestCompleted((notice) => {
|
|
138
|
+
if (notice.tenantId === tenantId) send("request_completed", notice);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
send("count", store.inFlightSnapshot());
|
|
142
|
+
return () => {
|
|
143
|
+
unsubscribe();
|
|
144
|
+
unsubscribeCompleted?.();
|
|
145
|
+
};
|
|
146
|
+
}),
|
|
147
|
+
);
|
|
123
148
|
} catch (e) {
|
|
124
149
|
return errorResponse(e, set, "Live operation failed");
|
|
125
150
|
}
|
|
126
|
-
return consoleSseResponse(
|
|
127
|
-
createConsoleSseStream(request.signal, ({ send }) => {
|
|
128
|
-
const store = config.stateStore;
|
|
129
|
-
if (!store) {
|
|
130
|
-
send("count", EMPTY_IN_FLIGHT);
|
|
131
|
-
return () => {};
|
|
132
|
-
}
|
|
133
|
-
const unsubscribe = store.subscribeInFlight((snapshot) => send("count", snapshot));
|
|
134
|
-
send("count", store.inFlightSnapshot());
|
|
135
|
-
return unsubscribe;
|
|
136
|
-
}),
|
|
137
|
-
);
|
|
138
151
|
})
|
|
139
152
|
.get("/live/pools", async ({ request, set }) => {
|
|
140
153
|
try {
|
|
@@ -176,5 +189,5 @@ export function createLiveRoutes(config: LiveConfig): Elysia {
|
|
|
176
189
|
};
|
|
177
190
|
}),
|
|
178
191
|
);
|
|
179
|
-
})
|
|
192
|
+
});
|
|
180
193
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// metadata and their args are redacted at the source, the same audience
|
|
9
9
|
// that already reads request/response bodies on Usage.
|
|
10
10
|
|
|
11
|
-
import { Elysia, t } from "elysia";
|
|
11
|
+
import { Elysia, t, type AnyElysia } from "elysia";
|
|
12
12
|
import { ConsoleDomainError, errorResponse, requireScope } from "../shared/errors";
|
|
13
13
|
import { parseQueryLimit } from "../shared/query";
|
|
14
14
|
import type { ConsoleAccessResolver } from "../auth/access";
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
} from "../../observability/log-ring";
|
|
24
24
|
import { consoleSseResponse, createConsoleSseStream } from "./sse";
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
interface LogsConfig {
|
|
27
27
|
readonly accessResolver: ConsoleAccessResolver;
|
|
28
28
|
readonly auditSink?: AuditSink;
|
|
29
29
|
}
|
|
@@ -37,7 +37,7 @@ const logsQuery = t.Object({
|
|
|
37
37
|
limit: t.Optional(t.String()),
|
|
38
38
|
});
|
|
39
39
|
|
|
40
|
-
export function createLogRoutes(config: LogsConfig):
|
|
40
|
+
export function createLogRoutes(config: LogsConfig): AnyElysia {
|
|
41
41
|
const readLogs = (access: AccessDecision | undefined, level?: string, limitRaw?: string) => {
|
|
42
42
|
requireScope(access, "dashboard:read");
|
|
43
43
|
if (level !== undefined && !isLogLevel(level)) {
|
|
@@ -83,5 +83,5 @@ export function createLogRoutes(config: LogsConfig): Elysia {
|
|
|
83
83
|
});
|
|
84
84
|
}),
|
|
85
85
|
);
|
|
86
|
-
})
|
|
86
|
+
});
|
|
87
87
|
}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
// this instance's own module graph and egress), so the route is guarded by
|
|
6
6
|
// `platform:admin` like the other instance-level operations.
|
|
7
7
|
|
|
8
|
-
import { Elysia } from "elysia";
|
|
8
|
+
import { Elysia, type AnyElysia } from "elysia";
|
|
9
9
|
import { errorResponse, requireGlobalAdmin } from "../shared/errors";
|
|
10
10
|
import { performanceMetricsSnapshot } from "../../observability/performance-metrics";
|
|
11
11
|
import type { PerformanceConfig } from "./performance-contracts";
|
|
12
12
|
|
|
13
|
-
export function createPerformanceRoutes(config: PerformanceConfig):
|
|
13
|
+
export function createPerformanceRoutes(config: PerformanceConfig): AnyElysia {
|
|
14
14
|
return new Elysia()
|
|
15
15
|
.get("/system/performance", ({ request, set }) => {
|
|
16
16
|
try {
|
|
@@ -19,5 +19,5 @@ export function createPerformanceRoutes(config: PerformanceConfig): Elysia {
|
|
|
19
19
|
} catch (e) {
|
|
20
20
|
return errorResponse(e, set, "Performance operation failed");
|
|
21
21
|
}
|
|
22
|
-
})
|
|
22
|
+
});
|
|
23
23
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Elysia, t } from "elysia";
|
|
1
|
+
import { Elysia, t, type AnyElysia } from "elysia";
|
|
2
2
|
import { ConsoleDomainError, consoleErrorHandler } from "../shared/errors";
|
|
3
3
|
import { USAGE_DIMENSIONS, type UsageDimension } from "./usage-dimensions";
|
|
4
4
|
import { createObservabilityOperations, type ObservabilityConfig } from "./contracts";
|
|
@@ -18,7 +18,7 @@ const telemetryDetailQuery = t.Object({
|
|
|
18
18
|
includePayload: t.Optional(t.String()),
|
|
19
19
|
createdAt: t.Optional(t.String()),
|
|
20
20
|
});
|
|
21
|
-
export function createObservabilityRoutes(config: ObservabilityConfig):
|
|
21
|
+
export function createObservabilityRoutes(config: ObservabilityConfig): AnyElysia {
|
|
22
22
|
const factory = createObservabilityOperations(config);
|
|
23
23
|
return new Elysia()
|
|
24
24
|
.error(consoleErrorHandler("Observability operation failed"))
|
|
@@ -114,5 +114,5 @@ export function createObservabilityRoutes(config: ObservabilityConfig): Elysia {
|
|
|
114
114
|
query.createdAt,
|
|
115
115
|
);
|
|
116
116
|
},
|
|
117
|
-
)
|
|
117
|
+
);
|
|
118
118
|
}
|
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
* the shared `buildSseEventFrame` core so the two layers cannot drift.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
interface SseSender {
|
|
9
9
|
send(event: string, data: unknown): void;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/** Register endpoint-specific SSE subscriptions; return their teardown callback. */
|
|
13
|
-
|
|
13
|
+
type SseSetup = (sender: SseSender) => () => void;
|
|
14
14
|
|
|
15
|
-
import { buildSseEventFrame as formatSseFrame } from "../../protocol/sse-frame";
|
|
15
|
+
import { TEXT_ENCODER, buildSseEventFrame as formatSseFrame } from "../../protocol/sse-frame";
|
|
16
16
|
|
|
17
17
|
export { formatSseFrame };
|
|
18
18
|
|
|
@@ -22,38 +22,82 @@ export { formatSseFrame };
|
|
|
22
22
|
*/
|
|
23
23
|
const SSE_HEARTBEAT_MS = 25_000;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Hard cap on one stream's lifetime. A tab that is abandoned but never
|
|
27
|
+
* unloads (a backgrounded browser window, a parked laptop) would otherwise
|
|
28
|
+
* hold its subscription and timers forever; the client reconnects on close,
|
|
29
|
+
* so this only forces a refresh. 45 minutes is far longer than any live view
|
|
30
|
+
* needs in one stretch.
|
|
31
|
+
*/
|
|
32
|
+
const SSE_MAX_LIFETIME_MS = 45 * 60_000;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Idle timeout: if no *data* frame is sent for this long, the stream sends a
|
|
36
|
+
* terminal `close` event and closes. Heartbeats deliberately do not count —
|
|
37
|
+
* they are there to keep proxies alive, not to prove someone is reading, so
|
|
38
|
+
* they must not defeat the abandoned-tab cutoff.
|
|
39
|
+
*/
|
|
40
|
+
const SSE_IDLE_TIMEOUT_MS = 5 * 60_000;
|
|
41
|
+
|
|
42
|
+
/** Watchdog cadence; the two cutoffs above are checked on this tick. */
|
|
43
|
+
const SSE_WATCHDOG_MS = 30_000;
|
|
44
|
+
|
|
45
|
+
/** Frame sent when the server cuts the stream (idle or max lifetime). */
|
|
46
|
+
function closeFrame(reason: string): Uint8Array {
|
|
47
|
+
return TEXT_ENCODER.encode(formatSseFrame("close", JSON.stringify({ reason })));
|
|
48
|
+
}
|
|
49
|
+
|
|
25
50
|
/**
|
|
26
51
|
* Console SSE response stream with uniform JSON event encoding, heartbeat,
|
|
27
|
-
* and abort/cancel cleanup. The setup callback runs
|
|
28
|
-
* start so the initial snapshot is enqueued before the
|
|
52
|
+
* idle/max-lifetime cutoff, and abort/cancel cleanup. The setup callback runs
|
|
53
|
+
* synchronously at stream start so the initial snapshot is enqueued before the
|
|
54
|
+
* first read.
|
|
55
|
+
*
|
|
56
|
+
* The encoder is the module-level shared `TextEncoder` from the frame module:
|
|
57
|
+
* allocating one per stream (let alone per send) is unnecessary garbage for a
|
|
58
|
+
* hot path that encodes a frame every few hundred milliseconds per connection.
|
|
29
59
|
*/
|
|
30
60
|
export function createConsoleSseStream(
|
|
31
61
|
signal: AbortSignal,
|
|
32
62
|
setup: SseSetup,
|
|
33
63
|
): ReadableStream<Uint8Array> {
|
|
34
|
-
const encoder = new TextEncoder();
|
|
35
64
|
let cleanupSubscription: (() => void) | undefined;
|
|
36
65
|
let heartbeat: ReturnType<typeof setInterval> | undefined;
|
|
66
|
+
let watchdog: ReturnType<typeof setInterval> | undefined;
|
|
37
67
|
let close: (() => void) | undefined;
|
|
38
68
|
|
|
39
69
|
return new ReadableStream<Uint8Array>({
|
|
40
70
|
start(controller) {
|
|
41
71
|
let closed = false;
|
|
72
|
+
const startedAt = Date.now();
|
|
73
|
+
let lastDataAt = startedAt;
|
|
42
74
|
const sender: SseSender = {
|
|
43
75
|
send(event, data) {
|
|
44
76
|
if (closed) return;
|
|
45
77
|
try {
|
|
46
|
-
|
|
78
|
+
lastDataAt = Date.now();
|
|
79
|
+
controller.enqueue(TEXT_ENCODER.encode(formatSseFrame(event, JSON.stringify(data))));
|
|
47
80
|
} catch {
|
|
48
81
|
close?.();
|
|
49
82
|
}
|
|
50
83
|
},
|
|
51
84
|
};
|
|
52
85
|
|
|
86
|
+
const terminate = (reason: string): void => {
|
|
87
|
+
if (closed) return;
|
|
88
|
+
try {
|
|
89
|
+
controller.enqueue(closeFrame(reason));
|
|
90
|
+
} catch {
|
|
91
|
+
// Fall through to close regardless.
|
|
92
|
+
}
|
|
93
|
+
close?.();
|
|
94
|
+
};
|
|
95
|
+
|
|
53
96
|
close = () => {
|
|
54
97
|
if (closed) return;
|
|
55
98
|
closed = true;
|
|
56
99
|
clearInterval(heartbeat);
|
|
100
|
+
clearInterval(watchdog);
|
|
57
101
|
cleanupSubscription?.();
|
|
58
102
|
try {
|
|
59
103
|
controller.close();
|
|
@@ -70,12 +114,22 @@ export function createConsoleSseStream(
|
|
|
70
114
|
heartbeat = setInterval(() => {
|
|
71
115
|
if (closed) return;
|
|
72
116
|
try {
|
|
73
|
-
controller.enqueue(
|
|
117
|
+
controller.enqueue(TEXT_ENCODER.encode(": ping\n\n"));
|
|
74
118
|
} catch {
|
|
75
119
|
close?.();
|
|
76
120
|
}
|
|
77
121
|
}, SSE_HEARTBEAT_MS);
|
|
78
122
|
|
|
123
|
+
watchdog = setInterval(() => {
|
|
124
|
+
if (closed) return;
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
if (now - lastDataAt > SSE_IDLE_TIMEOUT_MS) {
|
|
127
|
+
terminate("idle");
|
|
128
|
+
} else if (now - startedAt > SSE_MAX_LIFETIME_MS) {
|
|
129
|
+
terminate("max_lifetime");
|
|
130
|
+
}
|
|
131
|
+
}, SSE_WATCHDOG_MS);
|
|
132
|
+
|
|
79
133
|
signal.addEventListener("abort", close, { once: true });
|
|
80
134
|
},
|
|
81
135
|
cancel() {
|
|
@@ -7,11 +7,8 @@ import { type TelemetryEventRecord } from "../../observability/event-log";
|
|
|
7
7
|
import {
|
|
8
8
|
breakdownTelemetry,
|
|
9
9
|
chartTelemetry,
|
|
10
|
-
healthTelemetry,
|
|
11
10
|
queryTelemetryEvents as queryTelemetryEventPage,
|
|
12
|
-
|
|
13
|
-
summarizeUsagePerformanceSql,
|
|
14
|
-
summarizeTelemetry,
|
|
11
|
+
summarizeUsageWithPerformance,
|
|
15
12
|
} from "../../observability/event-query";
|
|
16
13
|
import { clientNameFromUserAgent } from "../../observability/client-name";
|
|
17
14
|
|
|
@@ -145,6 +142,7 @@ function mapUsageRequestItem(
|
|
|
145
142
|
: {}),
|
|
146
143
|
...(event.endpoint ? { endpoint: event.endpoint } : {}),
|
|
147
144
|
...(event.apiKeyId ? { apiKeyId: event.apiKeyId } : {}),
|
|
145
|
+
...(event.networkPoolId ? { networkPoolId: event.networkPoolId } : {}),
|
|
148
146
|
...(event.userAgent ? { userAgent: event.userAgent } : {}),
|
|
149
147
|
...(event.userAgent ? { clientName: clientNameFromUserAgent(event.userAgent) } : {}),
|
|
150
148
|
...(event.clientIp
|
|
@@ -186,6 +184,14 @@ async function resolveProxyLabel(
|
|
|
186
184
|
}
|
|
187
185
|
const HEALTH_WINDOW_MS = 24 * 3_600_000;
|
|
188
186
|
const TOP_N = 50;
|
|
187
|
+
/**
|
|
188
|
+
* TTL for the usage analytics read-through (summary, chart, breakdown, totals).
|
|
189
|
+
* The dashboard polls these every 5–10s; a 30s TTL means the heavy telemetry
|
|
190
|
+
* window scans run once per 30s and the polls in between are answered from
|
|
191
|
+
* Redis (or the in-process fallback) with a `304`. Health stays on the
|
|
192
|
+
* default 10s — it feeds the live status tile.
|
|
193
|
+
*/
|
|
194
|
+
const USAGE_READ_THROUGH_TTL_SECONDS = 30;
|
|
189
195
|
|
|
190
196
|
/**
|
|
191
197
|
* Nearest-rank percentile over a sorted array — kept for the JS-side
|
|
@@ -199,7 +205,7 @@ function percentile(sorted: readonly number[], fraction: number): number {
|
|
|
199
205
|
return Math.round(sorted[index] ?? 0);
|
|
200
206
|
}
|
|
201
207
|
|
|
202
|
-
|
|
208
|
+
interface UsagePerformanceSummary {
|
|
203
209
|
avgResolveMs: number;
|
|
204
210
|
avgDurationMs: number;
|
|
205
211
|
latencyP50Ms: number;
|
|
@@ -326,11 +332,10 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
326
332
|
// cost on the dashboard. `healthTelemetry` returns the totals and the
|
|
327
333
|
// database computes the percentiles.
|
|
328
334
|
const since = new Date(Date.now() - HEALTH_WINDOW_MS);
|
|
329
|
-
const totals = await
|
|
330
|
-
const performance = await summarizeHealthPerformance(this.db, tenantId, since);
|
|
335
|
+
const { summary: totals, performance } = await summarizeUsageWithPerformance(this.db, tenantId, since);
|
|
331
336
|
total = totals.requests;
|
|
332
337
|
errors = totals.errors;
|
|
333
|
-
avg =
|
|
338
|
+
avg = Math.round(performance.avgDurationMs ?? 0);
|
|
334
339
|
p95 = performance.latencyP95Ms ?? 0;
|
|
335
340
|
p99 = performance.latencyP99Ms ?? 0;
|
|
336
341
|
const inputTokens = totals.inputTokens;
|
|
@@ -392,6 +397,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
392
397
|
async usage(tenantId: string, period: string): Promise<CachedResult<UsageResponse>> {
|
|
393
398
|
return this.readThroughWithEtag(this.usageCacheKey(tenantId, period, "usage"), () =>
|
|
394
399
|
this.computeUsage(tenantId, period),
|
|
400
|
+
USAGE_READ_THROUGH_TTL_SECONDS,
|
|
395
401
|
);
|
|
396
402
|
}
|
|
397
403
|
|
|
@@ -408,8 +414,12 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
408
414
|
* configured — and returns the strong validator alongside it, so a repeated
|
|
409
415
|
* poll can be answered with a `304` instead of the whole payload.
|
|
410
416
|
*/
|
|
411
|
-
private readThroughWithEtag<T>(
|
|
412
|
-
|
|
417
|
+
private readThroughWithEtag<T>(
|
|
418
|
+
key: string,
|
|
419
|
+
compute: () => Promise<T>,
|
|
420
|
+
ttlSeconds?: number,
|
|
421
|
+
): Promise<CachedResult<T>> {
|
|
422
|
+
return cachedReadWithEtag(this.redis, key, compute, ttlSeconds);
|
|
413
423
|
}
|
|
414
424
|
|
|
415
425
|
private async computeUsage(tenantId: string, period: string): Promise<UsageResponse> {
|
|
@@ -417,8 +427,8 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
417
427
|
// Totals AND the top-model/top-provider counts come from SQL: the old
|
|
418
428
|
// shape parsed the whole retained window into an array to count two
|
|
419
429
|
// dimensions in JavaScript.
|
|
420
|
-
const [summary, models, providers] = await Promise.all([
|
|
421
|
-
|
|
430
|
+
const [{ summary }, models, providers] = await Promise.all([
|
|
431
|
+
summarizeUsageWithPerformance(this.db, tenantId, since),
|
|
422
432
|
breakdownTelemetry(this.db, tenantId, "model", since),
|
|
423
433
|
breakdownTelemetry(this.db, tenantId, "provider", since),
|
|
424
434
|
]);
|
|
@@ -462,18 +472,18 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
462
472
|
async usageSummary(tenantId: string, period: string): Promise<CachedResult<UsageSummaryResponse>> {
|
|
463
473
|
return this.readThroughWithEtag(this.usageCacheKey(tenantId, period, "summary"), () =>
|
|
464
474
|
this.computeSummary(tenantId, period),
|
|
475
|
+
USAGE_READ_THROUGH_TTL_SECONDS,
|
|
465
476
|
);
|
|
466
477
|
}
|
|
467
478
|
|
|
468
479
|
private async computeSummary(tenantId: string, period: string): Promise<UsageSummaryResponse> {
|
|
469
480
|
const since = this.periodSince(period);
|
|
470
481
|
// Totals, status breakdown, and latency percentiles all computed in SQL.
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
const [summary,
|
|
474
|
-
|
|
482
|
+
// The summary totals and performance figures come from ONE combined window
|
|
483
|
+
// scan (one percentile pass), not two independent scans.
|
|
484
|
+
const [{ summary, performance }, statuses] = await Promise.all([
|
|
485
|
+
summarizeUsageWithPerformance(this.db, tenantId, since),
|
|
475
486
|
breakdownTelemetry(this.db, tenantId, "status", since),
|
|
476
|
-
summarizeUsagePerformanceSql(this.db, tenantId, since),
|
|
477
487
|
]);
|
|
478
488
|
const inputTokens = summary.inputTokens;
|
|
479
489
|
const cachedTokens = summary.cachedInputTokens;
|
|
@@ -503,6 +513,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
503
513
|
async usageChart(tenantId: string, period: string): Promise<CachedResult<UsageChartResponse>> {
|
|
504
514
|
return this.readThroughWithEtag(this.usageCacheKey(tenantId, period, "chart"), () =>
|
|
505
515
|
this.computeChart(tenantId, period),
|
|
516
|
+
USAGE_READ_THROUGH_TTL_SECONDS,
|
|
506
517
|
);
|
|
507
518
|
}
|
|
508
519
|
|
|
@@ -526,7 +537,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
526
537
|
input: bucket.inputTokens,
|
|
527
538
|
// `cached` is the cached share of the prompt: the SQL reader sums
|
|
528
539
|
// cached_input_tokens, which is the same number the old JS loop used.
|
|
529
|
-
cached: bucket.
|
|
540
|
+
cached: bucket.cachedInputTokens,
|
|
530
541
|
output: bucket.outputTokens,
|
|
531
542
|
});
|
|
532
543
|
}
|
|
@@ -550,6 +561,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
550
561
|
): Promise<CachedResult<UsageByResponse>> {
|
|
551
562
|
return this.readThroughWithEtag(this.usageCacheKey(tenantId, `${dimension}:${period}`, "by"), () =>
|
|
552
563
|
this.computeBy(tenantId, dimension, period),
|
|
564
|
+
USAGE_READ_THROUGH_TTL_SECONDS,
|
|
553
565
|
);
|
|
554
566
|
}
|
|
555
567
|
|
|
@@ -655,7 +667,7 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
655
667
|
}
|
|
656
668
|
|
|
657
669
|
private async computeCache(tenantId: string, period: string): Promise<UsageCacheResponse> {
|
|
658
|
-
const summary = await
|
|
670
|
+
const { summary } = await summarizeUsageWithPerformance(this.db, tenantId, this.periodSince(period));
|
|
659
671
|
const inputTokens = summary.inputTokens;
|
|
660
672
|
const outputTokens = summary.outputTokens;
|
|
661
673
|
const cachedTokens = summary.cachedInputTokens;
|
|
@@ -766,7 +778,11 @@ export class DrizzleObservabilityStore implements ObservabilityStore {
|
|
|
766
778
|
const item = mapUsageRequestItem(event, hideClientIp);
|
|
767
779
|
const keyLabel = event.apiKeyId ? keyLabels?.get(event.apiKeyId) : undefined;
|
|
768
780
|
const labeled = keyLabel === undefined ? item : { ...item, apiKeyLabel: keyLabel };
|
|
769
|
-
const presented = {
|
|
781
|
+
const presented = {
|
|
782
|
+
...labeled,
|
|
783
|
+
proxy,
|
|
784
|
+
...(event.networkPoolId ? { networkPoolLabel: proxy } : {}),
|
|
785
|
+
};
|
|
770
786
|
// Filter the payload table directly instead of joining `telemetry_events`
|
|
771
787
|
// only to re-apply the tenant predicate: `telemetry_payloads` carries
|
|
772
788
|
// `tenant_id` itself, so the join added a second table's rows to filter for
|
|
@@ -23,7 +23,7 @@ import type { ProviderRecord } from "./contracts";
|
|
|
23
23
|
* purpose: the projection should not be able to reach a loader, so the type
|
|
24
24
|
* cannot drift into "call something expensive to answer a boolean".
|
|
25
25
|
*/
|
|
26
|
-
|
|
26
|
+
interface ProviderDiscoveryLookup {
|
|
27
27
|
hasModelDiscovery(providerId: string): boolean;
|
|
28
28
|
}
|
|
29
29
|
|