cartethyia 2.5.2 → 2.5.4

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 (277) hide show
  1. package/dist/dashboard/assets/{BannedPage-MsQaeQTs.js → BannedPage-C2orBsI2.js} +1 -1
  2. package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
  3. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +1 -0
  4. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolsPage-DfWHTJ7v.js → CliToolsPage-BV6pxVQo.js} +1 -1
  6. package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
  7. package/dist/dashboard/assets/{CombosPage-BrCBQDAc.js → CombosPage-Bsan4679.js} +1 -1
  8. package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
  9. package/dist/dashboard/assets/{ConsoleLogPage-C6Uh33er.js → ConsoleLogPage-CW-wPmJ6.js} +1 -1
  10. package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
  11. package/dist/dashboard/assets/{CustomizationPage-8aS9hyJu.js → CustomizationPage-0p8uX7vB.js} +1 -1
  12. package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
  13. package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js +1 -0
  14. package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
  15. package/dist/dashboard/assets/{LoginPage-C8hKyXBe.js → LoginPage-BvzCx8Kr.js} +1 -1
  16. package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
  17. package/dist/dashboard/assets/{ModelPicker-CWkTUtpX.js → ModelPicker-BY1aKEkP.js} +1 -1
  18. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
  19. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +1 -0
  20. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
  21. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +3 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
  23. package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js +1 -0
  24. package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
  25. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +7 -0
  26. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
  27. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +1 -0
  28. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
  29. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +1 -0
  30. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
  31. package/dist/dashboard/assets/{SetupPage-CXjUlfqr.js → SetupPage-DDbMQsoo.js} +1 -1
  32. package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
  33. package/dist/dashboard/assets/{SortableList-C-_oD3F2.js → SortableList-CB3Z7VTf.js} +1 -1
  34. package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
  35. package/dist/dashboard/assets/{StudioPage-u9IxmYOI.js → StudioPage-D95UCPHI.js} +3 -3
  36. package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
  37. package/dist/dashboard/assets/{UsagePage-BEVLVrwP.js → UsagePage-Cnae9SWA.js} +13 -13
  38. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
  39. package/dist/dashboard/assets/{api-keys-uNywYlfv.js → api-keys-VY68Mhd1.js} +1 -1
  40. package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
  41. package/dist/dashboard/assets/app-COlK95oi.css +2 -0
  42. package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
  43. package/dist/dashboard/assets/{assert-NHwYq95t.js → assert-Chi7pCnt.js} +1 -1
  44. package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
  45. package/dist/dashboard/assets/{badge-6uzDDvqs.js → badge-D4pQapKj.js} +1 -1
  46. package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
  47. package/dist/dashboard/assets/{banner-4_WNg2WZ.js → banner-DH6cg-_B.js} +1 -1
  48. package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
  49. package/dist/dashboard/assets/{card--AtFedAq.js → card-BKqlUOe4.js} +1 -1
  50. package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
  51. package/dist/dashboard/assets/{cli-tools-B3e7dx3N.js → cli-tools-fTgljTGA.js} +1 -1
  52. package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
  53. package/dist/dashboard/assets/{clipboard-button-NreUx6c8.js → clipboard-button-D5Ys_sM0.js} +1 -1
  54. package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
  55. package/dist/dashboard/assets/database-Dz9N3zGd.js +1 -0
  56. package/dist/dashboard/assets/database-Dz9N3zGd.js.gz +0 -0
  57. package/dist/dashboard/assets/{dialog-BtpsJU98.js → dialog-BYj-8WuK.js} +1 -1
  58. package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
  59. package/dist/dashboard/assets/{drawer-WwwtzihF.js → drawer-CmXIZ6H1.js} +1 -1
  60. package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
  61. package/dist/dashboard/assets/entry-CBg5zeu8.js +1 -0
  62. package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
  63. package/dist/dashboard/assets/entry-CQBr6U9c.js +1 -0
  64. package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CgdSAzEV.js +4 -0
  66. package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
  67. package/dist/dashboard/assets/{github-badge-D_eM3IgG.js → github-badge-BlptL8Uf.js} +1 -1
  68. package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
  69. package/dist/dashboard/assets/{index-DCBtROoK.js → index-js6TJvdr.js} +2 -2
  70. package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
  71. package/dist/dashboard/assets/{inline-BcNGF8Gr.js → inline-DUWDSmDV.js} +1 -1
  72. package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
  73. package/dist/dashboard/assets/{input-BG41et9G.js → input-LVjgZq4f.js} +1 -1
  74. package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
  75. package/dist/dashboard/assets/{layout-C8mer_Ak.js → layout-CPfxpsfy.js} +1 -1
  76. package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
  77. package/dist/dashboard/assets/{list-row-Gh_W4OR_.js → list-row-DupvLfDx.js} +1 -1
  78. package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
  79. package/dist/dashboard/assets/{live-BJGYRBnR.js → live-C4pEJUqI.js} +1 -1
  80. package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
  81. package/dist/dashboard/assets/model-bans-BRiuufkB.js +1 -0
  82. package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
  83. package/dist/dashboard/assets/{mutation-BkoLM5Ba.js → mutation-B4ROwk8L.js} +1 -1
  84. package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
  85. package/dist/dashboard/assets/numbers-YNcHvRY7.js +2 -0
  86. package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
  87. package/dist/dashboard/assets/{query-keys-D7wX2vM5.js → query-keys-gmjzC3RS.js} +1 -1
  88. package/dist/dashboard/assets/{query-keys-D7wX2vM5.js.gz → query-keys-gmjzC3RS.js.gz} +0 -0
  89. package/dist/dashboard/assets/{routing-CcusqXA7.js → routing-C7tBT5o-.js} +1 -1
  90. package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
  91. package/dist/dashboard/assets/{select-DsX5QT8K.js → select-WUCXorXw.js} +2 -2
  92. package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
  93. package/dist/dashboard/assets/{settings-mpmXTgUa.js → settings-C_zKl1GS.js} +1 -1
  94. package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
  95. package/dist/dashboard/assets/{stack-DwLmjUFK.js → stack-_3O0F8Xn.js} +1 -1
  96. package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
  97. package/dist/dashboard/assets/{state-DYdQmdAl.js → state-BgTxHcJS.js} +1 -1
  98. package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
  99. package/dist/dashboard/assets/switch-DEjTtOWf.js +1 -0
  100. package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
  101. package/dist/dashboard/assets/terminal-0_IjPWTk.js +1 -0
  102. package/dist/dashboard/assets/terminal-0_IjPWTk.js.gz +0 -0
  103. package/dist/dashboard/assets/{useMutation-w4u4CVue.js → useMutation-BWSC0UAS.js} +1 -1
  104. package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
  105. package/dist/dashboard/assets/zap-C4EeVW4q.js +1 -0
  106. package/dist/dashboard/assets/zap-C4EeVW4q.js.gz +0 -0
  107. package/dist/dashboard/donation/qris-risun-marke.png +0 -0
  108. package/dist/dashboard/index.html +1 -1
  109. package/dist/dashboard/index.html.gz +0 -0
  110. package/dist/dashboard/precompressed-assets.json +54 -54
  111. package/package.json +1 -1
  112. package/scripts/cli/autostart.ts +237 -0
  113. package/scripts/cli/command/console-menu.ts +244 -246
  114. package/scripts/cli/command/tray.ts +208 -204
  115. package/scripts/cli/command/update.ts +27 -10
  116. package/scripts/cli/main.ts +28 -1
  117. package/src/boot/app.ts +693 -693
  118. package/src/boot/dependencies.ts +646 -616
  119. package/src/config/spec.ts +81 -2
  120. package/src/config/telemetry.ts +46 -0
  121. package/src/console/api-keys/bucket-spend.ts +15 -4
  122. package/src/console/backup/contracts.ts +15 -2
  123. package/src/console/backup/routes.ts +52 -1
  124. package/src/console/backup/service.ts +60 -4
  125. package/src/console/console-router.ts +8 -0
  126. package/src/console/data-management/contracts.ts +93 -0
  127. package/src/console/data-management/operations.ts +229 -0
  128. package/src/console/data-management/routes.ts +104 -0
  129. package/src/console/domain-registration.ts +39 -0
  130. package/src/console/observability/contracts.ts +524 -485
  131. package/src/console/observability/store.ts +1115 -1018
  132. package/src/console/providers/catalog/contracts.ts +6 -0
  133. package/src/console/providers/catalog/provider-operations.ts +20 -0
  134. package/src/console/providers/catalog/routes.ts +7 -0
  135. package/src/console/providers/catalog/store.ts +22 -1
  136. package/src/console/quota/account-quota-shared.ts +52 -39
  137. package/src/console/quota/refresh.ts +441 -429
  138. package/src/console/routing/pools/import-parse.ts +206 -0
  139. package/src/console/routing/pools/operations.ts +543 -501
  140. package/src/console/routing/pools/routes.ts +181 -164
  141. package/src/console/settings/contracts.ts +37 -0
  142. package/src/console/settings/store.ts +51 -0
  143. package/src/console/share/share-router.ts +6 -9
  144. package/src/console/updates/routes.ts +16 -0
  145. package/src/main.ts +10 -0
  146. package/src/observability/event-compaction.ts +315 -0
  147. package/src/observability/event-day-index.ts +442 -0
  148. package/src/observability/event-log.ts +152 -3
  149. package/src/observability/payload-capture.ts +373 -344
  150. package/src/observability/payload-store.ts +440 -366
  151. package/src/observability/telemetry-status.ts +28 -16
  152. package/src/persistence/health-event-flush.ts +36 -0
  153. package/src/persistence/schema.ts +1402 -1360
  154. package/src/persistence/stores/api-key-store.ts +6 -0
  155. package/src/persistence/stores/share-store.ts +583 -556
  156. package/src/persistence/stores/telemetry-store.ts +237 -214
  157. package/src/protocol/codecs.ts +1 -2
  158. package/src/protocol/image-clamp.ts +19 -1
  159. package/src/protocol/registry.ts +8 -0
  160. package/src/protocol/request/gemini.ts +9 -2
  161. package/src/protocol/request/messages.ts +14 -2
  162. package/src/protocol/response/gemini.ts +18 -4
  163. package/src/providers/adapters/compatible-adapter.ts +3 -0
  164. package/src/providers/bundled-discovery-providers.ts +122 -119
  165. package/src/providers/configured-openai-providers.ts +136 -134
  166. package/src/providers/default-registry.ts +5 -4
  167. package/src/providers/discovery/openai-model-discovery.ts +5 -0
  168. package/src/providers/discovery/openrouter-free-roster.ts +15 -17
  169. package/src/providers/integrations/antigravity/antigravity-quota.ts +11 -3
  170. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +4 -4
  171. package/src/providers/integrations/buddy/workbuddy/shared.ts +201 -200
  172. package/src/providers/integrations/cline/cline-quota.ts +132 -128
  173. package/src/providers/integrations/codex/codex-headers.ts +25 -39
  174. package/src/providers/integrations/codex/codex.ts +2 -29
  175. package/src/providers/integrations/cursor/cursor-quota.ts +310 -0
  176. package/src/providers/integrations/cursor/cursor-request.ts +616 -471
  177. package/src/providers/integrations/cursor/cursor-session-manager.ts +319 -281
  178. package/src/providers/integrations/cursor/cursor.ts +1485 -960
  179. package/src/providers/integrations/cursor/protocol/messages.ts +25 -0
  180. package/src/providers/integrations/factory/factory.ts +8 -1
  181. package/src/providers/integrations/gemini.ts +6 -1
  182. package/src/providers/integrations/grok/grok-quota.ts +279 -177
  183. package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -0
  184. package/src/providers/integrations/grok/grok-ratelimit.ts +218 -0
  185. package/src/providers/integrations/opencode/provider.ts +531 -532
  186. package/src/providers/integrations/qoder/qoder-quota.ts +192 -0
  187. package/src/providers/integrations/tokenharbor.ts +2 -2
  188. package/src/providers/integrations/trae/trae-catalog.ts +5 -3
  189. package/src/providers/integrations/trae/trae-quota.ts +384 -0
  190. package/src/providers/operations/account-health-service.ts +1523 -1457
  191. package/src/providers/operations/client-versions.ts +9 -2
  192. package/src/providers/provider-contracts.ts +7 -0
  193. package/src/providers/provider-metadata.ts +13 -1
  194. package/src/providers/quota/quota-support.ts +8 -0
  195. package/src/security/api-key-auth.ts +504 -494
  196. package/src/transport/dispatch/attempt-finalize.ts +46 -5
  197. package/src/transport/dispatch/generation.ts +6 -0
  198. package/src/transport/dispatch/proxy-request.ts +33 -1
  199. package/src/transport/dispatch/ratelimit-capture.ts +37 -0
  200. package/src/transport/dispatch/streaming/stream.ts +30 -2
  201. package/src/transport/dispatch/upstream.ts +9 -0
  202. package/src/transport/request/preparer.ts +7 -6
  203. package/src/transport/request/state.ts +9 -0
  204. package/src/transport/request/tenant-preferences.ts +60 -0
  205. package/src/transport/routing/route-catalog.ts +854 -799
  206. package/dist/dashboard/assets/BannedPage-MsQaeQTs.js.gz +0 -0
  207. package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js +0 -1
  208. package/dist/dashboard/assets/CliToolDetailPage-BO9nKg9w.js.gz +0 -0
  209. package/dist/dashboard/assets/CliToolsPage-DfWHTJ7v.js.gz +0 -0
  210. package/dist/dashboard/assets/CombosPage-BrCBQDAc.js.gz +0 -0
  211. package/dist/dashboard/assets/ConsoleLogPage-C6Uh33er.js.gz +0 -0
  212. package/dist/dashboard/assets/CustomizationPage-8aS9hyJu.js.gz +0 -0
  213. package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js +0 -1
  214. package/dist/dashboard/assets/HealthEventsModal-qomXThxX.js.gz +0 -0
  215. package/dist/dashboard/assets/LoginPage-C8hKyXBe.js.gz +0 -0
  216. package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js.gz +0 -0
  217. package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js +0 -1
  218. package/dist/dashboard/assets/OverviewPage-C-ExCy1V.js.gz +0 -0
  219. package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js +0 -3
  220. package/dist/dashboard/assets/ProviderDetailPage-tr811uaF.js.gz +0 -0
  221. package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js +0 -1
  222. package/dist/dashboard/assets/ProvidersPage-BS9IEpvv.js.gz +0 -0
  223. package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js +0 -7
  224. package/dist/dashboard/assets/ProxyPage-Rn_qXScb.js.gz +0 -0
  225. package/dist/dashboard/assets/QuotaPage-BihkgQSq.js +0 -1
  226. package/dist/dashboard/assets/QuotaPage-BihkgQSq.js.gz +0 -0
  227. package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js +0 -1
  228. package/dist/dashboard/assets/SettingsPage-DhiEjm6T.js.gz +0 -0
  229. package/dist/dashboard/assets/SetupPage-CXjUlfqr.js.gz +0 -0
  230. package/dist/dashboard/assets/SortableList-C-_oD3F2.js.gz +0 -0
  231. package/dist/dashboard/assets/StudioPage-u9IxmYOI.js.gz +0 -0
  232. package/dist/dashboard/assets/UsagePage-BEVLVrwP.js.gz +0 -0
  233. package/dist/dashboard/assets/api-keys-uNywYlfv.js.gz +0 -0
  234. package/dist/dashboard/assets/app-DxivpfYG.css +0 -2
  235. package/dist/dashboard/assets/app-DxivpfYG.css.gz +0 -0
  236. package/dist/dashboard/assets/assert-NHwYq95t.js.gz +0 -0
  237. package/dist/dashboard/assets/badge-6uzDDvqs.js.gz +0 -0
  238. package/dist/dashboard/assets/banner-4_WNg2WZ.js.gz +0 -0
  239. package/dist/dashboard/assets/card--AtFedAq.js.gz +0 -0
  240. package/dist/dashboard/assets/cli-tools-B3e7dx3N.js.gz +0 -0
  241. package/dist/dashboard/assets/clipboard-button-NreUx6c8.js.gz +0 -0
  242. package/dist/dashboard/assets/dialog-BtpsJU98.js.gz +0 -0
  243. package/dist/dashboard/assets/download-A0SW9OCW.js +0 -1
  244. package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
  245. package/dist/dashboard/assets/drawer-WwwtzihF.js.gz +0 -0
  246. package/dist/dashboard/assets/entry-Dj9AR0gY.js +0 -4
  247. package/dist/dashboard/assets/entry-Dj9AR0gY.js.gz +0 -0
  248. package/dist/dashboard/assets/entry-TJIye_jT.js +0 -1
  249. package/dist/dashboard/assets/entry-TJIye_jT.js.gz +0 -0
  250. package/dist/dashboard/assets/entry-jy9_4-Ke.js +0 -1
  251. package/dist/dashboard/assets/entry-jy9_4-Ke.js.gz +0 -0
  252. package/dist/dashboard/assets/github-badge-D_eM3IgG.js.gz +0 -0
  253. package/dist/dashboard/assets/index-DCBtROoK.js.gz +0 -0
  254. package/dist/dashboard/assets/inline-BcNGF8Gr.js.gz +0 -0
  255. package/dist/dashboard/assets/input-BG41et9G.js.gz +0 -0
  256. package/dist/dashboard/assets/layout-C8mer_Ak.js.gz +0 -0
  257. package/dist/dashboard/assets/list-row-Gh_W4OR_.js.gz +0 -0
  258. package/dist/dashboard/assets/live-BJGYRBnR.js.gz +0 -0
  259. package/dist/dashboard/assets/model-bans-DeVLDA7I.js +0 -1
  260. package/dist/dashboard/assets/model-bans-DeVLDA7I.js.gz +0 -0
  261. package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
  262. package/dist/dashboard/assets/numbers-Bs4LOOuf.js +0 -2
  263. package/dist/dashboard/assets/numbers-Bs4LOOuf.js.gz +0 -0
  264. package/dist/dashboard/assets/routing-CcusqXA7.js.gz +0 -0
  265. package/dist/dashboard/assets/select-DsX5QT8K.js.gz +0 -0
  266. package/dist/dashboard/assets/settings-mpmXTgUa.js.gz +0 -0
  267. package/dist/dashboard/assets/sparkles-BRaRUxAU.js +0 -1
  268. package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
  269. package/dist/dashboard/assets/stack-DwLmjUFK.js.gz +0 -0
  270. package/dist/dashboard/assets/state-DYdQmdAl.js.gz +0 -0
  271. package/dist/dashboard/assets/switch-CidSfbG7.js +0 -1
  272. package/dist/dashboard/assets/switch-CidSfbG7.js.gz +0 -0
  273. package/dist/dashboard/assets/terminal-Bd4ee8TA.js +0 -1
  274. package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
  275. package/dist/dashboard/assets/useMutation-w4u4CVue.js.gz +0 -0
  276. /package/dist/dashboard/assets/{app-CafWtVXA.js → app-DCQZRmHY.js} +0 -0
  277. /package/dist/dashboard/assets/{app-CafWtVXA.js.gz → app-DCQZRmHY.js.gz} +0 -0
@@ -63,11 +63,25 @@ export function responseParts(parts: readonly Record<string, unknown>[]): {
63
63
 
64
64
  export function mapGeminiUsage(body: Record<string, unknown>): Record<string, unknown> {
65
65
  const usage = isRecord(body["usageMetadata"]) ? (body["usageMetadata"] as Record<string, unknown>) : {};
66
+ const prompt = nullableNumber(usage["promptTokenCount"]) ?? 0;
67
+ const candidates = nullableNumber(usage["candidatesTokenCount"]) ?? 0;
68
+ // Reasoning is billed output that Gemini reports in its own counter:
69
+ // `candidatesTokenCount` excludes `thoughtsTokenCount`, so dropping it here
70
+ // silently under-reported every thinking model's completion tokens. It is
71
+ // surfaced through `output_tokens_details` because that is the slot
72
+ // `normalizeUsage` reads for reasoning — keeping it separate from the
73
+ // candidate count it is added into, so downstream can still split them.
74
+ const thoughts = nullableNumber(usage["thoughtsTokenCount"]) ?? 0;
75
+ const output = candidates + thoughts;
76
+ const cached = nullableNumber(usage["cachedContentTokenCount"]) ?? 0;
66
77
  return {
67
- input_tokens: nullableNumber(usage["promptTokenCount"]) ?? 0,
68
- output_tokens: nullableNumber(usage["candidatesTokenCount"]) ?? 0,
69
- total_tokens: nullableNumber(usage["totalTokenCount"]) ?? 0,
70
- cached_tokens: nullableNumber(usage["cachedContentTokenCount"]) ?? 0,
78
+ input_tokens: prompt,
79
+ output_tokens: output,
80
+ total_tokens: nullableNumber(usage["totalTokenCount"]) ?? prompt + output,
81
+ cached_tokens: cached,
82
+ ...(thoughts > 0
83
+ ? { output_tokens_details: { reasoning_tokens: thoughts } }
84
+ : {}),
71
85
  };
72
86
  }
73
87
 
@@ -207,6 +207,9 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
207
207
  ...(this.config.chat_token_limit_field === undefined
208
208
  ? {}
209
209
  : { chatTokenLimitField: this.config.chat_token_limit_field }),
210
+ ...(context.image_clamp_max_bytes === undefined
211
+ ? {}
212
+ : { maxBytesOverride: context.image_clamp_max_bytes }),
210
213
  });
211
214
  if (
212
215
  wireFamily !== "messages" &&
@@ -1,119 +1,122 @@
1
- import type { ProviderModule } from "./provider-registry";
2
- import {
3
- GENERIC_API_KEY_SPECS,
4
- VERSIONED_ROOT_API_KEY_SPECS,
5
- } from "./configured-openai-providers";
6
- import { createApiKeyAdapter, type ApiKeyProviderSpec } from "./configured-provider";
7
-
8
- /**
9
- * Providers whose adapter and catalog discovery are the same bearer-auth
10
- * OpenAI-compatible contract. Providers with static catalogs or additional
11
- * upstream behavior remain declared beside their special handling.
12
- */
13
- export const DISCOVERY_BACKED_PROVIDER_IDS = [
14
- "groq",
15
- "together",
16
- "deepinfra",
17
- "siliconflow",
18
- "siliconflowcn",
19
- "novita",
20
- "venice",
21
- "nanogpt",
22
- "baseten",
23
- "synthetic",
24
- "stepfun",
25
- "sakana",
26
- "helmcode",
27
- "coralbricks",
28
- "aiand",
29
- "wafer",
30
- "firepass",
31
- "zhipucoding",
32
- "dashscope",
33
- "qianfan",
34
- ] as const;
35
-
36
- export type DiscoveryBackedProviderId = (typeof DISCOVERY_BACKED_PROVIDER_IDS)[number];
37
-
38
- type DiscoveryBackedCapabilities = Pick<
39
- ProviderModule,
40
- "endpointPathsByWireFamily" | "loadAdapter" | "loadModelDiscovery"
41
- >;
42
-
43
- type ModelDiscoveryFactory = NonNullable<ProviderModule["loadModelDiscovery"]>;
44
- type OpenAIModelDiscoveryFactory = (
45
- providerId: string,
46
- options?: {
47
- readonly headers?: (credential: string) => Readonly<Record<string, string>>;
48
- },
49
- ) => ModelDiscoveryFactory;
50
-
51
- const DISCOVERY_BACKED_PROVIDER_SPECS = {
52
- groq: VERSIONED_ROOT_API_KEY_SPECS.groq,
53
- together: GENERIC_API_KEY_SPECS.together,
54
- deepinfra: VERSIONED_ROOT_API_KEY_SPECS.deepinfra,
55
- siliconflow: GENERIC_API_KEY_SPECS.siliconflow,
56
- siliconflowcn: GENERIC_API_KEY_SPECS.siliconflowcn,
57
- novita: VERSIONED_ROOT_API_KEY_SPECS.novita,
58
- venice: VERSIONED_ROOT_API_KEY_SPECS.venice,
59
- nanogpt: GENERIC_API_KEY_SPECS.nanogpt,
60
- baseten: GENERIC_API_KEY_SPECS.baseten,
61
- synthetic: GENERIC_API_KEY_SPECS.synthetic,
62
- stepfun: GENERIC_API_KEY_SPECS.stepfun,
63
- sakana: GENERIC_API_KEY_SPECS.sakana,
64
- helmcode: GENERIC_API_KEY_SPECS.helmcode,
65
- coralbricks: GENERIC_API_KEY_SPECS.coralbricks,
66
- aiand: GENERIC_API_KEY_SPECS.aiand,
67
- wafer: GENERIC_API_KEY_SPECS.wafer,
68
- firepass: VERSIONED_ROOT_API_KEY_SPECS.firepass,
69
- zhipucoding: VERSIONED_ROOT_API_KEY_SPECS.zhipucoding,
70
- dashscope: GENERIC_API_KEY_SPECS.dashscope,
71
- qianfan: VERSIONED_ROOT_API_KEY_SPECS.qianfan,
72
- } satisfies Readonly<Record<DiscoveryBackedProviderId, ApiKeyProviderSpec>>;
73
-
74
- function discoveryBackedCapabilities(
75
- providerId: DiscoveryBackedProviderId,
76
- spec: ApiKeyProviderSpec,
77
- openAIModelDiscovery: OpenAIModelDiscoveryFactory,
78
- ): DiscoveryBackedCapabilities {
79
- return {
80
- ...(spec.endpoint_paths_by_wire_family === undefined
81
- ? {}
82
- : { endpointPathsByWireFamily: spec.endpoint_paths_by_wire_family }),
83
- loadAdapter: async () => createApiKeyAdapter(spec),
84
- loadModelDiscovery: openAIModelDiscovery(providerId, {
85
- headers: (credential) => ({ authorization: `Bearer ${credential}` }),
86
- }),
87
- };
88
- }
89
-
90
- /**
91
- * Creates the standard provider capability table using the registry's shared
92
- * discovery loader, keeping its lazy import and authentication behavior intact.
93
- */
94
- export function createDiscoveryBackedProviderCapabilities(
95
- openAIModelDiscovery: OpenAIModelDiscoveryFactory,
96
- ): Readonly<Record<DiscoveryBackedProviderId, DiscoveryBackedCapabilities>> {
97
- return {
98
- groq: discoveryBackedCapabilities("groq", DISCOVERY_BACKED_PROVIDER_SPECS.groq, openAIModelDiscovery),
99
- together: discoveryBackedCapabilities("together", DISCOVERY_BACKED_PROVIDER_SPECS.together, openAIModelDiscovery),
100
- deepinfra: discoveryBackedCapabilities("deepinfra", DISCOVERY_BACKED_PROVIDER_SPECS.deepinfra, openAIModelDiscovery),
101
- siliconflow: discoveryBackedCapabilities("siliconflow", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflow, openAIModelDiscovery),
102
- siliconflowcn: discoveryBackedCapabilities("siliconflowcn", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflowcn, openAIModelDiscovery),
103
- novita: discoveryBackedCapabilities("novita", DISCOVERY_BACKED_PROVIDER_SPECS.novita, openAIModelDiscovery),
104
- venice: discoveryBackedCapabilities("venice", DISCOVERY_BACKED_PROVIDER_SPECS.venice, openAIModelDiscovery),
105
- nanogpt: discoveryBackedCapabilities("nanogpt", DISCOVERY_BACKED_PROVIDER_SPECS.nanogpt, openAIModelDiscovery),
106
- baseten: discoveryBackedCapabilities("baseten", DISCOVERY_BACKED_PROVIDER_SPECS.baseten, openAIModelDiscovery),
107
- synthetic: discoveryBackedCapabilities("synthetic", DISCOVERY_BACKED_PROVIDER_SPECS.synthetic, openAIModelDiscovery),
108
- stepfun: discoveryBackedCapabilities("stepfun", DISCOVERY_BACKED_PROVIDER_SPECS.stepfun, openAIModelDiscovery),
109
- sakana: discoveryBackedCapabilities("sakana", DISCOVERY_BACKED_PROVIDER_SPECS.sakana, openAIModelDiscovery),
110
- helmcode: discoveryBackedCapabilities("helmcode", DISCOVERY_BACKED_PROVIDER_SPECS.helmcode, openAIModelDiscovery),
111
- coralbricks: discoveryBackedCapabilities("coralbricks", DISCOVERY_BACKED_PROVIDER_SPECS.coralbricks, openAIModelDiscovery),
112
- aiand: discoveryBackedCapabilities("aiand", DISCOVERY_BACKED_PROVIDER_SPECS.aiand, openAIModelDiscovery),
113
- wafer: discoveryBackedCapabilities("wafer", DISCOVERY_BACKED_PROVIDER_SPECS.wafer, openAIModelDiscovery),
114
- firepass: discoveryBackedCapabilities("firepass", DISCOVERY_BACKED_PROVIDER_SPECS.firepass, openAIModelDiscovery),
115
- zhipucoding: discoveryBackedCapabilities("zhipucoding", DISCOVERY_BACKED_PROVIDER_SPECS.zhipucoding, openAIModelDiscovery),
116
- dashscope: discoveryBackedCapabilities("dashscope", DISCOVERY_BACKED_PROVIDER_SPECS.dashscope, openAIModelDiscovery),
117
- qianfan: discoveryBackedCapabilities("qianfan", DISCOVERY_BACKED_PROVIDER_SPECS.qianfan, openAIModelDiscovery),
118
- };
119
- }
1
+ import type { ProviderModule } from "./provider-registry";
2
+ import {
3
+ GENERIC_API_KEY_SPECS,
4
+ VERSIONED_ROOT_API_KEY_SPECS,
5
+ } from "./configured-openai-providers";
6
+ import { createApiKeyAdapter, type ApiKeyProviderSpec } from "./configured-provider";
7
+
8
+ /**
9
+ * Providers whose adapter and catalog discovery are the same bearer-auth
10
+ * OpenAI-compatible contract. Providers with static catalogs or additional
11
+ * upstream behavior remain declared beside their special handling.
12
+ */
13
+ export const DISCOVERY_BACKED_PROVIDER_IDS = [
14
+ "groq",
15
+ "together",
16
+ "deepinfra",
17
+ "siliconflow",
18
+ "siliconflowcn",
19
+ "novita",
20
+ "larprouter",
21
+ "venice",
22
+ "nanogpt",
23
+ "baseten",
24
+ "synthetic",
25
+ "stepfun",
26
+ "sakana",
27
+ "helmcode",
28
+ "coralbricks",
29
+ "aiand",
30
+ "wafer",
31
+ "firepass",
32
+ "zhipucoding",
33
+ "dashscope",
34
+ "qianfan",
35
+ ] as const;
36
+
37
+ export type DiscoveryBackedProviderId = (typeof DISCOVERY_BACKED_PROVIDER_IDS)[number];
38
+
39
+ type DiscoveryBackedCapabilities = Pick<
40
+ ProviderModule,
41
+ "endpointPathsByWireFamily" | "loadAdapter" | "loadModelDiscovery"
42
+ >;
43
+
44
+ type ModelDiscoveryFactory = NonNullable<ProviderModule["loadModelDiscovery"]>;
45
+ type OpenAIModelDiscoveryFactory = (
46
+ providerId: string,
47
+ options?: {
48
+ readonly headers?: (credential: string) => Readonly<Record<string, string>>;
49
+ },
50
+ ) => ModelDiscoveryFactory;
51
+
52
+ const DISCOVERY_BACKED_PROVIDER_SPECS = {
53
+ groq: VERSIONED_ROOT_API_KEY_SPECS.groq,
54
+ larprouter: GENERIC_API_KEY_SPECS.larprouter,
55
+ together: GENERIC_API_KEY_SPECS.together,
56
+ deepinfra: VERSIONED_ROOT_API_KEY_SPECS.deepinfra,
57
+ siliconflow: GENERIC_API_KEY_SPECS.siliconflow,
58
+ siliconflowcn: GENERIC_API_KEY_SPECS.siliconflowcn,
59
+ novita: VERSIONED_ROOT_API_KEY_SPECS.novita,
60
+ venice: VERSIONED_ROOT_API_KEY_SPECS.venice,
61
+ nanogpt: GENERIC_API_KEY_SPECS.nanogpt,
62
+ baseten: GENERIC_API_KEY_SPECS.baseten,
63
+ synthetic: GENERIC_API_KEY_SPECS.synthetic,
64
+ stepfun: GENERIC_API_KEY_SPECS.stepfun,
65
+ sakana: GENERIC_API_KEY_SPECS.sakana,
66
+ helmcode: GENERIC_API_KEY_SPECS.helmcode,
67
+ coralbricks: GENERIC_API_KEY_SPECS.coralbricks,
68
+ aiand: GENERIC_API_KEY_SPECS.aiand,
69
+ wafer: GENERIC_API_KEY_SPECS.wafer,
70
+ firepass: VERSIONED_ROOT_API_KEY_SPECS.firepass,
71
+ zhipucoding: VERSIONED_ROOT_API_KEY_SPECS.zhipucoding,
72
+ dashscope: GENERIC_API_KEY_SPECS.dashscope,
73
+ qianfan: VERSIONED_ROOT_API_KEY_SPECS.qianfan,
74
+ } satisfies Readonly<Record<DiscoveryBackedProviderId, ApiKeyProviderSpec>>;
75
+
76
+ function discoveryBackedCapabilities(
77
+ providerId: DiscoveryBackedProviderId,
78
+ spec: ApiKeyProviderSpec,
79
+ openAIModelDiscovery: OpenAIModelDiscoveryFactory,
80
+ ): DiscoveryBackedCapabilities {
81
+ return {
82
+ ...(spec.endpoint_paths_by_wire_family === undefined
83
+ ? {}
84
+ : { endpointPathsByWireFamily: spec.endpoint_paths_by_wire_family }),
85
+ loadAdapter: async () => createApiKeyAdapter(spec),
86
+ loadModelDiscovery: openAIModelDiscovery(providerId, {
87
+ headers: (credential) => ({ authorization: `Bearer ${credential}` }),
88
+ }),
89
+ };
90
+ }
91
+
92
+ /**
93
+ * Creates the standard provider capability table using the registry's shared
94
+ * discovery loader, keeping its lazy import and authentication behavior intact.
95
+ */
96
+ export function createDiscoveryBackedProviderCapabilities(
97
+ openAIModelDiscovery: OpenAIModelDiscoveryFactory,
98
+ ): Readonly<Record<DiscoveryBackedProviderId, DiscoveryBackedCapabilities>> {
99
+ return {
100
+ groq: discoveryBackedCapabilities("groq", DISCOVERY_BACKED_PROVIDER_SPECS.groq, openAIModelDiscovery),
101
+ together: discoveryBackedCapabilities("together", DISCOVERY_BACKED_PROVIDER_SPECS.together, openAIModelDiscovery),
102
+ deepinfra: discoveryBackedCapabilities("deepinfra", DISCOVERY_BACKED_PROVIDER_SPECS.deepinfra, openAIModelDiscovery),
103
+ siliconflow: discoveryBackedCapabilities("siliconflow", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflow, openAIModelDiscovery),
104
+ siliconflowcn: discoveryBackedCapabilities("siliconflowcn", DISCOVERY_BACKED_PROVIDER_SPECS.siliconflowcn, openAIModelDiscovery),
105
+ novita: discoveryBackedCapabilities("novita", DISCOVERY_BACKED_PROVIDER_SPECS.novita, openAIModelDiscovery),
106
+ larprouter: discoveryBackedCapabilities("larprouter", DISCOVERY_BACKED_PROVIDER_SPECS.larprouter, openAIModelDiscovery),
107
+ venice: discoveryBackedCapabilities("venice", DISCOVERY_BACKED_PROVIDER_SPECS.venice, openAIModelDiscovery),
108
+ nanogpt: discoveryBackedCapabilities("nanogpt", DISCOVERY_BACKED_PROVIDER_SPECS.nanogpt, openAIModelDiscovery),
109
+ baseten: discoveryBackedCapabilities("baseten", DISCOVERY_BACKED_PROVIDER_SPECS.baseten, openAIModelDiscovery),
110
+ synthetic: discoveryBackedCapabilities("synthetic", DISCOVERY_BACKED_PROVIDER_SPECS.synthetic, openAIModelDiscovery),
111
+ stepfun: discoveryBackedCapabilities("stepfun", DISCOVERY_BACKED_PROVIDER_SPECS.stepfun, openAIModelDiscovery),
112
+ sakana: discoveryBackedCapabilities("sakana", DISCOVERY_BACKED_PROVIDER_SPECS.sakana, openAIModelDiscovery),
113
+ helmcode: discoveryBackedCapabilities("helmcode", DISCOVERY_BACKED_PROVIDER_SPECS.helmcode, openAIModelDiscovery),
114
+ coralbricks: discoveryBackedCapabilities("coralbricks", DISCOVERY_BACKED_PROVIDER_SPECS.coralbricks, openAIModelDiscovery),
115
+ aiand: discoveryBackedCapabilities("aiand", DISCOVERY_BACKED_PROVIDER_SPECS.aiand, openAIModelDiscovery),
116
+ wafer: discoveryBackedCapabilities("wafer", DISCOVERY_BACKED_PROVIDER_SPECS.wafer, openAIModelDiscovery),
117
+ firepass: discoveryBackedCapabilities("firepass", DISCOVERY_BACKED_PROVIDER_SPECS.firepass, openAIModelDiscovery),
118
+ zhipucoding: discoveryBackedCapabilities("zhipucoding", DISCOVERY_BACKED_PROVIDER_SPECS.zhipucoding, openAIModelDiscovery),
119
+ dashscope: discoveryBackedCapabilities("dashscope", DISCOVERY_BACKED_PROVIDER_SPECS.dashscope, openAIModelDiscovery),
120
+ qianfan: discoveryBackedCapabilities("qianfan", DISCOVERY_BACKED_PROVIDER_SPECS.qianfan, openAIModelDiscovery),
121
+ };
122
+ }
@@ -1,135 +1,137 @@
1
- import type { ApiKeyProviderSpec } from "./configured-provider";
2
- import type { ProviderId } from "./provider-contracts";
3
-
4
- /**
5
- * Builtin providers whose entire adapter contract is "bearer auth against the
6
- * provider's `BUNDLED_PROVIDER_METADATA` base URL, OpenAI-compatible chat +
7
- * responses, `/v1`-prefixed paths". They carry no catalog, no OAuth, and no
8
- * provider-specific payload hook, so they share one spec shape rather than
9
- * one module each.
10
- *
11
- * `base_url` is resolved per provider by `providerBaseUrl(provider_id)`.
12
- *
13
- * These providers list their models through live `/v1/models` discovery rather
14
- * than a static catalog: every one of them republishes an aggregator's whole
15
- * roster, which changes faster than a committed array can. Each registry row
16
- * pairs this spec with `openAIModelDiscovery`.
17
- */
18
- export const GENERIC_API_KEY_PROVIDER_IDS = [
19
- "mistral",
20
- "fireworks",
21
- "nvidia",
22
- "gmi",
23
- "ollamacloud",
24
- "together",
25
- "siliconflow",
26
- "siliconflowcn",
27
- "nanogpt",
28
- "baseten",
29
- "synthetic",
30
- "stepfun",
31
- "sakana",
32
- "helmcode",
33
- "coralbricks",
34
- "aiand",
35
- "wafer",
36
- "coreweave",
37
- "qwen-portal",
38
- "dashscope",
39
- // `deepseek` is intentionally absent: it dispatches on the Anthropic Messages
40
- // wire at its `/anthropic` root, not the OpenAI chat/responses wires, so it
41
- // carries a dedicated entry in `default-registry.ts` instead.
42
- //
43
- // The aggregators below are absent for a different reason: their base URL is
44
- // already rooted at a version segment that the `/v1`-prefixed path this shape
45
- // pins would duplicate (`/openai/v1`, `/v1/openai`, `/v3/openai`, `/api/v1`,
46
- // `/v2`, and `/inference/v1`), so `joinUrl` would produce
47
- // `…/v1/v1/chat/completions`. They use `versionedRootApiKeySpec` instead,
48
- // which pins the path below the version root — the same reason `cerebras`
49
- // declares `/chat/completions` explicitly.
50
- ] as const;
51
-
52
- /**
53
- * Ids whose base URL already ends at a version segment.
54
- *
55
- * `joinUrl` is plain concatenation and nothing rewrites a declared path, so a
56
- * base already rooted at a version plus a `/v1/…` path doubles the segment and
57
- * every request 404s. These specs therefore declare the path *below* the
58
- * version root. That is the provider stating the truth about its own wire, not
59
- * a correction applied to it: a wrong path now reaches the operator as the
60
- * wrong URL instead of being quietly rewritten into a different address.
61
- */
62
- export const VERSIONED_ROOT_API_KEY_PROVIDER_IDS = [
63
- "groq",
64
- "deepinfra",
65
- "novita",
66
- "venice",
67
- "qianfan",
68
- "zhipucoding",
69
- "firepass",
70
- ] as const;
71
-
72
- export type VersionedRootApiKeyProviderId =
73
- (typeof VERSIONED_ROOT_API_KEY_PROVIDER_IDS)[number];
74
-
75
- function versionedRootApiKeySpec(providerId: ProviderId): ApiKeyProviderSpec {
76
- return {
77
- provider_id: providerId,
78
- endpoint_paths_by_wire_family: {
79
- chat: "/chat/completions",
80
- responses: "/responses",
81
- },
82
- };
83
- }
84
-
85
- export const VERSIONED_ROOT_API_KEY_SPECS = {
86
- groq: versionedRootApiKeySpec("groq"),
87
- deepinfra: versionedRootApiKeySpec("deepinfra"),
88
- novita: versionedRootApiKeySpec("novita"),
89
- venice: versionedRootApiKeySpec("venice"),
90
- qianfan: versionedRootApiKeySpec("qianfan"),
91
- zhipucoding: versionedRootApiKeySpec("zhipucoding"),
92
- firepass: versionedRootApiKeySpec("firepass"),
93
- } satisfies Readonly<Record<VersionedRootApiKeyProviderId, ApiKeyProviderSpec>>;
94
-
95
- /**
96
- * One id that has both a generic spec and a registry row.
97
- *
98
- * Exported so the registry can be checked against the spec list rather than
99
- * repeating the id as a string: `discoveryBackedProvider` takes this type, so a
100
- * row naming a provider with no spec is a compile error instead of an
101
- * `undefined` adapter at first dispatch.
102
- */
103
- export type GenericApiKeyProviderId = (typeof GENERIC_API_KEY_PROVIDER_IDS)[number];
104
-
105
- function genericApiKeySpec(providerId: GenericApiKeyProviderId): ApiKeyProviderSpec {
106
- // These roots are *not* bare hosts — every one of them already ends at `/v1`
107
- // — so the path is declared below that root. It used to be pinned from
108
- // `BARE_ROOT_ENDPOINTS` and silently corrected at dispatch, which meant the
109
- // declared path was wrong for all of them and nothing said so. Both spec
110
- // shapes now declare the same thing, so this is the one implementation.
111
- return versionedRootApiKeySpec(providerId);
112
- }
113
-
114
- export const GENERIC_API_KEY_SPECS = {
115
- mistral: genericApiKeySpec("mistral"),
116
- fireworks: genericApiKeySpec("fireworks"),
117
- nvidia: genericApiKeySpec("nvidia"),
118
- gmi: genericApiKeySpec("gmi"),
119
- ollamacloud: genericApiKeySpec("ollamacloud"),
120
- together: genericApiKeySpec("together"),
121
- siliconflow: genericApiKeySpec("siliconflow"),
122
- siliconflowcn: genericApiKeySpec("siliconflowcn"),
123
- nanogpt: genericApiKeySpec("nanogpt"),
124
- baseten: genericApiKeySpec("baseten"),
125
- synthetic: genericApiKeySpec("synthetic"),
126
- stepfun: genericApiKeySpec("stepfun"),
127
- sakana: genericApiKeySpec("sakana"),
128
- helmcode: genericApiKeySpec("helmcode"),
129
- coralbricks: genericApiKeySpec("coralbricks"),
130
- aiand: genericApiKeySpec("aiand"),
131
- wafer: genericApiKeySpec("wafer"),
132
- coreweave: genericApiKeySpec("coreweave"),
133
- dashscope: genericApiKeySpec("dashscope"),
134
- "qwen-portal": genericApiKeySpec("qwen-portal"),
1
+ import type { ApiKeyProviderSpec } from "./configured-provider";
2
+ import type { ProviderId } from "./provider-contracts";
3
+
4
+ /**
5
+ * Builtin providers whose entire adapter contract is "bearer auth against the
6
+ * provider's `BUNDLED_PROVIDER_METADATA` base URL, OpenAI-compatible chat +
7
+ * responses, `/v1`-prefixed paths". They carry no catalog, no OAuth, and no
8
+ * provider-specific payload hook, so they share one spec shape rather than
9
+ * one module each.
10
+ *
11
+ * `base_url` is resolved per provider by `providerBaseUrl(provider_id)`.
12
+ *
13
+ * These providers list their models through live `/v1/models` discovery rather
14
+ * than a static catalog: every one of them republishes an aggregator's whole
15
+ * roster, which changes faster than a committed array can. Each registry row
16
+ * pairs this spec with `openAIModelDiscovery`.
17
+ */
18
+ export const GENERIC_API_KEY_PROVIDER_IDS = [
19
+ "larprouter",
20
+ "mistral",
21
+ "fireworks",
22
+ "nvidia",
23
+ "gmi",
24
+ "ollamacloud",
25
+ "together",
26
+ "siliconflow",
27
+ "siliconflowcn",
28
+ "nanogpt",
29
+ "baseten",
30
+ "synthetic",
31
+ "stepfun",
32
+ "sakana",
33
+ "helmcode",
34
+ "coralbricks",
35
+ "aiand",
36
+ "wafer",
37
+ "coreweave",
38
+ "qwen-portal",
39
+ "dashscope",
40
+ // `deepseek` is intentionally absent: it dispatches on the Anthropic Messages
41
+ // wire at its `/anthropic` root, not the OpenAI chat/responses wires, so it
42
+ // carries a dedicated entry in `default-registry.ts` instead.
43
+ //
44
+ // The aggregators below are absent for a different reason: their base URL is
45
+ // already rooted at a version segment that the `/v1`-prefixed path this shape
46
+ // pins would duplicate (`/openai/v1`, `/v1/openai`, `/v3/openai`, `/api/v1`,
47
+ // `/v2`, and `/inference/v1`), so `joinUrl` would produce
48
+ // `…/v1/v1/chat/completions`. They use `versionedRootApiKeySpec` instead,
49
+ // which pins the path below the version root — the same reason `cerebras`
50
+ // declares `/chat/completions` explicitly.
51
+ ] as const;
52
+
53
+ /**
54
+ * Ids whose base URL already ends at a version segment.
55
+ *
56
+ * `joinUrl` is plain concatenation and nothing rewrites a declared path, so a
57
+ * base already rooted at a version plus a `/v1/…` path doubles the segment and
58
+ * every request 404s. These specs therefore declare the path *below* the
59
+ * version root. That is the provider stating the truth about its own wire, not
60
+ * a correction applied to it: a wrong path now reaches the operator as the
61
+ * wrong URL instead of being quietly rewritten into a different address.
62
+ */
63
+ export const VERSIONED_ROOT_API_KEY_PROVIDER_IDS = [
64
+ "groq",
65
+ "deepinfra",
66
+ "novita",
67
+ "venice",
68
+ "qianfan",
69
+ "zhipucoding",
70
+ "firepass",
71
+ ] as const;
72
+
73
+ export type VersionedRootApiKeyProviderId =
74
+ (typeof VERSIONED_ROOT_API_KEY_PROVIDER_IDS)[number];
75
+
76
+ function versionedRootApiKeySpec(providerId: ProviderId): ApiKeyProviderSpec {
77
+ return {
78
+ provider_id: providerId,
79
+ endpoint_paths_by_wire_family: {
80
+ chat: "/chat/completions",
81
+ responses: "/responses",
82
+ },
83
+ };
84
+ }
85
+
86
+ export const VERSIONED_ROOT_API_KEY_SPECS = {
87
+ groq: versionedRootApiKeySpec("groq"),
88
+ deepinfra: versionedRootApiKeySpec("deepinfra"),
89
+ novita: versionedRootApiKeySpec("novita"),
90
+ venice: versionedRootApiKeySpec("venice"),
91
+ qianfan: versionedRootApiKeySpec("qianfan"),
92
+ zhipucoding: versionedRootApiKeySpec("zhipucoding"),
93
+ firepass: versionedRootApiKeySpec("firepass"),
94
+ } satisfies Readonly<Record<VersionedRootApiKeyProviderId, ApiKeyProviderSpec>>;
95
+
96
+ /**
97
+ * One id that has both a generic spec and a registry row.
98
+ *
99
+ * Exported so the registry can be checked against the spec list rather than
100
+ * repeating the id as a string: `discoveryBackedProvider` takes this type, so a
101
+ * row naming a provider with no spec is a compile error instead of an
102
+ * `undefined` adapter at first dispatch.
103
+ */
104
+ export type GenericApiKeyProviderId = (typeof GENERIC_API_KEY_PROVIDER_IDS)[number];
105
+
106
+ function genericApiKeySpec(providerId: GenericApiKeyProviderId): ApiKeyProviderSpec {
107
+ // These roots are *not* bare hosts — every one of them already ends at `/v1`
108
+ // — so the path is declared below that root. It used to be pinned from
109
+ // `BARE_ROOT_ENDPOINTS` and silently corrected at dispatch, which meant the
110
+ // declared path was wrong for all of them and nothing said so. Both spec
111
+ // shapes now declare the same thing, so this is the one implementation.
112
+ return versionedRootApiKeySpec(providerId);
113
+ }
114
+
115
+ export const GENERIC_API_KEY_SPECS = {
116
+ larprouter: genericApiKeySpec("larprouter"),
117
+ mistral: genericApiKeySpec("mistral"),
118
+ fireworks: genericApiKeySpec("fireworks"),
119
+ nvidia: genericApiKeySpec("nvidia"),
120
+ gmi: genericApiKeySpec("gmi"),
121
+ ollamacloud: genericApiKeySpec("ollamacloud"),
122
+ together: genericApiKeySpec("together"),
123
+ siliconflow: genericApiKeySpec("siliconflow"),
124
+ siliconflowcn: genericApiKeySpec("siliconflowcn"),
125
+ nanogpt: genericApiKeySpec("nanogpt"),
126
+ baseten: genericApiKeySpec("baseten"),
127
+ synthetic: genericApiKeySpec("synthetic"),
128
+ stepfun: genericApiKeySpec("stepfun"),
129
+ sakana: genericApiKeySpec("sakana"),
130
+ helmcode: genericApiKeySpec("helmcode"),
131
+ coralbricks: genericApiKeySpec("coralbricks"),
132
+ aiand: genericApiKeySpec("aiand"),
133
+ wafer: genericApiKeySpec("wafer"),
134
+ coreweave: genericApiKeySpec("coreweave"),
135
+ dashscope: genericApiKeySpec("dashscope"),
136
+ "qwen-portal": genericApiKeySpec("qwen-portal"),
135
137
  } satisfies Readonly<Record<GenericApiKeyProviderId, ApiKeyProviderSpec>>;
@@ -314,10 +314,7 @@ export const PROVIDER_CAPABILITIES = {
314
314
  loadAuthentication: oauthCapability(() => import("./integrations/cursor/cursor-auth"), "cursorOAuthClient", {
315
315
  withRefresher: true,
316
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
- //
317
+ loadQuotaCollector: quotaCapability(() => import("./integrations/cursor/cursor-quota"), "fetchCursorQuota"),
321
318
  // The roster is per-account and per-plan, and Cursor declares each model's
322
319
  // capabilities, so discovery is the catalog rather than a static list.
323
320
  loadModelDiscovery: async () => async ({ credential, fetcher }) =>
@@ -483,6 +480,7 @@ export const PROVIDER_CAPABILITIES = {
483
480
  // device flow, so the issued token is used exactly as issued until the
484
481
  // operator re-runs login — same shape as Kilo Code.
485
482
  loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderOAuthClient"),
483
+ loadQuotaCollector: quotaCapability(() => import("./integrations/qoder/qoder-quota"), "fetchQoderQuota"),
486
484
  // Discovery signed by the account's own COSY identity: the model list is
487
485
  // per-account and per-realm, and a GET without the signed body is 403.
488
486
  loadModelDiscovery: qoderDiscovery("intl", "qoder"),
@@ -498,6 +496,7 @@ export const PROVIDER_CAPABILITIES = {
498
496
  // `QODER_REALMS.cn` — its own login/token/userinfo hosts, client id, and
499
497
  // native redirect.
500
498
  loadAuthentication: oauthCapability(() => import("./integrations/qoder/qoder-oauth"), "qoderCnOAuthClient"),
499
+ loadQuotaCollector: quotaCapability(() => import("./integrations/qoder/qoder-quota"), "fetchQoderCnQuota"),
501
500
  loadModelDiscovery: qoderDiscovery("cn", "qodercn"),
502
501
  },
503
502
  trae: {
@@ -507,6 +506,7 @@ export const PROVIDER_CAPABILITIES = {
507
506
  // keeps it alive, so the refresher is registered rather than optional:
508
507
  // without it the account dies at first expiry.
509
508
  loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeOAuthClient", { withRefresher: true }),
509
+ loadQuotaCollector: quotaCapability(() => import("./integrations/trae/trae-quota"), "fetchTraeQuota"),
510
510
  // Live model list is intl-unsupported: upstream answers `403 no schema
511
511
  // found`, so discovery returning nothing is the truthful result and the
512
512
  // static roster above stays authoritative.
@@ -518,6 +518,7 @@ export const PROVIDER_CAPABILITIES = {
518
518
  // The CN client, not the intl one: the exchange runs on the CN account
519
519
  // host, and a refresh posted to the intl host is refused.
520
520
  loadAuthentication: oauthCapability(() => import("./integrations/trae/trae-oauth"), "traeCnOAuthClient", { withRefresher: true }),
521
+ loadQuotaCollector: quotaCapability(() => import("./integrations/trae/trae-quota"), "fetchTraeCnQuota"),
521
522
  loadModelDiscovery: traeDiscovery("cn", "traecn"),
522
523
  },
523
524
  inferhub: {
@@ -49,6 +49,11 @@ export async function fetchOpenAICompatibleModels(
49
49
  const parsedContext =
50
50
  positiveNumber(entry.context_length) ??
51
51
  positiveNumber((entry as Record<string, unknown>).input_token_limit) ??
52
+ // `context_window` is the spelling an OpenAI-shaped catalog uses for
53
+ // its own field. Unread, every model on such an upstream fell to the
54
+ // 200_000 default below and was advertised at the same wrong window no
55
+ // matter what the upstream reported — a 1M model shown as 200k.
56
+ positiveNumber((entry as Record<string, unknown>).context_window) ??
52
57
  positiveNumber(entry.contextWindow) ??
53
58
  positiveNumber(entry.max_input_tokens) ??
54
59
  modalityContextLimit(entry);