cartethyia 2.5.3 → 2.5.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 +13 -4
- package/README.md +2 -2
- package/dist/dashboard/assets/{BannedPage-hfCzi-Ux.js → BannedPage-CADDq4IU.js} +1 -1
- package/dist/dashboard/assets/BannedPage-CADDq4IU.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js +1 -0
- package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DEDyKBlC.js → CliToolsPage-DuO1Z7dq.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-DuO1Z7dq.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DNEPi3xU.js +1 -0
- package/dist/dashboard/assets/CombosPage-DNEPi3xU.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-bsLuZmYH.js → ConsoleLogPage-BVdpfiz1.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-BVdpfiz1.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-_UWhwziJ.js → CustomizationPage-BR5HHvbi.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-BR5HHvbi.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-DDVIfZGW.js → LoginPage-V5faV9V2.js} +1 -1
- package/dist/dashboard/assets/LoginPage-V5faV9V2.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C7pDb41R.js +1 -0
- package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js +7 -0
- package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js +1 -0
- package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-D6pmQ86L.js → SetupPage-UB690SE2.js} +1 -1
- package/dist/dashboard/assets/SetupPage-UB690SE2.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-DWvKiuSl.js → SortableList-BLujdX7N.js} +1 -1
- package/dist/dashboard/assets/SortableList-BLujdX7N.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CmkUrgdj.js → StudioPage-D5C2raAc.js} +3 -3
- package/dist/dashboard/assets/StudioPage-D5C2raAc.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-8uIcxa1W.js +56 -0
- package/dist/dashboard/assets/UsagePage-8uIcxa1W.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js +1 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css +2 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
- package/dist/dashboard/assets/{assert-NHwYq95t.js → assert-C9FD_JwJ.js} +1 -1
- package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
- package/dist/dashboard/assets/{badge-6uzDDvqs.js → badge-CR72dasT.js} +1 -1
- package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
- package/dist/dashboard/assets/{banner-4_WNg2WZ.js → banner-CI9_eSfO.js} +1 -1
- package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
- package/dist/dashboard/assets/{card--AtFedAq.js → card-DS7CQEsO.js} +1 -1
- package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-B3e7dx3N.js → cli-tools-CNqzrfdb.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-NreUx6c8.js → clipboard-button-611pSsaX.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
- package/dist/dashboard/assets/{fingerprint-pattern-BWuHtbW4.js → concurrency-BDF0ok7y.js} +1 -1
- package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js +1 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js.gz +0 -0
- package/dist/dashboard/assets/dialog-k37exjNt.js +1 -0
- package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
- package/dist/dashboard/assets/drawer-CX7N8ucR.js +1 -0
- package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
- package/dist/dashboard/assets/entry-B9Xvtnfj.js +1 -0
- package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
- package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
- package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
- package/dist/dashboard/assets/entry-DxBHnauy.js +4 -0
- package/dist/dashboard/assets/entry-DxBHnauy.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-D_eM3IgG.js → github-badge-sltk1qUi.js} +1 -1
- package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
- package/dist/dashboard/assets/{index-BydyKaDz.js → index-CmxZr14F.js} +2 -2
- package/dist/dashboard/assets/index-CmxZr14F.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BcNGF8Gr.js → inline-BhY2sSnO.js} +1 -1
- package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
- package/dist/dashboard/assets/{input-BG41et9G.js → input-V1umFiBk.js} +1 -1
- package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
- package/dist/dashboard/assets/layout-BBOYycyS.js +1 -0
- package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Gh_W4OR_.js → list-row-1zzZYM0B.js} +1 -1
- package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
- package/dist/dashboard/assets/{live-BJGYRBnR.js → live-BivGfuUs.js} +1 -1
- package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-CmffjLuG.js +1 -0
- package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-BkoLM5Ba.js → mutation-46P0oWMe.js} +1 -1
- package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
- package/dist/dashboard/assets/numbers-DkfMR5Qs.js +2 -0
- package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js → query-keys-BFhGpwR1.js} +1 -1
- package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
- package/dist/dashboard/assets/{routing-CcusqXA7.js → routing-CAb4F37R.js} +1 -1
- package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
- package/dist/dashboard/assets/{select-BO6h8yNv.js → select-BYR_5K2c.js} +2 -2
- package/dist/dashboard/assets/select-BYR_5K2c.js.gz +0 -0
- package/dist/dashboard/assets/{settings-mpmXTgUa.js → settings-DNX9sydi.js} +1 -1
- package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DwLmjUFK.js → stack-BHTfXdz_.js} +1 -1
- package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
- package/dist/dashboard/assets/{state-DYdQmdAl.js → state-mPDRlQkl.js} +1 -1
- package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
- package/dist/dashboard/assets/switch-DOmJxg7H.js +1 -0
- package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js +1 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js.gz +0 -0
- package/dist/dashboard/assets/tokens-COzario9.js +1 -0
- package/dist/dashboard/assets/tokens-COzario9.js.gz +0 -0
- package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js +1 -0
- package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-w4u4CVue.js → useMutation-Dem0lXQj.js} +1 -1
- package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js +1 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js.gz +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +57 -57
- package/migrations/README.md +52 -52
- package/migrations/lite-sqlite3/0000_baseline.sql +2 -2
- package/package.json +96 -95
- package/scripts/cli/admin.ts +125 -0
- package/scripts/cli/autostart.ts +237 -0
- package/scripts/cli/{ui/background.ts → background.ts} +1 -1
- package/scripts/cli/{command/console-menu.ts → console-menu.ts} +275 -248
- package/scripts/cli/doctor.ts +37 -0
- package/scripts/cli/{support/env.ts → env.ts} +99 -99
- package/scripts/cli/{gateway/spawn.ts → gateway.ts} +112 -24
- package/scripts/cli/instance.ts +224 -0
- package/scripts/cli/main.ts +88 -18
- package/scripts/cli/{support/platform.ts → platform.ts} +64 -64
- package/scripts/cli/port.ts +100 -0
- package/scripts/cli/{support/services.ts → services.ts} +88 -88
- package/scripts/cli/{command/setup.ts → setup.ts} +35 -34
- package/scripts/cli/{command/start.ts → start.ts} +10 -5
- package/scripts/cli/{support/startup-signal.ts → startup-signal.ts} +23 -23
- package/scripts/cli/tray/index.ts +62 -12
- package/scripts/cli/{command/tray.ts → tray.ts} +208 -208
- package/scripts/cli/update.ts +40 -0
- package/scripts/cli/version.ts +67 -0
- package/scripts/cli/{ui/wordmark.ts → wordmark.ts} +58 -58
- package/src/boot/app.ts +11 -7
- package/src/boot/dependencies.ts +50 -19
- package/src/boot/timeout.ts +2 -13
- package/src/config/cooldowns.ts +186 -138
- package/src/config/network.ts +8 -14
- package/src/config/providers.ts +7 -10
- package/src/config/runtime.ts +76 -76
- package/src/config/security.ts +15 -0
- package/src/config/spec.ts +52 -7
- package/src/config/telemetry.ts +26 -0
- package/src/config/timeouts.ts +0 -6
- package/src/console/admin/model-abuse/contracts.ts +28 -6
- package/src/console/admin/model-abuse/routes.ts +56 -3
- package/src/console/api-keys/bucket-spend.ts +15 -4
- package/src/console/api-keys/contracts.ts +410 -414
- package/src/console/api-keys/routes.ts +881 -880
- package/src/console/auth/credentials.ts +3 -3
- package/src/console/auth/setup-service.ts +2 -2
- package/src/console/backup/contracts.ts +15 -2
- package/src/console/backup/export-endpoint.ts +6 -2
- package/src/console/backup/nine-router.ts +2 -5
- package/src/console/backup/service.ts +4 -0
- package/src/console/backup/store.ts +192 -29
- package/src/console/backup/validate.ts +3 -45
- package/src/console/cli-tools/fs-ops.ts +487 -487
- package/src/console/console-router-guards.ts +1 -1
- package/src/console/console-router.ts +8 -0
- package/src/console/data-management/contracts.ts +100 -0
- package/src/console/data-management/operations.ts +234 -0
- package/src/console/data-management/routes.ts +103 -0
- package/src/console/domain-registration.ts +45 -1
- package/src/console/observability/contracts.ts +524 -485
- package/src/console/observability/live.ts +22 -0
- package/src/console/observability/store.ts +1138 -1018
- package/src/console/observability/usage-dimensions.ts +4 -4
- package/src/console/providers/catalog/catalog-projections.ts +6 -7
- package/src/console/providers/catalog/contracts.ts +6 -0
- package/src/console/providers/catalog/model-operations.ts +5 -2
- package/src/console/providers/catalog/provider-operations.ts +24 -4
- package/src/console/providers/catalog/public-model-store.ts +8 -11
- package/src/console/providers/catalog/routes.ts +7 -0
- package/src/console/providers/catalog/store.ts +1553 -1532
- package/src/console/providers/oauth/routes.ts +8 -12
- package/src/console/quota/account-quota-shared.ts +52 -39
- package/src/console/quota/account-quota-tenant.ts +6 -6
- package/src/console/quota/quota-view.ts +1 -1
- package/src/console/quota/refresh.ts +441 -429
- package/src/console/remote-support/contracts.ts +61 -0
- package/src/console/remote-support/routes.ts +65 -0
- package/src/console/remote-support/service.ts +207 -0
- package/src/console/response-compression.ts +0 -3
- package/src/console/routing/pools/import-parse.ts +206 -0
- package/src/console/routing/pools/operations.ts +543 -501
- package/src/console/routing/pools/probe-result.ts +3 -2
- package/src/console/routing/pools/probe-verdict.ts +132 -132
- package/src/console/routing/pools/routes.ts +181 -164
- package/src/console/routing/pools/store.ts +8 -8
- package/src/console/settings/contracts.ts +95 -2
- package/src/console/settings/store.ts +81 -3
- package/src/console/shared/cursor.ts +8 -8
- package/src/console/shared/errors.ts +1 -3
- package/src/console/updates/routes.ts +16 -0
- package/src/main.ts +10 -0
- package/src/network/http2-bidi.ts +2 -4
- package/src/network/pool/agent.ts +478 -478
- package/src/network/pool/selector.ts +5 -4
- package/src/network/retry.ts +1 -2
- package/src/network/ssrf.ts +5 -4
- package/src/observability/event-compaction.ts +317 -0
- package/src/observability/event-day-index.ts +440 -0
- package/src/observability/event-log.ts +155 -6
- package/src/observability/logger.ts +6 -6
- package/src/observability/payload-capture.ts +158 -33
- package/src/observability/payload-store.ts +82 -61
- package/src/observability/redaction.ts +5 -6
- package/src/observability/request-notify.ts +43 -0
- package/src/observability/telemetry-status.ts +8 -9
- package/src/observability/token-speed.ts +5 -4
- package/src/persistence/db-mode.ts +7 -7
- package/src/persistence/health-event-flush.ts +36 -0
- package/src/persistence/readiness.ts +1 -1
- package/src/persistence/schema.ts +75 -29
- package/src/persistence/shared-cache.ts +1 -2
- package/src/persistence/stores/api-key-store.ts +18 -6
- package/src/persistence/stores/share-store.ts +4 -3
- package/src/persistence/stores/telemetry-store.ts +33 -11
- package/src/protocol/canonical-model.ts +11 -3
- package/src/protocol/codecs.ts +139 -6
- package/src/protocol/gateway-error.ts +6 -4
- package/src/protocol/image-clamp.ts +19 -1
- package/src/protocol/registry.ts +8 -0
- package/src/protocol/request/chat.ts +21 -1
- package/src/protocol/request/codex.ts +10 -1
- package/src/protocol/request/gemini.ts +9 -2
- package/src/protocol/request/messages.ts +18 -7
- package/src/protocol/request/responses.ts +9 -1
- package/src/protocol/response/chat.ts +34 -4
- package/src/protocol/response/codex.ts +7 -4
- package/src/protocol/response/dsml.ts +140 -28
- package/src/protocol/response/responses.ts +11 -5
- package/src/protocol/stream-error-frames.ts +4 -5
- package/src/providers/adapters/compatible-adapter.ts +3 -0
- package/src/providers/authentication/jwt-validator.ts +9 -10
- package/src/providers/authentication/oauth-refresh-service.ts +9 -11
- package/src/providers/bundled-discovery-providers.ts +122 -119
- package/src/providers/configured-openai-providers.ts +4 -4
- package/src/providers/default-registry.ts +5 -4
- package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
- package/src/providers/discovery/catalog/catalog-format.ts +3 -6
- package/src/providers/discovery/models-dev-catalog.ts +354 -354
- package/src/providers/discovery/openai-model-discovery.ts +5 -0
- package/src/providers/discovery/openrouter-free-roster.ts +15 -17
- package/src/providers/discovery/probe-phases.ts +4 -4
- package/src/providers/discovery/probe-wire.ts +6 -13
- package/src/providers/discovery/probing-service.ts +1117 -1045
- package/src/providers/integrations/alibabacp/alibabacp.ts +1 -1
- package/src/providers/integrations/antigravity/antigravity-quota.ts +5 -7
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +23 -2
- package/src/providers/integrations/buddy/buddy-checkin.ts +1 -4
- package/src/providers/integrations/buddy/buddy-cli-headers.ts +23 -6
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -1
- package/src/providers/integrations/buddy/buddy-identity.ts +52 -0
- package/src/providers/integrations/buddy/buddy-media.ts +2 -2
- package/src/providers/integrations/buddy/buddy-usage-store.ts +3 -4
- package/src/providers/integrations/buddy/codebuddy/quota.ts +2 -13
- package/src/providers/integrations/buddy/codebuddy/shared.ts +118 -115
- package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -11
- package/src/providers/integrations/buddy/workbuddy/shared.ts +5 -2
- package/src/providers/integrations/claude/claude.ts +608 -608
- package/src/providers/integrations/cline/cline-quota.ts +27 -20
- package/src/providers/integrations/cline/cline.ts +537 -539
- package/src/providers/integrations/codex/codex-headers.ts +25 -39
- package/src/providers/integrations/codex/codex-oauth.ts +1 -1
- package/src/providers/integrations/codex/codex.ts +2 -29
- package/src/providers/integrations/commandcode/commandcode.ts +674 -675
- package/src/providers/integrations/commandcode/discovery.ts +117 -116
- package/src/providers/integrations/cursor/cursor-auth.ts +418 -418
- package/src/providers/integrations/cursor/cursor-quota.ts +309 -0
- package/src/providers/integrations/cursor/cursor-request.ts +616 -471
- package/src/providers/integrations/cursor/cursor-session-manager.ts +319 -281
- package/src/providers/integrations/cursor/cursor.ts +1333 -960
- package/src/providers/integrations/cursor/protocol/messages.ts +25 -0
- package/src/providers/integrations/factory/factory-models.ts +3 -5
- package/src/providers/integrations/factory/factory.ts +8 -1
- package/src/providers/integrations/gemini.ts +6 -1
- package/src/providers/integrations/grok/grok-install-id.ts +2 -3
- package/src/providers/integrations/grok/grok-quota.ts +279 -177
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -0
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -0
- package/src/providers/integrations/grok/grok.ts +6 -7
- package/src/providers/integrations/hermes.ts +14 -18
- package/src/providers/integrations/kiro/kiro-discovery.ts +1 -1
- package/src/providers/integrations/kiro/kiro.ts +1 -1
- package/src/providers/integrations/mistral.ts +6 -6
- package/src/providers/integrations/opencode/fingerprint.ts +3 -3
- package/src/providers/integrations/opencode/provider.ts +19 -20
- package/src/providers/integrations/qoder/qoder-catalog.ts +450 -450
- package/src/providers/integrations/qoder/qoder-oauth.ts +388 -310
- package/src/providers/integrations/qoder/qoder-quota.ts +192 -0
- package/src/providers/integrations/qoder/qoder.ts +884 -865
- package/src/providers/integrations/shared/connect.ts +6 -6
- package/src/providers/integrations/trae/trae-catalog.ts +1 -2
- package/src/providers/integrations/trae/trae-quota.ts +384 -0
- package/src/providers/integrations/trae/trae.ts +2 -2
- package/src/providers/integrations/zcode/oauth.ts +6 -1
- package/src/providers/operations/account-health-service.ts +75 -27
- package/src/providers/operations/account-reset-service.ts +1 -1
- package/src/providers/operations/client-versions.ts +6 -6
- package/src/providers/operations/custom-cli-headers.ts +3 -4
- package/src/providers/operations/provider-catalog-seeder.ts +95 -95
- package/src/providers/operations/provider-catalog-service.ts +3 -4
- package/src/providers/provider-contracts.ts +7 -0
- package/src/providers/provider-metadata.ts +10 -8
- package/src/providers/provider-registry.ts +6 -7
- package/src/providers/provider-usage.ts +1 -1
- package/src/providers/quota/quota-support.ts +8 -0
- package/src/security/abuse.ts +15 -10
- package/src/security/access-control.ts +144 -146
- package/src/security/admission/contracts.ts +11 -0
- package/src/security/admission/in-memory-store.ts +4 -3
- package/src/security/admission/lease-sweep.ts +6 -6
- package/src/security/admission/reasons.ts +5 -1
- package/src/security/admission/redis-store.ts +211 -210
- package/src/security/admission/service.ts +4 -0
- package/src/security/api-key-auth.ts +27 -17
- package/src/security/ip-boundary.ts +155 -15
- package/src/security/model-abuse.ts +366 -94
- package/src/security/outbound-headers.ts +3 -4
- package/src/shared/sleep.ts +4 -0
- package/src/transport/dispatch/attempt-finalize.ts +47 -5
- package/src/transport/dispatch/attempt-loop.ts +531 -530
- package/src/transport/dispatch/generation.ts +6 -0
- package/src/transport/dispatch/proxy-request.ts +24 -1
- package/src/transport/dispatch/ratelimit-capture.ts +37 -0
- package/src/transport/dispatch/stream-bridge.ts +1 -3
- package/src/transport/dispatch/streaming/finalize.ts +1 -1
- package/src/transport/dispatch/streaming/stream.ts +19 -6
- package/src/transport/dispatch/upstream.ts +9 -0
- package/src/transport/failure-policy.ts +162 -8
- package/src/transport/guards/auth-guard.ts +7 -4
- package/src/transport/guards/concurrency-guard.ts +0 -5
- package/src/transport/guards/error-lifecycle.ts +13 -6
- package/src/transport/guards/pipeline.ts +15 -3
- package/src/transport/guards/request-context.ts +8 -2
- package/src/transport/request/inflight.ts +5 -6
- package/src/transport/request/preparer.ts +9 -8
- package/src/transport/request/state.ts +21 -8
- package/src/transport/request/tenant-preferences.ts +60 -0
- package/src/transport/routing/admission.ts +4 -0
- package/src/transport/routing/route-catalog.ts +65 -10
- package/src/transport/routing/route-model.ts +46 -14
- package/src/transport/routing/router.ts +21 -14
- package/src/transport/surface/completion.ts +2 -3
- package/src/transport/surface/dialects.ts +5 -6
- package/src/transport/surface/responses/encode.ts +38 -0
- package/src/transport/surface/responses/parse.ts +4 -0
- package/src/transport/translation/capabilities.ts +2 -3
- package/src/transport/translation/quirks.ts +3 -3
- package/src/workers/buddy-growth-tasks.ts +5 -10
- package/src/workers/daily-checkin.ts +17 -23
- package/src/workers/quota-refresh-sweep.ts +26 -26
- package/dist/dashboard/assets/BannedPage-hfCzi-Ux.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DLGqYEwI.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-DLGqYEwI.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DEDyKBlC.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CfuYiQ8Z.js +0 -1
- package/dist/dashboard/assets/CombosPage-CfuYiQ8Z.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-bsLuZmYH.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-_UWhwziJ.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Cjfc5WFS.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-Cjfc5WFS.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DDVIfZGW.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js +0 -1
- package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B53YYMng.js +0 -1
- package/dist/dashboard/assets/OverviewPage-B53YYMng.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-B0KaAQf0.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-B0KaAQf0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Dx31DgIO.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-Dx31DgIO.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BpnR4kXT.js +0 -7
- package/dist/dashboard/assets/ProxyPage-BpnR4kXT.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BpOQCnun.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BpOQCnun.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DV1eo2J_.js +0 -1
- package/dist/dashboard/assets/SettingsPage-DV1eo2J_.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-D6pmQ86L.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DWvKiuSl.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-CmkUrgdj.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B47uOydr.js +0 -56
- package/dist/dashboard/assets/UsagePage-B47uOydr.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-uNywYlfv.js +0 -1
- package/dist/dashboard/assets/api-keys-uNywYlfv.js.gz +0 -0
- package/dist/dashboard/assets/app-DxivpfYG.css +0 -2
- package/dist/dashboard/assets/app-DxivpfYG.css.gz +0 -0
- package/dist/dashboard/assets/assert-NHwYq95t.js.gz +0 -0
- package/dist/dashboard/assets/badge-6uzDDvqs.js.gz +0 -0
- package/dist/dashboard/assets/banner-4_WNg2WZ.js.gz +0 -0
- package/dist/dashboard/assets/card--AtFedAq.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-B3e7dx3N.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-NreUx6c8.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BtpsJU98.js +0 -1
- package/dist/dashboard/assets/dialog-BtpsJU98.js.gz +0 -0
- package/dist/dashboard/assets/download-A0SW9OCW.js +0 -1
- package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-WwwtzihF.js +0 -1
- package/dist/dashboard/assets/drawer-WwwtzihF.js.gz +0 -0
- package/dist/dashboard/assets/entry-CkryrIea.js +0 -4
- package/dist/dashboard/assets/entry-CkryrIea.js.gz +0 -0
- package/dist/dashboard/assets/entry-TJIye_jT.js +0 -1
- package/dist/dashboard/assets/entry-TJIye_jT.js.gz +0 -0
- package/dist/dashboard/assets/entry-jy9_4-Ke.js +0 -1
- package/dist/dashboard/assets/entry-jy9_4-Ke.js.gz +0 -0
- package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-D_eM3IgG.js.gz +0 -0
- package/dist/dashboard/assets/index-BydyKaDz.js.gz +0 -0
- package/dist/dashboard/assets/inline-BcNGF8Gr.js.gz +0 -0
- package/dist/dashboard/assets/input-BG41et9G.js.gz +0 -0
- package/dist/dashboard/assets/layout-C8mer_Ak.js +0 -1
- package/dist/dashboard/assets/layout-C8mer_Ak.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Gh_W4OR_.js.gz +0 -0
- package/dist/dashboard/assets/live-BJGYRBnR.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js +0 -1
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js.gz +0 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js +0 -2
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-D7wX2vM5.js.gz +0 -0
- package/dist/dashboard/assets/routing-CcusqXA7.js.gz +0 -0
- package/dist/dashboard/assets/select-BO6h8yNv.js.gz +0 -0
- package/dist/dashboard/assets/settings-mpmXTgUa.js.gz +0 -0
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js +0 -1
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
- package/dist/dashboard/assets/stack-DwLmjUFK.js.gz +0 -0
- package/dist/dashboard/assets/state-DYdQmdAl.js.gz +0 -0
- package/dist/dashboard/assets/switch-CidSfbG7.js +0 -1
- package/dist/dashboard/assets/switch-CidSfbG7.js.gz +0 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js +0 -1
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
- package/dist/dashboard/assets/tokens-DDxMbSRL.js +0 -1
- package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
- package/dist/dashboard/assets/use-presence-BSZEBx7U.js +0 -1
- package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-w4u4CVue.js.gz +0 -0
- package/scripts/cli/command/admin.ts +0 -65
- package/scripts/cli/command/doctor.ts +0 -257
- package/scripts/cli/command/update.ts +0 -23
- package/scripts/cli/gateway/drain-token.ts +0 -78
- package/scripts/cli/gateway/instance-lock.ts +0 -105
- package/scripts/cli/gateway/stop.ts +0 -51
- package/scripts/cli/support/bun.ts +0 -27
- package/scripts/cli/support/version.ts +0 -37
- /package/dist/dashboard/assets/{app-CafWtVXA.js → app-BIt446yE.js} +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js.gz → app-BIt446yE.js.gz} +0 -0
- /package/scripts/cli/{ui/prompt.ts → prompt.ts} +0 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* DeepSeek sometimes emits
|
|
3
|
-
*
|
|
4
|
-
* becomes ordinary tool calls; anything incomplete stays text.
|
|
2
|
+
* CodeBuddy-family DeepSeek sometimes emits native tool markup as assistant text.
|
|
3
|
+
* Complete declared calls are recovered; incomplete and undeclared blocks stay text.
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const INVOKE = new RegExp(`<${PIPE}DSML${PIPE}\\s+invoke\\s+name=["']([^"']+)["']>([\\s\\S]*?)</${PIPE}DSML${PIPE}\\s+invoke>`, "gi");
|
|
10
|
-
const PARAMETER = new RegExp(`<${PIPE}DSML${PIPE}\\s+parameter\\s+name=["']([^"']+)["'][^>]*>([\\s\\S]*?)</${PIPE}DSML${PIPE}\\s+parameter>`, "gi");
|
|
5
|
+
const SEPARATORS = ["||", "|", "|"] as const;
|
|
6
|
+
const BLOCK_NAMES = ["calls", "function_calls"] as const;
|
|
7
|
+
const OPENERS = SEPARATORS.flatMap((separator) => BLOCK_NAMES.map((name) => `<${separator}DSML${separator} ${name}>`));
|
|
11
8
|
const TOOL_NAME = /^[A-Za-z0-9_][A-Za-z0-9_.:-]{0,63}$/;
|
|
12
9
|
|
|
10
|
+
/** Escapes regex metacharacters so a `|` separator is literal, not alternation. */
|
|
11
|
+
function escapeRegExp(value: string): string {
|
|
12
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
|
|
13
15
|
export interface DsmlToolCall {
|
|
14
16
|
readonly id: string;
|
|
15
17
|
readonly name: string;
|
|
@@ -21,27 +23,137 @@ export interface DsmlRecovery {
|
|
|
21
23
|
readonly calls: readonly DsmlToolCall[];
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
export
|
|
26
|
+
export class DsmlToolCallParser {
|
|
27
|
+
readonly #allowedNames: ReadonlySet<string>;
|
|
28
|
+
#pending = "";
|
|
29
|
+
#callSequence = 0;
|
|
30
|
+
|
|
31
|
+
constructor(allowedNames: ReadonlySet<string>) {
|
|
32
|
+
this.#allowedNames = allowedNames;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
push(chunk: string): DsmlRecovery {
|
|
36
|
+
this.#pending += chunk;
|
|
37
|
+
let cursor = 0;
|
|
38
|
+
let visible = "";
|
|
39
|
+
const calls: DsmlToolCall[] = [];
|
|
40
|
+
for (;;) {
|
|
41
|
+
let openIndex = -1;
|
|
42
|
+
let opener = "";
|
|
43
|
+
for (const candidate of OPENERS) {
|
|
44
|
+
const index = this.#pending.indexOf(candidate, cursor);
|
|
45
|
+
if (index >= 0 && (openIndex < 0 || index < openIndex)) {
|
|
46
|
+
openIndex = index;
|
|
47
|
+
opener = candidate;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (openIndex < 0) {
|
|
51
|
+
const safeEnd = this.#settledEnd(cursor);
|
|
52
|
+
visible += this.#pending.slice(cursor, safeEnd);
|
|
53
|
+
cursor = safeEnd;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
visible += this.#pending.slice(cursor, openIndex);
|
|
57
|
+
const separator = SEPARATORS.find((value) => opener.startsWith(`<${value}DSML`));
|
|
58
|
+
const blockName = BLOCK_NAMES.find((value) => opener.endsWith(` ${value}>`));
|
|
59
|
+
if (separator === undefined || blockName === undefined) {
|
|
60
|
+
visible += "<";
|
|
61
|
+
cursor = openIndex + 1;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const close = `</${separator}DSML${separator} ${blockName}>`;
|
|
65
|
+
const closeIndex = this.#pending.indexOf(close, openIndex + opener.length);
|
|
66
|
+
if (closeIndex < 0) {
|
|
67
|
+
cursor = openIndex;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
const end = closeIndex + close.length;
|
|
71
|
+
const block = this.#pending.slice(openIndex, end);
|
|
72
|
+
const parsed = parseBlock(block, opener, close, separator, this.#allowedNames);
|
|
73
|
+
if (parsed === undefined) visible += block;
|
|
74
|
+
else {
|
|
75
|
+
for (const call of parsed) calls.push({ ...call, id: `call_dsml_${this.#callSequence++}_${call.name}` });
|
|
76
|
+
}
|
|
77
|
+
cursor = end;
|
|
78
|
+
}
|
|
79
|
+
this.#pending = this.#pending.slice(cursor);
|
|
80
|
+
return { text: visible, calls };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
flush(): DsmlRecovery {
|
|
84
|
+
const text = this.#pending;
|
|
85
|
+
this.#pending = "";
|
|
86
|
+
return { text, calls: [] };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#settledEnd(start: number): number {
|
|
90
|
+
const remaining = this.#pending.slice(start);
|
|
91
|
+
for (let length = Math.min(OPENERS.reduce((max, opener) => Math.max(max, opener.length - 1), 0), remaining.length); length > 0; length -= 1) {
|
|
92
|
+
const suffix = remaining.slice(-length);
|
|
93
|
+
if (OPENERS.some((opener) => opener.startsWith(suffix))) return this.#pending.length - length;
|
|
94
|
+
}
|
|
95
|
+
return this.#pending.length;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function parseDsmlToolCalls(
|
|
100
|
+
text: string,
|
|
101
|
+
allowedNames: ReadonlySet<string> = new Set(),
|
|
102
|
+
): DsmlRecovery | undefined {
|
|
25
103
|
if (!text.includes("DSML")) return undefined;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
104
|
+
const parser = new DsmlToolCallParser(allowedNames);
|
|
105
|
+
const first = parser.push(text);
|
|
106
|
+
const last = parser.flush();
|
|
107
|
+
const recovered = [...first.calls, ...last.calls];
|
|
108
|
+
return recovered.length === 0 ? undefined : { text: `${first.text}${last.text}`.trim(), calls: recovered };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function parseBlock(
|
|
112
|
+
block: string,
|
|
113
|
+
opener: string,
|
|
114
|
+
close: string,
|
|
115
|
+
separator: string,
|
|
116
|
+
allowedNames: ReadonlySet<string>,
|
|
117
|
+
): Omit<DsmlToolCall, "id">[] | undefined {
|
|
118
|
+
const inner = block.slice(opener.length, -close.length);
|
|
119
|
+
const pipe = escapeRegExp(separator);
|
|
120
|
+
const invokePattern = new RegExp(`<${pipe}DSML${pipe}\\s+invoke\\s+name="([^"]*)"\\s*>`, "g");
|
|
121
|
+
const calls: Omit<DsmlToolCall, "id">[] = [];
|
|
122
|
+
// The allowlist is strict only when the caller knows the declared tools: a
|
|
123
|
+
// caller without one (a direct parse) keeps the generic name rule, while a
|
|
124
|
+
// dispatch that declared its tools must never execute a name it did not offer.
|
|
125
|
+
const strict = allowedNames.size > 0;
|
|
126
|
+
let cursor = 0;
|
|
127
|
+
for (const invoke of inner.matchAll(invokePattern)) {
|
|
128
|
+
const name = invoke[1] ?? "";
|
|
129
|
+
if (!TOOL_NAME.test(name) || (strict && !allowedNames.has(name)) || invoke.index === undefined) return undefined;
|
|
130
|
+
if (inner.slice(cursor, invoke.index).trim().length > 0) return undefined;
|
|
131
|
+
const bodyStart = invoke.index + invoke[0].length;
|
|
132
|
+
const invokeClose = `</${separator}DSML${separator} invoke>`;
|
|
133
|
+
const invokeEnd = inner.indexOf(invokeClose, bodyStart);
|
|
134
|
+
if (invokeEnd < 0) return undefined;
|
|
135
|
+
const parameterPattern = new RegExp(`<${pipe}DSML${pipe}\\s+parameter\\s+name="([^"]*)"(?:\\s+string="(true|false)")?\\s*>`, "g");
|
|
136
|
+
const body = inner.slice(bodyStart, invokeEnd);
|
|
137
|
+
const args: Record<string, unknown> = {};
|
|
138
|
+
let parameterCursor = 0;
|
|
139
|
+
for (const parameter of body.matchAll(parameterPattern)) {
|
|
140
|
+
const key = parameter[1] ?? "";
|
|
141
|
+
if (key.length === 0 || parameter.index === undefined || body.slice(parameterCursor, parameter.index).trim().length > 0) return undefined;
|
|
142
|
+
const valueStart = parameter.index + parameter[0].length;
|
|
143
|
+
const parameterClose = `</${separator}DSML${separator} parameter>`;
|
|
144
|
+
const valueEnd = body.indexOf(parameterClose, valueStart);
|
|
145
|
+
if (valueEnd < 0) return undefined;
|
|
146
|
+
const raw = body.slice(valueStart, valueEnd);
|
|
147
|
+
if (parameter[2] === "true") args[key] = raw;
|
|
148
|
+
else {
|
|
149
|
+
try { args[key] = JSON.parse(raw); }
|
|
150
|
+
catch { args[key] = raw; }
|
|
151
|
+
}
|
|
152
|
+
parameterCursor = valueEnd + parameterClose.length;
|
|
37
153
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
arguments: JSON.stringify(args),
|
|
42
|
-
});
|
|
154
|
+
if (body.slice(parameterCursor).trim().length > 0) return undefined;
|
|
155
|
+
calls.push({ name, arguments: JSON.stringify(args) });
|
|
156
|
+
cursor = invokeEnd + invokeClose.length;
|
|
43
157
|
}
|
|
44
|
-
|
|
45
|
-
const visible = `${text.slice(0, block.index)}${text.slice(block.index + block[0].length)}`.trim();
|
|
46
|
-
return { text: visible, calls };
|
|
158
|
+
return calls.length > 0 && inner.slice(cursor).trim().length === 0 ? calls : undefined;
|
|
47
159
|
}
|
|
@@ -182,7 +182,10 @@ export function parseResponsesResponseToEvents(
|
|
|
182
182
|
}
|
|
183
183
|
: { payload: text }),
|
|
184
184
|
...(position === 0 && encryptedContent !== undefined
|
|
185
|
-
? {
|
|
185
|
+
? {
|
|
186
|
+
encrypted_content: encryptedContent,
|
|
187
|
+
...(itemId === undefined ? {} : { item_id: itemId }),
|
|
188
|
+
}
|
|
186
189
|
: {}),
|
|
187
190
|
},
|
|
188
191
|
});
|
|
@@ -342,9 +345,9 @@ export async function* decodeResponsesSseStream(
|
|
|
342
345
|
const eventType = event["type"];
|
|
343
346
|
// An explicit failure inside a 200 OK. Two shapes carry one: a top-level
|
|
344
347
|
// `type: "error"` frame (the error object itself), and a `response.failed`
|
|
345
|
-
// terminal whose `response.error` explains why.
|
|
346
|
-
//
|
|
347
|
-
// `unknown_error`; the Claude and Gemini decoders already
|
|
348
|
+
// terminal whose `response.error` explains why. Recording either only as a
|
|
349
|
+
// `failed` terminal would leave the client with no code and telemetry with
|
|
350
|
+
// `unknown_error`; the Claude and Gemini decoders already raise.
|
|
348
351
|
const failedResponse = eventType === "response.failed" && isRecord(event["response"]) ? event["response"] : undefined;
|
|
349
352
|
const streamError = gatewayErrorFromStreamError(
|
|
350
353
|
eventType === "error" ? event : failedResponse?.["error"],
|
|
@@ -566,7 +569,10 @@ export async function* decodeResponsesSseStream(
|
|
|
566
569
|
? { payload: null, summary: text, summary_index: reasoningPart.index }
|
|
567
570
|
: { payload: text }),
|
|
568
571
|
...(position === 0 && encryptedContent !== undefined
|
|
569
|
-
? {
|
|
572
|
+
? {
|
|
573
|
+
encrypted_content: encryptedContent,
|
|
574
|
+
...(itemId === undefined ? {} : { item_id: itemId }),
|
|
575
|
+
}
|
|
570
576
|
: {}),
|
|
571
577
|
},
|
|
572
578
|
} as CanonicalEvent;
|
|
@@ -2,11 +2,10 @@
|
|
|
2
2
|
* OpenAI-family in-stream error frames → typed `GatewayError`.
|
|
3
3
|
*
|
|
4
4
|
* A `200 OK` whose SSE body carries an explicit error envelope is an upstream
|
|
5
|
-
* failure that arrived *after* the status line.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* decoders already threw for the identical event. This module is the one
|
|
5
|
+
* failure that arrived *after* the status line. Recording it only as a terminal
|
|
6
|
+
* `state: "failed"` leaves the client with no `error.code`, no message, and
|
|
7
|
+
* telemetry with the `unknown_error` category — while the Claude (`messages.ts`)
|
|
8
|
+
* and Gemini decoders throw for the identical event. This module is the one
|
|
10
9
|
* classifier those surfaces share.
|
|
11
10
|
*
|
|
12
11
|
* Classification reads **structured identifiers only** (`error.type`,
|
|
@@ -207,6 +207,9 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
|
|
|
207
207
|
...(this.config.chat_token_limit_field === undefined
|
|
208
208
|
? {}
|
|
209
209
|
: { chatTokenLimitField: this.config.chat_token_limit_field }),
|
|
210
|
+
...(context.image_clamp_max_bytes === undefined
|
|
211
|
+
? {}
|
|
212
|
+
: { maxBytesOverride: context.image_clamp_max_bytes }),
|
|
210
213
|
});
|
|
211
214
|
if (
|
|
212
215
|
wireFamily !== "messages" &&
|
|
@@ -236,14 +236,13 @@ function jsonResponse(body: unknown): Response {
|
|
|
236
236
|
*
|
|
237
237
|
* Key fetching, caching, in-flight deduplication, the minimum refresh interval
|
|
238
238
|
* on an unknown `kid`, and `kid`-rotation pickup are all delegated to
|
|
239
|
-
* `jose`'s `createRemoteJWKSet`
|
|
240
|
-
*
|
|
241
|
-
*
|
|
242
|
-
* be selected for verification.
|
|
239
|
+
* `jose`'s `createRemoteJWKSet`. `jose` additionally honours each JWK's `use`
|
|
240
|
+
* and `key_ops`, so an encryption key published alongside the signing keys
|
|
241
|
+
* cannot be selected for verification.
|
|
243
242
|
*
|
|
244
243
|
* The algorithm is checked against `SUPPORTED_ALGORITHMS` *before* any key is
|
|
245
|
-
* resolved, so the asymmetric-only allowlist (no `none`, no HMAC)
|
|
246
|
-
*
|
|
244
|
+
* resolved, so the asymmetric-only allowlist (no `none`, no HMAC) holds
|
|
245
|
+
* regardless of what the JWKS publishes.
|
|
247
246
|
*/
|
|
248
247
|
export class JwksVerifier {
|
|
249
248
|
readonly #keys: RemoteJWKSet;
|
|
@@ -317,10 +316,10 @@ export class JwksVerifier {
|
|
|
317
316
|
/**
|
|
318
317
|
* One verifier per URL, bounded and time-limited.
|
|
319
318
|
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
319
|
+
* An unbounded, never-evicted registry would pin every JWKS URL ever seen —
|
|
320
|
+
* and its verifier's key cache — for the process lifetime. A TTL plus a hard
|
|
321
|
+
* entry cap keeps a fleet of issuers from growing it without limit while still
|
|
322
|
+
* sharing a verifier's key cache across calls.
|
|
324
323
|
*/
|
|
325
324
|
const JWKS_VERIFIER_TTL_MS = 5 * 60 * 1_000;
|
|
326
325
|
const JWKS_VERIFIER_MAX_ENTRIES = 64;
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
import { randomUUID } from "node:crypto";
|
|
24
24
|
import { and, eq, inArray, isNull, lt, or, sql } from "drizzle-orm";
|
|
25
25
|
import type { CartethyiaDatabase } from "../../persistence/db-handle";
|
|
26
|
+
import { sleep } from "../../shared/sleep";
|
|
26
27
|
import { providerAccounts, providerOauthStates } from "../../persistence/schema";
|
|
27
28
|
import { decryptCredentialToString, encryptCredential } from "../../security/crypto";
|
|
28
29
|
import { invalidateCredentialCache } from "../operations/provider-credential-service";
|
|
@@ -258,6 +259,7 @@ async function disableAccount(
|
|
|
258
259
|
)
|
|
259
260
|
.returning({ id: providerOauthStates.providerAccountId });
|
|
260
261
|
if (leaseRows.length === 0) return;
|
|
262
|
+
const disabledRecoveryMs = resolveAccountDisabledRecoveryMs();
|
|
261
263
|
await tx
|
|
262
264
|
.update(providerAccounts)
|
|
263
265
|
.set({
|
|
@@ -271,13 +273,13 @@ async function disableAccount(
|
|
|
271
273
|
lastErrorCategory: "auth_invalidated",
|
|
272
274
|
lastErrorAt: new Date(),
|
|
273
275
|
// Carries a recovery deadline so `sweepExpiredCooldowns` can bring this
|
|
274
|
-
// account back once it elapses
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
...(
|
|
280
|
-
? { cooldownUntil: new Date(Date.now() +
|
|
276
|
+
// account back once it elapses; without one, one definitive rejection
|
|
277
|
+
// parks the credential for good. The deadline is also what distinguishes
|
|
278
|
+
// this (machine-disabled) from an operator's own disable, which leaves
|
|
279
|
+
// `cooldownUntil` null and is therefore never swept. See
|
|
280
|
+
// `resolveAccountDisabledRecoveryMs`.
|
|
281
|
+
...(disabledRecoveryMs > 0
|
|
282
|
+
? { cooldownUntil: new Date(Date.now() + disabledRecoveryMs) }
|
|
281
283
|
: {}),
|
|
282
284
|
})
|
|
283
285
|
.where(eq(providerAccounts.id, accountId));
|
|
@@ -311,10 +313,6 @@ async function markStaticToken(db: CartethyiaDatabase, accountId: string): Promi
|
|
|
311
313
|
.where(eq(providerAccounts.id, accountId));
|
|
312
314
|
}
|
|
313
315
|
|
|
314
|
-
function sleep(ms: number): Promise<void> {
|
|
315
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
316
|
-
}
|
|
317
|
-
|
|
318
316
|
function failureMessage(error: unknown): string {
|
|
319
317
|
if (error instanceof Error) return error.message;
|
|
320
318
|
return String(error);
|
|
@@ -1,119 +1,122 @@
|
|
|
1
|
-
import type { ProviderModule } from "./provider-registry";
|
|
2
|
-
import {
|
|
3
|
-
GENERIC_API_KEY_SPECS,
|
|
4
|
-
VERSIONED_ROOT_API_KEY_SPECS,
|
|
5
|
-
} from "./configured-openai-providers";
|
|
6
|
-
import { createApiKeyAdapter, type ApiKeyProviderSpec } from "./configured-provider";
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Providers whose adapter and catalog discovery are the same bearer-auth
|
|
10
|
-
* OpenAI-compatible contract. Providers with static catalogs or additional
|
|
11
|
-
* upstream behavior remain declared beside their special handling.
|
|
12
|
-
*/
|
|
13
|
-
export const DISCOVERY_BACKED_PROVIDER_IDS = [
|
|
14
|
-
"groq",
|
|
15
|
-
"together",
|
|
16
|
-
"deepinfra",
|
|
17
|
-
"siliconflow",
|
|
18
|
-
"siliconflowcn",
|
|
19
|
-
"novita",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
type
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
import type { ProviderModule } from "./provider-registry";
|
|
2
|
+
import {
|
|
3
|
+
GENERIC_API_KEY_SPECS,
|
|
4
|
+
VERSIONED_ROOT_API_KEY_SPECS,
|
|
5
|
+
} from "./configured-openai-providers";
|
|
6
|
+
import { createApiKeyAdapter, type ApiKeyProviderSpec } from "./configured-provider";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Providers whose adapter and catalog discovery are the same bearer-auth
|
|
10
|
+
* OpenAI-compatible contract. Providers with static catalogs or additional
|
|
11
|
+
* upstream behavior remain declared beside their special handling.
|
|
12
|
+
*/
|
|
13
|
+
export const DISCOVERY_BACKED_PROVIDER_IDS = [
|
|
14
|
+
"groq",
|
|
15
|
+
"together",
|
|
16
|
+
"deepinfra",
|
|
17
|
+
"siliconflow",
|
|
18
|
+
"siliconflowcn",
|
|
19
|
+
"novita",
|
|
20
|
+
"larprouter",
|
|
21
|
+
"venice",
|
|
22
|
+
"nanogpt",
|
|
23
|
+
"baseten",
|
|
24
|
+
"synthetic",
|
|
25
|
+
"stepfun",
|
|
26
|
+
"sakana",
|
|
27
|
+
"helmcode",
|
|
28
|
+
"coralbricks",
|
|
29
|
+
"aiand",
|
|
30
|
+
"wafer",
|
|
31
|
+
"firepass",
|
|
32
|
+
"zhipucoding",
|
|
33
|
+
"dashscope",
|
|
34
|
+
"qianfan",
|
|
35
|
+
] as const;
|
|
36
|
+
|
|
37
|
+
export type DiscoveryBackedProviderId = (typeof DISCOVERY_BACKED_PROVIDER_IDS)[number];
|
|
38
|
+
|
|
39
|
+
type DiscoveryBackedCapabilities = Pick<
|
|
40
|
+
ProviderModule,
|
|
41
|
+
"endpointPathsByWireFamily" | "loadAdapter" | "loadModelDiscovery"
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
type ModelDiscoveryFactory = NonNullable<ProviderModule["loadModelDiscovery"]>;
|
|
45
|
+
type OpenAIModelDiscoveryFactory = (
|
|
46
|
+
providerId: string,
|
|
47
|
+
options?: {
|
|
48
|
+
readonly headers?: (credential: string) => Readonly<Record<string, string>>;
|
|
49
|
+
},
|
|
50
|
+
) => ModelDiscoveryFactory;
|
|
51
|
+
|
|
52
|
+
const DISCOVERY_BACKED_PROVIDER_SPECS = {
|
|
53
|
+
groq: VERSIONED_ROOT_API_KEY_SPECS.groq,
|
|
54
|
+
larprouter: GENERIC_API_KEY_SPECS.larprouter,
|
|
55
|
+
together: GENERIC_API_KEY_SPECS.together,
|
|
56
|
+
deepinfra: VERSIONED_ROOT_API_KEY_SPECS.deepinfra,
|
|
57
|
+
siliconflow: GENERIC_API_KEY_SPECS.siliconflow,
|
|
58
|
+
siliconflowcn: GENERIC_API_KEY_SPECS.siliconflowcn,
|
|
59
|
+
novita: VERSIONED_ROOT_API_KEY_SPECS.novita,
|
|
60
|
+
venice: VERSIONED_ROOT_API_KEY_SPECS.venice,
|
|
61
|
+
nanogpt: GENERIC_API_KEY_SPECS.nanogpt,
|
|
62
|
+
baseten: GENERIC_API_KEY_SPECS.baseten,
|
|
63
|
+
synthetic: GENERIC_API_KEY_SPECS.synthetic,
|
|
64
|
+
stepfun: GENERIC_API_KEY_SPECS.stepfun,
|
|
65
|
+
sakana: GENERIC_API_KEY_SPECS.sakana,
|
|
66
|
+
helmcode: GENERIC_API_KEY_SPECS.helmcode,
|
|
67
|
+
coralbricks: GENERIC_API_KEY_SPECS.coralbricks,
|
|
68
|
+
aiand: GENERIC_API_KEY_SPECS.aiand,
|
|
69
|
+
wafer: GENERIC_API_KEY_SPECS.wafer,
|
|
70
|
+
firepass: VERSIONED_ROOT_API_KEY_SPECS.firepass,
|
|
71
|
+
zhipucoding: VERSIONED_ROOT_API_KEY_SPECS.zhipucoding,
|
|
72
|
+
dashscope: GENERIC_API_KEY_SPECS.dashscope,
|
|
73
|
+
qianfan: VERSIONED_ROOT_API_KEY_SPECS.qianfan,
|
|
74
|
+
} satisfies Readonly<Record<DiscoveryBackedProviderId, ApiKeyProviderSpec>>;
|
|
75
|
+
|
|
76
|
+
function discoveryBackedCapabilities(
|
|
77
|
+
providerId: DiscoveryBackedProviderId,
|
|
78
|
+
spec: ApiKeyProviderSpec,
|
|
79
|
+
openAIModelDiscovery: OpenAIModelDiscoveryFactory,
|
|
80
|
+
): DiscoveryBackedCapabilities {
|
|
81
|
+
return {
|
|
82
|
+
...(spec.endpoint_paths_by_wire_family === undefined
|
|
83
|
+
? {}
|
|
84
|
+
: { endpointPathsByWireFamily: spec.endpoint_paths_by_wire_family }),
|
|
85
|
+
loadAdapter: async () => createApiKeyAdapter(spec),
|
|
86
|
+
loadModelDiscovery: openAIModelDiscovery(providerId, {
|
|
87
|
+
headers: (credential) => ({ authorization: `Bearer ${credential}` }),
|
|
88
|
+
}),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Creates the standard provider capability table using the registry's shared
|
|
94
|
+
* discovery loader, keeping its lazy import and authentication behavior intact.
|
|
95
|
+
*/
|
|
96
|
+
export function createDiscoveryBackedProviderCapabilities(
|
|
97
|
+
openAIModelDiscovery: OpenAIModelDiscoveryFactory,
|
|
98
|
+
): Readonly<Record<DiscoveryBackedProviderId, DiscoveryBackedCapabilities>> {
|
|
99
|
+
return {
|
|
100
|
+
groq: discoveryBackedCapabilities("groq", DISCOVERY_BACKED_PROVIDER_SPECS.groq, openAIModelDiscovery),
|
|
101
|
+
together: discoveryBackedCapabilities("together", DISCOVERY_BACKED_PROVIDER_SPECS.together, openAIModelDiscovery),
|
|
102
|
+
deepinfra: discoveryBackedCapabilities("deepinfra", DISCOVERY_BACKED_PROVIDER_SPECS.deepinfra, openAIModelDiscovery),
|
|
103
|
+
siliconflow: discoveryBackedCapabilities("siliconflow", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflow, openAIModelDiscovery),
|
|
104
|
+
siliconflowcn: discoveryBackedCapabilities("siliconflowcn", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflowcn, openAIModelDiscovery),
|
|
105
|
+
novita: discoveryBackedCapabilities("novita", DISCOVERY_BACKED_PROVIDER_SPECS.novita, openAIModelDiscovery),
|
|
106
|
+
larprouter: discoveryBackedCapabilities("larprouter", DISCOVERY_BACKED_PROVIDER_SPECS.larprouter, openAIModelDiscovery),
|
|
107
|
+
venice: discoveryBackedCapabilities("venice", DISCOVERY_BACKED_PROVIDER_SPECS.venice, openAIModelDiscovery),
|
|
108
|
+
nanogpt: discoveryBackedCapabilities("nanogpt", DISCOVERY_BACKED_PROVIDER_SPECS.nanogpt, openAIModelDiscovery),
|
|
109
|
+
baseten: discoveryBackedCapabilities("baseten", DISCOVERY_BACKED_PROVIDER_SPECS.baseten, openAIModelDiscovery),
|
|
110
|
+
synthetic: discoveryBackedCapabilities("synthetic", DISCOVERY_BACKED_PROVIDER_SPECS.synthetic, openAIModelDiscovery),
|
|
111
|
+
stepfun: discoveryBackedCapabilities("stepfun", DISCOVERY_BACKED_PROVIDER_SPECS.stepfun, openAIModelDiscovery),
|
|
112
|
+
sakana: discoveryBackedCapabilities("sakana", DISCOVERY_BACKED_PROVIDER_SPECS.sakana, openAIModelDiscovery),
|
|
113
|
+
helmcode: discoveryBackedCapabilities("helmcode", DISCOVERY_BACKED_PROVIDER_SPECS.helmcode, openAIModelDiscovery),
|
|
114
|
+
coralbricks: discoveryBackedCapabilities("coralbricks", DISCOVERY_BACKED_PROVIDER_SPECS.coralbricks, openAIModelDiscovery),
|
|
115
|
+
aiand: discoveryBackedCapabilities("aiand", DISCOVERY_BACKED_PROVIDER_SPECS.aiand, openAIModelDiscovery),
|
|
116
|
+
wafer: discoveryBackedCapabilities("wafer", DISCOVERY_BACKED_PROVIDER_SPECS.wafer, openAIModelDiscovery),
|
|
117
|
+
firepass: discoveryBackedCapabilities("firepass", DISCOVERY_BACKED_PROVIDER_SPECS.firepass, openAIModelDiscovery),
|
|
118
|
+
zhipucoding: discoveryBackedCapabilities("zhipucoding", DISCOVERY_BACKED_PROVIDER_SPECS.zhipucoding, openAIModelDiscovery),
|
|
119
|
+
dashscope: discoveryBackedCapabilities("dashscope", DISCOVERY_BACKED_PROVIDER_SPECS.dashscope, openAIModelDiscovery),
|
|
120
|
+
qianfan: discoveryBackedCapabilities("qianfan", DISCOVERY_BACKED_PROVIDER_SPECS.qianfan, openAIModelDiscovery),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -16,6 +16,7 @@ import type { ProviderId } from "./provider-contracts";
|
|
|
16
16
|
* pairs this spec with `openAIModelDiscovery`.
|
|
17
17
|
*/
|
|
18
18
|
export const GENERIC_API_KEY_PROVIDER_IDS = [
|
|
19
|
+
"larprouter",
|
|
19
20
|
"mistral",
|
|
20
21
|
"fireworks",
|
|
21
22
|
"nvidia",
|
|
@@ -104,14 +105,13 @@ export type GenericApiKeyProviderId = (typeof GENERIC_API_KEY_PROVIDER_IDS)[numb
|
|
|
104
105
|
|
|
105
106
|
function genericApiKeySpec(providerId: GenericApiKeyProviderId): ApiKeyProviderSpec {
|
|
106
107
|
// These roots are *not* bare hosts — every one of them already ends at `/v1`
|
|
107
|
-
// — so the path is declared below that root.
|
|
108
|
-
//
|
|
109
|
-
// declared path was wrong for all of them and nothing said so. Both spec
|
|
110
|
-
// shapes now declare the same thing, so this is the one implementation.
|
|
108
|
+
// — so the path is declared below that root. Both spec shapes declare the same
|
|
109
|
+
// thing, so this is the one implementation.
|
|
111
110
|
return versionedRootApiKeySpec(providerId);
|
|
112
111
|
}
|
|
113
112
|
|
|
114
113
|
export const GENERIC_API_KEY_SPECS = {
|
|
114
|
+
larprouter: genericApiKeySpec("larprouter"),
|
|
115
115
|
mistral: genericApiKeySpec("mistral"),
|
|
116
116
|
fireworks: genericApiKeySpec("fireworks"),
|
|
117
117
|
nvidia: genericApiKeySpec("nvidia"),
|