cartethyia 2.5.10 → 2.6.0
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 +8 -0
- package/dist/dashboard/assets/{BannedPage-Cd30Z0b9.js → BannedPage-l6XMnfr9.js} +1 -1
- package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-wf5u-ww6.js → CliToolDetailPage-DwOzAW45.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DykPvuck.js → CliToolsPage-BT3Up3QA.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-DwvSD3vs.js → CombosPage-6kYIUpzR.js} +1 -1
- package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CIr7KDex.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-82X0DDdH.js → CustomizationPage-C7m-H1Rz.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-C7m-H1Rz.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-CS5mPuVF.js → LoginPage-CbphLvjg.js} +1 -1
- package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-C0UCUsVJ.js → ModelPicker-DVny4S5_.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-vdja5ZPK.js → ProvidersPage-Dfb2896L.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-BB4CNm4-.js → ProxyPage-BaCIdAUt.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-BaCIdAUt.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js +1 -0
- package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js +1 -0
- package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-FadUOl9S.js → SetupPage-D4g6vOGc.js} +1 -1
- package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-Cfy6_Khv.js → SortableList-C93i14BD.js} +1 -1
- package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CM92fgJf.js → StudioPage-SgQpymjm.js} +1 -1
- package/dist/dashboard/assets/{StudioPage-CM92fgJf.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
- package/dist/dashboard/assets/{UsagePage-BT4MyQeT.js → UsagePage-BFME-eba.js} +2 -2
- package/dist/dashboard/assets/UsagePage-BFME-eba.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
- package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
- package/dist/dashboard/assets/{app-B7pVRhJ1.js → app-2KhtHCv9.js} +1 -1
- package/dist/dashboard/assets/{app-B7pVRhJ1.js.gz → app-2KhtHCv9.js.gz} +0 -0
- package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
- package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
- package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
- package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
- package/dist/dashboard/assets/{badge-Bvyr7D0u.js → badge-CKsF123d.js} +1 -1
- package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
- package/dist/dashboard/assets/{banner-DIvKAZih.js → banner-8j7uChA9.js} +1 -1
- package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
- package/dist/dashboard/assets/{card-D5_gYIS_.js → card-CdsSlWA3.js} +1 -1
- package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
- package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-B6vDBtbm.js → clipboard-button-uL5aYLfW.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-CpjrgdwJ.js → dialog-C07hr5_G.js} +1 -1
- package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BWmt3b5y.js → drawer-BPO1TcKH.js} +1 -1
- package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
- package/dist/dashboard/assets/{entry-C_oakV3z.js → entry-Bz_CtDfC.js} +1 -1
- package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
- package/dist/dashboard/assets/entry-CwPRKk0d.js +4 -0
- package/dist/dashboard/assets/entry-CwPRKk0d.js.gz +0 -0
- package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
- package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-RRHHWGxh.js → github-badge-DmQreSDd.js} +1 -1
- package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
- package/dist/dashboard/assets/{index-Bhey_rg_.js → index-Bblu6erR.js} +2 -2
- package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
- package/dist/dashboard/assets/{inline-C2_EQ5Uf.js → inline-C9dCYaBZ.js} +1 -1
- package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
- package/dist/dashboard/assets/{input-BMRlQ450.js → input-CjCnXweJ.js} +1 -1
- package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
- package/dist/dashboard/assets/{layout-XR5xP8ew.js → layout-V6y8DAkl.js} +1 -1
- package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Cw07dioc.js → list-row-CM1AaG_y.js} +1 -1
- package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
- package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
- package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
- package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
- package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-DrdA9oSM.js → numbers-BOevJzdz.js} +1 -1
- package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
- package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
- package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
- package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
- package/dist/dashboard/assets/{select-CxVVB__N.js → select-C980c4cz.js} +1 -1
- package/dist/dashboard/assets/select-C980c4cz.js.gz +0 -0
- package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
- package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
- package/dist/dashboard/assets/{stack-uPOwM9Hs.js → stack-_gfTdLVB.js} +1 -1
- package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
- package/dist/dashboard/assets/{state-D1Yz79iL.js → state-2c5V4zo7.js} +1 -1
- package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
- package/dist/dashboard/assets/{switch-sevsRrRo.js → switch-Dkke7Naf.js} +1 -1
- package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
- package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +51 -51
- package/migrations/README.md +52 -52
- package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
- package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
- package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
- package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
- package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
- package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
- package/package.json +96 -95
- package/scripts/cli/admin.ts +126 -128
- package/scripts/cli/autostart.ts +237 -237
- package/scripts/cli/background.ts +120 -110
- package/scripts/cli/bin/carte.cjs +8 -8
- package/scripts/cli/bin/cartethyia.cjs +167 -167
- package/scripts/cli/console-menu.ts +39 -30
- package/scripts/cli/controller.ts +145 -0
- package/scripts/cli/env.ts +99 -99
- package/scripts/cli/gateway.ts +264 -260
- package/scripts/cli/instance.ts +234 -224
- package/scripts/cli/main.ts +188 -167
- package/scripts/cli/platform.ts +64 -64
- package/scripts/cli/prompt.ts +217 -79
- package/scripts/cli/services.ts +88 -88
- package/scripts/cli/setup.ts +445 -445
- package/scripts/cli/start.ts +85 -85
- package/scripts/cli/startup-signal.ts +23 -23
- package/scripts/cli/telemetry.ts +70 -0
- package/scripts/cli/tray/index.ts +263 -263
- package/scripts/cli/tray/windows.ps1 +107 -107
- package/scripts/cli/tray.ts +29 -4
- package/scripts/cli/update.ts +39 -39
- package/scripts/cli/version.ts +67 -67
- package/scripts/cli/wordmark.ts +58 -58
- package/src/boot/app.ts +16 -1
- package/src/boot/dependencies.ts +128 -25
- package/src/config/resources.ts +137 -0
- package/src/config/runtime.ts +133 -76
- package/src/config/spec.ts +30 -29
- package/src/config/telemetry.ts +0 -25
- package/src/console/api-keys/bucket-spend.ts +14 -17
- package/src/console/api-keys/contracts.ts +410 -410
- package/src/console/api-keys/routes.ts +12 -0
- package/src/console/audit/store.ts +2 -3
- package/src/console/auth/setup-service.ts +8 -1
- package/src/console/backup/routes.ts +7 -0
- package/src/console/backup/service.ts +463 -463
- package/src/console/backup/store.ts +16 -11
- package/src/console/backup/validate.ts +1 -4
- package/src/console/cli-tools/fs-ops.ts +18 -2
- package/src/console/data-management/contracts.ts +1 -8
- package/src/console/data-management/operations.ts +61 -48
- package/src/console/data-management/routes.ts +4 -2
- package/src/console/domain-registration.ts +25 -3
- package/src/console/inferhub/client.ts +139 -0
- package/src/console/inferhub/key-store.ts +129 -0
- package/src/console/inferhub/normalize.ts +347 -0
- package/src/console/inferhub/routes.ts +411 -0
- package/src/console/inferhub/store.ts +109 -0
- package/src/console/inferhub/types.ts +183 -0
- package/src/console/observability/contracts.ts +2 -41
- package/src/console/observability/store.ts +176 -371
- package/src/console/providers/catalog/public-model-store.ts +0 -0
- package/src/console/providers/catalog/store.ts +23 -36
- package/src/console/quota/account-quota-shared.ts +52 -52
- package/src/console/quota/account-quota-tenant.ts +16 -24
- package/src/console/quota/refresh.ts +441 -441
- package/src/console/routing/pools/import-parse.ts +206 -206
- package/src/console/routing/pools/operations.ts +543 -543
- package/src/console/routing/pools/probe-verdict.ts +132 -132
- package/src/console/routing/pools/routes.ts +181 -181
- package/src/console/settings/contracts.ts +42 -40
- package/src/console/settings/store.ts +25 -25
- package/src/console/share/share-stats.ts +22 -4
- package/src/console/share/share-usage.ts +30 -4
- package/src/console/shared/cursor.ts +15 -0
- package/src/console/updates/routes.ts +12 -0
- package/src/main.ts +13 -5
- package/src/network/pool/resolver.ts +1104 -1104
- package/src/observability/client-name.ts +22 -0
- package/src/observability/event-log.ts +5 -29
- package/src/observability/event-query.ts +690 -0
- package/src/observability/log-ring.ts +26 -2
- package/src/observability/log-sanitize.ts +118 -0
- package/src/observability/logger.ts +17 -13
- package/src/observability/metrics.ts +35 -0
- package/src/observability/payload-capture.ts +114 -41
- package/src/observability/payload-store.ts +249 -24
- package/src/observability/raw-event-writer.ts +118 -0
- package/src/observability/runtime-metrics.ts +71 -1
- package/src/observability/telemetry-buffer.ts +100 -17
- package/src/observability/telemetry-reconciliation.ts +417 -0
- package/src/persistence/boot.ts +20 -9
- package/src/persistence/db-pg.ts +13 -0
- package/src/persistence/db-sqlite.ts +569 -497
- package/src/persistence/dialect.ts +3 -2
- package/src/persistence/migrate.ts +181 -181
- package/src/persistence/schema.ts +1496 -1406
- package/src/persistence/shared-cache.ts +5 -1
- package/src/persistence/stores/api-key-store.ts +581 -581
- package/src/persistence/stores/telemetry-store.ts +124 -63
- package/src/protocol/reasoning-text.ts +30 -0
- package/src/protocol/response/chat.ts +33 -7
- package/src/protocol/response/codex.ts +14 -2
- package/src/protocol/response/messages.ts +5 -2
- package/src/providers/authentication/oauth-flow-store.ts +3 -10
- package/src/providers/bundled-discovery-providers.ts +122 -122
- package/src/providers/default-registry.ts +10 -0
- package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
- package/src/providers/discovery/models-dev-catalog.ts +354 -354
- package/src/providers/discovery/probe-phases.ts +43 -7
- package/src/providers/discovery/probing-service.ts +70 -32
- package/src/providers/integrations/antigravity/antigravity.ts +9 -2
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
- package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
- package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
- package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
- package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
- package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
- package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
- package/src/providers/integrations/claude/claude-quota.ts +2 -2
- package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
- package/src/providers/integrations/claude/claude.ts +3 -4
- package/src/providers/integrations/cline/cline.ts +94 -8
- package/src/providers/integrations/codex/codex.ts +61 -37
- package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
- package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
- package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
- package/src/providers/integrations/cursor/cursor-request.ts +11 -0
- package/src/providers/integrations/cursor/cursor.ts +29 -17
- package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
- package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
- package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
- package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
- package/src/providers/integrations/grok/grok-quota.ts +279 -279
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
- package/src/providers/integrations/hermes.ts +7 -1
- package/src/providers/integrations/inferhub.ts +201 -73
- package/src/providers/integrations/kilo/kilo.ts +152 -152
- package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
- package/src/providers/integrations/openrouter/provider.ts +129 -129
- package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
- package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
- package/src/providers/integrations/trae/trae-oauth.ts +4 -26
- package/src/providers/integrations/trae/trae-quota.ts +389 -384
- package/src/providers/integrations/trae/trae-realm.ts +15 -2
- package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
- package/src/providers/integrations/zcode/oauth.ts +1 -1
- package/src/providers/operations/account-health-service.ts +605 -279
- package/src/providers/provider-metadata.ts +12 -1
- package/src/providers/provider-model-definition.ts +373 -373
- package/src/providers/quota/quota-contracts.ts +3 -7
- package/src/providers/search/search-provider.ts +2 -6
- package/src/security/admission/contracts.ts +10 -0
- package/src/security/admission/in-memory-store.ts +89 -14
- package/src/security/admission/lua.ts +191 -182
- package/src/security/admission/redis-store.ts +30 -0
- package/src/security/admission/service.ts +18 -0
- package/src/security/api-key-auth-cache.ts +96 -0
- package/src/security/api-key-auth.ts +11 -100
- package/src/security/client-router-fingerprint.ts +3 -7
- package/src/security/ip-boundary.ts +7 -3
- package/src/shared/coerce.ts +67 -0
- package/src/shared/hash.ts +6 -0
- package/src/shared/time.ts +7 -0
- package/src/transport/dispatch/attempt-finalize.ts +26 -138
- package/src/transport/dispatch/attempt-loop.ts +103 -81
- package/src/transport/dispatch/capture-policy.ts +78 -0
- package/src/transport/dispatch/proxy-request.ts +4 -2
- package/src/transport/dispatch/streaming/encoder.ts +111 -5
- package/src/transport/dispatch/streaming/stream.ts +19 -2
- package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
- package/src/transport/failure-policy.ts +27 -0
- package/src/transport/guards/abuse-guard.ts +2 -2
- package/src/transport/guards/auth-guard.ts +17 -0
- package/src/transport/guards/body-policy.ts +3 -2
- package/src/transport/guards/concurrency-guard.ts +89 -13
- package/src/transport/guards/early-rejection-capture.ts +43 -3
- package/src/transport/guards/error-lifecycle.ts +10 -2
- package/src/transport/guards/guard-errors.ts +23 -0
- package/src/transport/guards/headroom-guard.ts +41 -7
- package/src/transport/guards/pipeline.ts +24 -0
- package/src/transport/guards/request-context.ts +2 -1
- package/src/transport/routing/admission.ts +51 -9
- package/src/transport/routing/bounded-lru.ts +49 -0
- package/src/transport/routing/candidate-index.ts +88 -0
- package/src/transport/routing/reservations.ts +121 -7
- package/src/transport/routing/round-robin.ts +10 -22
- package/src/transport/routing/route-catalog.ts +26 -13
- package/src/transport/routing/route-model.ts +22 -2
- package/src/transport/routing/router.ts +53 -31
- package/src/transport/surface/chat/encode.ts +2 -3
- package/src/transport/surface/chat/parse.ts +2 -1
- package/src/transport/surface/dialects.ts +11 -3
- package/src/transport/surface/messages/encode.ts +2 -1
- package/src/transport/surface/messages/parse.ts +3 -1
- package/src/transport/surface/messages/stream.ts +2 -6
- package/src/workers/maintenance-lease.ts +200 -0
- package/src/workers/scheduler.ts +101 -1
- package/dist/dashboard/assets/BannedPage-Cd30Z0b9.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-wf5u-ww6.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DykPvuck.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-DwvSD3vs.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CIr7KDex.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-82X0DDdH.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-BYPucTTn.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-CS5mPuVF.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-C0UCUsVJ.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js +0 -1
- package/dist/dashboard/assets/OverviewPage-Dk_ew3YU.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-CAiRn2Q0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-vdja5ZPK.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BB4CNm4-.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js +0 -1
- package/dist/dashboard/assets/QuotaPage-FEc4iNyq.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js +0 -1
- package/dist/dashboard/assets/SettingsPage-Dlfi5L4N.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-FadUOl9S.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-Cfy6_Khv.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BT4MyQeT.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
- package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
- package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
- package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
- package/dist/dashboard/assets/badge-Bvyr7D0u.js.gz +0 -0
- package/dist/dashboard/assets/banner-DIvKAZih.js.gz +0 -0
- package/dist/dashboard/assets/card-D5_gYIS_.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-B6vDBtbm.js.gz +0 -0
- package/dist/dashboard/assets/dialog-CpjrgdwJ.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BWmt3b5y.js.gz +0 -0
- package/dist/dashboard/assets/entry-B-gvimrg.js +0 -1
- package/dist/dashboard/assets/entry-B-gvimrg.js.gz +0 -0
- package/dist/dashboard/assets/entry-C_oakV3z.js.gz +0 -0
- package/dist/dashboard/assets/entry-Dj0cHfEc.js +0 -4
- package/dist/dashboard/assets/entry-Dj0cHfEc.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-RRHHWGxh.js.gz +0 -0
- package/dist/dashboard/assets/index-Bhey_rg_.js.gz +0 -0
- package/dist/dashboard/assets/inline-C2_EQ5Uf.js.gz +0 -0
- package/dist/dashboard/assets/input-BMRlQ450.js.gz +0 -0
- package/dist/dashboard/assets/layout-XR5xP8ew.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Cw07dioc.js.gz +0 -0
- package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
- package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
- package/dist/dashboard/assets/numbers-DrdA9oSM.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
- package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
- package/dist/dashboard/assets/select-CxVVB__N.js.gz +0 -0
- package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
- package/dist/dashboard/assets/stack-uPOwM9Hs.js.gz +0 -0
- package/dist/dashboard/assets/state-D1Yz79iL.js.gz +0 -0
- package/dist/dashboard/assets/switch-sevsRrRo.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
- package/src/observability/event-compaction.ts +0 -317
- package/src/observability/event-day-index.ts +0 -439
|
@@ -1,152 +1,152 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Kilo Code adapter.
|
|
3
|
-
*
|
|
4
|
-
* Kilo Code resells the OpenRouter catalog behind a bearer device token on an
|
|
5
|
-
* OpenAI-compatible chat surface, so this adapter reuses the shared factory for
|
|
6
|
-
* payload translation, transport, and SSE decoding.
|
|
7
|
-
*
|
|
8
|
-
* One thing sits outside the declarative `ApiKeyProviderSpec`: the stored
|
|
9
|
-
* credential is a JSON envelope (`{ accessToken, orgId }`) because the gateway
|
|
10
|
-
* scopes every request to the account's organization and the console stores one
|
|
11
|
-
* opaque string per account. The factory forwards that string as the bearer
|
|
12
|
-
* verbatim, so the envelope is decoded at the auth boundary here — the same
|
|
13
|
-
* arrangement `kimi/kimi.ts` uses for its own envelope credential.
|
|
14
|
-
*
|
|
15
|
-
* The base URL is the completions path itself, because that is the path Kilo
|
|
16
|
-
* Code publishes (`/api/openrouter/chat/completions`) and it is not derivable
|
|
17
|
-
* from an origin plus a wire-family suffix.
|
|
18
|
-
*/
|
|
19
|
-
import { defineModel } from "../../provider-model-definition";
|
|
20
|
-
import { openrouterFreeRoster } from "../../discovery/openrouter-free-roster";
|
|
21
|
-
import type { ModelDefinition } from "../../provider-model-definition";
|
|
22
|
-
import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
|
|
23
|
-
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
24
|
-
import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
|
|
25
|
-
import { providerBaseUrl } from "../../provider-metadata";
|
|
26
|
-
import { decodeKiloCredential } from "../../../security/credential-codec";
|
|
27
|
-
|
|
28
|
-
export const KILO_PROVIDER_ID = "kilo" as const;
|
|
29
|
-
export const KILO_BASE_URL = providerBaseUrl("kilo");
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Endpoint path recorded on this provider's model rows and used by the adapter.
|
|
33
|
-
*
|
|
34
|
-
* The base URL carries Kilo Code's API prefix (`/api/openrouter`), so this is
|
|
35
|
-
* the wire suffix that completes it — the same split Cline uses for
|
|
36
|
-
* `/api/v1` + `/chat/completions`.
|
|
37
|
-
*/
|
|
38
|
-
export const KILO_ENDPOINT_PATH = "/chat/completions" as const;
|
|
39
|
-
|
|
40
|
-
interface KiloModelOptions {
|
|
41
|
-
readonly vision?: boolean;
|
|
42
|
-
readonly document?: boolean;
|
|
43
|
-
readonly audio?: boolean;
|
|
44
|
-
readonly reasoning?: boolean;
|
|
45
|
-
readonly toolCall?: boolean;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function kiloModel(
|
|
49
|
-
modelId: string,
|
|
50
|
-
contextLimit: number,
|
|
51
|
-
outputLimit: number,
|
|
52
|
-
options: KiloModelOptions = {},
|
|
53
|
-
): ModelDefinition {
|
|
54
|
-
return defineModel({
|
|
55
|
-
id: modelId,
|
|
56
|
-
providerId: KILO_PROVIDER_ID,
|
|
57
|
-
wireFamily: "chat",
|
|
58
|
-
endpoint: KILO_ENDPOINT_PATH,
|
|
59
|
-
ctx: contextLimit,
|
|
60
|
-
out: outputLimit,
|
|
61
|
-
vision: options.vision ?? false,
|
|
62
|
-
document: options.document ?? false,
|
|
63
|
-
audio: options.audio ?? false,
|
|
64
|
-
reasoning: options.reasoning ?? false,
|
|
65
|
-
toolCall: options.toolCall ?? true,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Static fallback catalog, read from the live `/api/gateway/models` directory.
|
|
71
|
-
*
|
|
72
|
-
* Live discovery replaces this list whenever an account is available, so these
|
|
73
|
-
* rows are the offline floor: the gateway's own routing aliases plus one
|
|
74
|
-
* current model per family it resells. Limits and capability come from the
|
|
75
|
-
* directory entry's own `top_provider` / `architecture` /
|
|
76
|
-
* `supported_parameters` fields rather than from the base catalog, which prices
|
|
77
|
-
* the underlying model and not this reseller's serving.
|
|
78
|
-
*/
|
|
79
|
-
export const KILO_MODELS: readonly ModelDefinition[] = [
|
|
80
|
-
// Three routers, and nothing else. A committed catalog of specific ids was a
|
|
81
|
-
// snapshot of one afternoon: this provider resells the OpenRouter catalog,
|
|
82
|
-
// which adds and pulls models within days, so discovery is the authority and
|
|
83
|
-
// every hand-kept row outside these drifts out of truth.
|
|
84
|
-
//
|
|
85
|
-
// `kilo-auto/free` bills zero and `kilo-auto/small` bills a fraction of a
|
|
86
|
-
// cent; both route on the provider's own side, so their limits are the
|
|
87
|
-
// window the router may select into rather than one model's.
|
|
88
|
-
kiloModel("kilo-auto/free", 256_000, 32_768, { reasoning: true }),
|
|
89
|
-
kiloModel("kilo-auto/small", 262_144, 32_768, { vision: true, reasoning: true }),
|
|
90
|
-
];
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* The shared free roster, spelled for this provider's endpoint.
|
|
94
|
-
*
|
|
95
|
-
* The same 17 `:free` ids Cline and OpenRouter serve, because this is the same
|
|
96
|
-
* catalog behind a different origin. Kept separate from `KILO_MODELS` so the
|
|
97
|
-
* free tier is its own statement: those three rows are routers, these are the
|
|
98
|
-
* zero-cost models, and the model list groups them differently.
|
|
99
|
-
*/
|
|
100
|
-
export const KILO_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
|
|
101
|
-
providerId: KILO_PROVIDER_ID,
|
|
102
|
-
endpoint: KILO_ENDPOINT_PATH,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Adapter that decodes the credential envelope before the shared pipeline
|
|
107
|
-
* authenticates the request.
|
|
108
|
-
*
|
|
109
|
-
* `prepareHeaders` is corrected rather than rebuilt: every other header the
|
|
110
|
-
* factory contributes (content type, gateway identity, operator custom headers,
|
|
111
|
-
* route user-agent) stays exactly as every other provider gets it.
|
|
112
|
-
*/
|
|
113
|
-
class KiloAdapter extends OpenAICompatibleAdapter {
|
|
114
|
-
constructor(fetchImpl?: typeof fetch) {
|
|
115
|
-
super(
|
|
116
|
-
withBearerAuthentication({
|
|
117
|
-
provider_id: KILO_PROVIDER_ID,
|
|
118
|
-
base_url: KILO_BASE_URL,
|
|
119
|
-
endpoint_paths_by_wire_family: { chat: KILO_ENDPOINT_PATH },
|
|
120
|
-
...(fetchImpl ? { fetchImpl } : {}),
|
|
121
|
-
}),
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
protected override async prepareHeaders(
|
|
126
|
-
context: ProviderDispatchContext,
|
|
127
|
-
request: CanonicalRequest,
|
|
128
|
-
candidate: ProviderDispatchTarget,
|
|
129
|
-
): Promise<Record<string, string>> {
|
|
130
|
-
const headers = await super.prepareHeaders(context, request, candidate);
|
|
131
|
-
const secret = context.credential.secret;
|
|
132
|
-
if (secret === undefined || secret.length === 0) return headers;
|
|
133
|
-
// A credential that does not decode is left as the factory sent it: the
|
|
134
|
-
// request then fails closed at the upstream auth boundary, and the parse
|
|
135
|
-
// error belongs to the credential boundary rather than to this hook.
|
|
136
|
-
let credential: ReturnType<typeof decodeKiloCredential>;
|
|
137
|
-
try {
|
|
138
|
-
credential = decodeKiloCredential(secret);
|
|
139
|
-
} catch {
|
|
140
|
-
return headers;
|
|
141
|
-
}
|
|
142
|
-
headers.authorization = `Bearer ${credential.accessToken}`;
|
|
143
|
-
// The upstream's own header name, not ours: renaming the Cartethyia
|
|
144
|
-
// provider id does not rename a field the upstream reads.
|
|
145
|
-
if (credential.orgId !== undefined) headers["X-Kilocode-OrganizationID"] = credential.orgId;
|
|
146
|
-
return headers;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/** Kilo Code provider adapter. */
|
|
151
|
-
export const kiloAdapter: ProviderAdapter = new KiloAdapter();
|
|
152
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Kilo Code adapter.
|
|
3
|
+
*
|
|
4
|
+
* Kilo Code resells the OpenRouter catalog behind a bearer device token on an
|
|
5
|
+
* OpenAI-compatible chat surface, so this adapter reuses the shared factory for
|
|
6
|
+
* payload translation, transport, and SSE decoding.
|
|
7
|
+
*
|
|
8
|
+
* One thing sits outside the declarative `ApiKeyProviderSpec`: the stored
|
|
9
|
+
* credential is a JSON envelope (`{ accessToken, orgId }`) because the gateway
|
|
10
|
+
* scopes every request to the account's organization and the console stores one
|
|
11
|
+
* opaque string per account. The factory forwards that string as the bearer
|
|
12
|
+
* verbatim, so the envelope is decoded at the auth boundary here — the same
|
|
13
|
+
* arrangement `kimi/kimi.ts` uses for its own envelope credential.
|
|
14
|
+
*
|
|
15
|
+
* The base URL is the completions path itself, because that is the path Kilo
|
|
16
|
+
* Code publishes (`/api/openrouter/chat/completions`) and it is not derivable
|
|
17
|
+
* from an origin plus a wire-family suffix.
|
|
18
|
+
*/
|
|
19
|
+
import { defineModel } from "../../provider-model-definition";
|
|
20
|
+
import { openrouterFreeRoster } from "../../discovery/openrouter-free-roster";
|
|
21
|
+
import type { ModelDefinition } from "../../provider-model-definition";
|
|
22
|
+
import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
|
|
23
|
+
import type { CanonicalRequest } from "../../../protocol/canonical-model";
|
|
24
|
+
import { OpenAICompatibleAdapter, withBearerAuthentication } from "../../adapters/compatible-adapter";
|
|
25
|
+
import { providerBaseUrl } from "../../provider-metadata";
|
|
26
|
+
import { decodeKiloCredential } from "../../../security/credential-codec";
|
|
27
|
+
|
|
28
|
+
export const KILO_PROVIDER_ID = "kilo" as const;
|
|
29
|
+
export const KILO_BASE_URL = providerBaseUrl("kilo");
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Endpoint path recorded on this provider's model rows and used by the adapter.
|
|
33
|
+
*
|
|
34
|
+
* The base URL carries Kilo Code's API prefix (`/api/openrouter`), so this is
|
|
35
|
+
* the wire suffix that completes it — the same split Cline uses for
|
|
36
|
+
* `/api/v1` + `/chat/completions`.
|
|
37
|
+
*/
|
|
38
|
+
export const KILO_ENDPOINT_PATH = "/chat/completions" as const;
|
|
39
|
+
|
|
40
|
+
interface KiloModelOptions {
|
|
41
|
+
readonly vision?: boolean;
|
|
42
|
+
readonly document?: boolean;
|
|
43
|
+
readonly audio?: boolean;
|
|
44
|
+
readonly reasoning?: boolean;
|
|
45
|
+
readonly toolCall?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function kiloModel(
|
|
49
|
+
modelId: string,
|
|
50
|
+
contextLimit: number,
|
|
51
|
+
outputLimit: number,
|
|
52
|
+
options: KiloModelOptions = {},
|
|
53
|
+
): ModelDefinition {
|
|
54
|
+
return defineModel({
|
|
55
|
+
id: modelId,
|
|
56
|
+
providerId: KILO_PROVIDER_ID,
|
|
57
|
+
wireFamily: "chat",
|
|
58
|
+
endpoint: KILO_ENDPOINT_PATH,
|
|
59
|
+
ctx: contextLimit,
|
|
60
|
+
out: outputLimit,
|
|
61
|
+
vision: options.vision ?? false,
|
|
62
|
+
document: options.document ?? false,
|
|
63
|
+
audio: options.audio ?? false,
|
|
64
|
+
reasoning: options.reasoning ?? false,
|
|
65
|
+
toolCall: options.toolCall ?? true,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Static fallback catalog, read from the live `/api/gateway/models` directory.
|
|
71
|
+
*
|
|
72
|
+
* Live discovery replaces this list whenever an account is available, so these
|
|
73
|
+
* rows are the offline floor: the gateway's own routing aliases plus one
|
|
74
|
+
* current model per family it resells. Limits and capability come from the
|
|
75
|
+
* directory entry's own `top_provider` / `architecture` /
|
|
76
|
+
* `supported_parameters` fields rather than from the base catalog, which prices
|
|
77
|
+
* the underlying model and not this reseller's serving.
|
|
78
|
+
*/
|
|
79
|
+
export const KILO_MODELS: readonly ModelDefinition[] = [
|
|
80
|
+
// Three routers, and nothing else. A committed catalog of specific ids was a
|
|
81
|
+
// snapshot of one afternoon: this provider resells the OpenRouter catalog,
|
|
82
|
+
// which adds and pulls models within days, so discovery is the authority and
|
|
83
|
+
// every hand-kept row outside these drifts out of truth.
|
|
84
|
+
//
|
|
85
|
+
// `kilo-auto/free` bills zero and `kilo-auto/small` bills a fraction of a
|
|
86
|
+
// cent; both route on the provider's own side, so their limits are the
|
|
87
|
+
// window the router may select into rather than one model's.
|
|
88
|
+
kiloModel("kilo-auto/free", 256_000, 32_768, { reasoning: true }),
|
|
89
|
+
kiloModel("kilo-auto/small", 262_144, 32_768, { vision: true, reasoning: true }),
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The shared free roster, spelled for this provider's endpoint.
|
|
94
|
+
*
|
|
95
|
+
* The same 17 `:free` ids Cline and OpenRouter serve, because this is the same
|
|
96
|
+
* catalog behind a different origin. Kept separate from `KILO_MODELS` so the
|
|
97
|
+
* free tier is its own statement: those three rows are routers, these are the
|
|
98
|
+
* zero-cost models, and the model list groups them differently.
|
|
99
|
+
*/
|
|
100
|
+
export const KILO_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
|
|
101
|
+
providerId: KILO_PROVIDER_ID,
|
|
102
|
+
endpoint: KILO_ENDPOINT_PATH,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Adapter that decodes the credential envelope before the shared pipeline
|
|
107
|
+
* authenticates the request.
|
|
108
|
+
*
|
|
109
|
+
* `prepareHeaders` is corrected rather than rebuilt: every other header the
|
|
110
|
+
* factory contributes (content type, gateway identity, operator custom headers,
|
|
111
|
+
* route user-agent) stays exactly as every other provider gets it.
|
|
112
|
+
*/
|
|
113
|
+
class KiloAdapter extends OpenAICompatibleAdapter {
|
|
114
|
+
constructor(fetchImpl?: typeof fetch) {
|
|
115
|
+
super(
|
|
116
|
+
withBearerAuthentication({
|
|
117
|
+
provider_id: KILO_PROVIDER_ID,
|
|
118
|
+
base_url: KILO_BASE_URL,
|
|
119
|
+
endpoint_paths_by_wire_family: { chat: KILO_ENDPOINT_PATH },
|
|
120
|
+
...(fetchImpl ? { fetchImpl } : {}),
|
|
121
|
+
}),
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
protected override async prepareHeaders(
|
|
126
|
+
context: ProviderDispatchContext,
|
|
127
|
+
request: CanonicalRequest,
|
|
128
|
+
candidate: ProviderDispatchTarget,
|
|
129
|
+
): Promise<Record<string, string>> {
|
|
130
|
+
const headers = await super.prepareHeaders(context, request, candidate);
|
|
131
|
+
const secret = context.credential.secret;
|
|
132
|
+
if (secret === undefined || secret.length === 0) return headers;
|
|
133
|
+
// A credential that does not decode is left as the factory sent it: the
|
|
134
|
+
// request then fails closed at the upstream auth boundary, and the parse
|
|
135
|
+
// error belongs to the credential boundary rather than to this hook.
|
|
136
|
+
let credential: ReturnType<typeof decodeKiloCredential>;
|
|
137
|
+
try {
|
|
138
|
+
credential = decodeKiloCredential(secret);
|
|
139
|
+
} catch {
|
|
140
|
+
return headers;
|
|
141
|
+
}
|
|
142
|
+
headers.authorization = `Bearer ${credential.accessToken}`;
|
|
143
|
+
// The upstream's own header name, not ours: renaming the Cartethyia
|
|
144
|
+
// provider id does not rename a field the upstream reads.
|
|
145
|
+
if (credential.orgId !== undefined) headers["X-Kilocode-OrganizationID"] = credential.orgId;
|
|
146
|
+
return headers;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Kilo Code provider adapter. */
|
|
151
|
+
export const kiloAdapter: ProviderAdapter = new KiloAdapter();
|
|
152
|
+
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sha256Hex } from "../../../shared/hash";
|
|
1
2
|
/**
|
|
2
3
|
* Kiro machine identity.
|
|
3
4
|
*
|
|
@@ -21,7 +22,6 @@
|
|
|
21
22
|
* They are deliberately different per credential family, because an API key and
|
|
22
23
|
* a refresh token for the same account must not derive the same device id.
|
|
23
24
|
*/
|
|
24
|
-
import { createHash } from "node:crypto";
|
|
25
25
|
|
|
26
26
|
/** Prefix the observed client hashes for an OAuth (refresh-token) credential. */
|
|
27
27
|
const OAUTH_SALT = "KotlinNativeAPI/";
|
|
@@ -33,9 +33,7 @@ const FALLBACK_SALT = "KiroFallback/";
|
|
|
33
33
|
/** Length of a machine id, in hex characters. */
|
|
34
34
|
const MACHINE_ID_LENGTH = 64;
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
return createHash("sha256").update(input).digest("hex");
|
|
38
|
-
}
|
|
36
|
+
|
|
39
37
|
|
|
40
38
|
/**
|
|
41
39
|
* Normalizes a machine id supplied from outside the derivation.
|
|
@@ -1,129 +1,129 @@
|
|
|
1
|
-
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
2
|
-
import type { ModelDefinition } from "../../provider-model-definition";
|
|
3
|
-
import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
|
|
4
|
-
import { providerBaseUrl } from "../../provider-metadata";
|
|
5
|
-
import type { DiscoveryInput } from "../../discovery/discovery-types";
|
|
6
|
-
import { defineModel } from "../../provider-model-definition";
|
|
7
|
-
import { openrouterFreeRoster } from "../../discovery/openrouter-free-roster";
|
|
8
|
-
|
|
9
|
-
const OPENROUTER_PROVIDER_ID = "openrouter" as const;
|
|
10
|
-
|
|
11
|
-
/** OpenRouter requires these on every request for ranking/attribution. */
|
|
12
|
-
const OPENROUTER_REQUIRED_HEADERS: Readonly<Record<string, string>> = {
|
|
13
|
-
"HTTP-Referer": "https://endpoint-proxy.local",
|
|
14
|
-
"X-Title": "Endpoint Proxy",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* OpenRouter's non-chat service models.
|
|
19
|
-
*
|
|
20
|
-
* OpenRouter fronts the System One decision API (`/api/v1/systemone`) as
|
|
21
|
-
* `typesafe/jev-1.13`, which is not a chat model: it answers `{answers}` to a
|
|
22
|
-
* `{state, questions}` body. `/api/v1/models` does not list it under a wire the
|
|
23
|
-
* generic fetcher can classify, so it is declared here — a `serviceKind` row
|
|
24
|
-
* served by the native System One route, never by the chat surface.
|
|
25
|
-
*/
|
|
26
|
-
export const OPENROUTER_MODELS: readonly ModelDefinition[] = [
|
|
27
|
-
// No committed chat rows. OpenRouter adds and pulls models within days, so a
|
|
28
|
-
// hand-kept list of ids drifts out of truth and discovery is the authority;
|
|
29
|
-
// the free roster below stays as the offline floor. `openrouter/auto` was the
|
|
30
|
-
// last committed chat row and went with the rest of the static catalog — it
|
|
31
|
-
// publishes no limits of its own anyway, since a router's pricing is -1.
|
|
32
|
-
// Not a chat row: it answers `{answers}` to a `{state, questions}` body, and
|
|
33
|
-
// is served by the native System One route. Kept because deleting it removes
|
|
34
|
-
// that route, which is a capability, not a stale catalog entry.
|
|
35
|
-
defineModel({
|
|
36
|
-
id: "typesafe/jev-1.13",
|
|
37
|
-
providerId: "openrouter",
|
|
38
|
-
serviceKind: "systemone",
|
|
39
|
-
wireFamily: "chat",
|
|
40
|
-
endpoint: "/systemone",
|
|
41
|
-
ctx: 200_000,
|
|
42
|
-
out: 8_192,
|
|
43
|
-
toolCall: false,
|
|
44
|
-
}),
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* OpenRouter's `:free` tier, as a default catalog.
|
|
50
|
-
*
|
|
51
|
-
* OpenRouter runs live `/api/v1/models` discovery, so this is a floor rather
|
|
52
|
-
* than the only source — but without it the provider lists nothing at all
|
|
53
|
-
* until a discovery run happens to fetch it, and the free tier is the one part
|
|
54
|
-
* of OpenRouter an operator can use with no spend.
|
|
55
|
-
*
|
|
56
|
-
* Fetched 2026-10-12 from `https://openrouter.ai/api/v1/models`, which served
|
|
57
|
-
* 15 `:free` rows; the 14 that the base catalog also files under `openrouter`
|
|
58
|
-
* are listed here. `apodex/apodex-1.1-mini:free` is absent because the base
|
|
59
|
-
* catalog has no row for it under any provider, so its limits and price would
|
|
60
|
-
* have to be guessed — and a published guess reads as a measurement. Discovery
|
|
61
|
-
* still picks it up, which is the correct path for a row with no catalog data.
|
|
62
|
-
*
|
|
63
|
-
* Every row is marked `freeTier` as well as `free`, because the two answer
|
|
64
|
-
* different questions: `free` says this bills zero per token, and `freeTier` is
|
|
65
|
-
* what the model list groups on so the free roster is labelled as such rather
|
|
66
|
-
* than mixed in with the billed catalog.
|
|
67
|
-
*/
|
|
68
|
-
export const OPENROUTER_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
|
|
69
|
-
providerId: OPENROUTER_PROVIDER_ID,
|
|
70
|
-
endpoint: "/chat/completions",
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* OpenRouter's `:free` rows, discovered live.
|
|
76
|
-
*
|
|
77
|
-
* OpenRouter rotates its free tier constantly — models are added and pulled
|
|
78
|
-
* within days — so a committed list is only ever a snapshot of one afternoon.
|
|
79
|
-
* This is the same shape as the OpenCode Zen free fetch: filter the provider's
|
|
80
|
-
* own live listing down to the free rows and mark each one `freeTier`, which is
|
|
81
|
-
* what the model list groups under "Free models (auto)".
|
|
82
|
-
*
|
|
83
|
-
* The rows are the fetcher's own definitions, spread rather than rebuilt: it
|
|
84
|
-
* has already resolved limits, pricing, and the wire family from the id, and
|
|
85
|
-
* re-deriving that here would discard the resolution and let the two drift.
|
|
86
|
-
*/
|
|
87
|
-
export async function discoverOpenrouterFreeModels(
|
|
88
|
-
input: DiscoveryInput,
|
|
89
|
-
): Promise<readonly ModelDefinition[] | null> {
|
|
90
|
-
const listed = await discoverOpenrouterModels(input);
|
|
91
|
-
if (listed === null) return null;
|
|
92
|
-
return (
|
|
93
|
-
listed
|
|
94
|
-
// OpenRouter's free-tier spelling is a `:free` id suffix, matched exactly
|
|
95
|
-
// rather than as a substring so a model whose own name contains "free" is
|
|
96
|
-
// not swept in by accident.
|
|
97
|
-
.filter((model) => model.modelId.endsWith(":free"))
|
|
98
|
-
.map((model) => ({
|
|
99
|
-
...model,
|
|
100
|
-
// `free` is a billing statement and `freeTier` a catalog one. The
|
|
101
|
-
// `:free` suffix answers both, so both are set; the cost is left as the
|
|
102
|
-
// fetcher resolved it because OpenRouter publishes a real zero price.
|
|
103
|
-
free: true,
|
|
104
|
-
freeTier: true,
|
|
105
|
-
}))
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
/** OpenRouter adapter spec; the registry builds it via `createApiKeyAdapter`. */
|
|
111
|
-
export const OPENROUTER_SPEC: ApiKeyProviderSpec = {
|
|
112
|
-
provider_id: OPENROUTER_PROVIDER_ID,
|
|
113
|
-
endpoint_paths_by_wire_family: {},
|
|
114
|
-
extra_headers: OPENROUTER_REQUIRED_HEADERS,
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
export async function discoverOpenrouterModels(
|
|
118
|
-
input: DiscoveryInput,
|
|
119
|
-
): Promise<readonly ModelDefinition[] | null> {
|
|
120
|
-
return fetchOpenAICompatibleModels({
|
|
121
|
-
baseUrl: providerBaseUrl("openrouter"),
|
|
122
|
-
headers: {
|
|
123
|
-
authorization: `Bearer ${input.credential}`,
|
|
124
|
-
...OPENROUTER_REQUIRED_HEADERS,
|
|
125
|
-
},
|
|
126
|
-
...(input.signal ? { signal: input.signal } : {}),
|
|
127
|
-
...(input.fetcher ? { fetcher: input.fetcher } : {}),
|
|
128
|
-
});
|
|
129
|
-
}
|
|
1
|
+
import type { ApiKeyProviderSpec } from "../../configured-provider";
|
|
2
|
+
import type { ModelDefinition } from "../../provider-model-definition";
|
|
3
|
+
import { fetchOpenAICompatibleModels } from "../../discovery/openai-model-discovery";
|
|
4
|
+
import { providerBaseUrl } from "../../provider-metadata";
|
|
5
|
+
import type { DiscoveryInput } from "../../discovery/discovery-types";
|
|
6
|
+
import { defineModel } from "../../provider-model-definition";
|
|
7
|
+
import { openrouterFreeRoster } from "../../discovery/openrouter-free-roster";
|
|
8
|
+
|
|
9
|
+
const OPENROUTER_PROVIDER_ID = "openrouter" as const;
|
|
10
|
+
|
|
11
|
+
/** OpenRouter requires these on every request for ranking/attribution. */
|
|
12
|
+
const OPENROUTER_REQUIRED_HEADERS: Readonly<Record<string, string>> = {
|
|
13
|
+
"HTTP-Referer": "https://endpoint-proxy.local",
|
|
14
|
+
"X-Title": "Endpoint Proxy",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* OpenRouter's non-chat service models.
|
|
19
|
+
*
|
|
20
|
+
* OpenRouter fronts the System One decision API (`/api/v1/systemone`) as
|
|
21
|
+
* `typesafe/jev-1.13`, which is not a chat model: it answers `{answers}` to a
|
|
22
|
+
* `{state, questions}` body. `/api/v1/models` does not list it under a wire the
|
|
23
|
+
* generic fetcher can classify, so it is declared here — a `serviceKind` row
|
|
24
|
+
* served by the native System One route, never by the chat surface.
|
|
25
|
+
*/
|
|
26
|
+
export const OPENROUTER_MODELS: readonly ModelDefinition[] = [
|
|
27
|
+
// No committed chat rows. OpenRouter adds and pulls models within days, so a
|
|
28
|
+
// hand-kept list of ids drifts out of truth and discovery is the authority;
|
|
29
|
+
// the free roster below stays as the offline floor. `openrouter/auto` was the
|
|
30
|
+
// last committed chat row and went with the rest of the static catalog — it
|
|
31
|
+
// publishes no limits of its own anyway, since a router's pricing is -1.
|
|
32
|
+
// Not a chat row: it answers `{answers}` to a `{state, questions}` body, and
|
|
33
|
+
// is served by the native System One route. Kept because deleting it removes
|
|
34
|
+
// that route, which is a capability, not a stale catalog entry.
|
|
35
|
+
defineModel({
|
|
36
|
+
id: "typesafe/jev-1.13",
|
|
37
|
+
providerId: "openrouter",
|
|
38
|
+
serviceKind: "systemone",
|
|
39
|
+
wireFamily: "chat",
|
|
40
|
+
endpoint: "/systemone",
|
|
41
|
+
ctx: 200_000,
|
|
42
|
+
out: 8_192,
|
|
43
|
+
toolCall: false,
|
|
44
|
+
}),
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* OpenRouter's `:free` tier, as a default catalog.
|
|
50
|
+
*
|
|
51
|
+
* OpenRouter runs live `/api/v1/models` discovery, so this is a floor rather
|
|
52
|
+
* than the only source — but without it the provider lists nothing at all
|
|
53
|
+
* until a discovery run happens to fetch it, and the free tier is the one part
|
|
54
|
+
* of OpenRouter an operator can use with no spend.
|
|
55
|
+
*
|
|
56
|
+
* Fetched 2026-10-12 from `https://openrouter.ai/api/v1/models`, which served
|
|
57
|
+
* 15 `:free` rows; the 14 that the base catalog also files under `openrouter`
|
|
58
|
+
* are listed here. `apodex/apodex-1.1-mini:free` is absent because the base
|
|
59
|
+
* catalog has no row for it under any provider, so its limits and price would
|
|
60
|
+
* have to be guessed — and a published guess reads as a measurement. Discovery
|
|
61
|
+
* still picks it up, which is the correct path for a row with no catalog data.
|
|
62
|
+
*
|
|
63
|
+
* Every row is marked `freeTier` as well as `free`, because the two answer
|
|
64
|
+
* different questions: `free` says this bills zero per token, and `freeTier` is
|
|
65
|
+
* what the model list groups on so the free roster is labelled as such rather
|
|
66
|
+
* than mixed in with the billed catalog.
|
|
67
|
+
*/
|
|
68
|
+
export const OPENROUTER_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
|
|
69
|
+
providerId: OPENROUTER_PROVIDER_ID,
|
|
70
|
+
endpoint: "/chat/completions",
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* OpenRouter's `:free` rows, discovered live.
|
|
76
|
+
*
|
|
77
|
+
* OpenRouter rotates its free tier constantly — models are added and pulled
|
|
78
|
+
* within days — so a committed list is only ever a snapshot of one afternoon.
|
|
79
|
+
* This is the same shape as the OpenCode Zen free fetch: filter the provider's
|
|
80
|
+
* own live listing down to the free rows and mark each one `freeTier`, which is
|
|
81
|
+
* what the model list groups under "Free models (auto)".
|
|
82
|
+
*
|
|
83
|
+
* The rows are the fetcher's own definitions, spread rather than rebuilt: it
|
|
84
|
+
* has already resolved limits, pricing, and the wire family from the id, and
|
|
85
|
+
* re-deriving that here would discard the resolution and let the two drift.
|
|
86
|
+
*/
|
|
87
|
+
export async function discoverOpenrouterFreeModels(
|
|
88
|
+
input: DiscoveryInput,
|
|
89
|
+
): Promise<readonly ModelDefinition[] | null> {
|
|
90
|
+
const listed = await discoverOpenrouterModels(input);
|
|
91
|
+
if (listed === null) return null;
|
|
92
|
+
return (
|
|
93
|
+
listed
|
|
94
|
+
// OpenRouter's free-tier spelling is a `:free` id suffix, matched exactly
|
|
95
|
+
// rather than as a substring so a model whose own name contains "free" is
|
|
96
|
+
// not swept in by accident.
|
|
97
|
+
.filter((model) => model.modelId.endsWith(":free"))
|
|
98
|
+
.map((model) => ({
|
|
99
|
+
...model,
|
|
100
|
+
// `free` is a billing statement and `freeTier` a catalog one. The
|
|
101
|
+
// `:free` suffix answers both, so both are set; the cost is left as the
|
|
102
|
+
// fetcher resolved it because OpenRouter publishes a real zero price.
|
|
103
|
+
free: true,
|
|
104
|
+
freeTier: true,
|
|
105
|
+
}))
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
/** OpenRouter adapter spec; the registry builds it via `createApiKeyAdapter`. */
|
|
111
|
+
export const OPENROUTER_SPEC: ApiKeyProviderSpec = {
|
|
112
|
+
provider_id: OPENROUTER_PROVIDER_ID,
|
|
113
|
+
endpoint_paths_by_wire_family: {},
|
|
114
|
+
extra_headers: OPENROUTER_REQUIRED_HEADERS,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export async function discoverOpenrouterModels(
|
|
118
|
+
input: DiscoveryInput,
|
|
119
|
+
): Promise<readonly ModelDefinition[] | null> {
|
|
120
|
+
return fetchOpenAICompatibleModels({
|
|
121
|
+
baseUrl: providerBaseUrl("openrouter"),
|
|
122
|
+
headers: {
|
|
123
|
+
authorization: `Bearer ${input.credential}`,
|
|
124
|
+
...OPENROUTER_REQUIRED_HEADERS,
|
|
125
|
+
},
|
|
126
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
127
|
+
...(input.fetcher ? { fetcher: input.fetcher } : {}),
|
|
128
|
+
});
|
|
129
|
+
}
|