cartethyia 2.7.4 → 2.7.6
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 +5 -0
- package/README.md +18 -6
- package/dist/dashboard/assets/BannedPage-B1N603cM.js +1 -0
- package/dist/dashboard/assets/BannedPage-B1N603cM.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js +3 -0
- package/dist/dashboard/assets/CliToolDetailPage-9q4_4NoK.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js +1 -0
- package/dist/dashboard/assets/CliToolsPage-DwshGtK-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js +1 -0
- package/dist/dashboard/assets/CombosPage-D762MIkp.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js +1 -0
- package/dist/dashboard/assets/ConsoleLogPage-KRYjHZsX.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js +1 -0
- package/dist/dashboard/assets/CustomizationPage-DXsxk5uM.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BEjAjD4F.js.gz +0 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js +899 -0
- package/dist/dashboard/assets/InjectSystemPromptPanel-d5v3K_Yc.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js +1 -0
- package/dist/dashboard/assets/LoginPage-Ccv4tjNS.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-C6WlpU5E.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-C6WlpU5E.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DN9fYNWA.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js +5 -0
- package/dist/dashboard/assets/ProviderDetailPage-BY0ieUgz.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-DNsbfea2.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-DxjvUzSD.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-DxjvUzSD.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js +1 -0
- package/dist/dashboard/assets/QuotaPage-OaHScjpX.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js +1 -0
- package/dist/dashboard/assets/SettingsPage-BW4AKj2H.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js +1 -0
- package/dist/dashboard/assets/SetupPage-44BZrxFC.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-DRPavCdU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-DRPavCdU.js.gz +0 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js +1 -0
- package/dist/dashboard/assets/ToolIcon-CfeLA-Z_.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js +56 -0
- package/dist/dashboard/assets/UsagePage-B7M7LvMM.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js +1 -0
- package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js +9 -0
- package/dist/dashboard/assets/app-DRnQLhsc.js.gz +0 -0
- package/dist/dashboard/assets/app-mweRcsKp.css +2 -0
- package/dist/dashboard/assets/app-mweRcsKp.css.gz +0 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js +1 -0
- package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
- package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-BaX2GTrn.js} +1 -1
- package/dist/dashboard/assets/badge-BaX2GTrn.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DympBNq4.js → banner-DFH4Bkte.js} +1 -1
- package/dist/dashboard/assets/banner-DFH4Bkte.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-CxDw0lK6.js} +1 -1
- package/dist/dashboard/assets/card-CxDw0lK6.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/circle-question-mark-Cz4un8sH.js +1 -0
- package/dist/dashboard/assets/circle-question-mark-Cz4un8sH.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +1 -0
- package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-DfS1ntiq.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DfS1ntiq.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js +1 -0
- package/dist/dashboard/assets/dialog-BK-NRr5u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-QqPul6sC.js} +1 -1
- package/dist/dashboard/assets/drawer-QqPul6sC.js.gz +0 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js +1 -0
- package/dist/dashboard/assets/entry-BMlYJVFj.js.gz +0 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js +4 -0
- package/dist/dashboard/assets/entry-D6WvojeD.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js +1 -0
- package/dist/dashboard/assets/entry-Dmx7gBiN.js.gz +0 -0
- package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-u7JPB5BX.js} +1 -1
- package/dist/dashboard/assets/formatters-u7JPB5BX.js.gz +0 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js +1 -0
- package/dist/dashboard/assets/house-h9AZlJuT.js.gz +0 -0
- package/dist/dashboard/assets/{index-DBNPOfhV.js → index-Ko4dLRnV.js} +2 -2
- package/dist/dashboard/assets/index-Ko4dLRnV.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-CHJQwxLa.js} +1 -1
- package/dist/dashboard/assets/inline-CHJQwxLa.js.gz +0 -0
- package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BlmlizVV.js} +1 -1
- package/dist/dashboard/assets/input-BlmlizVV.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-Bz93I-yE.js} +1 -1
- package/dist/dashboard/assets/layout-Bz93I-yE.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Ml16KCfu.js} +1 -1
- package/dist/dashboard/assets/list-row-Ml16KCfu.js.gz +0 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js +1 -0
- package/dist/dashboard/assets/live-7_QpnYGu.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-Rr0TIvcj.js → mutation-GU7XdEjz.js} +1 -1
- package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js +1 -0
- package/dist/dashboard/assets/network-CuMDaTzT.js.gz +0 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js +2 -0
- package/dist/dashboard/assets/numbers-CoqpaDMx.js.gz +0 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js +1 -0
- package/dist/dashboard/assets/pagination-B5aOoweZ.js.gz +0 -0
- package/dist/dashboard/assets/providers/zai.webp +0 -0
- package/dist/dashboard/assets/providers/zcode.webp +0 -0
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js → query-keys-YSoQOUh6.js} +1 -1
- package/dist/dashboard/assets/{query-keys-BloKtaXJ.js.gz → query-keys-YSoQOUh6.js.gz} +0 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js +1 -0
- package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js +1 -0
- package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
- package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BHqpd-bg.js} +2 -2
- package/dist/dashboard/assets/select-BHqpd-bg.js.gz +0 -0
- package/dist/dashboard/assets/settings-BxslsErn.js +1 -0
- package/dist/dashboard/assets/settings-BxslsErn.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-j7cXjgYX.js} +1 -1
- package/dist/dashboard/assets/stack-j7cXjgYX.js.gz +0 -0
- package/dist/dashboard/assets/{state-CkfdYWel.js → state-DHmEnLa2.js} +1 -1
- package/dist/dashboard/assets/state-DHmEnLa2.js.gz +0 -0
- package/dist/dashboard/assets/{switch-SYm237HG.js → switch-DmZcyTIC.js} +1 -1
- package/dist/dashboard/assets/switch-DmZcyTIC.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-CbCP4w1o.js} +1 -1
- package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
- package/dist/dashboard/console-backgrounds.jpg +0 -0
- package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +60 -59
- 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/full-postgres/0042_add_telemetry_degenerate_stop.sql +14 -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/migrations/lite-sqlite3/0042_add_telemetry_degenerate_stop.sql +12 -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 +794 -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 +19 -14
- package/src/config/resources.ts +0 -5
- package/src/config/runtime.ts +2 -5
- package/src/config/spec.ts +33 -6
- package/src/config/usage.ts +27 -0
- 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 +56 -24
- 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 +43 -299
- package/src/console/cli-tools/fs-ops.ts +29 -0
- package/src/console/cli-tools/injectors/claude.ts +3 -3
- package/src/console/cli-tools/injectors/codex.ts +181 -181
- package/src/console/cli-tools/injectors/driver.ts +150 -247
- package/src/console/cli-tools/injectors/kilo.ts +146 -21
- package/src/console/cli-tools/injectors/opencode.ts +176 -153
- package/src/console/cli-tools/routes.ts +7 -1
- package/src/console/cli-tools/service.ts +8 -7
- 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 +7 -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 +23 -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 +11 -13
- 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 +9 -2
- package/src/observability/event-query.ts +61 -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 +19 -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 +121 -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 +29 -2
- 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 +8 -125
- 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 +71 -4
- 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 +35 -37
- 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 +88 -28
- package/src/providers/integrations/antigravity/antigravity-quota.ts +18 -6
- package/src/providers/integrations/antigravity/antigravity.ts +22 -13
- 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 +35 -3
- 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 +70 -12
- package/src/providers/integrations/github/github-oauth.ts +184 -14
- package/src/providers/integrations/github/github.ts +134 -26
- 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 +80 -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 +94 -11
- 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 +422 -71
- 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 +51 -8
- 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 +198 -133
- package/src/providers/operations/account-health-service.ts +31 -39
- package/src/providers/operations/account-reset-service.ts +58 -1
- package/src/providers/operations/byok-wire-profile.ts +19 -15
- 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 +50 -19
- 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 +13 -6
- package/src/security/admission/ttl.ts +61 -61
- package/src/security/api-key-auth.ts +17 -3
- 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 +70 -22
- package/src/transport/dispatch/attempt-loop.ts +22 -0
- 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 +21 -1
- package/src/transport/guards/auth-guard.ts +0 -6
- package/src/transport/guards/body-policy.ts +3 -3
- package/src/transport/guards/error-lifecycle.ts +4 -0
- 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 +7 -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 +159 -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/reasoning-summary.ts +9 -14
- 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 +431 -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 +0 -1
- package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +0 -1
- 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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/ToolIcon-K1ckcDKg.js +0 -1
- package/dist/dashboard/assets/ToolIcon-K1ckcDKg.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-BayTTy01.js +0 -9
- package/dist/dashboard/assets/app-BayTTy01.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 +0 -1
- 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 +0 -1
- 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 +0 -1
- 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/mutation-Rr0TIvcj.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/providers/zai-coding-plan.svg +0 -6
- package/dist/dashboard/assets/providers/zai-coding-plan.svg.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/console/cli-tools/injectors/cline.ts +0 -110
- package/src/console/cli-tools/injectors/copilot.ts +0 -108
- package/src/console/cli-tools/injectors/cowork.ts +0 -64
- package/src/console/cli-tools/injectors/deepseek-tui.ts +0 -85
- package/src/console/cli-tools/injectors/droid.ts +0 -96
- package/src/console/cli-tools/injectors/grok-build.ts +0 -70
- package/src/console/cli-tools/injectors/hermes.ts +0 -101
- package/src/console/cli-tools/injectors/jcode.ts +0 -115
- package/src/console/cli-tools/injectors/openclaw.ts +0 -161
- 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/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
- /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
|
@@ -41,6 +41,77 @@ const MIN_TOKEN_LENGTH = 20;
|
|
|
41
41
|
*/
|
|
42
42
|
const SHARE_STATS_STREAM_INTERVAL_MS = 30_000;
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* A subscriber of the process-wide share-stats sampler. A recipient is keyed
|
|
46
|
+
* by its family (`tenantId` + template key) so one sampler tick can push to
|
|
47
|
+
* many links without a per-connection timer.
|
|
48
|
+
*/
|
|
49
|
+
type ShareStatsListener = (family: ShareFamilyStats) => void;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* One sampler per gateway for share-stats SSE delivery. Previously each
|
|
53
|
+
* `/share/:token/stats/stream` connection ran its own 30s timer and re-read
|
|
54
|
+
* the family rollup; with N open tabs that is N timers and N rollups all
|
|
55
|
+
* reading the same data. Now a single process-level sampler ticks on the
|
|
56
|
+
* shared cadence and fans each computed rollup out to the subscribers whose
|
|
57
|
+
* family it matches. Timers run only while at least one stream is open.
|
|
58
|
+
*/
|
|
59
|
+
function createShareStatsSampler(config: {
|
|
60
|
+
readonly db: CartethyiaDatabase;
|
|
61
|
+
readonly shareStore: ShareLinkStore;
|
|
62
|
+
readonly stats: ShareStatsPort;
|
|
63
|
+
}): { subscribe(token: string, listener: ShareStatsListener): () => void } {
|
|
64
|
+
const subscribers = new Map<string, Set<ShareStatsListener>>();
|
|
65
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
66
|
+
|
|
67
|
+
const tick = async (): Promise<void> => {
|
|
68
|
+
// One resolve per family token: a recipient with several tabs shares one
|
|
69
|
+
// rollup, and a family with no open stream is never computed.
|
|
70
|
+
const tokens = new Set(subscribers.keys());
|
|
71
|
+
for (const token of tokens) {
|
|
72
|
+
const listeners = subscribers.get(token);
|
|
73
|
+
if (listeners === undefined || listeners.size === 0) continue;
|
|
74
|
+
try {
|
|
75
|
+
const family = await resolveFamilyStats(config.db, config.shareStore, config.stats, token);
|
|
76
|
+
if (family === null) continue;
|
|
77
|
+
for (const listener of listeners) listener(family);
|
|
78
|
+
} catch {
|
|
79
|
+
// A transient read must not interrupt the sampler.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const start = (): void => {
|
|
85
|
+
if (timer !== undefined) return;
|
|
86
|
+
timer = setTimeout(async function run() {
|
|
87
|
+
timer = setTimeout(run, SHARE_STATS_STREAM_INTERVAL_MS);
|
|
88
|
+
await tick();
|
|
89
|
+
}, SHARE_STATS_STREAM_INTERVAL_MS);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const stop = (): void => {
|
|
93
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
94
|
+
timer = undefined;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
subscribe(token, listener) {
|
|
99
|
+
let listeners = subscribers.get(token);
|
|
100
|
+
if (listeners === undefined) {
|
|
101
|
+
listeners = new Set();
|
|
102
|
+
subscribers.set(token, listeners);
|
|
103
|
+
}
|
|
104
|
+
listeners.add(listener);
|
|
105
|
+
if (subscribers.size > 0) start();
|
|
106
|
+
return () => {
|
|
107
|
+
listeners.delete(listener);
|
|
108
|
+
if (listeners.size === 0) subscribers.delete(token);
|
|
109
|
+
if (subscribers.size === 0) stop();
|
|
110
|
+
};
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
44
115
|
/**
|
|
45
116
|
* Context and capabilities for one allowed model, sourced from the public
|
|
46
117
|
* catalog. Every field is nullable/optional so the page can show what is known
|
|
@@ -56,7 +127,7 @@ export interface ShareModelInfo {
|
|
|
56
127
|
readonly webSearch: boolean;
|
|
57
128
|
}
|
|
58
129
|
|
|
59
|
-
|
|
130
|
+
interface ShareRouterOptions {
|
|
60
131
|
readonly db: CartethyiaDatabase;
|
|
61
132
|
readonly shareStore: ShareLinkStore;
|
|
62
133
|
/** Resolves the normalized client IP through the trusted-proxy boundary. */
|
|
@@ -263,6 +334,12 @@ async function resolveFamilyStats(
|
|
|
263
334
|
/** Creates the public enrollment page and one-time shared-key issuance route. */
|
|
264
335
|
export function createShareRouter(options: ShareRouterOptions): AnyElysia {
|
|
265
336
|
const { db, shareStore } = options;
|
|
337
|
+
// The sampler is shared by every stats stream this router serves; it is a
|
|
338
|
+
// no-op when the composition omits `stats` (tests that do not exercise the
|
|
339
|
+
// stream), because `tick` never runs with no subscribers.
|
|
340
|
+
const statsSampler = options.stats === undefined
|
|
341
|
+
? undefined
|
|
342
|
+
: createShareStatsSampler({ db, shareStore, stats: options.stats });
|
|
266
343
|
|
|
267
344
|
return new Elysia()
|
|
268
345
|
/**
|
|
@@ -296,6 +373,7 @@ export function createShareRouter(options: ShareRouterOptions): AnyElysia {
|
|
|
296
373
|
oneTimeLimit: row.lifetimeTokenBudget,
|
|
297
374
|
requestsPerMinute: row.requestsPerMinute,
|
|
298
375
|
maxConcurrentRequests: row.maxConcurrentRequests,
|
|
376
|
+
concurrencyScope: row.concurrencyScope ?? "family",
|
|
299
377
|
modelPrefix: row.modelPrefix,
|
|
300
378
|
models,
|
|
301
379
|
modelInfo,
|
|
@@ -442,48 +520,38 @@ export function createShareRouter(options: ShareRouterOptions): AnyElysia {
|
|
|
442
520
|
/**
|
|
443
521
|
* Live family activity for the share page's stats section, pushed over SSE.
|
|
444
522
|
*
|
|
445
|
-
* The stream sends one snapshot immediately on connect, then
|
|
446
|
-
*
|
|
447
|
-
* refreshing. Telemetry is buffered server-side and drained in
|
|
448
|
-
* second, so
|
|
449
|
-
* be. Same bearer token and same masked-IP rollup as the one-shot
|
|
450
|
-
* token that stops resolving closes the stream rather than
|
|
523
|
+
* The stream sends one snapshot immediately on connect, then pushes on a
|
|
524
|
+
* shared sampler cadence so the recipient watches the shared quota move
|
|
525
|
+
* instead of refreshing. Telemetry is buffered server-side and drained in
|
|
526
|
+
* under a second, so the sampler's DB re-read is as fresh as an event bus
|
|
527
|
+
* would be. Same bearer token and same masked-IP rollup as the one-shot
|
|
528
|
+
* route; a token that stops resolving closes the stream rather than
|
|
529
|
+
* reporting zeros.
|
|
451
530
|
*/
|
|
452
531
|
.get("/share/:token/stats/stream", async ({ params, request }) => {
|
|
453
532
|
if (typeof params.token !== "string") return notFound();
|
|
454
533
|
const token = params.token;
|
|
455
534
|
if (token.length < MIN_TOKEN_LENGTH) return notFound();
|
|
456
535
|
const stats = options.stats;
|
|
457
|
-
if (!stats
|
|
536
|
+
if (!stats || statsSampler === undefined) {
|
|
537
|
+
return json({ error: { code: "stats_unavailable", message: "Stats are unavailable" } }, 503);
|
|
538
|
+
}
|
|
539
|
+
const sampler = statsSampler;
|
|
458
540
|
return consoleSseResponse(
|
|
459
541
|
createConsoleSseStream(request.signal, (sender) => {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
542
|
+
const unsubscribe = sampler.subscribe(token, (family) => sender.send("stats", family));
|
|
543
|
+
// Bootstrap: deliver the link's current rollup immediately, and close
|
|
544
|
+
// the stream if the token no longer resolves — the same terminal
|
|
545
|
+
// behavior the per-connection timer had on a dead link.
|
|
546
|
+
void resolveFamilyStats(db, shareStore, stats, token).then((family) => {
|
|
465
547
|
if (family === null) {
|
|
466
548
|
sender.send("error", { code: "link_not_found" });
|
|
467
|
-
|
|
468
|
-
|
|
549
|
+
unsubscribe();
|
|
550
|
+
} else {
|
|
551
|
+
sender.send("stats", family);
|
|
469
552
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
const schedule = () => {
|
|
473
|
-
timer = setTimeout(() => {
|
|
474
|
-
if (closed) return;
|
|
475
|
-
void push().finally(() => {
|
|
476
|
-
if (!closed) schedule();
|
|
477
|
-
});
|
|
478
|
-
}, SHARE_STATS_STREAM_INTERVAL_MS);
|
|
479
|
-
};
|
|
480
|
-
void push().finally(() => {
|
|
481
|
-
if (!closed) schedule();
|
|
482
|
-
});
|
|
483
|
-
return () => {
|
|
484
|
-
closed = true;
|
|
485
|
-
clearTimeout(timer);
|
|
486
|
-
};
|
|
553
|
+
}).catch(() => undefined);
|
|
554
|
+
return unsubscribe;
|
|
487
555
|
}),
|
|
488
556
|
);
|
|
489
557
|
})
|
|
@@ -30,7 +30,7 @@ import { cachedRead } from "../shared/read-through-cache";
|
|
|
30
30
|
import { utcDayStart, utcMonthStart } from "../shared/day";
|
|
31
31
|
|
|
32
32
|
/** Totals for the whole share family, all-time plus the windows the UI draws. */
|
|
33
|
-
|
|
33
|
+
interface ShareFamilyTotals {
|
|
34
34
|
readonly requests: number;
|
|
35
35
|
readonly errors: number;
|
|
36
36
|
readonly inputTokens: number;
|
|
@@ -45,7 +45,7 @@ export interface ShareFamilyTotals {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/** One hour bucket of the last 24 hours, oldest first. */
|
|
48
|
-
|
|
48
|
+
interface ShareHourlyBucket {
|
|
49
49
|
/** ISO instant at the top of the hour. */
|
|
50
50
|
readonly hour: string;
|
|
51
51
|
readonly requests: number;
|
|
@@ -53,7 +53,7 @@ export interface ShareHourlyBucket {
|
|
|
53
53
|
readonly tokens: number;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
interface ShareTopModel {
|
|
57
57
|
readonly modelId: string;
|
|
58
58
|
readonly requests: number;
|
|
59
59
|
readonly tokens: number;
|
|
@@ -63,7 +63,7 @@ export interface ShareTopModel {
|
|
|
63
63
|
readonly avgTtfbMs: number | null;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
interface ShareTopClientIp {
|
|
67
67
|
/** Always masked: this payload is served to the recipient, not the tenant. */
|
|
68
68
|
readonly ip: string;
|
|
69
69
|
readonly requests: number;
|
|
@@ -371,11 +371,9 @@ async function computeFamilyStatsBody(
|
|
|
371
371
|
.where(eq(apiKeys.id, templateKeyId))
|
|
372
372
|
.limit(1),
|
|
373
373
|
]);
|
|
374
|
-
// Cumulative family spend: the template's own counter
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
// likewise stay counted, so the running total is monotonic and consistent
|
|
378
|
-
// across the overview, the share dialog, and this page.
|
|
374
|
+
// Cumulative family spend: the template's own counter is the live
|
|
375
|
+
// accumulator (updated by every recipient commit), so it IS the total.
|
|
376
|
+
// Telemetry still drives the bounded daily/monthly windows below.
|
|
379
377
|
const templateLifetime = Number(template[0]?.lifetime ?? 0);
|
|
380
378
|
|
|
381
379
|
// The ranked tables need real events, bounded to the 24-hour window. The
|
|
@@ -398,10 +396,10 @@ async function computeFamilyStatsBody(
|
|
|
398
396
|
});
|
|
399
397
|
rollup.totals = {
|
|
400
398
|
...rollup.totals,
|
|
401
|
-
// The template counter
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
totalTokens: templateLifetime
|
|
399
|
+
// The template counter IS the running family total (live accumulator).
|
|
400
|
+
// Daily/monthly windows stay telemetry-only (the counter has no time
|
|
401
|
+
// axis), so those keep their own sums.
|
|
402
|
+
totalTokens: templateLifetime,
|
|
405
403
|
todayTokens,
|
|
406
404
|
monthTokens,
|
|
407
405
|
// Lifetime counts come from the durable rollup, not the page: a family
|
|
@@ -13,7 +13,7 @@ import { apiKeys, telemetryUsageTotals } from "../../persistence/schema";
|
|
|
13
13
|
import { shouldMaskClientIp } from "../shared/ip-privacy";
|
|
14
14
|
import { utcDayStart } from "../shared/day";
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
interface SharedKeyTokenUsage {
|
|
17
17
|
readonly requests: number;
|
|
18
18
|
readonly errors: number;
|
|
19
19
|
readonly inputTokens: number;
|
|
@@ -7,7 +7,7 @@ import { formatPublicErrorMessage } from "../../protocol/gateway-error";
|
|
|
7
7
|
// (or the storage-layer BackupError, same code/status/message shape) and
|
|
8
8
|
// shapes it through errorResponse; guards narrow to TenantAccessDecision.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
interface ErrorResponseOptions {
|
|
11
11
|
readonly detailsPolicy?: "omit" | "include-if-present" | "always-include";
|
|
12
12
|
}
|
|
13
13
|
|
|
@@ -105,7 +105,7 @@ export function requireAnyScope(
|
|
|
105
105
|
return access;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
type TenantAccessDecision = AccessDecision & { readonly tenantId: string };
|
|
109
109
|
|
|
110
110
|
export function requireTenantScope(
|
|
111
111
|
access: AccessDecision | undefined,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds an object from `source`, omitting absent values.
|
|
3
|
+
*
|
|
4
|
+
* The console domains hand-roll the same `...(x === undefined ? {} : { x })`
|
|
5
|
+
* field-omission spread many times (key create/update patches, response
|
|
6
|
+
* sanitizers). This is the single helper for that pattern; `omitNull` extends
|
|
7
|
+
* it to also drop `null` values (the `== null` variant), matching call sites
|
|
8
|
+
* that treat null as "clear this field" rather than "set it to null".
|
|
9
|
+
*/
|
|
10
|
+
export function pickDefined<T extends object>(source: T, omitNull = false): { [K in keyof T]?: Exclude<T[K], undefined> } {
|
|
11
|
+
const out: Record<string, unknown> = {};
|
|
12
|
+
for (const [key, value] of Object.entries(source)) {
|
|
13
|
+
if (value === undefined) continue;
|
|
14
|
+
if (omitNull && value === null) continue;
|
|
15
|
+
out[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return out as { [K in keyof T]?: Exclude<T[K], undefined> };
|
|
18
|
+
}
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
import { createHash } from "node:crypto";
|
|
32
32
|
|
|
33
33
|
/** The slice of Redis this cache needs, so it can be tested without a server. */
|
|
34
|
-
|
|
34
|
+
interface ReadThroughCacheClient {
|
|
35
35
|
get(key: string): Promise<string | null>;
|
|
36
36
|
set(key: string, value: string, mode: "EX", ttlSeconds: number): Promise<unknown>;
|
|
37
37
|
}
|
|
@@ -41,7 +41,7 @@ export interface ReadThroughCacheClient {
|
|
|
41
41
|
* more often pass a shorter TTL; this value suits the dashboard's polling
|
|
42
42
|
* cadence and the append-only telemetry log.
|
|
43
43
|
*/
|
|
44
|
-
|
|
44
|
+
const READ_THROUGH_DEFAULT_TTL_SECONDS = 10;
|
|
45
45
|
|
|
46
46
|
/** The cached value plus the strong validator for the bytes it serializes to. */
|
|
47
47
|
export interface CachedResult<T> {
|
|
@@ -59,7 +59,7 @@ function etagFor(bytes: string): string {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/** The sibling key holding the validator, so a cached body is never re-hashed. */
|
|
62
|
-
|
|
62
|
+
function etagKey(key: string): string {
|
|
63
63
|
return `${key}:etag`;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -196,7 +196,7 @@ export function conditionalResponse<T>(
|
|
|
196
196
|
}
|
|
197
197
|
|
|
198
198
|
/** True when an `If-None-Match` header names this validator. */
|
|
199
|
-
|
|
199
|
+
function matchesEtag(header: string | null, etag: string): boolean {
|
|
200
200
|
if (header === null) return false;
|
|
201
201
|
const trimmed = header.trim();
|
|
202
202
|
if (trimmed === "*") return true;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CartethyiaDatabase } from "../../persistence/db-handle";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Casts a Drizzle nested-transaction handle to the shared database type.
|
|
5
|
+
*
|
|
6
|
+
* Drizzle types a nested transaction callback with the dialect's own
|
|
7
|
+
* transaction handle, which differs from `CartethyiaDatabase`. The cast is
|
|
8
|
+
* required (both drivers implement the surface stores use), but it is a type
|
|
9
|
+
* hole every time it appears raw — so it is centralized here rather than
|
|
10
|
+
* scattered across call sites.
|
|
11
|
+
*/
|
|
12
|
+
export function asConsoleDb(tx: unknown): CartethyiaDatabase {
|
|
13
|
+
return tx as unknown as CartethyiaDatabase;
|
|
14
|
+
}
|
|
@@ -16,33 +16,70 @@ export interface PromptSetting {
|
|
|
16
16
|
export const PROMPT_MODES = ["append", "override"] as const;
|
|
17
17
|
export type PromptMode = (typeof PROMPT_MODES)[number];
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/**
|
|
20
|
+
* A named, reusable prompt. Scopes reference presets by id instead of each
|
|
21
|
+
* carrying its own text, so one tone/ruleset can be applied to many scopes.
|
|
22
|
+
*/
|
|
23
|
+
export interface SystemPromptPreset {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly enabled: boolean;
|
|
27
|
+
readonly mode: PromptMode;
|
|
28
|
+
readonly text: string;
|
|
24
29
|
}
|
|
25
30
|
|
|
31
|
+
/**
|
|
32
|
+
* How one scope decides what to inject. Modes:
|
|
33
|
+
*
|
|
34
|
+
* - `off` — explicitly inject nothing for this scope; scope-specific stop,
|
|
35
|
+
* does NOT fall through to the global prompt.
|
|
36
|
+
* - `global` — follow the tenant's global prompt (the default posture).
|
|
37
|
+
* - `preset` — use the referenced named preset (disabled preset = no inject).
|
|
38
|
+
* - `custom` — carry this scope's own prompt inline.
|
|
39
|
+
*
|
|
40
|
+
* A scope with no entry at all behaves as `global` (resolution falls through
|
|
41
|
+
* to the global prompt), so omitting a key is the same as an explicit
|
|
42
|
+
* `{ kind: "global" }` reference. The global scope itself never uses
|
|
43
|
+
* `{ kind: "global" }` — it is `null` (off), a preset, or a custom setting.
|
|
44
|
+
*/
|
|
45
|
+
export type ScopePromptRef =
|
|
46
|
+
| { readonly kind: "off" }
|
|
47
|
+
| { readonly kind: "global" }
|
|
48
|
+
| { readonly kind: "preset"; readonly presetId: string }
|
|
49
|
+
| { readonly kind: "custom"; readonly setting: PromptSetting };
|
|
50
|
+
|
|
26
51
|
/** The full per-tenant configuration, one row in `tenant_system_prompts`. */
|
|
27
52
|
export interface TenantSystemPrompts {
|
|
28
|
-
/** `null` =
|
|
29
|
-
readonly global:
|
|
30
|
-
/**
|
|
31
|
-
readonly
|
|
32
|
-
/**
|
|
33
|
-
readonly
|
|
53
|
+
/** `null` = no global injection — distinct from an explicit disabled setting. */
|
|
54
|
+
readonly global: ScopePromptRef | null;
|
|
55
|
+
/** preset id → preset */
|
|
56
|
+
readonly presets: Readonly<Record<string, SystemPromptPreset>>;
|
|
57
|
+
/** providerId → ref */
|
|
58
|
+
readonly providers: Readonly<Record<string, ScopePromptRef>>;
|
|
59
|
+
/** `${providerId}::${modelId}` → ref */
|
|
60
|
+
readonly models: Readonly<Record<string, ScopePromptRef>>;
|
|
61
|
+
/** combo name → ref */
|
|
62
|
+
readonly combos: Readonly<Record<string, ScopePromptRef>>;
|
|
63
|
+
/** alias name → ref */
|
|
64
|
+
readonly aliases: Readonly<Record<string, ScopePromptRef>>;
|
|
34
65
|
}
|
|
35
66
|
|
|
36
67
|
/** Empty configuration: nothing configured anywhere. */
|
|
37
68
|
export const EMPTY_TENANT_SYSTEM_PROMPTS: TenantSystemPrompts = {
|
|
38
69
|
global: null,
|
|
70
|
+
presets: {},
|
|
39
71
|
providers: {},
|
|
40
72
|
models: {},
|
|
73
|
+
combos: {},
|
|
74
|
+
aliases: {},
|
|
41
75
|
};
|
|
42
76
|
|
|
43
77
|
/** Maximum stored text per scope (5 MB). Enforced at the console API. */
|
|
44
78
|
export const SYSTEM_PROMPT_TEXT_CAP_BYTES = 5_000_000;
|
|
45
79
|
|
|
80
|
+
/** Maximum stored preset-name length. Enforced at the console API. */
|
|
81
|
+
export const SYSTEM_PROMPT_PRESET_NAME_CAP = 200;
|
|
82
|
+
|
|
46
83
|
/**
|
|
47
84
|
* Marker wrapping tenant text injected into a provider wire whose upstream
|
|
48
85
|
* validates the system prompt as a channel identity (the buddy family). The
|
|
@@ -52,12 +89,21 @@ export const SYSTEM_PROMPT_TEXT_CAP_BYTES = 5_000_000;
|
|
|
52
89
|
export const SYSTEM_PROMPT_WRAPPER_PREFIX = "<cartethyia:system-prompt>";
|
|
53
90
|
export const SYSTEM_PROMPT_WRAPPER_SUFFIX = "</cartethyia:system-prompt>";
|
|
54
91
|
|
|
92
|
+
/** Maximum number of presets stored for one tenant. */
|
|
93
|
+
export const SYSTEM_PROMPT_PRESET_LIMIT = 64;
|
|
94
|
+
|
|
55
95
|
/** Maximum number of per-provider entries stored for one tenant. */
|
|
56
96
|
export const SYSTEM_PROMPT_PROVIDER_LIMIT = 256;
|
|
57
97
|
|
|
58
98
|
/** Maximum number of per-model entries stored for one tenant. */
|
|
59
99
|
export const SYSTEM_PROMPT_MODEL_LIMIT = 512;
|
|
60
100
|
|
|
101
|
+
/** Maximum number of per-combo entries stored for one tenant. */
|
|
102
|
+
export const SYSTEM_PROMPT_COMBO_LIMIT = 512;
|
|
103
|
+
|
|
104
|
+
/** Maximum number of per-alias entries stored for one tenant. */
|
|
105
|
+
export const SYSTEM_PROMPT_ALIAS_LIMIT = 512;
|
|
106
|
+
|
|
61
107
|
/**
|
|
62
108
|
* Providers whose upstream validates the fixed system prompt as a channel
|
|
63
109
|
* identity. Their system turn must keep the fixed prompt as the opener, so
|
|
@@ -66,7 +112,7 @@ export const SYSTEM_PROMPT_MODEL_LIMIT = 512;
|
|
|
66
112
|
* `override` mode is not honoured for these providers — it would strip the
|
|
67
113
|
* identity and the upstream would refuse the request.
|
|
68
114
|
*/
|
|
69
|
-
|
|
115
|
+
const WRAPPED_INJECTION_PROVIDERS: ReadonlySet<string> = new Set([
|
|
70
116
|
"cb", // CodeBuddy International
|
|
71
117
|
"cbcn", // CodeBuddy CN
|
|
72
118
|
"workbuddy",
|
|
@@ -100,3 +146,34 @@ export function isPromptSetting(value: unknown): value is PromptSetting {
|
|
|
100
146
|
typeof candidate.text === "string"
|
|
101
147
|
);
|
|
102
148
|
}
|
|
149
|
+
|
|
150
|
+
/** True when the value is a well-formed preset (shape only, not size). */
|
|
151
|
+
export function isSystemPromptPreset(value: unknown): value is SystemPromptPreset {
|
|
152
|
+
if (typeof value !== "object" || value === null) return false;
|
|
153
|
+
const candidate = value as Partial<SystemPromptPreset>;
|
|
154
|
+
return (
|
|
155
|
+
typeof candidate.id === "string" &&
|
|
156
|
+
candidate.id.length > 0 &&
|
|
157
|
+
typeof candidate.name === "string" &&
|
|
158
|
+
candidate.name.length > 0 &&
|
|
159
|
+
typeof candidate.enabled === "boolean" &&
|
|
160
|
+
typeof candidate.mode === "string" &&
|
|
161
|
+
(PROMPT_MODES as readonly string[]).includes(candidate.mode) &&
|
|
162
|
+
typeof candidate.text === "string"
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** True when the value is a well-formed scope reference (shape only). */
|
|
167
|
+
export function isScopePromptRef(value: unknown): value is ScopePromptRef {
|
|
168
|
+
if (typeof value !== "object" || value === null) return false;
|
|
169
|
+
const kind = (value as { kind?: unknown }).kind;
|
|
170
|
+
if (kind === "off" || kind === "global") return true;
|
|
171
|
+
if (kind === "preset") {
|
|
172
|
+
const presetId = (value as { presetId?: unknown }).presetId;
|
|
173
|
+
return typeof presetId === "string" && presetId.length > 0;
|
|
174
|
+
}
|
|
175
|
+
if (kind === "custom") {
|
|
176
|
+
return isPromptSetting((value as { setting?: unknown }).setting);
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|