cartethyia 2.4.6 → 2.5.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/README.md +45 -13
- package/dist/dashboard/assets/BannedPage-9igfctfZ.js +1 -0
- package/dist/dashboard/assets/BannedPage-9igfctfZ.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-Bcy150Jo.js → CliToolDetailPage-ZRr2K2sF.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-ZRr2K2sF.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DyNXefph.js → CliToolsPage-D3xqZbN-.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-D3xqZbN-.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CVnQPBBz.js +1 -0
- package/dist/dashboard/assets/CombosPage-CVnQPBBz.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CATpAEOz.js → ConsoleLogPage-u6W1UXSc.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-D6jEU7nL.js → CustomizationPage-CTTpCb25.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-CTTpCb25.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-CZkpn0a7.js → HealthEventsModal-C5XpWlvy.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-BJlMVN4U.js → LoginPage-DHoB3Agn.js} +1 -1
- package/dist/dashboard/assets/LoginPage-DHoB3Agn.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-Br3CXEau.js → ModelPicker-oQ-SDXp8.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js +1 -0
- package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
- package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js +7 -0
- package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js +1 -0
- package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js.gz +0 -0
- package/dist/dashboard/assets/{SettingsPage-BHW4Zt06.js → SettingsPage-CvjZxHE4.js} +1 -1
- package/dist/dashboard/assets/SettingsPage-CvjZxHE4.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-VOYC_lIa.js → SetupPage-D3nza7LH.js} +1 -1
- package/dist/dashboard/assets/SetupPage-D3nza7LH.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-Dtt12WT1.js +1 -0
- package/dist/dashboard/assets/SortableList-Dtt12WT1.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-BNIDLiU6.js → StudioPage-CbK3hXvU.js} +4 -4
- package/dist/dashboard/assets/StudioPage-CbK3hXvU.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BQlWbWg2.js +56 -0
- package/dist/dashboard/assets/UsagePage-BQlWbWg2.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-BETfaMYZ.js → api-keys-BmDbsior.js} +1 -1
- package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
- package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
- package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
- package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
- package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
- package/dist/dashboard/assets/{badge-BTyGk_DL.js → badge-DpXT4Ixt.js} +1 -1
- package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
- package/dist/dashboard/assets/{banner-bujTWYM4.js → banner-CSAAWLJv.js} +1 -1
- package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
- package/dist/dashboard/assets/{card-B0Bnx5CA.js → card-DEhRXXw4.js} +1 -1
- package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-DE2ug812.js → cli-tools-B0wBq-RL.js} +1 -1
- package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-R_rArH8S.js → clipboard-button-DOo6EU8O.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BWIP_EvW.js → dialog-BvQeBMfP.js} +1 -1
- package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-BKcgVugF.js → drawer-CMwPXwQB.js} +1 -1
- package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CcWkGR4a.js → entry-D4O2229X.js} +1 -1
- package/dist/dashboard/assets/{entry-CcWkGR4a.js.gz → entry-D4O2229X.js.gz} +0 -0
- package/dist/dashboard/assets/{entry-kTiTFrvh.js → entry-DKvr5Q9K.js} +1 -1
- package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
- package/dist/dashboard/assets/entry-FQCejoDY.js +4 -0
- package/dist/dashboard/assets/entry-FQCejoDY.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-Booc5mNe.js → github-badge-zliLvBwr.js} +1 -1
- package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
- package/dist/dashboard/assets/{index-D70pChfn.js → index-CXm3FIyt.js} +2 -2
- package/dist/dashboard/assets/index-CXm3FIyt.js.gz +0 -0
- package/dist/dashboard/assets/{inline-D1TCqM2D.js → inline-D1IlZZ8H.js} +1 -1
- package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
- package/dist/dashboard/assets/{input-B9oyU93y.js → input-BpVZdrbc.js} +1 -1
- package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
- package/dist/dashboard/assets/{layout-BArzXirQ.js → layout-BioLW7gN.js} +1 -1
- package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-BVZzaoHF.js → list-row-CwVcGAIc.js} +1 -1
- package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
- package/dist/dashboard/assets/{live-EmuIayqp.js → live-yfEJFF9T.js} +1 -1
- package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
- package/dist/dashboard/assets/{model-bans-CSPQ9xB0.js → model-bans-CT-TxSNX.js} +1 -1
- package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
- package/dist/dashboard/assets/providers/cursor.webp +0 -0
- package/dist/dashboard/assets/providers/trae.webp +0 -0
- package/dist/dashboard/assets/{routing-BExgxxBU.js → routing-Cs6jl49L.js} +1 -1
- package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
- package/dist/dashboard/assets/select-C0Rer3gF.js +41 -0
- package/dist/dashboard/assets/select-C0Rer3gF.js.gz +0 -0
- package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
- package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
- package/dist/dashboard/assets/{stack-Ca5HxI5i.js → stack-C9_uUjaA.js} +1 -1
- package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
- package/dist/dashboard/assets/{state-CzUPfLXo.js → state-DA0B95UQ.js} +1 -1
- package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
- package/dist/dashboard/assets/{switch-DOUIky_i.js → switch-Cittxy-x.js} +1 -1
- package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
- package/dist/dashboard/assets/{toast-C76WrMhc.js → toast-CNt_jzO4.js} +1 -1
- package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-D87FZwH0.js → useMutation-BQKMcJ1H.js} +1 -1
- package/dist/dashboard/assets/useMutation-BQKMcJ1H.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 -52
- package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
- package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
- package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
- package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
- package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
- package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
- package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
- package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
- package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
- package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
- package/package.json +3 -2
- package/scripts/cli/command/console-menu.ts +30 -11
- package/scripts/cli/command/start.ts +77 -13
- package/scripts/cli/command/update.ts +1 -1
- package/scripts/cli/gateway/instance-lock.ts +105 -0
- package/scripts/cli/gateway/spawn.ts +173 -101
- package/scripts/cli/ui/background.ts +110 -49
- package/src/boot/app.ts +20 -6
- package/src/boot/dependencies.ts +19 -0
- package/src/boot/elysia-typebox-bridge.ts +37 -0
- package/src/boot/lifecycle.ts +2 -0
- package/src/config/cooldowns.ts +138 -138
- package/src/config/providers.ts +5 -5
- package/src/config/runtime.ts +19 -3
- package/src/config/spec.ts +9 -0
- package/src/console/api-keys/contracts.ts +414 -391
- package/src/console/api-keys/routes.ts +880 -870
- package/src/console/auth/account-reset-store.ts +14 -0
- package/src/console/auth/account-reset.ts +3 -2
- package/src/console/auth/setup-service.ts +6 -3
- package/src/console/domain-registration.ts +9 -2
- package/src/console/observability/contracts.ts +475 -455
- package/src/console/observability/store.ts +1015 -952
- package/src/console/providers/catalog/contracts.ts +31 -0
- package/src/console/providers/catalog/provider-operations.ts +8 -0
- package/src/console/providers/catalog/store.ts +1532 -1525
- package/src/console/providers/oauth/callback-listener.ts +18 -3
- package/src/console/providers/oauth/routes.ts +38 -15
- package/src/console/quota/refresh.ts +19 -0
- package/src/console/updates/routes.ts +162 -4
- package/src/main.ts +3 -0
- package/src/network/http2-bidi.ts +85 -0
- package/src/network/outbound-fetch.ts +1 -26
- package/src/network/pool/agent.ts +478 -460
- package/src/network/pool/resolver.ts +1104 -544
- package/src/network/pool-health-machine.ts +12 -5
- package/src/observability/payload-capture.ts +344 -324
- package/src/persistence/db-pg.ts +9 -3
- package/src/persistence/db-sqlite.ts +497 -495
- package/src/persistence/health-event-flush.ts +137 -0
- package/src/persistence/migrate.ts +181 -129
- package/src/persistence/schema.ts +1360 -1295
- package/src/persistence/settings-revision.ts +25 -0
- package/src/persistence/shared-cache.ts +217 -0
- package/src/persistence/stores/share-store.ts +556 -528
- package/src/persistence/usage-flush.ts +61 -1
- package/src/protocol/canonical-model.ts +23 -1
- package/src/protocol/response/chat.ts +143 -10
- package/src/protocol/response/omp-tool-call-markup.ts +221 -0
- package/src/providers/default-registry.ts +173 -1
- package/src/providers/discovery/openai-model-discovery.ts +39 -3
- package/src/providers/discovery/openrouter-free-roster.ts +98 -0
- package/src/providers/discovery/probing-service.ts +1022 -1001
- package/src/providers/integrations/buddy/buddy-catalog-shared.ts +39 -0
- package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
- package/src/providers/integrations/buddy/buddy-conversation-headers.ts +18 -5
- package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
- package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
- package/src/providers/integrations/buddy/codebuddy/shared.ts +15 -6
- package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
- package/src/providers/integrations/buddy/workbuddy/shared.ts +3 -3
- package/src/providers/integrations/claude/claude.ts +606 -582
- package/src/providers/integrations/cline/cline-quota.ts +18 -16
- package/src/providers/integrations/cline/cline.ts +539 -468
- package/src/providers/integrations/commandcode/commandcode.ts +675 -541
- package/src/providers/integrations/commandcode/discovery.ts +116 -0
- package/src/providers/integrations/commandcode/quota.ts +160 -0
- package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
- package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
- package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
- package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
- package/src/providers/integrations/cursor/cursor-request.ts +471 -0
- package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
- package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
- package/src/providers/integrations/cursor/cursor.ts +960 -0
- package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
- package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
- package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
- package/src/providers/integrations/github/github.ts +4 -4
- package/src/providers/integrations/hermes.ts +79 -8
- package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
- package/src/providers/integrations/kilo/kilo.ts +153 -146
- package/src/providers/integrations/opencode/provider.ts +532 -538
- package/src/providers/integrations/openrouter/provider.ts +139 -281
- package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
- package/src/providers/integrations/qoder/qoder-oauth.ts +310 -257
- package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
- package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
- package/src/providers/integrations/qoder/qoder.ts +865 -730
- package/src/providers/integrations/trae/trae-catalog.ts +190 -0
- package/src/providers/integrations/trae/trae-headers.ts +149 -0
- package/src/providers/integrations/trae/trae-oauth.ts +773 -0
- package/src/providers/integrations/trae/trae-protocol.ts +400 -0
- package/src/providers/integrations/trae/trae-realm.ts +220 -0
- package/src/providers/integrations/trae/trae.ts +458 -0
- package/src/providers/operations/account-health-service.ts +107 -10
- package/src/providers/operations/client-versions.ts +133 -6
- package/src/providers/operations/provider-catalog-seeder.ts +95 -86
- package/src/providers/operations/provider-credential-service.ts +46 -7
- package/src/providers/provider-contracts.ts +76 -0
- package/src/providers/provider-metadata.ts +78 -6
- package/src/providers/provider-model-definition.ts +373 -349
- package/src/security/api-key-auth.ts +126 -8
- package/src/transport/contracts.ts +3 -0
- package/src/transport/dispatch/attempt-finalize.ts +32 -1
- package/src/transport/dispatch/attempt-loop.ts +530 -515
- package/src/transport/dispatch/generation.ts +88 -21
- package/src/transport/dispatch/leases.ts +99 -2
- package/src/transport/dispatch/proxy-request.ts +60 -3
- package/src/transport/dispatch/streaming/finalize.ts +16 -1
- package/src/transport/dispatch/streaming/stream.ts +22 -2
- package/src/transport/dispatch/upstream.ts +19 -1
- package/src/transport/guards/auth-guard.ts +26 -1
- package/src/transport/guards/body-policy.ts +5 -4
- package/src/transport/request/preparer.ts +103 -0
- package/src/transport/request/state.ts +14 -0
- package/src/transport/routing/plan-gate.ts +45 -0
- package/src/transport/routing/route-catalog.ts +799 -777
- package/src/transport/routing/route-model.ts +52 -1
- package/src/transport/routing/router.ts +51 -0
- package/dist/dashboard/assets/BannedPage-QhvbJB9o.js +0 -1
- package/dist/dashboard/assets/BannedPage-QhvbJB9o.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-Bcy150Jo.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DyNXefph.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js +0 -1
- package/dist/dashboard/assets/CombosPage-Cak0ljnO.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CATpAEOz.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-D6jEU7nL.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-CZkpn0a7.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-BJlMVN4U.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-Br3CXEau.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js +0 -1
- package/dist/dashboard/assets/OverviewPage-CQxXbo2g.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage--0RBNh99.js.gz +0 -0
- package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
- package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-1M-C3mbu.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js +0 -7
- package/dist/dashboard/assets/ProxyPage-CXiumA53.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BGDIfIYP.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BHW4Zt06.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-VOYC_lIa.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js +0 -1
- package/dist/dashboard/assets/SortableList-DpOTnGuH.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-BNIDLiU6.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-BAFaSDQV.js +0 -56
- package/dist/dashboard/assets/UsagePage-BAFaSDQV.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-BETfaMYZ.js.gz +0 -0
- package/dist/dashboard/assets/app-BLCvGdzb.css +0 -2
- package/dist/dashboard/assets/app-BLCvGdzb.css.gz +0 -0
- package/dist/dashboard/assets/assert-7J6_LVD3.js +0 -1
- package/dist/dashboard/assets/assert-7J6_LVD3.js.gz +0 -0
- package/dist/dashboard/assets/badge-BTyGk_DL.js.gz +0 -0
- package/dist/dashboard/assets/banner-bujTWYM4.js.gz +0 -0
- package/dist/dashboard/assets/card-B0Bnx5CA.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-DE2ug812.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-R_rArH8S.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BWIP_EvW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-BKcgVugF.js.gz +0 -0
- package/dist/dashboard/assets/entry-7dpgvpJ3.js +0 -4
- package/dist/dashboard/assets/entry-7dpgvpJ3.js.gz +0 -0
- package/dist/dashboard/assets/entry-kTiTFrvh.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-Booc5mNe.js.gz +0 -0
- package/dist/dashboard/assets/index-D70pChfn.js.gz +0 -0
- package/dist/dashboard/assets/inline-D1TCqM2D.js.gz +0 -0
- package/dist/dashboard/assets/input-B9oyU93y.js.gz +0 -0
- package/dist/dashboard/assets/layout-BArzXirQ.js.gz +0 -0
- package/dist/dashboard/assets/list-row-BVZzaoHF.js.gz +0 -0
- package/dist/dashboard/assets/live-EmuIayqp.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-CSPQ9xB0.js.gz +0 -0
- package/dist/dashboard/assets/routing-BExgxxBU.js.gz +0 -0
- package/dist/dashboard/assets/select-C9mMoEpJ.js +0 -41
- package/dist/dashboard/assets/select-C9mMoEpJ.js.gz +0 -0
- package/dist/dashboard/assets/settings-C4_Gn_wq.js +0 -1
- package/dist/dashboard/assets/settings-C4_Gn_wq.js.gz +0 -0
- package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
- package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js.gz +0 -0
- package/dist/dashboard/assets/stack-Ca5HxI5i.js.gz +0 -0
- package/dist/dashboard/assets/state-CzUPfLXo.js.gz +0 -0
- package/dist/dashboard/assets/switch-DOUIky_i.js.gz +0 -0
- package/dist/dashboard/assets/toast-C76WrMhc.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-D87FZwH0.js.gz +0 -0
- package/src/network/tls/bun-client-hello.ts +0 -112
- /package/dist/dashboard/assets/{app-Cjq7nrwu.js → app-C-Y4oZT0.js} +0 -0
- /package/dist/dashboard/assets/{app-Cjq7nrwu.js.gz → app-C-Y4oZT0.js.gz} +0 -0
|
@@ -12,6 +12,8 @@ import { createAnthropicCompatibleAdapter } from "./integrations/anthropic";
|
|
|
12
12
|
import { defineModel } from "./provider-model-definition";
|
|
13
13
|
import type { ProviderModelDiscovery } from "./discovery/discovery-types";
|
|
14
14
|
import type { ProviderDispatchContext } from "./provider-contracts";
|
|
15
|
+
import type { QoderRealm } from "./integrations/qoder/qoder-realm";
|
|
16
|
+
import type { TraeRealm } from "./integrations/trae/trae-realm";
|
|
15
17
|
import type { WireFamily } from "../protocol/canonical-model";
|
|
16
18
|
import type { CanonicalRequest } from "../protocol/canonical-model";
|
|
17
19
|
|
|
@@ -25,6 +27,106 @@ function configuredProvider(
|
|
|
25
27
|
};
|
|
26
28
|
}
|
|
27
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Qoder's live model list for one realm.
|
|
32
|
+
*
|
|
33
|
+
* The request has to be signed with the account's COSY identity and has to
|
|
34
|
+
* carry the body that was signed — a bare GET is refused — so discovery cannot
|
|
35
|
+
* use the generic bearer helper. It resolves the same identity dispatch uses
|
|
36
|
+
* (PAT exchange or the persisted OAuth state) and then lists against the
|
|
37
|
+
* realm's own gateway hosts.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Trae model discovery for one realm.
|
|
41
|
+
*
|
|
42
|
+
* The listing is per account region: it answers on CN and on the intl region
|
|
43
|
+
* host that serves the account. This returns the static roster when the live
|
|
44
|
+
* call yields nothing, rather than raising, so one unsupported account cannot
|
|
45
|
+
* fail the whole catalog refresh.
|
|
46
|
+
*/
|
|
47
|
+
function traeDiscovery(
|
|
48
|
+
realm: TraeRealm,
|
|
49
|
+
providerId: string,
|
|
50
|
+
): NonNullable<ProviderModuleCapabilities["loadModelDiscovery"]> {
|
|
51
|
+
return async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
|
|
52
|
+
const { discoverTraeModels } = await import("./integrations/trae/trae");
|
|
53
|
+
const { TRAE_INTL_MODELS, TRAE_CN_MODELS } = await import("./integrations/trae/trae-catalog");
|
|
54
|
+
const secret = request.credential.trim();
|
|
55
|
+
const fetcher = request.fetcher as unknown as typeof fetch | undefined;
|
|
56
|
+
if (secret.length === 0 || fetcher === undefined) {
|
|
57
|
+
return realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
|
|
58
|
+
}
|
|
59
|
+
let token = secret;
|
|
60
|
+
if (secret.startsWith("{")) {
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(secret) as Record<string, unknown>;
|
|
63
|
+
const found = ["accessToken", "access_token", "token"].find(
|
|
64
|
+
(key) => typeof parsed[key] === "string" && (parsed[key] as string).length > 0,
|
|
65
|
+
);
|
|
66
|
+
if (found !== undefined) token = parsed[found] as string;
|
|
67
|
+
} catch {
|
|
68
|
+
// Use the raw secret as the token.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const region = request.authState?.["region"];
|
|
72
|
+
const rows = await discoverTraeModels({
|
|
73
|
+
realm,
|
|
74
|
+
token,
|
|
75
|
+
uid: request.authState?.["accountId"] as string | undefined ?? "",
|
|
76
|
+
fetcher,
|
|
77
|
+
providerId,
|
|
78
|
+
...(typeof region === "string" ? { region } : {}),
|
|
79
|
+
});
|
|
80
|
+
if (rows.length === 0) return realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
|
|
81
|
+
const fallback = realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
|
|
82
|
+
const byId = new Map(fallback.map((model) => [model.modelId, model]));
|
|
83
|
+
return rows.map((row) => {
|
|
84
|
+
const existing = byId.get(row.id);
|
|
85
|
+
if (existing === undefined) {
|
|
86
|
+
// Discovered upstream but absent from the static roster: clone the
|
|
87
|
+
// realm's first row so a new model is routable with the shape this
|
|
88
|
+
// provider serves, carrying the window upstream reported.
|
|
89
|
+
const template = fallback[0];
|
|
90
|
+
if (template === undefined) return undefined;
|
|
91
|
+
return { ...template, modelId: row.id, contextLimit: row.ctx ?? null };
|
|
92
|
+
}
|
|
93
|
+
return row.ctx === undefined ? existing : { ...existing, contextLimit: row.ctx };
|
|
94
|
+
}).filter((model): model is NonNullable<typeof model> => model !== undefined);
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function qoderDiscovery(
|
|
99
|
+
realm: QoderRealm,
|
|
100
|
+
providerId: string,
|
|
101
|
+
): NonNullable<ProviderModuleCapabilities["loadModelDiscovery"]> {
|
|
102
|
+
return async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
|
|
103
|
+
const { discoverQoderModels } = await import("./integrations/qoder/qoder-catalog");
|
|
104
|
+
const { resolveQoderAuth, qoderSignerFor, qoderEncodeBody } = await import("./integrations/qoder/qoder");
|
|
105
|
+
const secret = request.credential.trim();
|
|
106
|
+
if (secret.length === 0) throw new Error("Qoder credential is required");
|
|
107
|
+
const fetcher = request.fetcher as unknown as typeof fetch | undefined;
|
|
108
|
+
// The discovery context carries only the secret plus the non-secret
|
|
109
|
+
// `authState` an OAuth login persisted; the account id lives there too, so
|
|
110
|
+
// an OAuth credential resolves to the same identity dispatch would use.
|
|
111
|
+
const auth = await resolveQoderAuth({
|
|
112
|
+
secret,
|
|
113
|
+
authState: request.authState,
|
|
114
|
+
signal: AbortSignal.timeout(15_000),
|
|
115
|
+
fetcher: (url: string, init: RequestInit) => (fetcher ?? globalThis.fetch)(url, init),
|
|
116
|
+
});
|
|
117
|
+
const signer = qoderSignerFor(auth);
|
|
118
|
+
return discoverQoderModels({
|
|
119
|
+
realm,
|
|
120
|
+
providerId,
|
|
121
|
+
credential: secret,
|
|
122
|
+
headers: (url: string, body: string) => Promise.resolve(signer(url, body)),
|
|
123
|
+
...(fetcher === undefined ? {} : { fetcher }),
|
|
124
|
+
encode: qoderEncodeBody,
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
28
130
|
/**
|
|
29
131
|
* Builds the `loadAdapter` + `loadModelDiscovery` pair every plain bearer
|
|
30
132
|
* provider needs.
|
|
@@ -201,6 +303,29 @@ export const PROVIDER_CAPABILITIES = {
|
|
|
201
303
|
loadAuthentication: oauthCapability(() => import("./integrations/kimi/kimi-oauth"), "kimiCodeOAuthClient", { withRefresher: true }),
|
|
202
304
|
loadQuotaCollector: quotaCapability(() => import("./integrations/kimi/kimi-quota"), "fetchKimiQuota"),
|
|
203
305
|
},
|
|
306
|
+
cursor: {
|
|
307
|
+
// Cursor's Run is a Connect-RPC bidi stream on a *dynamically discovered*
|
|
308
|
+
// agent origin, not the API host the auth and catalog calls use. The path
|
|
309
|
+
// is pinned here so a probe verifies the endpoint dispatch actually calls;
|
|
310
|
+
// the origin itself is resolved per dispatch from GetServerConfig.
|
|
311
|
+
endpointPathsByWireFamily: { chat: "/agent.v1.AgentService/Run" },
|
|
312
|
+
loadAdapter: async () => (await import("./integrations/cursor/cursor")).cursorAdapter,
|
|
313
|
+
loadModels: async () => (await import("./integrations/cursor/cursor-catalog")).CURSOR_MODELS,
|
|
314
|
+
loadAuthentication: oauthCapability(() => import("./integrations/cursor/cursor-auth"), "cursorOAuthClient", {
|
|
315
|
+
withRefresher: true,
|
|
316
|
+
}),
|
|
317
|
+
// No quota collector: no Cursor quota endpoint is established by the donor
|
|
318
|
+
// or the API evidence, and inventing one would publish a balance this
|
|
319
|
+
// gateway cannot measure.
|
|
320
|
+
//
|
|
321
|
+
// The roster is per-account and per-plan, and Cursor declares each model's
|
|
322
|
+
// capabilities, so discovery is the catalog rather than a static list.
|
|
323
|
+
loadModelDiscovery: async () => async ({ credential, fetcher }) =>
|
|
324
|
+
(await import("./integrations/cursor/cursor-catalog")).discoverCursorModels({
|
|
325
|
+
credential,
|
|
326
|
+
...(fetcher === undefined ? {} : { fetcher }),
|
|
327
|
+
}),
|
|
328
|
+
},
|
|
204
329
|
cerebras: {
|
|
205
330
|
endpointPathsByWireFamily: { chat: "/chat/completions" },
|
|
206
331
|
loadAdapter: async () => createApiKeyAdapter((await import("./integrations/cerebras")).CEREBRAS_SPEC),
|
|
@@ -324,7 +449,10 @@ export const PROVIDER_CAPABILITIES = {
|
|
|
324
449
|
},
|
|
325
450
|
kilo: {
|
|
326
451
|
loadAdapter: async () => (await import("./integrations/kilo/kilo")).kiloAdapter,
|
|
327
|
-
loadModels: async () =>
|
|
452
|
+
loadModels: async () => {
|
|
453
|
+
const spec = await import("./integrations/kilo/kilo");
|
|
454
|
+
return [...spec.KILO_MODELS, ...spec.KILO_FREE_MODELS];
|
|
455
|
+
},
|
|
328
456
|
// No `withRefresher`: Kilo Code has no refresh grant, so this client
|
|
329
457
|
// declares no refresher and the stored token is used exactly as issued.
|
|
330
458
|
// Registering one would make the 401 retry path call a method that always
|
|
@@ -339,6 +467,14 @@ export const PROVIDER_CAPABILITIES = {
|
|
|
339
467
|
commandcode: {
|
|
340
468
|
loadAdapter: async () => (await import("./integrations/commandcode/commandcode")).createCommandCodeAdapter(),
|
|
341
469
|
loadModels: async () => (await import("./integrations/commandcode/commandcode")).COMMANDCODE_MODELS,
|
|
470
|
+
// The Provider API publishes the real roster with each model's wire, so the
|
|
471
|
+
// static seed above is the offline floor rather than the catalog.
|
|
472
|
+
loadModelDiscovery: async () => async (input) =>
|
|
473
|
+
(await import("./integrations/commandcode/discovery")).discoverCommandCodeModels(input),
|
|
474
|
+
loadQuotaCollector: quotaCapability(
|
|
475
|
+
() => import("./integrations/commandcode/quota"),
|
|
476
|
+
"fetchCommandCodeQuota",
|
|
477
|
+
),
|
|
342
478
|
},
|
|
343
479
|
qoder: {
|
|
344
480
|
loadAdapter: async () => (await import("./integrations/qoder/qoder")).createQoderAdapter(),
|
|
@@ -347,6 +483,42 @@ export const PROVIDER_CAPABILITIES = {
|
|
|
347
483
|
// device flow, so the issued token is used exactly as issued until the
|
|
348
484
|
// operator re-runs login — same shape as Kilo Code.
|
|
349
485
|
loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderOAuthClient"),
|
|
486
|
+
// Discovery signed by the account's own COSY identity: the model list is
|
|
487
|
+
// per-account and per-realm, and a GET without the signed body is 403.
|
|
488
|
+
loadModelDiscovery: qoderDiscovery("intl", "qoder"),
|
|
489
|
+
},
|
|
490
|
+
// Separate provider, not a region flag: a CN account has its own gateway
|
|
491
|
+
// host, OAuth client id, and model roster, and is refused by the global host.
|
|
492
|
+
qodercn: {
|
|
493
|
+
loadAdapter: async () => (await import("./integrations/qoder/qoder")).createQoderCnAdapter(),
|
|
494
|
+
loadModels: async () => (await import("./integrations/qoder/qoder-catalog")).QODER_CN_MODELS,
|
|
495
|
+
// The CN client, not the intl one: a device login opened on
|
|
496
|
+
// `qoder.com/device/selectAccounts` polled `openapi.qoder.sh`, which a CN
|
|
497
|
+
// account is refused by. `qoderCnOAuthClient` is the same class bound to
|
|
498
|
+
// `QODER_REALMS.cn` — its own login/token/userinfo hosts, client id, and
|
|
499
|
+
// native redirect.
|
|
500
|
+
loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderCnOAuthClient"),
|
|
501
|
+
loadModelDiscovery: qoderDiscovery("cn", "qodercn"),
|
|
502
|
+
},
|
|
503
|
+
trae: {
|
|
504
|
+
loadAdapter: async () => (await import("./integrations/trae/trae")).createTraeAdapter(),
|
|
505
|
+
loadModels: async () => (await import("./integrations/trae/trae-catalog")).TRAE_INTL_MODELS,
|
|
506
|
+
// A Trae credential is an access/refresh pair and the refresh token is what
|
|
507
|
+
// keeps it alive, so the refresher is registered rather than optional:
|
|
508
|
+
// without it the account dies at first expiry.
|
|
509
|
+
loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeOAuthClient", { withRefresher: true }),
|
|
510
|
+
// Live model list is intl-unsupported: upstream answers `403 no schema
|
|
511
|
+
// found`, so discovery returning nothing is the truthful result and the
|
|
512
|
+
// static roster above stays authoritative.
|
|
513
|
+
loadModelDiscovery: traeDiscovery("intl", "trae"),
|
|
514
|
+
},
|
|
515
|
+
traecn: {
|
|
516
|
+
loadAdapter: async () => (await import("./integrations/trae/trae")).createTraeCnAdapter(),
|
|
517
|
+
loadModels: async () => (await import("./integrations/trae/trae-catalog")).TRAE_CN_MODELS,
|
|
518
|
+
// The CN client, not the intl one: the exchange runs on the CN account
|
|
519
|
+
// host, and a refresh posted to the intl host is refused.
|
|
520
|
+
loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeCnOAuthClient", { withRefresher: true }),
|
|
521
|
+
loadModelDiscovery: traeDiscovery("cn", "traecn"),
|
|
350
522
|
},
|
|
351
523
|
inferhub: {
|
|
352
524
|
loadAdapter: async () => (await import("./integrations/inferhub")).createInferhubAdapter(),
|
|
@@ -54,10 +54,18 @@ export async function fetchOpenAICompatibleModels(
|
|
|
54
54
|
modalityContextLimit(entry);
|
|
55
55
|
const contextWindow = parsedContext ?? fallback?.contextLimit ?? 200_000;
|
|
56
56
|
|
|
57
|
+
// `max_completion_tokens` first: it is the name an OpenAI-shaped catalog
|
|
58
|
+
// uses, and it is the name this gateway's own `/v1/models` emits. A
|
|
59
|
+
// reader that knew only `max_output_tokens`/`maxTokens` saw none of them
|
|
60
|
+
// and fell through to the 64_192 default, so every model on such an
|
|
61
|
+
// upstream was advertised at the same wrong ceiling no matter what the
|
|
62
|
+
// upstream reported.
|
|
57
63
|
const parsedOutput =
|
|
64
|
+
positiveNumber(entry.max_completion_tokens) ??
|
|
58
65
|
positiveNumber(entry.max_output_tokens) ??
|
|
59
66
|
positiveNumber((entry as Record<string, unknown>).max_output_tokens) ??
|
|
60
67
|
positiveNumber(entry.maxTokens) ??
|
|
68
|
+
positiveNumber((entry as Record<string, unknown>).completion_token_limit) ??
|
|
61
69
|
modalityOutputLimit(entry);
|
|
62
70
|
const maxOutputTokens = parsedOutput ?? fallback?.outputLimit ?? 64_192;
|
|
63
71
|
const outputTokens = Math.min(maxOutputTokens, contextWindow);
|
|
@@ -74,7 +82,14 @@ export async function fetchOpenAICompatibleModels(
|
|
|
74
82
|
// the upstream declares for the model it serves. A catalog that declares
|
|
75
83
|
// it as an `input_modalities[]` array instead of a `modality` string was
|
|
76
84
|
// read as text-only, so a vision model lost image input.
|
|
77
|
-
|
|
85
|
+
// `capabilities.input` is a third spelling — an array of modality names,
|
|
86
|
+
// used by OpenAI-shaped catalogs including this gateway's own. Read
|
|
87
|
+
// alongside the other two so a vision model is not downgraded to
|
|
88
|
+
// text-only, which then drops image parts before they reach the upstream.
|
|
89
|
+
const hasImage =
|
|
90
|
+
rawModality.includes("image") ||
|
|
91
|
+
modalityImageInput(entry) ||
|
|
92
|
+
capabilityImageInput(entry);
|
|
78
93
|
const responsesWire = isResponsesNativeModelId(id);
|
|
79
94
|
byId.set(id, {
|
|
80
95
|
modelId: id,
|
|
@@ -83,8 +98,14 @@ export async function fetchOpenAICompatibleModels(
|
|
|
83
98
|
contextLimit: contextWindow,
|
|
84
99
|
outputLimit: outputTokens,
|
|
85
100
|
modalities: { input: hasImage ? ["text", "image"] : ["text"], output: ["text"] },
|
|
86
|
-
reasoning
|
|
87
|
-
|
|
101
|
+
// Upstream declares reasoning, so believe it rather than pinning false:
|
|
102
|
+
// a reasoning model advertised as non-reasoning is routed without the
|
|
103
|
+
// thinking budget it needs, and the caller's `reasoning_effort` is
|
|
104
|
+
// dropped as unsupported.
|
|
105
|
+
reasoning: entry.reasoning === true,
|
|
106
|
+
// Same for tool calling — an upstream that names a model as
|
|
107
|
+
// non-tool-capable must not have tools routed to it.
|
|
108
|
+
toolCall: entry.tool_call === false ? false : true,
|
|
88
109
|
cost,
|
|
89
110
|
});
|
|
90
111
|
}
|
|
@@ -150,6 +171,21 @@ function modalityImageInput(entry: Record<string, unknown>): boolean {
|
|
|
150
171
|
|
|
151
172
|
|
|
152
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Image input from a `capabilities.input` array.
|
|
176
|
+
*
|
|
177
|
+
* The field is a plain list of modality names (`["text","image"]`), not the
|
|
178
|
+
* structured `input_modalities[]` objects the sibling reader expects. A catalog
|
|
179
|
+
* that spells it this way was read as text-only.
|
|
180
|
+
*/
|
|
181
|
+
function capabilityImageInput(entry: Record<string, unknown>): boolean {
|
|
182
|
+
const capabilities = entry.capabilities;
|
|
183
|
+
if (!isRecord(capabilities)) return false;
|
|
184
|
+
const inputs = capabilities.input;
|
|
185
|
+
if (!Array.isArray(inputs)) return false;
|
|
186
|
+
return inputs.some((name) => typeof name === "string" && name.toLowerCase().includes("image"));
|
|
187
|
+
}
|
|
188
|
+
|
|
153
189
|
function extractEntries(payload: unknown): readonly Record<string, unknown>[] | null {
|
|
154
190
|
if (Array.isArray(payload)) return payload.filter(isRecord);
|
|
155
191
|
if (typeof payload !== "object" || payload === null) return null;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The free tier shared by the OpenRouter-backed providers.
|
|
3
|
+
*
|
|
4
|
+
* Cline, Kilo Code and OpenRouter serve one model catalog: the same 469 ids,
|
|
5
|
+
* and the same 17 of them carrying a `:free` suffix. Verified against all three
|
|
6
|
+
* live listings — every id below is present under `openrouter`, `kilo` and
|
|
7
|
+
* `cline` — so this roster is a catalog fact, not a per-provider guess, and it
|
|
8
|
+
* lives in one place rather than being restated three times.
|
|
9
|
+
*
|
|
10
|
+
* The limits, modalities and capability flags are read from OpenRouter's own
|
|
11
|
+
* `/api/v1/models`, which states `context_length`,
|
|
12
|
+
* `top_provider.max_completion_tokens`, `architecture.input_modalities` and
|
|
13
|
+
* `supported_parameters`. That is the serving catalog's declaration, so these
|
|
14
|
+
* are measurements rather than defaults.
|
|
15
|
+
*
|
|
16
|
+
* This is a floor, not the authority: each provider also discovers live, and a
|
|
17
|
+
* row the listing carries that this roster does not is still found there. The
|
|
18
|
+
* roster exists so a fresh install has a usable free tier before any fetch, and
|
|
19
|
+
* so the free section is populated even when discovery is unavailable.
|
|
20
|
+
*/
|
|
21
|
+
import { defineModel } from "../provider-model-definition";
|
|
22
|
+
import type { ModelDefinition } from "../provider-model-definition";
|
|
23
|
+
|
|
24
|
+
export interface FreeRosterOptions {
|
|
25
|
+
readonly providerId: string;
|
|
26
|
+
/** The wire suffix that completes the provider's base URL. */
|
|
27
|
+
readonly endpoint: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface FreeRow {
|
|
31
|
+
readonly id: string;
|
|
32
|
+
readonly ctx: number;
|
|
33
|
+
readonly out: number;
|
|
34
|
+
readonly vision?: boolean;
|
|
35
|
+
/** `supported_parameters` omits `tools` on the safety classifier only. */
|
|
36
|
+
readonly toolCall?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The 17 `:free` ids, with the limits the catalog states for each.
|
|
41
|
+
*
|
|
42
|
+
* Every row declares `reasoning`: `supported_parameters` lists it on all
|
|
43
|
+
* seventeen. `toolCall` is `true` unless stated otherwise, because a row that
|
|
44
|
+
* advertises tools must keep them — a false `toolCall` makes the preflight
|
|
45
|
+
* strip `tools` from the request, which is a wrong capability rather than a
|
|
46
|
+
* conservative one.
|
|
47
|
+
*/
|
|
48
|
+
const FREE_ROWS: readonly FreeRow[] = [
|
|
49
|
+
{ id: "cohere/north-mini-code:free", ctx: 256_000, out: 64_000 },
|
|
50
|
+
{ id: "dots-studio/dots-3-note-preview:free", ctx: 512_000, out: 460_800, vision: true },
|
|
51
|
+
{ id: "google/gemma-4-26b-a4b-it:free", ctx: 262_144, out: 32_768, vision: true },
|
|
52
|
+
{ id: "google/gemma-4-31b-it:free", ctx: 262_144, out: 32_768, vision: true },
|
|
53
|
+
{ id: "liquid/lfm-2.5-2.6b:free", ctx: 65_536, out: 8_192 },
|
|
54
|
+
{ id: "minimax/minimax-m3.1-flash:free", ctx: 1_000_000, out: 524_288, vision: true },
|
|
55
|
+
{
|
|
56
|
+
id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
|
|
57
|
+
ctx: 256_000,
|
|
58
|
+
out: 65_536,
|
|
59
|
+
vision: true,
|
|
60
|
+
},
|
|
61
|
+
{ id: "nvidia/nemotron-3-super-120b-a12b:free", ctx: 262_144, out: 235_929 },
|
|
62
|
+
{ id: "nvidia/nemotron-3-ultra-550b-a55b:free", ctx: 1_000_000, out: 65_536 },
|
|
63
|
+
{
|
|
64
|
+
id: "nvidia/nemotron-3.5-content-safety:free",
|
|
65
|
+
ctx: 128_000,
|
|
66
|
+
out: 8_192,
|
|
67
|
+
vision: true,
|
|
68
|
+
toolCall: false,
|
|
69
|
+
},
|
|
70
|
+
{ id: "nvidia/nemotron-3.5-lightning:free", ctx: 1_000_000, out: 65_536 },
|
|
71
|
+
{ id: "nvidia/nemotron-3.5-super-vl:free", ctx: 1_000_000, out: 131_072, vision: true },
|
|
72
|
+
{ id: "poolside/laguna-s-2.1:free", ctx: 262_144, out: 32_768 },
|
|
73
|
+
{ id: "poolside/laguna-xs-2.1:free", ctx: 262_144, out: 32_768 },
|
|
74
|
+
{ id: "thinkingmachines/inkling-small:free", ctx: 1_048_576, out: 262_144, vision: true },
|
|
75
|
+
{ id: "thinkingmachines/inkling:free", ctx: 1_048_576, out: 262_144, vision: true },
|
|
76
|
+
{ id: "xingchen-agi/xing4.0-29b-a4b:free", ctx: 262_144, out: 235_929 },
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
/** Builds this roster for one provider, since each spells its own endpoint. */
|
|
80
|
+
export function openrouterFreeRoster(options: FreeRosterOptions): readonly ModelDefinition[] {
|
|
81
|
+
return FREE_ROWS.map((row) =>
|
|
82
|
+
defineModel({
|
|
83
|
+
id: row.id,
|
|
84
|
+
providerId: options.providerId,
|
|
85
|
+
wireFamily: "chat",
|
|
86
|
+
endpoint: options.endpoint,
|
|
87
|
+
ctx: row.ctx,
|
|
88
|
+
out: row.out,
|
|
89
|
+
vision: row.vision ?? false,
|
|
90
|
+
reasoning: true,
|
|
91
|
+
toolCall: row.toolCall ?? true,
|
|
92
|
+
// `free` is the billing statement and `freeTier` the catalog one. The
|
|
93
|
+
// `:free` suffix makes both true, and the model list groups on the tier.
|
|
94
|
+
free: true,
|
|
95
|
+
freeTier: true,
|
|
96
|
+
}),
|
|
97
|
+
);
|
|
98
|
+
}
|