cartethyia 2.4.5 → 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.
Files changed (415) hide show
  1. package/.env.example +4 -1
  2. package/README.md +63 -13
  3. package/dist/dashboard/assets/AccountCooldown-ChpdzxRH.js.gz +0 -0
  4. package/dist/dashboard/assets/BannedPage-9igfctfZ.js +1 -0
  5. package/dist/dashboard/assets/BannedPage-9igfctfZ.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolDetailPage-BzGevuql.js → CliToolDetailPage-ZRr2K2sF.js} +1 -1
  7. package/dist/dashboard/assets/CliToolDetailPage-ZRr2K2sF.js.gz +0 -0
  8. package/dist/dashboard/assets/{CliToolsPage-BaRM_7We.js → CliToolsPage-D3xqZbN-.js} +1 -1
  9. package/dist/dashboard/assets/CliToolsPage-D3xqZbN-.js.gz +0 -0
  10. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js +1 -0
  11. package/dist/dashboard/assets/CombosPage-CVnQPBBz.js.gz +0 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js +1 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-u6W1UXSc.js.gz +0 -0
  14. package/dist/dashboard/assets/{CustomizationPage-DqUGcoH0.js → CustomizationPage-CTTpCb25.js} +1 -1
  15. package/dist/dashboard/assets/CustomizationPage-CTTpCb25.js.gz +0 -0
  16. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js +1 -0
  17. package/dist/dashboard/assets/HealthEventsModal-C5XpWlvy.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-DbhTGfhb.js → LoginPage-DHoB3Agn.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-DHoB3Agn.js.gz +0 -0
  20. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js +1 -0
  21. package/dist/dashboard/assets/ModelPicker-oQ-SDXp8.js.gz +0 -0
  22. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js +1 -0
  23. package/dist/dashboard/assets/OverviewPage-BrY4SgIt.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js +3 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-D9VSt7T_.js.gz +0 -0
  26. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +1 -0
  27. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  28. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js +1 -0
  29. package/dist/dashboard/assets/ProvidersPage-Df77V5I5.js.gz +0 -0
  30. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js +7 -0
  31. package/dist/dashboard/assets/ProxyPage-CDfxP7AC.js.gz +0 -0
  32. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js +1 -0
  33. package/dist/dashboard/assets/QuotaPage-CY4o2t4p.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-YxRml8AT.js → SettingsPage-CvjZxHE4.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-CvjZxHE4.js.gz +0 -0
  36. package/dist/dashboard/assets/SetupPage-D3nza7LH.js +1 -0
  37. package/dist/dashboard/assets/SetupPage-D3nza7LH.js.gz +0 -0
  38. package/dist/dashboard/assets/{SortableList-Bol1ASmI.js → SortableList-Dtt12WT1.js} +1 -1
  39. package/dist/dashboard/assets/SortableList-Dtt12WT1.js.gz +0 -0
  40. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js +31 -0
  41. package/dist/dashboard/assets/StudioPage-CbK3hXvU.js.gz +0 -0
  42. package/dist/dashboard/assets/ToolIcon-K1ckcDKg.js.gz +0 -0
  43. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js +56 -0
  44. package/dist/dashboard/assets/UsagePage-BQlWbWg2.js.gz +0 -0
  45. package/dist/dashboard/assets/api-keys-BmDbsior.js +1 -0
  46. package/dist/dashboard/assets/api-keys-BmDbsior.js.gz +0 -0
  47. package/dist/dashboard/assets/app-BbpSarVV.css +2 -0
  48. package/dist/dashboard/assets/app-BbpSarVV.css.gz +0 -0
  49. package/dist/dashboard/assets/{app-BDJWMThu.js → app-C-Y4oZT0.js} +3 -3
  50. package/dist/dashboard/assets/app-C-Y4oZT0.js.gz +0 -0
  51. package/dist/dashboard/assets/arrow-left-CpBxkoxI.js.gz +0 -0
  52. package/dist/dashboard/assets/arrow-right-Dl5yKnp8.js.gz +0 -0
  53. package/dist/dashboard/assets/assert-BHfaei-X.js +1 -0
  54. package/dist/dashboard/assets/assert-BHfaei-X.js.gz +0 -0
  55. package/dist/dashboard/assets/backup-file-gdKIlg8U.js.gz +0 -0
  56. package/dist/dashboard/assets/{badge-BwmwEOgA.js → badge-DpXT4Ixt.js} +1 -1
  57. package/dist/dashboard/assets/badge-DpXT4Ixt.js.gz +0 -0
  58. package/dist/dashboard/assets/{banner-BKBfKTqn.js → banner-CSAAWLJv.js} +1 -1
  59. package/dist/dashboard/assets/banner-CSAAWLJv.js.gz +0 -0
  60. package/dist/dashboard/assets/brain-Cwed_72z.js.gz +0 -0
  61. package/dist/dashboard/assets/{card-BTdbRFFg.js → card-DEhRXXw4.js} +1 -1
  62. package/dist/dashboard/assets/card-DEhRXXw4.js.gz +0 -0
  63. package/dist/dashboard/assets/check-D69FzdvC.js.gz +0 -0
  64. package/dist/dashboard/assets/chevron-right-BXIy5l3h.js.gz +0 -0
  65. package/dist/dashboard/assets/circle-alert-CntYHV5v.js.gz +0 -0
  66. package/dist/dashboard/assets/circle-check-BU3v_mFW.js.gz +0 -0
  67. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js +1 -0
  68. package/dist/dashboard/assets/cli-tools-B0wBq-RL.js.gz +0 -0
  69. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js +1 -0
  70. package/dist/dashboard/assets/clipboard-button-DOo6EU8O.js.gz +0 -0
  71. package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
  72. package/dist/dashboard/assets/copy-ngmQ9zcZ.js.gz +0 -0
  73. package/dist/dashboard/assets/{dialog-iocKA3jr.js → dialog-BvQeBMfP.js} +1 -1
  74. package/dist/dashboard/assets/dialog-BvQeBMfP.js.gz +0 -0
  75. package/dist/dashboard/assets/dialog-actions-B1axpEg7.js.gz +0 -0
  76. package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
  77. package/dist/dashboard/assets/download-dRFo5_Wu.js.gz +0 -0
  78. package/dist/dashboard/assets/{drawer-CDKOTZdY.js → drawer-CMwPXwQB.js} +1 -1
  79. package/dist/dashboard/assets/drawer-CMwPXwQB.js.gz +0 -0
  80. package/dist/dashboard/assets/entry-D4O2229X.js +1 -0
  81. package/dist/dashboard/assets/entry-D4O2229X.js.gz +0 -0
  82. package/dist/dashboard/assets/entry-DKvr5Q9K.js +1 -0
  83. package/dist/dashboard/assets/entry-DKvr5Q9K.js.gz +0 -0
  84. package/dist/dashboard/assets/entry-FQCejoDY.js +4 -0
  85. package/dist/dashboard/assets/entry-FQCejoDY.js.gz +0 -0
  86. package/dist/dashboard/assets/eye-C_hawfH4.js.gz +0 -0
  87. package/dist/dashboard/assets/eye-off-Bk5g2luF.js.gz +0 -0
  88. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  89. package/dist/dashboard/assets/gauge-BbIMy7MB.js.gz +0 -0
  90. package/dist/dashboard/assets/github-badge-zliLvBwr.js +1 -0
  91. package/dist/dashboard/assets/github-badge-zliLvBwr.js.gz +0 -0
  92. package/dist/dashboard/assets/image-BPaouViG.js.gz +0 -0
  93. package/dist/dashboard/assets/{index-C4hXfAMs.js → index-CXm3FIyt.js} +2 -2
  94. package/dist/dashboard/assets/index-CXm3FIyt.js.gz +0 -0
  95. package/dist/dashboard/assets/{inline-DCejSLlA.js → inline-D1IlZZ8H.js} +1 -1
  96. package/dist/dashboard/assets/inline-D1IlZZ8H.js.gz +0 -0
  97. package/dist/dashboard/assets/{input-Bn4_kNav.js → input-BpVZdrbc.js} +1 -1
  98. package/dist/dashboard/assets/input-BpVZdrbc.js.gz +0 -0
  99. package/dist/dashboard/assets/jsx-runtime-CXUMngI_.js.gz +0 -0
  100. package/dist/dashboard/assets/key-round-UkavsGxp.js.gz +0 -0
  101. package/dist/dashboard/assets/layers-2-glBbjl.js.gz +0 -0
  102. package/dist/dashboard/assets/{layout-Bv-NxqZ5.js → layout-BioLW7gN.js} +1 -1
  103. package/dist/dashboard/assets/layout-BioLW7gN.js.gz +0 -0
  104. package/dist/dashboard/assets/{list-row-BLA0sldD.js → list-row-CwVcGAIc.js} +1 -1
  105. package/dist/dashboard/assets/list-row-CwVcGAIc.js.gz +0 -0
  106. package/dist/dashboard/assets/{live-YlifPYox.js → live-yfEJFF9T.js} +1 -1
  107. package/dist/dashboard/assets/live-yfEJFF9T.js.gz +0 -0
  108. package/dist/dashboard/assets/log-in-BmRjy60c.js.gz +0 -0
  109. package/dist/dashboard/assets/message-circle-CCxGwRvv.js.gz +0 -0
  110. package/dist/dashboard/assets/model-bans-CT-TxSNX.js +1 -0
  111. package/dist/dashboard/assets/model-bans-CT-TxSNX.js.gz +0 -0
  112. package/dist/dashboard/assets/mutation-BkoLM5Ba.js +1 -0
  113. package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
  114. package/dist/dashboard/assets/numbers-CFL4_Dqc.js.gz +0 -0
  115. package/dist/dashboard/assets/pencil-768ysRAr.js.gz +0 -0
  116. package/dist/dashboard/assets/plus-DIdX_g-x.js.gz +0 -0
  117. package/dist/dashboard/assets/power-off-Yjw9GMJh.js +1 -0
  118. package/dist/dashboard/assets/power-off-Yjw9GMJh.js.gz +0 -0
  119. package/dist/dashboard/assets/privacy-mode-GM8bej85.js +1 -0
  120. package/dist/dashboard/assets/privacy-mode-GM8bej85.js.gz +0 -0
  121. package/dist/dashboard/assets/providers/agentrouter.svg.gz +0 -0
  122. package/dist/dashboard/assets/providers/aihubmix.svg.gz +0 -0
  123. package/dist/dashboard/assets/providers/alibaba-coding-plan.svg.gz +0 -0
  124. package/dist/dashboard/assets/providers/alibaba.svg.gz +0 -0
  125. package/dist/dashboard/assets/providers/antigravity.svg.gz +0 -0
  126. package/dist/dashboard/assets/providers/bai.svg.gz +0 -0
  127. package/dist/dashboard/assets/providers/blackbox.svg.gz +0 -0
  128. package/dist/dashboard/assets/providers/claude-code.svg.gz +0 -0
  129. package/dist/dashboard/assets/providers/cursor.webp +0 -0
  130. package/dist/dashboard/assets/providers/exa.svg.gz +0 -0
  131. package/dist/dashboard/assets/providers/gmi-cloud.svg.gz +0 -0
  132. package/dist/dashboard/assets/providers/inferhub.svg.gz +0 -0
  133. package/dist/dashboard/assets/providers/muse.svg.gz +0 -0
  134. package/dist/dashboard/assets/providers/nous-research.svg.gz +0 -0
  135. package/dist/dashboard/assets/providers/openai-light.svg.gz +0 -0
  136. package/dist/dashboard/assets/providers/parallel.svg.gz +0 -0
  137. package/dist/dashboard/assets/providers/tokenharbor.svg.gz +0 -0
  138. package/dist/dashboard/assets/providers/trae.webp +0 -0
  139. package/dist/dashboard/assets/providers/zai-coding-plan.svg.gz +0 -0
  140. package/dist/dashboard/assets/{query-keys-ROf-g1Wi.js → query-keys-D7wX2vM5.js} +1 -1
  141. package/dist/dashboard/assets/query-keys-D7wX2vM5.js.gz +0 -0
  142. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  143. package/dist/dashboard/assets/refresh-cw-BqJFk4sU.js.gz +0 -0
  144. package/dist/dashboard/assets/rotate-ccw-CufcqITi.js.gz +0 -0
  145. package/dist/dashboard/assets/route-CNSNj9Zm.js.gz +0 -0
  146. package/dist/dashboard/assets/routing-Cs6jl49L.js +1 -0
  147. package/dist/dashboard/assets/routing-Cs6jl49L.js.gz +0 -0
  148. package/dist/dashboard/assets/scaling-nWE4Cx8f.js.gz +0 -0
  149. package/dist/dashboard/assets/search-JOKus9rb.js.gz +0 -0
  150. package/dist/dashboard/assets/select-C0Rer3gF.js +41 -0
  151. package/dist/dashboard/assets/select-C0Rer3gF.js.gz +0 -0
  152. package/dist/dashboard/assets/settings-CfcTcOyU.js +1 -0
  153. package/dist/dashboard/assets/settings-CfcTcOyU.js.gz +0 -0
  154. package/dist/dashboard/assets/shield-check-DVS0Foqh.js.gz +0 -0
  155. package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
  156. package/dist/dashboard/assets/{stack-C1kTcOmP.js → stack-C9_uUjaA.js} +1 -1
  157. package/dist/dashboard/assets/stack-C9_uUjaA.js.gz +0 -0
  158. package/dist/dashboard/assets/{state-DHKdg-pm.js → state-DA0B95UQ.js} +1 -1
  159. package/dist/dashboard/assets/state-DA0B95UQ.js.gz +0 -0
  160. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  161. package/dist/dashboard/assets/{switch-DIDeAiz9.js → switch-Cittxy-x.js} +1 -1
  162. package/dist/dashboard/assets/switch-Cittxy-x.js.gz +0 -0
  163. package/dist/dashboard/assets/terminal-Bd4ee8TA.js +1 -0
  164. package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
  165. package/dist/dashboard/assets/toast-CNt_jzO4.js +2 -0
  166. package/dist/dashboard/assets/toast-CNt_jzO4.js.gz +0 -0
  167. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  168. package/dist/dashboard/assets/trash-Cppn5c3R.js.gz +0 -0
  169. package/dist/dashboard/assets/use-clipboard-B0Sy03fE.js.gz +0 -0
  170. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  171. package/dist/dashboard/assets/use-reduced-motion-C4B0R6Sz.js.gz +0 -0
  172. package/dist/dashboard/assets/use-timeout-BwcBBRrT.js.gz +0 -0
  173. package/dist/dashboard/assets/{useMutation-DVmwOKU-.js → useMutation-BQKMcJ1H.js} +1 -1
  174. package/dist/dashboard/assets/useMutation-BQKMcJ1H.js.gz +0 -0
  175. package/dist/dashboard/assets/wrench-B6E1oEuY.js.gz +0 -0
  176. package/dist/dashboard/index.html +1 -1
  177. package/dist/dashboard/index.html.gz +0 -0
  178. package/dist/dashboard/precompressed-assets.json +122 -0
  179. package/migrations/full-postgres/0013_add_providers_tenant_id_index.sql +22 -0
  180. package/migrations/full-postgres/0014_add_provider_accounts_tenant_id_index.sql +21 -0
  181. package/migrations/full-postgres/0015_add_payload_stages.sql +18 -0
  182. package/migrations/full-postgres/0016_add_share_link_slug.sql +20 -0
  183. package/migrations/full-postgres/0017_add_models_pro_only.sql +18 -0
  184. package/migrations/full-postgres/0018_add_accounts_quota_plan.sql +18 -0
  185. package/migrations/full-postgres/0019_add_models_free_tier.sql +15 -0
  186. package/migrations/lite-sqlite3/0000_baseline.sql +4 -2
  187. package/migrations/lite-sqlite3/0013_add_providers_tenant_id_index.sql +4 -0
  188. package/migrations/lite-sqlite3/0014_add_provider_accounts_tenant_id_index.sql +4 -0
  189. package/migrations/lite-sqlite3/0015_add_payload_stages.sql +18 -0
  190. package/migrations/lite-sqlite3/0016_add_share_link_slug.sql +20 -0
  191. package/migrations/lite-sqlite3/0017_add_models_pro_only.sql +18 -0
  192. package/migrations/lite-sqlite3/0018_add_accounts_quota_plan.sql +18 -0
  193. package/migrations/lite-sqlite3/0019_add_models_free_tier.sql +15 -0
  194. package/package.json +26 -30
  195. package/scripts/cli/{carte-launcher.cjs → bin/carte.cjs} +8 -8
  196. package/scripts/cli/{cli-launcher.cjs → bin/cartethyia.cjs} +167 -134
  197. package/scripts/cli/command/admin.ts +65 -0
  198. package/scripts/cli/command/console-menu.ts +246 -0
  199. package/scripts/cli/{doctor.ts → command/doctor.ts} +257 -258
  200. package/scripts/cli/{setup.ts → command/setup.ts} +8 -12
  201. package/scripts/cli/command/start.ts +77 -0
  202. package/scripts/cli/command/tray.ts +165 -0
  203. package/scripts/cli/command/update.ts +23 -0
  204. package/scripts/cli/{runtime-state.ts → gateway/drain-token.ts} +78 -78
  205. package/scripts/cli/gateway/instance-lock.ts +105 -0
  206. package/scripts/cli/gateway/spawn.ts +173 -0
  207. package/scripts/cli/gateway/stop.ts +51 -0
  208. package/scripts/cli/main.ts +94 -0
  209. package/scripts/cli/support/bun.ts +27 -0
  210. package/scripts/cli/support/env.ts +99 -0
  211. package/scripts/cli/support/platform.ts +64 -0
  212. package/scripts/cli/support/services.ts +88 -0
  213. package/scripts/cli/support/startup-signal.ts +23 -0
  214. package/scripts/cli/{version.ts → support/version.ts} +1 -1
  215. package/scripts/cli/tray/hidden-window.vbs +28 -0
  216. package/scripts/cli/{tray.ts → tray/index.ts} +3 -3
  217. package/scripts/cli/{tray.ps1 → tray/windows.ps1} +107 -98
  218. package/scripts/cli/ui/background.ts +110 -0
  219. package/src/boot/app.ts +23 -7
  220. package/src/boot/dependencies.ts +55 -13
  221. package/src/boot/elysia-typebox-bridge.ts +37 -0
  222. package/src/boot/lifecycle.ts +2 -0
  223. package/src/config/cooldowns.ts +138 -138
  224. package/src/config/providers.ts +31 -5
  225. package/src/config/runtime.ts +19 -3
  226. package/src/config/spec.ts +20 -0
  227. package/src/console/api-keys/contracts.ts +414 -391
  228. package/src/console/api-keys/routes.ts +880 -870
  229. package/src/console/auth/account-reset-store.ts +14 -0
  230. package/src/console/auth/account-reset.ts +3 -2
  231. package/src/console/auth/setup-service.ts +6 -3
  232. package/src/console/backup/routes.ts +8 -0
  233. package/src/console/cli-tools/contracts.ts +6 -6
  234. package/src/console/console-router.ts +5 -3
  235. package/src/console/dashboard-assets.ts +81 -11
  236. package/src/console/domain-registration.ts +9 -2
  237. package/src/console/observability/contracts.ts +475 -423
  238. package/src/console/observability/routes.ts +31 -6
  239. package/src/console/observability/store.ts +1015 -912
  240. package/src/console/providers/catalog/contracts.ts +31 -0
  241. package/src/console/providers/catalog/provider-operations.ts +8 -0
  242. package/src/console/providers/catalog/public-model-store.ts +91 -60
  243. package/src/console/providers/catalog/store.ts +1532 -1521
  244. package/src/console/providers/oauth/callback-listener.ts +18 -3
  245. package/src/console/providers/oauth/routes.ts +38 -15
  246. package/src/console/quota/account-quota-tenant.ts +9 -6
  247. package/src/console/quota/refresh.ts +19 -0
  248. package/src/console/response-compression.ts +69 -2
  249. package/src/console/routing/pools/probe-verdict.ts +72 -0
  250. package/src/console/share/share-router.ts +7 -4
  251. package/src/console/share/share-stats.ts +12 -5
  252. package/src/console/shared/read-through-cache.ts +133 -7
  253. package/src/console/updates/repository-updates.ts +39 -34
  254. package/src/console/updates/routes.ts +162 -4
  255. package/src/main.ts +3 -0
  256. package/src/network/http2-bidi.ts +85 -0
  257. package/src/network/outbound-fetch.ts +87 -24
  258. package/src/network/pool/agent.ts +478 -460
  259. package/src/network/pool/resolver.ts +1104 -544
  260. package/src/network/pool-health-machine.ts +12 -5
  261. package/src/observability/event-log.ts +29 -8
  262. package/src/observability/metrics.ts +40 -13
  263. package/src/observability/payload-capture.ts +344 -324
  264. package/src/observability/runtime-metrics.ts +7 -0
  265. package/src/persistence/db-pg.ts +9 -3
  266. package/src/persistence/db-sqlite.ts +497 -495
  267. package/src/persistence/health-event-flush.ts +137 -0
  268. package/src/persistence/migrate.ts +181 -129
  269. package/src/persistence/schema.ts +1360 -1257
  270. package/src/persistence/settings-revision.ts +25 -0
  271. package/src/persistence/shared-cache.ts +217 -0
  272. package/src/persistence/stores/share-store.ts +556 -528
  273. package/src/persistence/usage-flush.ts +61 -1
  274. package/src/protocol/canonical-model.ts +23 -1
  275. package/src/protocol/response/chat.ts +143 -10
  276. package/src/protocol/response/codex.ts +9 -75
  277. package/src/protocol/response/omp-tool-call-markup.ts +221 -0
  278. package/src/protocol/tool-identity.ts +43 -9
  279. package/src/providers/authentication/jwt-validator.ts +130 -187
  280. package/src/providers/authentication/oauth-flow-store.ts +16 -9
  281. package/src/providers/default-registry.ts +177 -1
  282. package/src/providers/discovery/catalog/catalog-format.ts +20 -0
  283. package/src/providers/discovery/models-dev-catalog.ts +39 -22
  284. package/src/providers/discovery/openai-model-discovery.ts +39 -3
  285. package/src/providers/discovery/openrouter-free-roster.ts +98 -0
  286. package/src/providers/discovery/probe-wire.ts +29 -5
  287. package/src/providers/discovery/probing-service.ts +1022 -1001
  288. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +42 -2
  289. package/src/providers/integrations/buddy/buddy-chat-shared.ts +913 -914
  290. package/src/providers/integrations/buddy/buddy-cli-headers.ts +88 -0
  291. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +22 -5
  292. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +33 -1
  293. package/src/providers/integrations/buddy/buddy-identity.ts +46 -0
  294. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +37 -1
  295. package/src/providers/integrations/buddy/buddy-usage-store.ts +40 -5
  296. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +4 -0
  297. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -175
  298. package/src/providers/integrations/buddy/codebuddy/shared.ts +115 -73
  299. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +5 -2
  300. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -204
  301. package/src/providers/integrations/buddy/workbuddy/quota.ts +172 -159
  302. package/src/providers/integrations/buddy/workbuddy/shared.ts +200 -171
  303. package/src/providers/integrations/claude/claude.ts +606 -582
  304. package/src/providers/integrations/cline/cline-quota.ts +18 -16
  305. package/src/providers/integrations/cline/cline.ts +539 -468
  306. package/src/providers/integrations/codex/codex.ts +5 -8
  307. package/src/providers/integrations/commandcode/commandcode.ts +675 -541
  308. package/src/providers/integrations/commandcode/discovery.ts +116 -0
  309. package/src/providers/integrations/commandcode/quota.ts +160 -0
  310. package/src/providers/integrations/cursor/cursor-auth.ts +418 -0
  311. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -0
  312. package/src/providers/integrations/cursor/cursor-http2.ts +300 -0
  313. package/src/providers/integrations/cursor/cursor-identity.ts +92 -0
  314. package/src/providers/integrations/cursor/cursor-request.ts +471 -0
  315. package/src/providers/integrations/cursor/cursor-session-manager.ts +281 -0
  316. package/src/providers/integrations/cursor/cursor-shared.ts +108 -0
  317. package/src/providers/integrations/cursor/cursor.ts +960 -0
  318. package/src/providers/integrations/cursor/protocol/framing.ts +129 -0
  319. package/src/providers/integrations/cursor/protocol/messages.ts +2355 -0
  320. package/src/providers/integrations/cursor/protocol/struct.ts +305 -0
  321. package/src/providers/integrations/factory/factory-oauth.ts +7 -11
  322. package/src/providers/integrations/github/github.ts +4 -4
  323. package/src/providers/integrations/hermes.ts +79 -8
  324. package/src/providers/integrations/kilo/kilo-discovery.ts +10 -1
  325. package/src/providers/integrations/kilo/kilo.ts +153 -146
  326. package/src/providers/integrations/opencode/opencode-go-quota.ts +130 -0
  327. package/src/providers/integrations/opencode/provider.ts +532 -499
  328. package/src/providers/integrations/openrouter/provider.ts +139 -281
  329. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -0
  330. package/src/providers/integrations/qoder/qoder-oauth.ts +310 -263
  331. package/src/providers/integrations/qoder/qoder-realm.ts +106 -0
  332. package/src/providers/integrations/qoder/qoder-virtual.ts +77 -0
  333. package/src/providers/integrations/qoder/qoder.ts +865 -730
  334. package/src/providers/integrations/shared/install-id.ts +29 -2
  335. package/src/providers/integrations/trae/trae-catalog.ts +190 -0
  336. package/src/providers/integrations/trae/trae-headers.ts +149 -0
  337. package/src/providers/integrations/trae/trae-oauth.ts +773 -0
  338. package/src/providers/integrations/trae/trae-protocol.ts +400 -0
  339. package/src/providers/integrations/trae/trae-realm.ts +220 -0
  340. package/src/providers/integrations/trae/trae.ts +458 -0
  341. package/src/providers/operations/account-health-service.ts +107 -10
  342. package/src/providers/operations/client-versions.ts +143 -6
  343. package/src/providers/operations/model-catalog-cache.ts +18 -3
  344. package/src/providers/operations/provider-catalog-seeder.ts +95 -86
  345. package/src/providers/operations/provider-catalog-service.ts +76 -0
  346. package/src/providers/operations/provider-credential-service.ts +46 -7
  347. package/src/providers/provider-contracts.ts +76 -0
  348. package/src/providers/provider-metadata.ts +78 -6
  349. package/src/providers/provider-model-definition.ts +373 -349
  350. package/src/security/api-key-auth.ts +126 -8
  351. package/src/transport/contracts.ts +3 -0
  352. package/src/transport/dispatch/attempt-finalize.ts +39 -2
  353. package/src/transport/dispatch/attempt-loop.ts +530 -513
  354. package/src/transport/dispatch/empty-stream.ts +17 -26
  355. package/src/transport/dispatch/generation.ts +88 -21
  356. package/src/transport/dispatch/leases.ts +99 -2
  357. package/src/transport/dispatch/proxy-request.ts +60 -3
  358. package/src/transport/dispatch/streaming/finalize.ts +16 -1
  359. package/src/transport/dispatch/streaming/stream.ts +22 -2
  360. package/src/transport/dispatch/upstream.ts +19 -1
  361. package/src/transport/failure-policy.ts +20 -0
  362. package/src/transport/guards/auth-guard.ts +26 -1
  363. package/src/transport/guards/body-policy.ts +5 -4
  364. package/src/transport/request/preparer.ts +103 -0
  365. package/src/transport/request/state.ts +14 -0
  366. package/src/transport/routing/plan-gate.ts +45 -0
  367. package/src/transport/routing/route-catalog.ts +799 -738
  368. package/src/transport/routing/route-model.ts +52 -1
  369. package/src/transport/routing/router.ts +51 -0
  370. package/src/transport/surface/chat/encode.ts +18 -31
  371. package/src/transport/surface/messages/stream.ts +3 -2
  372. package/src/transport/translation/tool-repair.ts +37 -16
  373. package/src/workers/account-identity-sweep.ts +14 -12
  374. package/src/workers/daily-checkin.ts +62 -0
  375. package/src/workers/quota-refresh-sweep.ts +27 -2
  376. package/dist/dashboard/assets/BannedPage-DUrXpp-X.js +0 -1
  377. package/dist/dashboard/assets/CombosPage-B7ETkfVH.js +0 -1
  378. package/dist/dashboard/assets/ConsoleLogPage-AisQzCI1.js +0 -1
  379. package/dist/dashboard/assets/HealthEventsModal-BNflDm_f.js +0 -1
  380. package/dist/dashboard/assets/ModelPicker-CAiPR5Vd.js +0 -1
  381. package/dist/dashboard/assets/OverviewPage-C3NIzsDx.js +0 -1
  382. package/dist/dashboard/assets/ProviderDetailPage-BK8i5B5X.js +0 -3
  383. package/dist/dashboard/assets/ProviderIcon-paOCq8I0.js +0 -1
  384. package/dist/dashboard/assets/ProvidersPage-CvCVgm1e.js +0 -1
  385. package/dist/dashboard/assets/ProxyPage-DjabkuzP.js +0 -7
  386. package/dist/dashboard/assets/QuotaPage-Dxe0B0iu.js +0 -1
  387. package/dist/dashboard/assets/SetupPage-BaD4P_jW.js +0 -1
  388. package/dist/dashboard/assets/StudioPage-CLP4le3U.js +0 -31
  389. package/dist/dashboard/assets/UsagePage-Djes-Epy.js +0 -56
  390. package/dist/dashboard/assets/api-keys-CjIGQhe7.js +0 -1
  391. package/dist/dashboard/assets/app-Cjgo4-Lf.css +0 -2
  392. package/dist/dashboard/assets/assert-Bwh6DJTK.js +0 -1
  393. package/dist/dashboard/assets/cli-tools-DccaOfhX.js +0 -1
  394. package/dist/dashboard/assets/clipboard-button-DQmMikNQ.js +0 -1
  395. package/dist/dashboard/assets/entry-Cpi0rph1.js +0 -4
  396. package/dist/dashboard/assets/entry-Dm3PpDCO.js +0 -1
  397. package/dist/dashboard/assets/entry-keNDZ_Wz.js +0 -1
  398. package/dist/dashboard/assets/github-badge-BuAJr8oU.js +0 -1
  399. package/dist/dashboard/assets/model-bans-CVvHZ-qz.js +0 -1
  400. package/dist/dashboard/assets/mutation-BIizFZav.js +0 -1
  401. package/dist/dashboard/assets/privacy-mode-CQjbZ3xk.js +0 -1
  402. package/dist/dashboard/assets/routing-jntw9-Ui.js +0 -1
  403. package/dist/dashboard/assets/select-CGUuTQmj.js +0 -41
  404. package/dist/dashboard/assets/settings-BAS6QbmJ.js +0 -1
  405. package/dist/dashboard/assets/sliders-horizontal-ClG7dBeJ.js +0 -1
  406. package/dist/dashboard/assets/terminal-C9mZ4Ugm.js +0 -1
  407. package/dist/dashboard/assets/toast-DKAdP2mo.js +0 -2
  408. package/scripts/cli/cli.ts +0 -771
  409. package/scripts/operations/probe-egress.ts +0 -335
  410. package/scripts/operations/restart.ts +0 -120
  411. package/scripts/shared/env.ts +0 -269
  412. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.ico +0 -0
  413. /package/{tray-assets → scripts/cli/tray/assets}/cartethyia.png +0 -0
  414. /package/scripts/cli/{menu.ts → ui/prompt.ts} +0 -0
  415. /package/scripts/cli/{wordmark.ts → ui/wordmark.ts} +0 -0
@@ -1,281 +1,139 @@
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
-
8
- const OPENROUTER_PROVIDER_ID = "openrouter" as const;
9
-
10
- /** OpenRouter requires these on every request for ranking/attribution. */
11
- const OPENROUTER_REQUIRED_HEADERS: Readonly<Record<string, string>> = {
12
- "HTTP-Referer": "https://endpoint-proxy.local",
13
- "X-Title": "Endpoint Proxy",
14
- };
15
-
16
- /**
17
- * OpenRouter's non-chat service models.
18
- *
19
- * OpenRouter fronts the System One decision API (`/api/v1/systemone`) as
20
- * `typesafe/jev-1.13`, which is not a chat model: it answers `{answers}` to a
21
- * `{state, questions}` body. `/api/v1/models` does not list it under a wire the
22
- * generic fetcher can classify, so it is declared here — a `serviceKind` row
23
- * served by the native System One route, never by the chat surface.
24
- */
25
- export const OPENROUTER_MODELS: readonly ModelDefinition[] = [
26
- defineModel({
27
- id: "typesafe/jev-1.13",
28
- providerId: "openrouter",
29
- serviceKind: "systemone",
30
- wireFamily: "chat",
31
- endpoint: "/systemone",
32
- ctx: 200_000,
33
- out: 8_192,
34
- toolCall: false,
35
- }),
36
- ];
37
-
38
-
39
- /**
40
- * OpenRouter's `:free` tier, as a default catalog.
41
- *
42
- * OpenRouter runs live `/api/v1/models` discovery, so this is a floor rather
43
- * than the only source — but without it the provider lists nothing at all
44
- * until a discovery run happens to fetch it, and the free tier is the one part
45
- * of OpenRouter an operator can use with no spend.
46
- *
47
- * Fetched 2026-10-12 from `https://openrouter.ai/api/v1/models`, which served
48
- * 15 `:free` rows; the 14 that the base catalog also files under `openrouter`
49
- * are listed here. `apodex/apodex-1.1-mini:free` is absent because the base
50
- * catalog has no row for it under any provider, so its limits and price would
51
- * have to be guessed — and a published guess reads as a measurement. Discovery
52
- * still picks it up, which is the correct path for a row with no catalog data.
53
- *
54
- * Every row is marked `freeTier` as well as `free`, because the two answer
55
- * different questions: `free` says this bills zero per token, and `freeTier` is
56
- * what the model list groups on so the free roster is labelled as such rather
57
- * than mixed in with the billed catalog.
58
- */
59
- export const OPENROUTER_FREE_MODELS: readonly ModelDefinition[] = [
60
- defineModel({
61
- id: "cohere/north-mini-code:free",
62
- providerId: OPENROUTER_PROVIDER_ID,
63
- reasoning: true,
64
- toolCall: true,
65
- free: true,
66
- freeTier: true,
67
- }),
68
- defineModel({
69
- id: "dots-studio/dots-3-note-preview:free",
70
- providerId: OPENROUTER_PROVIDER_ID,
71
- reasoning: true,
72
- toolCall: true,
73
- free: true,
74
- freeTier: true,
75
- }),
76
- defineModel({
77
- id: "google/gemma-4-26b-a4b-it:free",
78
- providerId: OPENROUTER_PROVIDER_ID,
79
- reasoning: true,
80
- toolCall: true,
81
- free: true,
82
- freeTier: true,
83
- }),
84
- defineModel({
85
- id: "google/gemma-4-31b-it:free",
86
- providerId: OPENROUTER_PROVIDER_ID,
87
- reasoning: true,
88
- toolCall: true,
89
- free: true,
90
- freeTier: true,
91
- }),
92
- defineModel({
93
- id: "inclusionai/ling-3.0-flash-fin:free",
94
- providerId: OPENROUTER_PROVIDER_ID,
95
- reasoning: true,
96
- toolCall: true,
97
- free: true,
98
- freeTier: true,
99
- }),
100
- defineModel({
101
- id: "inclusionai/ling-3.0-flash-sante:free",
102
- providerId: OPENROUTER_PROVIDER_ID,
103
- reasoning: true,
104
- toolCall: true,
105
- free: true,
106
- freeTier: true,
107
- }),
108
- defineModel({
109
- id: "liquid/lfm-2.5-2.6b:free",
110
- providerId: OPENROUTER_PROVIDER_ID,
111
- reasoning: true,
112
- toolCall: true,
113
- free: true,
114
- freeTier: true,
115
- }),
116
- defineModel({
117
- id: "nex-agi/nex-n2.5-mini:free",
118
- providerId: OPENROUTER_PROVIDER_ID,
119
- reasoning: true,
120
- toolCall: true,
121
- free: true,
122
- freeTier: true,
123
- }),
124
- defineModel({
125
- id: "nex-agi/nex-n2.5-pro:free",
126
- providerId: OPENROUTER_PROVIDER_ID,
127
- reasoning: true,
128
- toolCall: true,
129
- free: true,
130
- freeTier: true,
131
- }),
132
- defineModel({
133
- id: "nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free",
134
- providerId: OPENROUTER_PROVIDER_ID,
135
- audio: true,
136
- reasoning: true,
137
- toolCall: true,
138
- free: true,
139
- freeTier: true,
140
- }),
141
- defineModel({
142
- id: "nvidia/nemotron-3-super-120b-a12b:free",
143
- providerId: OPENROUTER_PROVIDER_ID,
144
- reasoning: true,
145
- toolCall: true,
146
- free: true,
147
- freeTier: true,
148
- }),
149
- defineModel({
150
- id: "nvidia/nemotron-3-ultra-550b-a55b:free",
151
- providerId: OPENROUTER_PROVIDER_ID,
152
- reasoning: true,
153
- toolCall: true,
154
- free: true,
155
- freeTier: true,
156
- }),
157
- defineModel({
158
- id: "nvidia/nemotron-3.5-content-safety:free",
159
- providerId: OPENROUTER_PROVIDER_ID,
160
- reasoning: true,
161
- // A content-safety classifier, not a chat model: it is published on the
162
- // same free tier and serves no tool calls.
163
- toolCall: false,
164
- free: true,
165
- freeTier: true,
166
- }),
167
- defineModel({
168
- id: "nvidia/nemotron-3.5-lightning:free",
169
- providerId: OPENROUTER_PROVIDER_ID,
170
- reasoning: true,
171
- toolCall: true,
172
- free: true,
173
- freeTier: true,
174
- }),
175
- defineModel({
176
- id: "poolside/laguna-s-2.1:free",
177
- providerId: OPENROUTER_PROVIDER_ID,
178
- reasoning: true,
179
- toolCall: true,
180
- free: true,
181
- freeTier: true,
182
- }),
183
- defineModel({
184
- id: "poolside/laguna-xs-2.1:free",
185
- providerId: OPENROUTER_PROVIDER_ID,
186
- reasoning: true,
187
- toolCall: true,
188
- free: true,
189
- freeTier: true,
190
- }),
191
- defineModel({
192
- id: "qwen/qwen3.8-27b:free",
193
- providerId: OPENROUTER_PROVIDER_ID,
194
- reasoning: true,
195
- toolCall: true,
196
- free: true,
197
- freeTier: true,
198
- }),
199
- defineModel({
200
- id: "thinkingmachines/inkling-small:free",
201
- providerId: OPENROUTER_PROVIDER_ID,
202
- reasoning: true,
203
- toolCall: true,
204
- free: true,
205
- freeTier: true,
206
- }),
207
- defineModel({
208
- id: "thinkingmachines/inkling:free",
209
- providerId: OPENROUTER_PROVIDER_ID,
210
- reasoning: true,
211
- toolCall: true,
212
- free: true,
213
- freeTier: true,
214
- }),
215
- defineModel({
216
- id: "z-ai/glm-5.2:free",
217
- providerId: OPENROUTER_PROVIDER_ID,
218
- reasoning: true,
219
- toolCall: true,
220
- free: true,
221
- freeTier: true,
222
- }),
223
- ];
224
-
225
-
226
- /**
227
- * OpenRouter's `:free` rows, discovered live.
228
- *
229
- * OpenRouter rotates its free tier constantly — models are added and pulled
230
- * within days — so a committed list is only ever a snapshot of one afternoon.
231
- * This is the same shape as the OpenCode Zen free fetch: filter the provider's
232
- * own live listing down to the free rows and mark each one `freeTier`, which is
233
- * what the model list groups under "Free models (auto)".
234
- *
235
- * The rows are the fetcher's own definitions, spread rather than rebuilt: it
236
- * has already resolved limits, pricing, and the wire family from the id, and
237
- * re-deriving that here would discard the resolution and let the two drift.
238
- */
239
- export async function discoverOpenrouterFreeModels(
240
- input: DiscoveryInput,
241
- ): Promise<readonly ModelDefinition[] | null> {
242
- const listed = await discoverOpenrouterModels(input);
243
- if (listed === null) return null;
244
- return (
245
- listed
246
- // OpenRouter's free-tier spelling is a `:free` id suffix, matched exactly
247
- // rather than as a substring so a model whose own name contains "free" is
248
- // not swept in by accident.
249
- .filter((model) => model.modelId.endsWith(":free"))
250
- .map((model) => ({
251
- ...model,
252
- // `free` is a billing statement and `freeTier` a catalog one. The
253
- // `:free` suffix answers both, so both are set; the cost is left as the
254
- // fetcher resolved it because OpenRouter publishes a real zero price.
255
- free: true,
256
- freeTier: true,
257
- }))
258
- );
259
- }
260
-
261
-
262
- /** OpenRouter adapter spec; the registry builds it via `createApiKeyAdapter`. */
263
- export const OPENROUTER_SPEC: ApiKeyProviderSpec = {
264
- provider_id: OPENROUTER_PROVIDER_ID,
265
- endpoint_paths_by_wire_family: {},
266
- extra_headers: OPENROUTER_REQUIRED_HEADERS,
267
- };
268
-
269
- export async function discoverOpenrouterModels(
270
- input: DiscoveryInput,
271
- ): Promise<readonly ModelDefinition[] | null> {
272
- return fetchOpenAICompatibleModels({
273
- baseUrl: providerBaseUrl("openrouter"),
274
- headers: {
275
- authorization: `Bearer ${input.credential}`,
276
- ...OPENROUTER_REQUIRED_HEADERS,
277
- },
278
- ...(input.signal ? { signal: input.signal } : {}),
279
- ...(input.fetcher ? { fetcher: input.fetcher } : {}),
280
- });
281
- }
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
+ // The router, and only the router. A hand-kept catalog of specific ids was a
28
+ // snapshot of one afternoon: OpenRouter adds and pulls models within days, so
29
+ // every committed row outside this one drifts out of truth. Discovery is the
30
+ // authority, and the free roster below is the offline floor.
31
+ defineModel({
32
+ id: "openrouter/auto",
33
+ providerId: OPENROUTER_PROVIDER_ID,
34
+ wireFamily: "chat",
35
+ endpoint: "/chat/completions",
36
+ // The catalog publishes no limits for a router (pricing is -1, meaning
37
+ // "decided at dispatch"), so this is the largest window it may select into.
38
+ ctx: 2_000_000,
39
+ out: 128_000,
40
+ reasoning: true,
41
+ }),
42
+ // Not a chat row: it answers `{answers}` to a `{state, questions}` body, and
43
+ // is served by the native System One route. Kept because deleting it removes
44
+ // that route, which is a capability, not a stale catalog entry.
45
+ defineModel({
46
+ id: "typesafe/jev-1.13",
47
+ providerId: "openrouter",
48
+ serviceKind: "systemone",
49
+ wireFamily: "chat",
50
+ endpoint: "/systemone",
51
+ ctx: 200_000,
52
+ out: 8_192,
53
+ toolCall: false,
54
+ }),
55
+ ];
56
+
57
+
58
+ /**
59
+ * OpenRouter's `:free` tier, as a default catalog.
60
+ *
61
+ * OpenRouter runs live `/api/v1/models` discovery, so this is a floor rather
62
+ * than the only source — but without it the provider lists nothing at all
63
+ * until a discovery run happens to fetch it, and the free tier is the one part
64
+ * of OpenRouter an operator can use with no spend.
65
+ *
66
+ * Fetched 2026-10-12 from `https://openrouter.ai/api/v1/models`, which served
67
+ * 15 `:free` rows; the 14 that the base catalog also files under `openrouter`
68
+ * are listed here. `apodex/apodex-1.1-mini:free` is absent because the base
69
+ * catalog has no row for it under any provider, so its limits and price would
70
+ * have to be guessed — and a published guess reads as a measurement. Discovery
71
+ * still picks it up, which is the correct path for a row with no catalog data.
72
+ *
73
+ * Every row is marked `freeTier` as well as `free`, because the two answer
74
+ * different questions: `free` says this bills zero per token, and `freeTier` is
75
+ * what the model list groups on so the free roster is labelled as such rather
76
+ * than mixed in with the billed catalog.
77
+ */
78
+ export const OPENROUTER_FREE_MODELS: readonly ModelDefinition[] = openrouterFreeRoster({
79
+ providerId: OPENROUTER_PROVIDER_ID,
80
+ endpoint: "/chat/completions",
81
+ });
82
+
83
+
84
+ /**
85
+ * OpenRouter's `:free` rows, discovered live.
86
+ *
87
+ * OpenRouter rotates its free tier constantly — models are added and pulled
88
+ * within days — so a committed list is only ever a snapshot of one afternoon.
89
+ * This is the same shape as the OpenCode Zen free fetch: filter the provider's
90
+ * own live listing down to the free rows and mark each one `freeTier`, which is
91
+ * what the model list groups under "Free models (auto)".
92
+ *
93
+ * The rows are the fetcher's own definitions, spread rather than rebuilt: it
94
+ * has already resolved limits, pricing, and the wire family from the id, and
95
+ * re-deriving that here would discard the resolution and let the two drift.
96
+ */
97
+ export async function discoverOpenrouterFreeModels(
98
+ input: DiscoveryInput,
99
+ ): Promise<readonly ModelDefinition[] | null> {
100
+ const listed = await discoverOpenrouterModels(input);
101
+ if (listed === null) return null;
102
+ return (
103
+ listed
104
+ // OpenRouter's free-tier spelling is a `:free` id suffix, matched exactly
105
+ // rather than as a substring so a model whose own name contains "free" is
106
+ // not swept in by accident.
107
+ .filter((model) => model.modelId.endsWith(":free"))
108
+ .map((model) => ({
109
+ ...model,
110
+ // `free` is a billing statement and `freeTier` a catalog one. The
111
+ // `:free` suffix answers both, so both are set; the cost is left as the
112
+ // fetcher resolved it because OpenRouter publishes a real zero price.
113
+ free: true,
114
+ freeTier: true,
115
+ }))
116
+ );
117
+ }
118
+
119
+
120
+ /** OpenRouter adapter spec; the registry builds it via `createApiKeyAdapter`. */
121
+ export const OPENROUTER_SPEC: ApiKeyProviderSpec = {
122
+ provider_id: OPENROUTER_PROVIDER_ID,
123
+ endpoint_paths_by_wire_family: {},
124
+ extra_headers: OPENROUTER_REQUIRED_HEADERS,
125
+ };
126
+
127
+ export async function discoverOpenrouterModels(
128
+ input: DiscoveryInput,
129
+ ): Promise<readonly ModelDefinition[] | null> {
130
+ return fetchOpenAICompatibleModels({
131
+ baseUrl: providerBaseUrl("openrouter"),
132
+ headers: {
133
+ authorization: `Bearer ${input.credential}`,
134
+ ...OPENROUTER_REQUIRED_HEADERS,
135
+ },
136
+ ...(input.signal ? { signal: input.signal } : {}),
137
+ ...(input.fetcher ? { fetcher: input.fetcher } : {}),
138
+ });
139
+ }