@srouterhq/server 0.0.0-stage → 0.9.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 (1027) hide show
  1. package/LICENSE +21 -0
  2. package/client/dist/assets/am-TQ7Jmdqe.js +1 -0
  3. package/client/dist/assets/ar-Bf5a7yfC.js +1 -0
  4. package/client/dist/assets/az-CrosE1xH.js +1 -0
  5. package/client/dist/assets/bg-BvWnmcUz.js +1 -0
  6. package/client/dist/assets/bn-ams5TsJp.js +1 -0
  7. package/client/dist/assets/cs-Dh67CaJ_.js +1 -0
  8. package/client/dist/assets/da-9WlT8Iq7.js +1 -0
  9. package/client/dist/assets/de-lWhJJzz7.js +1 -0
  10. package/client/dist/assets/el-Cu7_GhNq.js +1 -0
  11. package/client/dist/assets/es-BZuzsBcP.js +1 -0
  12. package/client/dist/assets/fa-Dwdn-jKS.js +1 -0
  13. package/client/dist/assets/fi-BFrFyOTy.js +1 -0
  14. package/client/dist/assets/fr-XhbtmPpj.js +1 -0
  15. package/client/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  16. package/client/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  17. package/client/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  18. package/client/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  19. package/client/dist/assets/geist-mono-cyrillic-ext-wght-normal-I4S5GZfc.woff2 +0 -0
  20. package/client/dist/assets/geist-mono-cyrillic-wght-normal-BmXc_FBt.woff2 +0 -0
  21. package/client/dist/assets/geist-mono-latin-ext-wght-normal-DrnZ1wKl.woff2 +0 -0
  22. package/client/dist/assets/geist-mono-latin-wght-normal-B_7UjwxQ.woff2 +0 -0
  23. package/client/dist/assets/geist-mono-symbols2-wght-normal-GZpp1pK2.woff2 +0 -0
  24. package/client/dist/assets/geist-mono-vietnamese-wght-normal-D8KDMBhC.woff2 +0 -0
  25. package/client/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  26. package/client/dist/assets/gu-D0uhLUB8.js +1 -0
  27. package/client/dist/assets/ha-CVlm9pqp.js +1 -0
  28. package/client/dist/assets/he-CMIFeoWr.js +1 -0
  29. package/client/dist/assets/hi-ENTwhBpn.js +1 -0
  30. package/client/dist/assets/hr-fc03vMy_.js +1 -0
  31. package/client/dist/assets/hu-YBo2BIYt.js +1 -0
  32. package/client/dist/assets/id-BEWXYX69.js +1 -0
  33. package/client/dist/assets/ig-BKLZFKka.js +1 -0
  34. package/client/dist/assets/index-D9I4KtvR.js +145 -0
  35. package/client/dist/assets/index-txhEmCdb.css +2 -0
  36. package/client/dist/assets/it-Bzmei1Y2.js +1 -0
  37. package/client/dist/assets/ja-BfcpuqEl.js +1 -0
  38. package/client/dist/assets/ka-CnWjRgLo.js +1 -0
  39. package/client/dist/assets/km-BAjPR3Qj.js +1 -0
  40. package/client/dist/assets/kn-B15WKU5m.js +1 -0
  41. package/client/dist/assets/ko-C61fAB-w.js +1 -0
  42. package/client/dist/assets/lt-CYTr4_YW.js +1 -0
  43. package/client/dist/assets/ml-CtqxgyH3.js +1 -0
  44. package/client/dist/assets/mr-X5TMY7aR.js +1 -0
  45. package/client/dist/assets/ms-DSg8RqPS.js +1 -0
  46. package/client/dist/assets/my-D7RqR8uE.js +1 -0
  47. package/client/dist/assets/ne-DaflxkDj.js +1 -0
  48. package/client/dist/assets/nl-BOqqtsC8.js +1 -0
  49. package/client/dist/assets/no-BSHp_StB.js +1 -0
  50. package/client/dist/assets/or-BkLR9Vub.js +1 -0
  51. package/client/dist/assets/pa-CarJ2XgI.js +1 -0
  52. package/client/dist/assets/pl-C2n0V-0k.js +1 -0
  53. package/client/dist/assets/pt-BR-CqJdNhg2.js +1 -0
  54. package/client/dist/assets/pt-PT-C_HpMyKz.js +1 -0
  55. package/client/dist/assets/ro-DVRZqSAS.js +1 -0
  56. package/client/dist/assets/ru-DwAJG7VC.js +1 -0
  57. package/client/dist/assets/si-BxUezXm0.js +1 -0
  58. package/client/dist/assets/sk-eI1VcIfY.js +1 -0
  59. package/client/dist/assets/sr-CJF3auCr.js +1 -0
  60. package/client/dist/assets/srouter-logo-C6ZfjGIi.svg +14 -0
  61. package/client/dist/assets/sv-nqvwHAq_.js +1 -0
  62. package/client/dist/assets/sw-DWynE2pW.js +1 -0
  63. package/client/dist/assets/ta-BVM12knC.js +1 -0
  64. package/client/dist/assets/te-oyzEkF7_.js +1 -0
  65. package/client/dist/assets/th-COVeE0ZQ.js +1 -0
  66. package/client/dist/assets/tl-DsJANnQz.js +1 -0
  67. package/client/dist/assets/tr-B-Fl-urO.js +1 -0
  68. package/client/dist/assets/uk-C5qketAO.js +1 -0
  69. package/client/dist/assets/ur-QU9KugfV.js +1 -0
  70. package/client/dist/assets/uz-DL9cG_mY.js +1 -0
  71. package/client/dist/assets/vi-CQiVy3Pu.js +1 -0
  72. package/client/dist/assets/yo-DqazMdrZ.js +1 -0
  73. package/client/dist/assets/zh-CN-DnYL_Kio.js +1 -0
  74. package/client/dist/assets/zh-TW-5bdbosKj.js +1 -0
  75. package/client/dist/favicon.svg +14 -0
  76. package/client/dist/icons.svg +24 -0
  77. package/client/dist/index.html +37 -0
  78. package/dist/app.d.ts +4 -0
  79. package/dist/app.d.ts.map +1 -0
  80. package/dist/app.js +372 -0
  81. package/dist/app.js.map +1 -0
  82. package/dist/db/index.d.ts +49 -0
  83. package/dist/db/index.d.ts.map +1 -0
  84. package/dist/db/index.js +203 -0
  85. package/dist/db/index.js.map +1 -0
  86. package/dist/db/migrate/TEMPLATE.d.ts +4 -0
  87. package/dist/db/migrate/TEMPLATE.d.ts.map +1 -0
  88. package/dist/db/migrate/TEMPLATE.js +18 -0
  89. package/dist/db/migrate/TEMPLATE.js.map +1 -0
  90. package/dist/db/migrate/cli.d.ts +2 -0
  91. package/dist/db/migrate/cli.d.ts.map +1 -0
  92. package/dist/db/migrate/cli.js +177 -0
  93. package/dist/db/migrate/cli.js.map +1 -0
  94. package/dist/db/migrate/defaults.d.ts +52 -0
  95. package/dist/db/migrate/defaults.d.ts.map +1 -0
  96. package/dist/db/migrate/defaults.js +126 -0
  97. package/dist/db/migrate/defaults.js.map +1 -0
  98. package/dist/db/migrate/runner.d.ts +16 -0
  99. package/dist/db/migrate/runner.d.ts.map +1 -0
  100. package/dist/db/migrate/runner.js +178 -0
  101. package/dist/db/migrate/runner.js.map +1 -0
  102. package/dist/db/migrations/20260101_000000_legacy_baseline.d.ts +4 -0
  103. package/dist/db/migrations/20260101_000000_legacy_baseline.d.ts.map +1 -0
  104. package/dist/db/migrations/20260101_000000_legacy_baseline.js +2240 -0
  105. package/dist/db/migrations/20260101_000000_legacy_baseline.js.map +1 -0
  106. package/dist/db/migrations/20260627_000001_custom_provider_modalities.d.ts +4 -0
  107. package/dist/db/migrations/20260627_000001_custom_provider_modalities.d.ts.map +1 -0
  108. package/dist/db/migrations/20260627_000001_custom_provider_modalities.js +27 -0
  109. package/dist/db/migrations/20260627_000001_custom_provider_modalities.js.map +1 -0
  110. package/dist/db/migrations/20260627_000002_catalog_model_state.d.ts +4 -0
  111. package/dist/db/migrations/20260627_000002_catalog_model_state.d.ts.map +1 -0
  112. package/dist/db/migrations/20260627_000002_catalog_model_state.js +30 -0
  113. package/dist/db/migrations/20260627_000002_catalog_model_state.js.map +1 -0
  114. package/dist/db/migrations/20260628_120000_request_aggregates.d.ts +6 -0
  115. package/dist/db/migrations/20260628_120000_request_aggregates.d.ts.map +1 -0
  116. package/dist/db/migrations/20260628_120000_request_aggregates.js +104 -0
  117. package/dist/db/migrations/20260628_120000_request_aggregates.js.map +1 -0
  118. package/dist/db/migrations/20260630_000001_github_gpt41_context.d.ts +9 -0
  119. package/dist/db/migrations/20260630_000001_github_gpt41_context.d.ts.map +1 -0
  120. package/dist/db/migrations/20260630_000001_github_gpt41_context.js +22 -0
  121. package/dist/db/migrations/20260630_000001_github_gpt41_context.js.map +1 -0
  122. package/dist/db/migrations/20260706_000001_request_client_info.d.ts +4 -0
  123. package/dist/db/migrations/20260706_000001_request_client_info.d.ts.map +1 -0
  124. package/dist/db/migrations/20260706_000001_request_client_info.js +30 -0
  125. package/dist/db/migrations/20260706_000001_request_client_info.js.map +1 -0
  126. package/dist/db/migrations/20260706_000002_custom_model_tool_support.d.ts +17 -0
  127. package/dist/db/migrations/20260706_000002_custom_model_tool_support.d.ts.map +1 -0
  128. package/dist/db/migrations/20260706_000002_custom_model_tool_support.js +20 -0
  129. package/dist/db/migrations/20260706_000002_custom_model_tool_support.js.map +1 -0
  130. package/dist/db/migrations/20260714_000001_profile_chain_backfill.d.ts +12 -0
  131. package/dist/db/migrations/20260714_000001_profile_chain_backfill.d.ts.map +1 -0
  132. package/dist/db/migrations/20260714_000001_profile_chain_backfill.js +45 -0
  133. package/dist/db/migrations/20260714_000001_profile_chain_backfill.js.map +1 -0
  134. package/dist/db/migrations/20260720_000001_key_health_error.d.ts +5 -0
  135. package/dist/db/migrations/20260720_000001_key_health_error.d.ts.map +1 -0
  136. package/dist/db/migrations/20260720_000001_key_health_error.js +16 -0
  137. package/dist/db/migrations/20260720_000001_key_health_error.js.map +1 -0
  138. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.d.ts +4 -0
  139. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.d.ts.map +1 -0
  140. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.js +38 -0
  141. package/dist/db/migrations/20260726_000001_cooldown_probe_provenance.js.map +1 -0
  142. package/dist/db/migrations/20260726_000002_request_attempts.d.ts +4 -0
  143. package/dist/db/migrations/20260726_000002_request_attempts.d.ts.map +1 -0
  144. package/dist/db/migrations/20260726_000002_request_attempts.js +43 -0
  145. package/dist/db/migrations/20260726_000002_request_attempts.js.map +1 -0
  146. package/dist/db/migrations/20260726_000003_model_source_provenance.d.ts +4 -0
  147. package/dist/db/migrations/20260726_000003_model_source_provenance.d.ts.map +1 -0
  148. package/dist/db/migrations/20260726_000003_model_source_provenance.js +80 -0
  149. package/dist/db/migrations/20260726_000003_model_source_provenance.js.map +1 -0
  150. package/dist/db/migrations/20260726_000004_media_model_meta.d.ts +4 -0
  151. package/dist/db/migrations/20260726_000004_media_model_meta.d.ts.map +1 -0
  152. package/dist/db/migrations/20260726_000004_media_model_meta.js +34 -0
  153. package/dist/db/migrations/20260726_000004_media_model_meta.js.map +1 -0
  154. package/dist/db/migrations/20260726_000005_request_served_model.d.ts +4 -0
  155. package/dist/db/migrations/20260726_000005_request_served_model.d.ts.map +1 -0
  156. package/dist/db/migrations/20260726_000005_request_served_model.js +31 -0
  157. package/dist/db/migrations/20260726_000005_request_served_model.js.map +1 -0
  158. package/dist/db/migrations/20260726_000006_attempt_error_summary.d.ts +4 -0
  159. package/dist/db/migrations/20260726_000006_attempt_error_summary.d.ts.map +1 -0
  160. package/dist/db/migrations/20260726_000006_attempt_error_summary.js +29 -0
  161. package/dist/db/migrations/20260726_000006_attempt_error_summary.js.map +1 -0
  162. package/dist/db/migrations/20260727_000001_agent_compatibility.d.ts +4 -0
  163. package/dist/db/migrations/20260727_000001_agent_compatibility.d.ts.map +1 -0
  164. package/dist/db/migrations/20260727_000001_agent_compatibility.js +41 -0
  165. package/dist/db/migrations/20260727_000001_agent_compatibility.js.map +1 -0
  166. package/dist/db/migrations/20260728_000001_tombstone_provenance.d.ts +12 -0
  167. package/dist/db/migrations/20260728_000001_tombstone_provenance.d.ts.map +1 -0
  168. package/dist/db/migrations/20260728_000001_tombstone_provenance.js +37 -0
  169. package/dist/db/migrations/20260728_000001_tombstone_provenance.js.map +1 -0
  170. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.d.ts +4 -0
  171. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.d.ts.map +1 -0
  172. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.js +145 -0
  173. package/dist/db/migrations/20260729_000001_custom_model_endpoint_identity.js.map +1 -0
  174. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.d.ts +6 -0
  175. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.d.ts.map +1 -0
  176. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.js +52 -0
  177. package/dist/db/migrations/20260802_000001_custom_endpoint_host_labels.js.map +1 -0
  178. package/dist/db/migrations/20260805_000001_key_model_scope.d.ts +6 -0
  179. package/dist/db/migrations/20260805_000001_key_model_scope.d.ts.map +1 -0
  180. package/dist/db/migrations/20260805_000001_key_model_scope.js +17 -0
  181. package/dist/db/migrations/20260805_000001_key_model_scope.js.map +1 -0
  182. package/dist/db/migrations/20260805_000002_client_profiles.d.ts +4 -0
  183. package/dist/db/migrations/20260805_000002_client_profiles.d.ts.map +1 -0
  184. package/dist/db/migrations/20260805_000002_client_profiles.js +33 -0
  185. package/dist/db/migrations/20260805_000002_client_profiles.js.map +1 -0
  186. package/dist/db/migrations/20260810_000001_api_key_proxy.d.ts +4 -0
  187. package/dist/db/migrations/20260810_000001_api_key_proxy.d.ts.map +1 -0
  188. package/dist/db/migrations/20260810_000001_api_key_proxy.js +33 -0
  189. package/dist/db/migrations/20260810_000001_api_key_proxy.js.map +1 -0
  190. package/dist/db/migrations/20260819_000001_custom_model_tombstones.d.ts +4 -0
  191. package/dist/db/migrations/20260819_000001_custom_model_tombstones.d.ts.map +1 -0
  192. package/dist/db/migrations/20260819_000001_custom_model_tombstones.js +19 -0
  193. package/dist/db/migrations/20260819_000001_custom_model_tombstones.js.map +1 -0
  194. package/dist/db/migrations/20260820_000001_playground_conversations.d.ts +4 -0
  195. package/dist/db/migrations/20260820_000001_playground_conversations.d.ts.map +1 -0
  196. package/dist/db/migrations/20260820_000001_playground_conversations.js +47 -0
  197. package/dist/db/migrations/20260820_000001_playground_conversations.js.map +1 -0
  198. package/dist/db/migrations/20260823_000001_server_logs.d.ts +4 -0
  199. package/dist/db/migrations/20260823_000001_server_logs.d.ts.map +1 -0
  200. package/dist/db/migrations/20260823_000001_server_logs.js +53 -0
  201. package/dist/db/migrations/20260823_000001_server_logs.js.map +1 -0
  202. package/dist/db/migrations/20260823_000002_backups_table.d.ts +8 -0
  203. package/dist/db/migrations/20260823_000002_backups_table.d.ts.map +1 -0
  204. package/dist/db/migrations/20260823_000002_backups_table.js +22 -0
  205. package/dist/db/migrations/20260823_000002_backups_table.js.map +1 -0
  206. package/dist/db/migrations/20260823_000003_attempt_key_label.d.ts +19 -0
  207. package/dist/db/migrations/20260823_000003_attempt_key_label.d.ts.map +1 -0
  208. package/dist/db/migrations/20260823_000003_attempt_key_label.js +28 -0
  209. package/dist/db/migrations/20260823_000003_attempt_key_label.js.map +1 -0
  210. package/dist/db/migrations/20260823_000004_profile_auto_include.d.ts +14 -0
  211. package/dist/db/migrations/20260823_000004_profile_auto_include.d.ts.map +1 -0
  212. package/dist/db/migrations/20260823_000004_profile_auto_include.js +25 -0
  213. package/dist/db/migrations/20260823_000004_profile_auto_include.js.map +1 -0
  214. package/dist/db/migrations/20260901_000001_idempotency_claims.d.ts +4 -0
  215. package/dist/db/migrations/20260901_000001_idempotency_claims.d.ts.map +1 -0
  216. package/dist/db/migrations/20260901_000001_idempotency_claims.js +46 -0
  217. package/dist/db/migrations/20260901_000001_idempotency_claims.js.map +1 -0
  218. package/dist/db/migrations/20260901_000002_quota_observation_lookup.d.ts +4 -0
  219. package/dist/db/migrations/20260901_000002_quota_observation_lookup.d.ts.map +1 -0
  220. package/dist/db/migrations/20260901_000002_quota_observation_lookup.js +37 -0
  221. package/dist/db/migrations/20260901_000002_quota_observation_lookup.js.map +1 -0
  222. package/dist/db/migrations/20260901_000003_request_caller.d.ts +4 -0
  223. package/dist/db/migrations/20260901_000003_request_caller.d.ts.map +1 -0
  224. package/dist/db/migrations/20260901_000003_request_caller.js +27 -0
  225. package/dist/db/migrations/20260901_000003_request_caller.js.map +1 -0
  226. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.d.ts +4 -0
  227. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.d.ts.map +1 -0
  228. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.js +35 -0
  229. package/dist/db/migrations/20260902_000001_analytics_latency_percentile_index.js.map +1 -0
  230. package/dist/db/migrations/20260903_000001_mcp_enabled_default.d.ts +4 -0
  231. package/dist/db/migrations/20260903_000001_mcp_enabled_default.d.ts.map +1 -0
  232. package/dist/db/migrations/20260903_000001_mcp_enabled_default.js +37 -0
  233. package/dist/db/migrations/20260903_000001_mcp_enabled_default.js.map +1 -0
  234. package/dist/db/migrations/20260903_000002_response_cache.d.ts +4 -0
  235. package/dist/db/migrations/20260903_000002_response_cache.d.ts.map +1 -0
  236. package/dist/db/migrations/20260903_000002_response_cache.js +53 -0
  237. package/dist/db/migrations/20260903_000002_response_cache.js.map +1 -0
  238. package/dist/db/migrations/20260904_000001_key_monthly_budget.d.ts +13 -0
  239. package/dist/db/migrations/20260904_000001_key_monthly_budget.d.ts.map +1 -0
  240. package/dist/db/migrations/20260904_000001_key_monthly_budget.js +35 -0
  241. package/dist/db/migrations/20260904_000001_key_monthly_budget.js.map +1 -0
  242. package/dist/db/migrations/20260913_000001_request_model_attribution.d.ts +4 -0
  243. package/dist/db/migrations/20260913_000001_request_model_attribution.d.ts.map +1 -0
  244. package/dist/db/migrations/20260913_000001_request_model_attribution.js +68 -0
  245. package/dist/db/migrations/20260913_000001_request_model_attribution.js.map +1 -0
  246. package/dist/db/migrations/20260914_000001_key_monthly_usage.d.ts +5 -0
  247. package/dist/db/migrations/20260914_000001_key_monthly_usage.d.ts.map +1 -0
  248. package/dist/db/migrations/20260914_000001_key_monthly_usage.js +37 -0
  249. package/dist/db/migrations/20260914_000001_key_monthly_usage.js.map +1 -0
  250. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.d.ts +4 -0
  251. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.d.ts.map +1 -0
  252. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.js +28 -0
  253. package/dist/db/migrations/20260915_000001_quota_snapshot_freshness.js.map +1 -0
  254. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.d.ts +4 -0
  255. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.d.ts.map +1 -0
  256. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.js +25 -0
  257. package/dist/db/migrations/20261004_000001_unified_key_sr_prefix.js.map +1 -0
  258. package/dist/db/migrations/20261005_000001_key_budget_period.d.ts +10 -0
  259. package/dist/db/migrations/20261005_000001_key_budget_period.d.ts.map +1 -0
  260. package/dist/db/migrations/20261005_000001_key_budget_period.js +78 -0
  261. package/dist/db/migrations/20261005_000001_key_budget_period.js.map +1 -0
  262. package/dist/db/migrations/20261005_000002_key_budget_period_auto.d.ts +21 -0
  263. package/dist/db/migrations/20261005_000002_key_budget_period_auto.d.ts.map +1 -0
  264. package/dist/db/migrations/20261005_000002_key_budget_period_auto.js +41 -0
  265. package/dist/db/migrations/20261005_000002_key_budget_period_auto.js.map +1 -0
  266. package/dist/db/model-pricing.d.ts +39 -0
  267. package/dist/db/model-pricing.d.ts.map +1 -0
  268. package/dist/db/model-pricing.js +274 -0
  269. package/dist/db/model-pricing.js.map +1 -0
  270. package/dist/db/node-sqlite.d.ts +9 -0
  271. package/dist/db/node-sqlite.d.ts.map +1 -0
  272. package/dist/db/node-sqlite.js +87 -0
  273. package/dist/db/node-sqlite.js.map +1 -0
  274. package/dist/db/types.d.ts +22 -0
  275. package/dist/db/types.d.ts.map +1 -0
  276. package/dist/db/types.js +2 -0
  277. package/dist/db/types.js.map +1 -0
  278. package/dist/docs/docs-page.d.ts +2 -0
  279. package/dist/docs/docs-page.d.ts.map +1 -0
  280. package/dist/docs/docs-page.js +319 -0
  281. package/dist/docs/docs-page.js.map +1 -0
  282. package/dist/docs/openapi.d.ts +1896 -0
  283. package/dist/docs/openapi.d.ts.map +1 -0
  284. package/dist/docs/openapi.js +1096 -0
  285. package/dist/docs/openapi.js.map +1 -0
  286. package/dist/env.d.ts +2 -0
  287. package/dist/env.d.ts.map +1 -0
  288. package/dist/env.js +9 -0
  289. package/dist/env.js.map +1 -0
  290. package/dist/index.d.ts +2 -0
  291. package/dist/index.d.ts.map +1 -0
  292. package/dist/index.js +144 -0
  293. package/dist/index.js.map +1 -0
  294. package/dist/lib/anthropic-documents.d.ts +41 -0
  295. package/dist/lib/anthropic-documents.d.ts.map +1 -0
  296. package/dist/lib/anthropic-documents.js +132 -0
  297. package/dist/lib/anthropic-documents.js.map +1 -0
  298. package/dist/lib/app-version.d.ts +5 -0
  299. package/dist/lib/app-version.d.ts.map +1 -0
  300. package/dist/lib/app-version.js +61 -0
  301. package/dist/lib/app-version.js.map +1 -0
  302. package/dist/lib/attempt-trace.d.ts +23 -0
  303. package/dist/lib/attempt-trace.d.ts.map +1 -0
  304. package/dist/lib/attempt-trace.js +32 -0
  305. package/dist/lib/attempt-trace.js.map +1 -0
  306. package/dist/lib/budget.d.ts +6 -0
  307. package/dist/lib/budget.d.ts.map +1 -0
  308. package/dist/lib/budget.js +40 -0
  309. package/dist/lib/budget.js.map +1 -0
  310. package/dist/lib/client-classifier.d.ts +10 -0
  311. package/dist/lib/client-classifier.d.ts.map +1 -0
  312. package/dist/lib/client-classifier.js +126 -0
  313. package/dist/lib/client-classifier.js.map +1 -0
  314. package/dist/lib/client-context.d.ts +10 -0
  315. package/dist/lib/client-context.d.ts.map +1 -0
  316. package/dist/lib/client-context.js +39 -0
  317. package/dist/lib/client-context.js.map +1 -0
  318. package/dist/lib/config.d.ts +33 -0
  319. package/dist/lib/config.d.ts.map +1 -0
  320. package/dist/lib/config.js +94 -0
  321. package/dist/lib/config.js.map +1 -0
  322. package/dist/lib/content.d.ts +33 -0
  323. package/dist/lib/content.d.ts.map +1 -0
  324. package/dist/lib/content.js +201 -0
  325. package/dist/lib/content.js.map +1 -0
  326. package/dist/lib/credential.d.ts +11 -0
  327. package/dist/lib/credential.d.ts.map +1 -0
  328. package/dist/lib/credential.js +18 -0
  329. package/dist/lib/credential.js.map +1 -0
  330. package/dist/lib/crypto.d.ts +31 -0
  331. package/dist/lib/crypto.d.ts.map +1 -0
  332. package/dist/lib/crypto.js +206 -0
  333. package/dist/lib/crypto.js.map +1 -0
  334. package/dist/lib/custom-provider-cleanup.d.ts +13 -0
  335. package/dist/lib/custom-provider-cleanup.d.ts.map +1 -0
  336. package/dist/lib/custom-provider-cleanup.js +43 -0
  337. package/dist/lib/custom-provider-cleanup.js.map +1 -0
  338. package/dist/lib/db-backup.d.ts +31 -0
  339. package/dist/lib/db-backup.d.ts.map +1 -0
  340. package/dist/lib/db-backup.js +255 -0
  341. package/dist/lib/db-backup.js.map +1 -0
  342. package/dist/lib/endpoint-scope.d.ts +42 -0
  343. package/dist/lib/endpoint-scope.d.ts.map +1 -0
  344. package/dist/lib/endpoint-scope.js +95 -0
  345. package/dist/lib/endpoint-scope.js.map +1 -0
  346. package/dist/lib/env-drift.d.ts +17 -0
  347. package/dist/lib/env-drift.d.ts.map +1 -0
  348. package/dist/lib/env-drift.js +108 -0
  349. package/dist/lib/env-drift.js.map +1 -0
  350. package/dist/lib/error-classify.d.ts +40 -0
  351. package/dist/lib/error-classify.d.ts.map +1 -0
  352. package/dist/lib/error-classify.js +687 -0
  353. package/dist/lib/error-classify.js.map +1 -0
  354. package/dist/lib/error-redaction.d.ts +8 -0
  355. package/dist/lib/error-redaction.d.ts.map +1 -0
  356. package/dist/lib/error-redaction.js +45 -0
  357. package/dist/lib/error-redaction.js.map +1 -0
  358. package/dist/lib/fallback-loop.d.ts +306 -0
  359. package/dist/lib/fallback-loop.d.ts.map +1 -0
  360. package/dist/lib/fallback-loop.js +1336 -0
  361. package/dist/lib/fallback-loop.js.map +1 -0
  362. package/dist/lib/file-permissions.d.ts +98 -0
  363. package/dist/lib/file-permissions.d.ts.map +1 -0
  364. package/dist/lib/file-permissions.js +159 -0
  365. package/dist/lib/file-permissions.js.map +1 -0
  366. package/dist/lib/gemini-wire.d.ts +76 -0
  367. package/dist/lib/gemini-wire.d.ts.map +1 -0
  368. package/dist/lib/gemini-wire.js +392 -0
  369. package/dist/lib/gemini-wire.js.map +1 -0
  370. package/dist/lib/guardrails.d.ts +37 -0
  371. package/dist/lib/guardrails.d.ts.map +1 -0
  372. package/dist/lib/guardrails.js +106 -0
  373. package/dist/lib/guardrails.js.map +1 -0
  374. package/dist/lib/header-value.d.ts +8 -0
  375. package/dist/lib/header-value.d.ts.map +1 -0
  376. package/dist/lib/header-value.js +55 -0
  377. package/dist/lib/header-value.js.map +1 -0
  378. package/dist/lib/image-normalize.d.ts +21 -0
  379. package/dist/lib/image-normalize.d.ts.map +1 -0
  380. package/dist/lib/image-normalize.js +218 -0
  381. package/dist/lib/image-normalize.js.map +1 -0
  382. package/dist/lib/inbound-chat.d.ts +48 -0
  383. package/dist/lib/inbound-chat.d.ts.map +1 -0
  384. package/dist/lib/inbound-chat.js +406 -0
  385. package/dist/lib/inbound-chat.js.map +1 -0
  386. package/dist/lib/key-parser.d.ts +79 -0
  387. package/dist/lib/key-parser.d.ts.map +1 -0
  388. package/dist/lib/key-parser.js +701 -0
  389. package/dist/lib/key-parser.js.map +1 -0
  390. package/dist/lib/key-proxy.d.ts +49 -0
  391. package/dist/lib/key-proxy.d.ts.map +1 -0
  392. package/dist/lib/key-proxy.js +92 -0
  393. package/dist/lib/key-proxy.js.map +1 -0
  394. package/dist/lib/log-redaction.d.ts +28 -0
  395. package/dist/lib/log-redaction.d.ts.map +1 -0
  396. package/dist/lib/log-redaction.js +166 -0
  397. package/dist/lib/log-redaction.js.map +1 -0
  398. package/dist/lib/model-scope.d.ts +9 -0
  399. package/dist/lib/model-scope.d.ts.map +1 -0
  400. package/dist/lib/model-scope.js +29 -0
  401. package/dist/lib/model-scope.js.map +1 -0
  402. package/dist/lib/one-time-code.d.ts +15 -0
  403. package/dist/lib/one-time-code.d.ts.map +1 -0
  404. package/dist/lib/one-time-code.js +41 -0
  405. package/dist/lib/one-time-code.js.map +1 -0
  406. package/dist/lib/output-cap.d.ts +24 -0
  407. package/dist/lib/output-cap.d.ts.map +1 -0
  408. package/dist/lib/output-cap.js +80 -0
  409. package/dist/lib/output-cap.js.map +1 -0
  410. package/dist/lib/password.d.ts +3 -0
  411. package/dist/lib/password.d.ts.map +1 -0
  412. package/dist/lib/password.js +27 -0
  413. package/dist/lib/password.js.map +1 -0
  414. package/dist/lib/process-safety-net.d.ts +32 -0
  415. package/dist/lib/process-safety-net.d.ts.map +1 -0
  416. package/dist/lib/process-safety-net.js +123 -0
  417. package/dist/lib/process-safety-net.js.map +1 -0
  418. package/dist/lib/provider-identity.d.ts +37 -0
  419. package/dist/lib/provider-identity.d.ts.map +1 -0
  420. package/dist/lib/provider-identity.js +110 -0
  421. package/dist/lib/provider-identity.js.map +1 -0
  422. package/dist/lib/provider-size-parser.d.ts +6 -0
  423. package/dist/lib/provider-size-parser.d.ts.map +1 -0
  424. package/dist/lib/provider-size-parser.js +72 -0
  425. package/dist/lib/provider-size-parser.js.map +1 -0
  426. package/dist/lib/provider-timeout.d.ts +17 -0
  427. package/dist/lib/provider-timeout.d.ts.map +1 -0
  428. package/dist/lib/provider-timeout.js +70 -0
  429. package/dist/lib/provider-timeout.js.map +1 -0
  430. package/dist/lib/proxy.d.ts +180 -0
  431. package/dist/lib/proxy.d.ts.map +1 -0
  432. package/dist/lib/proxy.js +1002 -0
  433. package/dist/lib/proxy.js.map +1 -0
  434. package/dist/lib/request-log.d.ts +4 -0
  435. package/dist/lib/request-log.d.ts.map +1 -0
  436. package/dist/lib/request-log.js +161 -0
  437. package/dist/lib/request-log.js.map +1 -0
  438. package/dist/lib/reset-code.d.ts +5 -0
  439. package/dist/lib/reset-code.d.ts.map +1 -0
  440. package/dist/lib/reset-code.js +39 -0
  441. package/dist/lib/reset-code.js.map +1 -0
  442. package/dist/lib/retry-hint.d.ts +14 -0
  443. package/dist/lib/retry-hint.d.ts.map +1 -0
  444. package/dist/lib/retry-hint.js +36 -0
  445. package/dist/lib/retry-hint.js.map +1 -0
  446. package/dist/lib/route-live.d.ts +29 -0
  447. package/dist/lib/route-live.d.ts.map +1 -0
  448. package/dist/lib/route-live.js +97 -0
  449. package/dist/lib/route-live.js.map +1 -0
  450. package/dist/lib/sampling-params.d.ts +183 -0
  451. package/dist/lib/sampling-params.d.ts.map +1 -0
  452. package/dist/lib/sampling-params.js +386 -0
  453. package/dist/lib/sampling-params.js.map +1 -0
  454. package/dist/lib/scheduler.d.ts +13 -0
  455. package/dist/lib/scheduler.d.ts.map +1 -0
  456. package/dist/lib/scheduler.js +11 -0
  457. package/dist/lib/scheduler.js.map +1 -0
  458. package/dist/lib/served-model.d.ts +16 -0
  459. package/dist/lib/served-model.d.ts.map +1 -0
  460. package/dist/lib/served-model.js +0 -0
  461. package/dist/lib/served-model.js.map +1 -0
  462. package/dist/lib/server-logs.d.ts +132 -0
  463. package/dist/lib/server-logs.d.ts.map +1 -0
  464. package/dist/lib/server-logs.js +473 -0
  465. package/dist/lib/server-logs.js.map +1 -0
  466. package/dist/lib/setup-code.d.ts +5 -0
  467. package/dist/lib/setup-code.d.ts.map +1 -0
  468. package/dist/lib/setup-code.js +35 -0
  469. package/dist/lib/setup-code.js.map +1 -0
  470. package/dist/lib/structured-output.d.ts +9 -0
  471. package/dist/lib/structured-output.d.ts.map +1 -0
  472. package/dist/lib/structured-output.js +72 -0
  473. package/dist/lib/structured-output.js.map +1 -0
  474. package/dist/lib/system-prompt.d.ts +30 -0
  475. package/dist/lib/system-prompt.d.ts.map +1 -0
  476. package/dist/lib/system-prompt.js +66 -0
  477. package/dist/lib/system-prompt.js.map +1 -0
  478. package/dist/lib/task-type.d.ts +18 -0
  479. package/dist/lib/task-type.d.ts.map +1 -0
  480. package/dist/lib/task-type.js +92 -0
  481. package/dist/lib/task-type.js.map +1 -0
  482. package/dist/lib/think-tags.d.ts +37 -0
  483. package/dist/lib/think-tags.d.ts.map +1 -0
  484. package/dist/lib/think-tags.js +203 -0
  485. package/dist/lib/think-tags.js.map +1 -0
  486. package/dist/lib/tool-args.d.ts +36 -0
  487. package/dist/lib/tool-args.d.ts.map +1 -0
  488. package/dist/lib/tool-args.js +190 -0
  489. package/dist/lib/tool-args.js.map +1 -0
  490. package/dist/lib/tool-call-rescue.d.ts +62 -0
  491. package/dist/lib/tool-call-rescue.d.ts.map +1 -0
  492. package/dist/lib/tool-call-rescue.js +258 -0
  493. package/dist/lib/tool-call-rescue.js.map +1 -0
  494. package/dist/lib/tool-capability.d.ts +13 -0
  495. package/dist/lib/tool-capability.d.ts.map +1 -0
  496. package/dist/lib/tool-capability.js +70 -0
  497. package/dist/lib/tool-capability.js.map +1 -0
  498. package/dist/lib/tool-validate.d.ts +44 -0
  499. package/dist/lib/tool-validate.d.ts.map +1 -0
  500. package/dist/lib/tool-validate.js +165 -0
  501. package/dist/lib/tool-validate.js.map +1 -0
  502. package/dist/lib/ttfb-budget.d.ts +13 -0
  503. package/dist/lib/ttfb-budget.d.ts.map +1 -0
  504. package/dist/lib/ttfb-budget.js +153 -0
  505. package/dist/lib/ttfb-budget.js.map +1 -0
  506. package/dist/lib/url-guard.d.ts +47 -0
  507. package/dist/lib/url-guard.d.ts.map +1 -0
  508. package/dist/lib/url-guard.js +229 -0
  509. package/dist/lib/url-guard.js.map +1 -0
  510. package/dist/lib/wake-detect.d.ts +12 -0
  511. package/dist/lib/wake-detect.d.ts.map +1 -0
  512. package/dist/lib/wake-detect.js +99 -0
  513. package/dist/lib/wake-detect.js.map +1 -0
  514. package/dist/middleware/errorHandler.d.ts +3 -0
  515. package/dist/middleware/errorHandler.d.ts.map +1 -0
  516. package/dist/middleware/errorHandler.js +45 -0
  517. package/dist/middleware/errorHandler.js.map +1 -0
  518. package/dist/middleware/rateLimit.d.ts +4 -0
  519. package/dist/middleware/rateLimit.d.ts.map +1 -0
  520. package/dist/middleware/rateLimit.js +125 -0
  521. package/dist/middleware/rateLimit.js.map +1 -0
  522. package/dist/middleware/requireAuth.d.ts +3 -0
  523. package/dist/middleware/requireAuth.d.ts.map +1 -0
  524. package/dist/middleware/requireAuth.js +17 -0
  525. package/dist/middleware/requireAuth.js.map +1 -0
  526. package/dist/providers/aclide.d.ts +18 -0
  527. package/dist/providers/aclide.d.ts.map +1 -0
  528. package/dist/providers/aclide.js +174 -0
  529. package/dist/providers/aclide.js.map +1 -0
  530. package/dist/providers/aihorde.d.ts +42 -0
  531. package/dist/providers/aihorde.d.ts.map +1 -0
  532. package/dist/providers/aihorde.js +192 -0
  533. package/dist/providers/aihorde.js.map +1 -0
  534. package/dist/providers/airforce.d.ts +11 -0
  535. package/dist/providers/airforce.d.ts.map +1 -0
  536. package/dist/providers/airforce.js +32 -0
  537. package/dist/providers/airforce.js.map +1 -0
  538. package/dist/providers/base.d.ts +177 -0
  539. package/dist/providers/base.d.ts.map +1 -0
  540. package/dist/providers/base.js +354 -0
  541. package/dist/providers/base.js.map +1 -0
  542. package/dist/providers/blaze.d.ts +11 -0
  543. package/dist/providers/blaze.d.ts.map +1 -0
  544. package/dist/providers/blaze.js +33 -0
  545. package/dist/providers/blaze.js.map +1 -0
  546. package/dist/providers/blockrun.d.ts +14 -0
  547. package/dist/providers/blockrun.d.ts.map +1 -0
  548. package/dist/providers/blockrun.js +36 -0
  549. package/dist/providers/blockrun.js.map +1 -0
  550. package/dist/providers/clod.d.ts +11 -0
  551. package/dist/providers/clod.d.ts.map +1 -0
  552. package/dist/providers/clod.js +39 -0
  553. package/dist/providers/clod.js.map +1 -0
  554. package/dist/providers/cloudflare.d.ts +15 -0
  555. package/dist/providers/cloudflare.d.ts.map +1 -0
  556. package/dist/providers/cloudflare.js +175 -0
  557. package/dist/providers/cloudflare.js.map +1 -0
  558. package/dist/providers/cohere.d.ts +11 -0
  559. package/dist/providers/cohere.d.ts.map +1 -0
  560. package/dist/providers/cohere.js +117 -0
  561. package/dist/providers/cohere.js.map +1 -0
  562. package/dist/providers/dreamprompting.d.ts +11 -0
  563. package/dist/providers/dreamprompting.d.ts.map +1 -0
  564. package/dist/providers/dreamprompting.js +41 -0
  565. package/dist/providers/dreamprompting.js.map +1 -0
  566. package/dist/providers/electronhub.d.ts +10 -0
  567. package/dist/providers/electronhub.d.ts.map +1 -0
  568. package/dist/providers/electronhub.js +56 -0
  569. package/dist/providers/electronhub.js.map +1 -0
  570. package/dist/providers/experiential.d.ts +10 -0
  571. package/dist/providers/experiential.d.ts.map +1 -0
  572. package/dist/providers/experiential.js +33 -0
  573. package/dist/providers/experiential.js.map +1 -0
  574. package/dist/providers/gizmo.d.ts +15 -0
  575. package/dist/providers/gizmo.d.ts.map +1 -0
  576. package/dist/providers/gizmo.js +54 -0
  577. package/dist/providers/gizmo.js.map +1 -0
  578. package/dist/providers/google.d.ts +30 -0
  579. package/dist/providers/google.d.ts.map +1 -0
  580. package/dist/providers/google.js +766 -0
  581. package/dist/providers/google.js.map +1 -0
  582. package/dist/providers/index.d.ts +13 -0
  583. package/dist/providers/index.d.ts.map +1 -0
  584. package/dist/providers/index.js +561 -0
  585. package/dist/providers/index.js.map +1 -0
  586. package/dist/providers/llmtr.d.ts +15 -0
  587. package/dist/providers/llmtr.d.ts.map +1 -0
  588. package/dist/providers/llmtr.js +51 -0
  589. package/dist/providers/llmtr.js.map +1 -0
  590. package/dist/providers/logfare.d.ts +11 -0
  591. package/dist/providers/logfare.d.ts.map +1 -0
  592. package/dist/providers/logfare.js +33 -0
  593. package/dist/providers/logfare.js.map +1 -0
  594. package/dist/providers/lucidity.d.ts +11 -0
  595. package/dist/providers/lucidity.d.ts.map +1 -0
  596. package/dist/providers/lucidity.js +37 -0
  597. package/dist/providers/lucidity.js.map +1 -0
  598. package/dist/providers/modelscope.d.ts +50 -0
  599. package/dist/providers/modelscope.d.ts.map +1 -0
  600. package/dist/providers/modelscope.js +143 -0
  601. package/dist/providers/modelscope.js.map +1 -0
  602. package/dist/providers/moondream.d.ts +17 -0
  603. package/dist/providers/moondream.d.ts.map +1 -0
  604. package/dist/providers/moondream.js +140 -0
  605. package/dist/providers/moondream.js.map +1 -0
  606. package/dist/providers/openai-compat.d.ts +140 -0
  607. package/dist/providers/openai-compat.d.ts.map +1 -0
  608. package/dist/providers/openai-compat.js +537 -0
  609. package/dist/providers/openai-compat.js.map +1 -0
  610. package/dist/providers/opencode-free.d.ts +24 -0
  611. package/dist/providers/opencode-free.d.ts.map +1 -0
  612. package/dist/providers/opencode-free.js +262 -0
  613. package/dist/providers/opencode-free.js.map +1 -0
  614. package/dist/providers/pollinations.d.ts +32 -0
  615. package/dist/providers/pollinations.d.ts.map +1 -0
  616. package/dist/providers/pollinations.js +65 -0
  617. package/dist/providers/pollinations.js.map +1 -0
  618. package/dist/providers/router9.d.ts +16 -0
  619. package/dist/providers/router9.d.ts.map +1 -0
  620. package/dist/providers/router9.js +42 -0
  621. package/dist/providers/router9.js.map +1 -0
  622. package/dist/providers/sail.d.ts +44 -0
  623. package/dist/providers/sail.d.ts.map +1 -0
  624. package/dist/providers/sail.js +302 -0
  625. package/dist/providers/sail.js.map +1 -0
  626. package/dist/providers/septor.d.ts +10 -0
  627. package/dist/providers/septor.d.ts.map +1 -0
  628. package/dist/providers/septor.js +36 -0
  629. package/dist/providers/septor.js.map +1 -0
  630. package/dist/providers/speechify.d.ts +14 -0
  631. package/dist/providers/speechify.d.ts.map +1 -0
  632. package/dist/providers/speechify.js +28 -0
  633. package/dist/providers/speechify.js.map +1 -0
  634. package/dist/providers/speka.d.ts +12 -0
  635. package/dist/providers/speka.d.ts.map +1 -0
  636. package/dist/providers/speka.js +37 -0
  637. package/dist/providers/speka.js.map +1 -0
  638. package/dist/providers/waterfall.d.ts +11 -0
  639. package/dist/providers/waterfall.d.ts.map +1 -0
  640. package/dist/providers/waterfall.js +33 -0
  641. package/dist/providers/waterfall.js.map +1 -0
  642. package/dist/providers/xkiro.d.ts +71 -0
  643. package/dist/providers/xkiro.d.ts.map +1 -0
  644. package/dist/providers/xkiro.js +119 -0
  645. package/dist/providers/xkiro.js.map +1 -0
  646. package/dist/providers/zhipu.d.ts +43 -0
  647. package/dist/providers/zhipu.d.ts.map +1 -0
  648. package/dist/providers/zhipu.js +95 -0
  649. package/dist/providers/zhipu.js.map +1 -0
  650. package/dist/routes/analytics.d.ts +2 -0
  651. package/dist/routes/analytics.d.ts.map +1 -0
  652. package/dist/routes/analytics.js +738 -0
  653. package/dist/routes/analytics.js.map +1 -0
  654. package/dist/routes/anthropic.d.ts +7 -0
  655. package/dist/routes/anthropic.d.ts.map +1 -0
  656. package/dist/routes/anthropic.js +1076 -0
  657. package/dist/routes/anthropic.js.map +1 -0
  658. package/dist/routes/auth.d.ts +2 -0
  659. package/dist/routes/auth.d.ts.map +1 -0
  660. package/dist/routes/auth.js +310 -0
  661. package/dist/routes/auth.js.map +1 -0
  662. package/dist/routes/backups.d.ts +2 -0
  663. package/dist/routes/backups.d.ts.map +1 -0
  664. package/dist/routes/backups.js +127 -0
  665. package/dist/routes/backups.js.map +1 -0
  666. package/dist/routes/cache.d.ts +2 -0
  667. package/dist/routes/cache.d.ts.map +1 -0
  668. package/dist/routes/cache.js +40 -0
  669. package/dist/routes/cache.js.map +1 -0
  670. package/dist/routes/client-profiles.d.ts +2 -0
  671. package/dist/routes/client-profiles.d.ts.map +1 -0
  672. package/dist/routes/client-profiles.js +128 -0
  673. package/dist/routes/client-profiles.js.map +1 -0
  674. package/dist/routes/compression.d.ts +2 -0
  675. package/dist/routes/compression.d.ts.map +1 -0
  676. package/dist/routes/compression.js +82 -0
  677. package/dist/routes/compression.js.map +1 -0
  678. package/dist/routes/conversations.d.ts +3 -0
  679. package/dist/routes/conversations.d.ts.map +1 -0
  680. package/dist/routes/conversations.js +215 -0
  681. package/dist/routes/conversations.js.map +1 -0
  682. package/dist/routes/docs.d.ts +2 -0
  683. package/dist/routes/docs.d.ts.map +1 -0
  684. package/dist/routes/docs.js +21 -0
  685. package/dist/routes/docs.js.map +1 -0
  686. package/dist/routes/embeddings.d.ts +2 -0
  687. package/dist/routes/embeddings.d.ts.map +1 -0
  688. package/dist/routes/embeddings.js +255 -0
  689. package/dist/routes/embeddings.js.map +1 -0
  690. package/dist/routes/fallback.d.ts +2 -0
  691. package/dist/routes/fallback.d.ts.map +1 -0
  692. package/dist/routes/fallback.js +631 -0
  693. package/dist/routes/fallback.js.map +1 -0
  694. package/dist/routes/free-tier.d.ts +22 -0
  695. package/dist/routes/free-tier.d.ts.map +1 -0
  696. package/dist/routes/free-tier.js +175 -0
  697. package/dist/routes/free-tier.js.map +1 -0
  698. package/dist/routes/gemini.d.ts +2 -0
  699. package/dist/routes/gemini.d.ts.map +1 -0
  700. package/dist/routes/gemini.js +218 -0
  701. package/dist/routes/gemini.js.map +1 -0
  702. package/dist/routes/health.d.ts +2 -0
  703. package/dist/routes/health.d.ts.map +1 -0
  704. package/dist/routes/health.js +72 -0
  705. package/dist/routes/health.js.map +1 -0
  706. package/dist/routes/keys.d.ts +17 -0
  707. package/dist/routes/keys.d.ts.map +1 -0
  708. package/dist/routes/keys.js +1787 -0
  709. package/dist/routes/keys.js.map +1 -0
  710. package/dist/routes/logs.d.ts +2 -0
  711. package/dist/routes/logs.d.ts.map +1 -0
  712. package/dist/routes/logs.js +88 -0
  713. package/dist/routes/logs.js.map +1 -0
  714. package/dist/routes/mcp.d.ts +4 -0
  715. package/dist/routes/mcp.d.ts.map +1 -0
  716. package/dist/routes/mcp.js +563 -0
  717. package/dist/routes/mcp.js.map +1 -0
  718. package/dist/routes/media.d.ts +2 -0
  719. package/dist/routes/media.d.ts.map +1 -0
  720. package/dist/routes/media.js +180 -0
  721. package/dist/routes/media.js.map +1 -0
  722. package/dist/routes/models.d.ts +2 -0
  723. package/dist/routes/models.d.ts.map +1 -0
  724. package/dist/routes/models.js +439 -0
  725. package/dist/routes/models.js.map +1 -0
  726. package/dist/routes/ollama.d.ts +7 -0
  727. package/dist/routes/ollama.d.ts.map +1 -0
  728. package/dist/routes/ollama.js +595 -0
  729. package/dist/routes/ollama.js.map +1 -0
  730. package/dist/routes/profiles.d.ts +3 -0
  731. package/dist/routes/profiles.d.ts.map +1 -0
  732. package/dist/routes/profiles.js +431 -0
  733. package/dist/routes/profiles.js.map +1 -0
  734. package/dist/routes/proxy.d.ts +32 -0
  735. package/dist/routes/proxy.d.ts.map +1 -0
  736. package/dist/routes/proxy.js +2793 -0
  737. package/dist/routes/proxy.js.map +1 -0
  738. package/dist/routes/responses.d.ts +1161 -0
  739. package/dist/routes/responses.d.ts.map +1 -0
  740. package/dist/routes/responses.js +1521 -0
  741. package/dist/routes/responses.js.map +1 -0
  742. package/dist/routes/settings.d.ts +2 -0
  743. package/dist/routes/settings.d.ts.map +1 -0
  744. package/dist/routes/settings.js +549 -0
  745. package/dist/routes/settings.js.map +1 -0
  746. package/dist/routes/status.d.ts +3 -0
  747. package/dist/routes/status.d.ts.map +1 -0
  748. package/dist/routes/status.js +214 -0
  749. package/dist/routes/status.js.map +1 -0
  750. package/dist/routes/update.d.ts +31 -0
  751. package/dist/routes/update.d.ts.map +1 -0
  752. package/dist/routes/update.js +536 -0
  753. package/dist/routes/update.js.map +1 -0
  754. package/dist/routes/url-tokens.d.ts +2 -0
  755. package/dist/routes/url-tokens.d.ts.map +1 -0
  756. package/dist/routes/url-tokens.js +31 -0
  757. package/dist/routes/url-tokens.js.map +1 -0
  758. package/dist/scripts/export-catalog.d.ts +2 -0
  759. package/dist/scripts/export-catalog.d.ts.map +1 -0
  760. package/dist/scripts/export-catalog.js +114 -0
  761. package/dist/scripts/export-catalog.js.map +1 -0
  762. package/dist/scripts/rotate-encryption-key.d.ts +81 -0
  763. package/dist/scripts/rotate-encryption-key.d.ts.map +1 -0
  764. package/dist/scripts/rotate-encryption-key.js +232 -0
  765. package/dist/scripts/rotate-encryption-key.js.map +1 -0
  766. package/dist/scripts/routing-sim.d.ts +2 -0
  767. package/dist/scripts/routing-sim.d.ts.map +1 -0
  768. package/dist/scripts/routing-sim.js +130 -0
  769. package/dist/scripts/routing-sim.js.map +1 -0
  770. package/dist/scripts/test-all-models.d.ts +2 -0
  771. package/dist/scripts/test-all-models.d.ts.map +1 -0
  772. package/dist/scripts/test-all-models.js +56 -0
  773. package/dist/scripts/test-all-models.js.map +1 -0
  774. package/dist/services/anthropic-map.d.ts +39 -0
  775. package/dist/services/anthropic-map.d.ts.map +1 -0
  776. package/dist/services/anthropic-map.js +138 -0
  777. package/dist/services/anthropic-map.js.map +1 -0
  778. package/dist/services/auth.d.ts +30 -0
  779. package/dist/services/auth.d.ts.map +1 -0
  780. package/dist/services/auth.js +124 -0
  781. package/dist/services/auth.js.map +1 -0
  782. package/dist/services/auto-discover.d.ts +77 -0
  783. package/dist/services/auto-discover.d.ts.map +1 -0
  784. package/dist/services/auto-discover.js +1047 -0
  785. package/dist/services/auto-discover.js.map +1 -0
  786. package/dist/services/backups.d.ts +67 -0
  787. package/dist/services/backups.d.ts.map +1 -0
  788. package/dist/services/backups.js +444 -0
  789. package/dist/services/backups.js.map +1 -0
  790. package/dist/services/builtin-model-discovery.d.ts +107 -0
  791. package/dist/services/builtin-model-discovery.d.ts.map +1 -0
  792. package/dist/services/builtin-model-discovery.js +296 -0
  793. package/dist/services/builtin-model-discovery.js.map +1 -0
  794. package/dist/services/cache.d.ts +190 -0
  795. package/dist/services/cache.d.ts.map +1 -0
  796. package/dist/services/cache.js +617 -0
  797. package/dist/services/cache.js.map +1 -0
  798. package/dist/services/catalog-sync.d.ts +257 -0
  799. package/dist/services/catalog-sync.d.ts.map +1 -0
  800. package/dist/services/catalog-sync.js +1041 -0
  801. package/dist/services/catalog-sync.js.map +1 -0
  802. package/dist/services/compression/config.d.ts +33 -0
  803. package/dist/services/compression/config.d.ts.map +1 -0
  804. package/dist/services/compression/config.js +158 -0
  805. package/dist/services/compression/config.js.map +1 -0
  806. package/dist/services/compression/engines/aging.d.ts +2 -0
  807. package/dist/services/compression/engines/aging.d.ts.map +1 -0
  808. package/dist/services/compression/engines/aging.js +53 -0
  809. package/dist/services/compression/engines/aging.js.map +1 -0
  810. package/dist/services/compression/engines/custom-filters.d.ts +4 -0
  811. package/dist/services/compression/engines/custom-filters.d.ts.map +1 -0
  812. package/dist/services/compression/engines/custom-filters.js +49 -0
  813. package/dist/services/compression/engines/custom-filters.js.map +1 -0
  814. package/dist/services/compression/engines/dedup.d.ts +2 -0
  815. package/dist/services/compression/engines/dedup.d.ts.map +1 -0
  816. package/dist/services/compression/engines/dedup.js +61 -0
  817. package/dist/services/compression/engines/dedup.js.map +1 -0
  818. package/dist/services/compression/engines/filter-definitions.d.ts +75 -0
  819. package/dist/services/compression/engines/filter-definitions.d.ts.map +1 -0
  820. package/dist/services/compression/engines/filter-definitions.js +45 -0
  821. package/dist/services/compression/engines/filter-definitions.js.map +1 -0
  822. package/dist/services/compression/engines/hard-budget.d.ts +2 -0
  823. package/dist/services/compression/engines/hard-budget.d.ts.map +1 -0
  824. package/dist/services/compression/engines/hard-budget.js +52 -0
  825. package/dist/services/compression/engines/hard-budget.js.map +1 -0
  826. package/dist/services/compression/engines/index.d.ts +9 -0
  827. package/dist/services/compression/engines/index.d.ts.map +1 -0
  828. package/dist/services/compression/engines/index.js +9 -0
  829. package/dist/services/compression/engines/index.js.map +1 -0
  830. package/dist/services/compression/engines/jsoncompact.d.ts +3 -0
  831. package/dist/services/compression/engines/jsoncompact.d.ts.map +1 -0
  832. package/dist/services/compression/engines/jsoncompact.js +145 -0
  833. package/dist/services/compression/engines/jsoncompact.js.map +1 -0
  834. package/dist/services/compression/engines/lite.d.ts +2 -0
  835. package/dist/services/compression/engines/lite.d.ts.map +1 -0
  836. package/dist/services/compression/engines/lite.js +34 -0
  837. package/dist/services/compression/engines/lite.js.map +1 -0
  838. package/dist/services/compression/engines/read-lifecycle.d.ts +2 -0
  839. package/dist/services/compression/engines/read-lifecycle.d.ts.map +1 -0
  840. package/dist/services/compression/engines/read-lifecycle.js +70 -0
  841. package/dist/services/compression/engines/read-lifecycle.js.map +1 -0
  842. package/dist/services/compression/engines/relevance.d.ts +2 -0
  843. package/dist/services/compression/engines/relevance.d.ts.map +1 -0
  844. package/dist/services/compression/engines/relevance.js +74 -0
  845. package/dist/services/compression/engines/relevance.js.map +1 -0
  846. package/dist/services/compression/engines/toolfilter.d.ts +2 -0
  847. package/dist/services/compression/engines/toolfilter.d.ts.map +1 -0
  848. package/dist/services/compression/engines/toolfilter.js +195 -0
  849. package/dist/services/compression/engines/toolfilter.js.map +1 -0
  850. package/dist/services/compression/fidelity-gate.d.ts +12 -0
  851. package/dist/services/compression/fidelity-gate.d.ts.map +1 -0
  852. package/dist/services/compression/fidelity-gate.js +90 -0
  853. package/dist/services/compression/fidelity-gate.js.map +1 -0
  854. package/dist/services/compression/helpers.d.ts +9 -0
  855. package/dist/services/compression/helpers.d.ts.map +1 -0
  856. package/dist/services/compression/helpers.js +52 -0
  857. package/dist/services/compression/helpers.js.map +1 -0
  858. package/dist/services/compression/pipeline.d.ts +7 -0
  859. package/dist/services/compression/pipeline.d.ts.map +1 -0
  860. package/dist/services/compression/pipeline.js +245 -0
  861. package/dist/services/compression/pipeline.js.map +1 -0
  862. package/dist/services/compression/preservation.d.ts +27 -0
  863. package/dist/services/compression/preservation.d.ts.map +1 -0
  864. package/dist/services/compression/preservation.js +109 -0
  865. package/dist/services/compression/preservation.js.map +1 -0
  866. package/dist/services/compression/registry.d.ts +6 -0
  867. package/dist/services/compression/registry.d.ts.map +1 -0
  868. package/dist/services/compression/registry.js +16 -0
  869. package/dist/services/compression/registry.js.map +1 -0
  870. package/dist/services/compression/stats.d.ts +29 -0
  871. package/dist/services/compression/stats.d.ts.map +1 -0
  872. package/dist/services/compression/stats.js +55 -0
  873. package/dist/services/compression/stats.js.map +1 -0
  874. package/dist/services/compression/types.d.ts +90 -0
  875. package/dist/services/compression/types.d.ts.map +1 -0
  876. package/dist/services/compression/types.js +2 -0
  877. package/dist/services/compression/types.js.map +1 -0
  878. package/dist/services/context-handoff.d.ts +22 -0
  879. package/dist/services/context-handoff.d.ts.map +1 -0
  880. package/dist/services/context-handoff.js +164 -0
  881. package/dist/services/context-handoff.js.map +1 -0
  882. package/dist/services/cooldown-probe.d.ts +24 -0
  883. package/dist/services/cooldown-probe.d.ts.map +1 -0
  884. package/dist/services/cooldown-probe.js +181 -0
  885. package/dist/services/cooldown-probe.js.map +1 -0
  886. package/dist/services/custom-endpoint.d.ts +58 -0
  887. package/dist/services/custom-endpoint.d.ts.map +1 -0
  888. package/dist/services/custom-endpoint.js +167 -0
  889. package/dist/services/custom-endpoint.js.map +1 -0
  890. package/dist/services/custom-media-register.d.ts +22 -0
  891. package/dist/services/custom-media-register.d.ts.map +1 -0
  892. package/dist/services/custom-media-register.js +45 -0
  893. package/dist/services/custom-media-register.js.map +1 -0
  894. package/dist/services/custom-model-register.d.ts +50 -0
  895. package/dist/services/custom-model-register.d.ts.map +1 -0
  896. package/dist/services/custom-model-register.js +103 -0
  897. package/dist/services/custom-model-register.js.map +1 -0
  898. package/dist/services/custom-model-seed.d.ts +18 -0
  899. package/dist/services/custom-model-seed.d.ts.map +1 -0
  900. package/dist/services/custom-model-seed.js +42 -0
  901. package/dist/services/custom-model-seed.js.map +1 -0
  902. package/dist/services/custom-model-sync.d.ts +37 -0
  903. package/dist/services/custom-model-sync.d.ts.map +1 -0
  904. package/dist/services/custom-model-sync.js +118 -0
  905. package/dist/services/custom-model-sync.js.map +1 -0
  906. package/dist/services/custom-model-tombstone.d.ts +5 -0
  907. package/dist/services/custom-model-tombstone.d.ts.map +1 -0
  908. package/dist/services/custom-model-tombstone.js +30 -0
  909. package/dist/services/custom-model-tombstone.js.map +1 -0
  910. package/dist/services/declarative-config.d.ts +356 -0
  911. package/dist/services/declarative-config.d.ts.map +1 -0
  912. package/dist/services/declarative-config.js +427 -0
  913. package/dist/services/declarative-config.js.map +1 -0
  914. package/dist/services/degradation.d.ts +40 -0
  915. package/dist/services/degradation.d.ts.map +1 -0
  916. package/dist/services/degradation.js +119 -0
  917. package/dist/services/degradation.js.map +1 -0
  918. package/dist/services/embeddings.d.ts +76 -0
  919. package/dist/services/embeddings.d.ts.map +1 -0
  920. package/dist/services/embeddings.js +319 -0
  921. package/dist/services/embeddings.js.map +1 -0
  922. package/dist/services/fusion.d.ts +162 -0
  923. package/dist/services/fusion.d.ts.map +1 -0
  924. package/dist/services/fusion.js +789 -0
  925. package/dist/services/fusion.js.map +1 -0
  926. package/dist/services/gemini-map.d.ts +14 -0
  927. package/dist/services/gemini-map.d.ts.map +1 -0
  928. package/dist/services/gemini-map.js +78 -0
  929. package/dist/services/gemini-map.js.map +1 -0
  930. package/dist/services/health.d.ts +52 -0
  931. package/dist/services/health.d.ts.map +1 -0
  932. package/dist/services/health.js +352 -0
  933. package/dist/services/health.js.map +1 -0
  934. package/dist/services/idempotency.d.ts +49 -0
  935. package/dist/services/idempotency.d.ts.map +1 -0
  936. package/dist/services/idempotency.js +140 -0
  937. package/dist/services/idempotency.js.map +1 -0
  938. package/dist/services/key-budget.d.ts +74 -0
  939. package/dist/services/key-budget.d.ts.map +1 -0
  940. package/dist/services/key-budget.js +200 -0
  941. package/dist/services/key-budget.js.map +1 -0
  942. package/dist/services/media.d.ts +123 -0
  943. package/dist/services/media.d.ts.map +1 -0
  944. package/dist/services/media.js +954 -0
  945. package/dist/services/media.js.map +1 -0
  946. package/dist/services/model-discovery.d.ts +126 -0
  947. package/dist/services/model-discovery.d.ts.map +1 -0
  948. package/dist/services/model-discovery.js +662 -0
  949. package/dist/services/model-discovery.js.map +1 -0
  950. package/dist/services/model-groups.d.ts +149 -0
  951. package/dist/services/model-groups.d.ts.map +1 -0
  952. package/dist/services/model-groups.js +314 -0
  953. package/dist/services/model-groups.js.map +1 -0
  954. package/dist/services/model-listing.d.ts +18 -0
  955. package/dist/services/model-listing.d.ts.map +1 -0
  956. package/dist/services/model-listing.js +94 -0
  957. package/dist/services/model-listing.js.map +1 -0
  958. package/dist/services/model-retirement.d.ts +29 -0
  959. package/dist/services/model-retirement.d.ts.map +1 -0
  960. package/dist/services/model-retirement.js +86 -0
  961. package/dist/services/model-retirement.js.map +1 -0
  962. package/dist/services/model-state.d.ts +90 -0
  963. package/dist/services/model-state.d.ts.map +1 -0
  964. package/dist/services/model-state.js +342 -0
  965. package/dist/services/model-state.js.map +1 -0
  966. package/dist/services/model-weight-overrides.d.ts +48 -0
  967. package/dist/services/model-weight-overrides.d.ts.map +1 -0
  968. package/dist/services/model-weight-overrides.js +127 -0
  969. package/dist/services/model-weight-overrides.js.map +1 -0
  970. package/dist/services/notification-emitter.d.ts +50 -0
  971. package/dist/services/notification-emitter.d.ts.map +1 -0
  972. package/dist/services/notification-emitter.js +177 -0
  973. package/dist/services/notification-emitter.js.map +1 -0
  974. package/dist/services/opencode-free-sync.d.ts +29 -0
  975. package/dist/services/opencode-free-sync.d.ts.map +1 -0
  976. package/dist/services/opencode-free-sync.js +206 -0
  977. package/dist/services/opencode-free-sync.js.map +1 -0
  978. package/dist/services/penalty-inspector.d.ts +56 -0
  979. package/dist/services/penalty-inspector.d.ts.map +1 -0
  980. package/dist/services/penalty-inspector.js +167 -0
  981. package/dist/services/penalty-inspector.js.map +1 -0
  982. package/dist/services/profile-models.d.ts +5 -0
  983. package/dist/services/profile-models.d.ts.map +1 -0
  984. package/dist/services/profile-models.js +62 -0
  985. package/dist/services/profile-models.js.map +1 -0
  986. package/dist/services/provider-credential.d.ts +19 -0
  987. package/dist/services/provider-credential.d.ts.map +1 -0
  988. package/dist/services/provider-credential.js +51 -0
  989. package/dist/services/provider-credential.js.map +1 -0
  990. package/dist/services/provider-quota.d.ts +64 -0
  991. package/dist/services/provider-quota.d.ts.map +1 -0
  992. package/dist/services/provider-quota.js +563 -0
  993. package/dist/services/provider-quota.js.map +1 -0
  994. package/dist/services/quirks.d.ts +0 -0
  995. package/dist/services/quirks.d.ts.map +1 -0
  996. package/dist/services/quirks.js +0 -0
  997. package/dist/services/quirks.js.map +1 -0
  998. package/dist/services/quota-forecast.d.ts +50 -0
  999. package/dist/services/quota-forecast.d.ts.map +1 -0
  1000. package/dist/services/quota-forecast.js +150 -0
  1001. package/dist/services/quota-forecast.js.map +1 -0
  1002. package/dist/services/quota-outlook.d.ts +4 -0
  1003. package/dist/services/quota-outlook.d.ts.map +1 -0
  1004. package/dist/services/quota-outlook.js +92 -0
  1005. package/dist/services/quota-outlook.js.map +1 -0
  1006. package/dist/services/ratelimit.d.ts +249 -0
  1007. package/dist/services/ratelimit.d.ts.map +1 -0
  1008. package/dist/services/ratelimit.js +1182 -0
  1009. package/dist/services/ratelimit.js.map +1 -0
  1010. package/dist/services/request-retention.d.ts +60 -0
  1011. package/dist/services/request-retention.d.ts.map +1 -0
  1012. package/dist/services/request-retention.js +229 -0
  1013. package/dist/services/request-retention.js.map +1 -0
  1014. package/dist/services/router.d.ts +384 -0
  1015. package/dist/services/router.d.ts.map +1 -0
  1016. package/dist/services/router.js +1986 -0
  1017. package/dist/services/router.js.map +1 -0
  1018. package/dist/services/scoring.d.ts +156 -0
  1019. package/dist/services/scoring.d.ts.map +1 -0
  1020. package/dist/services/scoring.js +435 -0
  1021. package/dist/services/scoring.js.map +1 -0
  1022. package/dist/services/url-tokens.d.ts +15 -0
  1023. package/dist/services/url-tokens.d.ts.map +1 -0
  1024. package/dist/services/url-tokens.js +55 -0
  1025. package/dist/services/url-tokens.js.map +1 -0
  1026. package/package.json +77 -4
  1027. package/README.md +0 -3
@@ -0,0 +1,631 @@
1
+ /**
2
+ * Express router handles model fallback configuration and token budget reporting.
3
+ * It integrates named profiles dynamically into the fallback routing logic and aggregates
4
+ * monthly token consumption and rate limits (RPM/RPD/TPM/TPD) across configured models.
5
+ */
6
+ import { Router } from 'express';
7
+ import { z } from 'zod';
8
+ import { getDb } from '../db/index.js';
9
+ import { getAllPenalties, getRoutingScores, getRoutingStrategy, setRoutingStrategy, setCustomWeights, getExploreEnabled, setExploreEnabled, getPeakHoursConfig, setPeakHoursConfig, getActiveRoutingWeights, getKeySelectionStrategy, setKeySelectionStrategy } from '../services/router.js';
10
+ import { BANDIT_PRESETS, isValidTimezone } from '../services/scoring.js';
11
+ import { parseBudget, monthlyBudgetScore } from '../lib/budget.js';
12
+ import { getModelGroups } from '../services/model-groups.js';
13
+ import { getPenaltyInspector, clearRouterPressure } from '../services/penalty-inspector.js';
14
+ import { getCooldownCeilingMs, setCooldownCeilingMs, MIN_COOLDOWN_CEILING_MS, MAX_COOLDOWN_CEILING_MS } from '../services/ratelimit.js';
15
+ import { getActiveProfileId } from '../services/profile-models.js';
16
+ import { qualifiedModelMemberId } from '../lib/endpoint-scope.js';
17
+ import { overriddenFieldNames } from '../services/model-state.js';
18
+ import { parseModelScope, scopeAllows } from '../lib/model-scope.js';
19
+ import { getQuotaOutlook } from '../services/quota-outlook.js';
20
+ export const fallbackRouter = Router();
21
+ // Dashboard-session authenticated by app.ts. Polling only reads saved quota
22
+ // observations and request history, never provider endpoints or key material.
23
+ fallbackRouter.get('/quota-forecast', (_req, res) => {
24
+ res.json(getQuotaOutlook());
25
+ });
26
+ // ── Bandit routing strategy ─────────────────────────────────────────────────
27
+ // GET /routing → active strategy, preset weights, and the per-model score
28
+ // breakdown (reliability / speed / intelligence + guardrails).
29
+ fallbackRouter.get('/routing', (_req, res) => {
30
+ const { peakHours, ...rest } = getRoutingScores();
31
+ res.json({
32
+ ...rest,
33
+ peakHoursAdjust: peakHours.enabled,
34
+ peakStartHour: peakHours.startHour,
35
+ peakEndHour: peakHours.endHour,
36
+ peakTimezone: peakHours.timezone,
37
+ cooldownCeilingMs: getCooldownCeilingMs(),
38
+ });
39
+ });
40
+ fallbackRouter.get('/penalty-inspector', (_req, res) => {
41
+ res.json(getPenaltyInspector());
42
+ });
43
+ // DELETE /penalty-inspector → lift every cooldown, penalty and failure streak
44
+ // at once (#952). The per-key DELETE /api/keys/:id/cooldowns stays for the
45
+ // surgical case; this is the escape hatch for a pool that cannot route at all.
46
+ fallbackRouter.delete('/penalty-inspector', (_req, res) => {
47
+ res.json(clearRouterPressure());
48
+ });
49
+ const routingSchema = z.object({
50
+ strategy: z.enum(['priority', 'balanced', 'smartest', 'fastest', 'reliable', 'custom']),
51
+ // Only meaningful with strategy 'custom': the user's weight vector. Any
52
+ // non-negative vector is accepted; setCustomWeights renormalizes to sum 1.
53
+ weights: z.object({
54
+ reliability: z.number().nonnegative(),
55
+ speed: z.number().nonnegative(),
56
+ intelligence: z.number().nonnegative(),
57
+ }).optional(),
58
+ // Exploration toggle: give unmeasured models a guaranteed chance to be tried.
59
+ exploreEnabled: z.boolean().optional(),
60
+ // Peak-hours adjustment (#760), off by default. Hours are whole numbers in
61
+ // 0-23 and are read in `peakTimezone`, never the server's local clock, so the
62
+ // window means the same thing on a UTC container as on the operator's laptop.
63
+ peakHoursAdjust: z.boolean().optional(),
64
+ peakStartHour: z.number().int().min(0).max(23, { message: 'peakStartHour must be an integer between 0 and 23' }).optional(),
65
+ peakEndHour: z.number().int().min(0).max(23, { message: 'peakEndHour must be an integer between 0 and 23' }).optional(),
66
+ peakTimezone: z.string().refine(isValidTimezone, { message: 'peakTimezone must be a valid IANA timezone name' }).optional(),
67
+ // How to pick between several keys of one platform (#919). Independent of
68
+ // `strategy`, which ranks MODELS — the two are set from the same form, so
69
+ // they round-trip through the same request.
70
+ keySelectionStrategy: z.enum(['auto', 'least-remaining']).optional(),
71
+ // Ceiling on automatic cooldowns (#952): 1 min .. 24 h in ms, null = no cap
72
+ // (the escalation ladder keeps its 24h top step and 402/403 bench a day).
73
+ cooldownCeilingMs: z.number().int()
74
+ .min(MIN_COOLDOWN_CEILING_MS, { message: `cooldownCeilingMs must be at least ${MIN_COOLDOWN_CEILING_MS} (1 minute)` })
75
+ .max(MAX_COOLDOWN_CEILING_MS, { message: `cooldownCeilingMs must be at most ${MAX_COOLDOWN_CEILING_MS} (24 hours)` })
76
+ .nullable().optional(),
77
+ });
78
+ // PUT /routing → switch strategy. Presets are just weight vectors over the three
79
+ // axes; 'priority' falls back to the legacy manual chain order; 'custom' uses
80
+ // the user's saved weights (optionally updated in the same request).
81
+ fallbackRouter.put('/routing', (req, res) => {
82
+ const parsed = routingSchema.safeParse(req.body);
83
+ if (!parsed.success) {
84
+ res.status(400).json({ error: { message: parsed.error.errors.map(e => e.message).join(', ') } });
85
+ return;
86
+ }
87
+ // Persist the weights before flipping the strategy so the new mode reads the
88
+ // intended vector immediately. setCustomWeights throws on an all-zero vector.
89
+ if (parsed.data.weights) {
90
+ try {
91
+ setCustomWeights(parsed.data.weights);
92
+ }
93
+ catch (err) {
94
+ res.status(400).json({ error: { message: err?.message ?? 'Invalid custom weights' } });
95
+ return;
96
+ }
97
+ }
98
+ setRoutingStrategy(parsed.data.strategy);
99
+ if (parsed.data.exploreEnabled !== undefined) {
100
+ setExploreEnabled(parsed.data.exploreEnabled);
101
+ }
102
+ if (parsed.data.keySelectionStrategy !== undefined) {
103
+ setKeySelectionStrategy(parsed.data.keySelectionStrategy);
104
+ }
105
+ if (parsed.data.cooldownCeilingMs !== undefined) {
106
+ setCooldownCeilingMs(parsed.data.cooldownCeilingMs);
107
+ }
108
+ try {
109
+ setPeakHoursConfig({
110
+ enabled: parsed.data.peakHoursAdjust,
111
+ startHour: parsed.data.peakStartHour,
112
+ endHour: parsed.data.peakEndHour,
113
+ timezone: parsed.data.peakTimezone,
114
+ });
115
+ }
116
+ catch (err) {
117
+ res.status(400).json({ error: { message: err?.message ?? 'Invalid peak-hours settings' } });
118
+ return;
119
+ }
120
+ // `presets` is the raw preset table (unchanged); `weights` is what the router
121
+ // will actually use right now, which differs from the preset while the
122
+ // peak-hours adjustment is firing. Returning both keeps the echo honest
123
+ // without breaking clients that read `presets` (#760).
124
+ const active = getActiveRoutingWeights();
125
+ const peak = getPeakHoursConfig();
126
+ res.json({
127
+ strategy: getRoutingStrategy(),
128
+ exploreEnabled: getExploreEnabled(),
129
+ keySelectionStrategy: getKeySelectionStrategy(),
130
+ presets: BANDIT_PRESETS,
131
+ weights: active.weights,
132
+ peakAdjusted: active.adjusted,
133
+ peakHoursAdjust: peak.enabled,
134
+ peakStartHour: peak.startHour,
135
+ peakEndHour: peak.endHour,
136
+ peakTimezone: peak.timezone,
137
+ cooldownCeilingMs: getCooldownCeilingMs(),
138
+ });
139
+ });
140
+ // The catalog columns every fallback row carries, whichever table supplies the
141
+ // priority/enabled pair. Kept in one place so the profile and the no-profile
142
+ // query can never drift apart.
143
+ const MODEL_COLUMNS = `
144
+ m.platform, m.model_id, m.display_name, m.intelligence_rank,
145
+ m.speed_rank, m.size_label, m.rpm_limit, m.rpd_limit,
146
+ m.tpm_limit, m.tpd_limit, m.context_window,
147
+ m.monthly_token_budget, m.supports_vision, m.supports_tools,
148
+ m.key_id, m.endpoint_scope, m.source AS model_source, ak.label AS key_label,
149
+ mo.overrides_json IS NOT NULL AS has_overrides,
150
+ mo.overrides_json,
151
+ ts.source AS tombstone_source, ts.reason AS tombstone_reason`;
152
+ const MODEL_JOINS = `
153
+ LEFT JOIN api_keys ak ON ak.id = m.key_id
154
+ LEFT JOIN model_overrides mo ON mo.platform = m.platform AND mo.model_id = m.model_id
155
+ LEFT JOIN catalog_model_tombstones ts
156
+ ON ts.kind = 'chat' AND ts.platform = m.platform AND ts.model_id = m.model_id`;
157
+ // The whole catalog seen THROUGH one chain (#1021). A chain is a set of opt-ins,
158
+ // not a copy of the catalog: a model the chain names keeps the priority and the
159
+ // on/off flag stored against it, and a model it does not name is still listed —
160
+ // switched OFF, ranked after everything the chain does name. That is what makes
161
+ // a hand-built ("start empty") chain usable at all: it renders as "the catalog,
162
+ // nothing turned on yet" instead of an empty page, and turning a row on is the
163
+ // PUT below, which writes the row into the chain. Nothing is persisted by GET.
164
+ const PROFILE_CHAIN_SQL = `
165
+ SELECT m.id AS model_db_id, pm.priority AS chain_priority, pm.enabled AS chain_enabled,
166
+ fc.priority AS catalog_priority,
167
+ ${MODEL_COLUMNS}
168
+ FROM models m
169
+ LEFT JOIN profile_models pm ON pm.profile_id = ? AND pm.model_db_id = m.id
170
+ LEFT JOIN fallback_config fc ON fc.model_db_id = m.id
171
+ ${MODEL_JOINS}
172
+ WHERE m.enabled = 1
173
+ `;
174
+ const GLOBAL_CHAIN_SQL = `
175
+ SELECT fc.model_db_id, fc.priority, fc.enabled,
176
+ ${MODEL_COLUMNS}
177
+ FROM fallback_config fc
178
+ JOIN models m ON m.id = fc.model_db_id
179
+ ${MODEL_JOINS}
180
+ WHERE m.enabled = 1
181
+ ORDER BY fc.priority ASC
182
+ `;
183
+ /**
184
+ * Order a chain-scoped catalog read and give every row a priority.
185
+ *
186
+ * Rows the chain names come first, in their stored order and keeping their
187
+ * stored numbers. Rows it does not name follow in catalog order, numbered after
188
+ * the last stored one, so the list stays monotonic and stable between reads
189
+ * without writing anything back.
190
+ */
191
+ function orderProfileRows(rows) {
192
+ const inChain = rows.filter(r => r.chain_priority != null);
193
+ const rest = rows.filter(r => r.chain_priority == null);
194
+ inChain.sort((a, b) => a.chain_priority - b.chain_priority || a.model_db_id - b.model_db_id);
195
+ rest.sort((a, b) => (a.catalog_priority ?? Number.MAX_SAFE_INTEGER) - (b.catalog_priority ?? Number.MAX_SAFE_INTEGER)
196
+ || a.model_db_id - b.model_db_id);
197
+ const maxStored = inChain.length ? inChain[inChain.length - 1].chain_priority : 0;
198
+ return [
199
+ ...inChain.map(r => ({ ...r, priority: r.chain_priority, enabled: r.chain_enabled })),
200
+ ...rest.map((r, i) => ({ ...r, priority: maxStored + 1 + i, enabled: 0 })),
201
+ ];
202
+ }
203
+ // Get fallback chain (with dynamic penalties)
204
+ fallbackRouter.get('/', (req, res) => {
205
+ const db = getDb();
206
+ // #1047: an explicit ?profile= pins the read to that chain, so a client
207
+ // caching per-chain can never have "the active chain, whichever that is right
208
+ // now" written into a specific chain's cache entry. During an activation the
209
+ // active id changes between the client's two fetches; that race is how chain
210
+ // B's rows ended up rendered (and nearly saved) under chain A's name.
211
+ let activeProfileId = getActiveProfileId(db);
212
+ const requestedRaw = req.query.profile;
213
+ if (requestedRaw !== undefined) {
214
+ const requested = Number.parseInt(String(requestedRaw), 10);
215
+ if (!Number.isInteger(requested) || requested <= 0
216
+ || !db.prepare('SELECT 1 FROM profiles WHERE id = ?').get(requested)) {
217
+ res.status(404).json({ error: { message: `no such profile: ${String(requestedRaw)}` } });
218
+ return;
219
+ }
220
+ activeProfileId = requested;
221
+ }
222
+ // `fallback_config` is the chain only for an install that has no profiles at
223
+ // all. Once one is active it is authoritative even when it is empty — falling
224
+ // through to the global table there is what made two different empty chains
225
+ // show (and save) the same configuration (#1021).
226
+ const rows = activeProfileId != null
227
+ ? orderProfileRows(db.prepare(PROFILE_CHAIN_SQL).all(activeProfileId))
228
+ : db.prepare(GLOBAL_CHAIN_SQL).all();
229
+ // Count usable keys per platform — enabled AND healthy/unknown status. Unified
230
+ // with /token-usage and the routing scorer (#456) so budget pooling is computed
231
+ // from the same key set everywhere (a disabled or invalid key adds no capacity).
232
+ const keyCounts = db.prepare(`
233
+ SELECT platform, COUNT(*) as count
234
+ FROM api_keys WHERE enabled = 1 AND status IN ('healthy', 'unknown')
235
+ GROUP BY platform
236
+ `).all();
237
+ const keyCountMap = new Map(keyCounts.map(k => [k.platform, k.count]));
238
+ // Get current dynamic penalties
239
+ const penalties = getAllPenalties();
240
+ const penaltyMap = new Map(penalties.map(p => [p.modelDbId, p]));
241
+ // Logical-model grouping per row, so the dashboard can collapse the same
242
+ // model served by several providers into one expandable group. Always sent
243
+ // (cheap); the client renders grouped only when its unify toggle is on.
244
+ const groupByDbId = new Map();
245
+ for (const g of getModelGroups()) {
246
+ for (const m of g.members) {
247
+ groupByDbId.set(m.model_db_id, { groupKey: g.groupKey, canonicalId: g.canonicalId, groupLabel: g.groupLabel });
248
+ }
249
+ }
250
+ res.json(rows.map(r => {
251
+ const penalty = penaltyMap.get(r.model_db_id);
252
+ const group = groupByDbId.get(r.model_db_id);
253
+ return {
254
+ modelDbId: r.model_db_id,
255
+ groupKey: group?.groupKey,
256
+ canonicalId: group?.canonicalId,
257
+ groupLabel: group?.groupLabel,
258
+ priority: r.priority,
259
+ effectivePriority: r.priority + (penalty?.penalty ?? 0),
260
+ penalty: penalty?.penalty ?? 0,
261
+ rateLimitHits: penalty?.count ?? 0,
262
+ enabled: r.enabled === 1,
263
+ platform: r.platform,
264
+ modelId: r.model_id,
265
+ displayName: r.display_name,
266
+ intelligenceRank: r.intelligence_rank,
267
+ speedRank: r.speed_rank,
268
+ sizeLabel: r.size_label,
269
+ rpmLimit: r.rpm_limit,
270
+ rpdLimit: r.rpd_limit,
271
+ tpmLimit: r.tpm_limit,
272
+ tpdLimit: r.tpd_limit,
273
+ // Max context length (tokens), used by the dashboard catalog filter. Null
274
+ // for models whose context window the catalog doesn't record.
275
+ contextWindow: r.context_window,
276
+ monthlyTokenBudget: r.monthly_token_budget,
277
+ // Parsed once here (single source of truth) so the dashboard never re-implements
278
+ // budget-label parsing; 0 for rate-limited/placeholder labels. See lib/budget.ts.
279
+ // Scaled by healthy/enabled key count for multi-account pooled capacity.
280
+ monthlyTokenBudgetTokens: parseBudget(r.monthly_token_budget) * Math.max(1, keyCountMap.get(r.platform) ?? 1),
281
+ supportsVision: r.supports_vision === 1,
282
+ supportsTools: r.supports_tools === 1,
283
+ // 'discovered' (#1348): fetched from a built-in provider's /models because
284
+ // the catalog carries none for it. Routes like a catalog row.
285
+ source: r.platform === 'custom' || r.key_id != null
286
+ ? 'custom'
287
+ : r.model_source === 'discovered' ? 'discovered' : 'catalog',
288
+ keyId: r.key_id ?? null,
289
+ keyLabel: r.key_label ?? null,
290
+ // Which relay endpoint a custom row belongs to, and the id that names it
291
+ // unambiguously (#651). Null for catalog models only — every custom row
292
+ // bound to an endpoint carries both, including a lone one. Deciding when
293
+ // they are worth showing is the client's job (see memberProviderLabel /
294
+ // providerPinId / memberEndpointTitle): it reveals them only where two
295
+ // endpoints actually serve the same model id.
296
+ endpointScope: r.endpoint_scope || null,
297
+ qualifiedModelId: qualifiedModelMemberId(r.platform, r.model_id, r.endpoint_scope),
298
+ hasOverrides: Boolean(r.has_overrides),
299
+ // Which fields the local override actually replaces, so the model page
300
+ // can mark the individual inputs it edits (#551).
301
+ overrideFields: overriddenFieldNames(r.overrides_json),
302
+ // Why the switch is off: a model auto-disabled because the provider
303
+ // retired it upstream (410 / end of life, #634) is a different state from
304
+ // one the user turned off, and the dashboard says so. The reason is the
305
+ // provider's own (redacted) wording.
306
+ retiredUpstream: r.tombstone_source === 'upstream_eol',
307
+ retiredReason: r.tombstone_source === 'upstream_eol' ? (r.tombstone_reason ?? null) : null,
308
+ keyCount: keyCountMap.get(r.platform) ?? 0,
309
+ };
310
+ }));
311
+ });
312
+ const updateSchema = z.array(z.object({
313
+ modelDbId: z.number(),
314
+ priority: z.number(),
315
+ enabled: z.boolean(),
316
+ }));
317
+ /**
318
+ * Model ids that actually exist, so a stale row in a client's snapshot cannot
319
+ * turn an INSERT into a foreign-key failure (the old UPDATE simply matched
320
+ * nothing).
321
+ */
322
+ function knownModelIds(db) {
323
+ return new Set(db.prepare('SELECT id FROM models').all().map(m => m.id));
324
+ }
325
+ // Update fallback chain (full replace)
326
+ fallbackRouter.put('/', (req, res) => {
327
+ const parsed = updateSchema.safeParse(req.body);
328
+ if (!parsed.success) {
329
+ res.status(400).json({ error: { message: parsed.error.errors.map(e => e.message).join(', ') } });
330
+ return;
331
+ }
332
+ const db = getDb();
333
+ const activeProfileId = getActiveProfileId(db);
334
+ // Writing to the active chain UPSERTS: the row may not be in the chain yet,
335
+ // which is the normal state of every model in a hand-built one. The old
336
+ // UPDATE-only write is why an empty chain could never gain its first model —
337
+ // and why, having matched nothing, the edit was quietly redirected into the
338
+ // single global table shared by every chain (#1021).
339
+ const writeAll = activeProfileId != null
340
+ ? (() => {
341
+ const known = knownModelIds(db);
342
+ const upsert = db.prepare(`
343
+ INSERT INTO profile_models (profile_id, model_db_id, priority, enabled)
344
+ VALUES (?, ?, ?, ?)
345
+ ON CONFLICT(profile_id, model_db_id)
346
+ DO UPDATE SET priority = excluded.priority, enabled = excluded.enabled
347
+ `);
348
+ return db.transaction(() => {
349
+ for (const entry of parsed.data) {
350
+ if (!known.has(entry.modelDbId))
351
+ continue;
352
+ upsert.run(activeProfileId, entry.modelDbId, entry.priority, entry.enabled ? 1 : 0);
353
+ }
354
+ });
355
+ })()
356
+ : (() => {
357
+ const update = db.prepare('UPDATE fallback_config SET priority = ?, enabled = ? WHERE model_db_id = ?');
358
+ return db.transaction(() => {
359
+ for (const entry of parsed.data)
360
+ update.run(entry.priority, entry.enabled ? 1 : 0, entry.modelDbId);
361
+ });
362
+ })();
363
+ writeAll();
364
+ res.json({ success: true });
365
+ });
366
+ // `intelligence_rank` is scoped to each provider's own catalog — a provider's
367
+ // #1 model is not globally #1 (see issue #135: MiniMax's top model outranking
368
+ // Gemini Pro because both read "Intel #1"). `size_label` IS a cross-provider
369
+ // capability tier, so normalize on it first and use intelligence_rank only as
370
+ // an in-tier tiebreaker. Unknown labels sort last.
371
+ const INTELLIGENCE_TIER = "CASE m.size_label WHEN 'Frontier' THEN 1 WHEN 'Large' THEN 2 WHEN 'Medium' THEN 3 WHEN 'Small' THEN 4 ELSE 5 END";
372
+ // Sort presets — `orderBy` is selected from a fixed whitelist, never from
373
+ // user input directly, so the interpolation below is safe.
374
+ const SORT_PRESETS = {
375
+ intelligence: `${INTELLIGENCE_TIER} ASC, m.intelligence_rank ASC`,
376
+ speed: 'm.speed_rank ASC',
377
+ };
378
+ fallbackRouter.post('/sort/:preset', (req, res) => {
379
+ const preset = String(req.params.preset);
380
+ const db = getDb();
381
+ let models = [];
382
+ const activeProfileId = getActiveProfileId(db);
383
+ if (preset === 'budget') {
384
+ const allModels = db.prepare(`SELECT id, monthly_token_budget, tpd_limit FROM models`).all();
385
+ allModels.sort((a, b) => monthlyBudgetScore(b) - monthlyBudgetScore(a));
386
+ models = allModels.map(m => ({ id: m.id }));
387
+ }
388
+ else {
389
+ const orderBy = SORT_PRESETS[preset];
390
+ if (!orderBy) {
391
+ res.status(400).json({ error: { message: `Unknown preset: ${preset}. Use: intelligence, speed, budget` } });
392
+ return;
393
+ }
394
+ models = db.prepare(`SELECT m.id FROM models m ORDER BY ${orderBy}`).all();
395
+ }
396
+ // Same upsert story as the PUT above: a preset sorts the list the dashboard
397
+ // shows, which is the whole catalog seen through the chain, so a model the
398
+ // chain has not named yet gets its row written here too — switched OFF, the
399
+ // state it was displayed in. Sorting must never enable anything; a row
400
+ // already in the chain keeps whatever flag it had.
401
+ const reorder = activeProfileId != null
402
+ ? (() => {
403
+ const upsert = db.prepare(`
404
+ INSERT INTO profile_models (profile_id, model_db_id, priority, enabled)
405
+ VALUES (?, ?, ?, 0)
406
+ ON CONFLICT(profile_id, model_db_id) DO UPDATE SET priority = excluded.priority
407
+ `);
408
+ return db.transaction(() => {
409
+ for (let i = 0; i < models.length; i++)
410
+ upsert.run(activeProfileId, models[i].id, i + 1);
411
+ });
412
+ })()
413
+ : (() => {
414
+ const update = db.prepare('UPDATE fallback_config SET priority = ? WHERE model_db_id = ?');
415
+ return db.transaction(() => {
416
+ for (let i = 0; i < models.length; i++)
417
+ update.run(i + 1, models[i].id);
418
+ });
419
+ })();
420
+ reorder();
421
+ res.json({ success: true, preset });
422
+ });
423
+ // Token usage per model for the stacked bar
424
+ fallbackRouter.get('/token-usage', (_req, res) => {
425
+ const db = getDb();
426
+ // Get platforms that have enabled keys
427
+ const platforms = db.prepare(`
428
+ SELECT DISTINCT ak.platform
429
+ FROM api_keys ak
430
+ WHERE ak.enabled = 1
431
+ `).all();
432
+ const platformSet = new Set(platforms.map(p => p.platform));
433
+ // Check if there is an active profile
434
+ const settingRow = db.prepare(`SELECT value FROM settings WHERE key = 'active_profile_id'`).get();
435
+ const activeProfileId = settingRow ? (parseInt(settingRow.value) || null) : null;
436
+ // Verify active profile still exists
437
+ const activeProfile = activeProfileId
438
+ ? db.prepare('SELECT id FROM profiles WHERE id = ?').get(activeProfileId)
439
+ : null;
440
+ // Ordered by intelligence (rank 1 = smartest), not chain priority: the
441
+ // dashboard's monthly-budget bar and legend follow this order, and chain
442
+ // priority is seeded provider by provider, which read as "grouped by
443
+ // provider" (#1243). Priority stays as the tiebreaker within a rank.
444
+ let rawModels;
445
+ if (activeProfile) {
446
+ // Profile mode: use profile_models chain (all models in profile, checked against enabled)
447
+ rawModels = db.prepare(`
448
+ SELECT m.id as model_db_id, m.platform, m.model_id, m.display_name, m.monthly_token_budget,
449
+ pm.priority, pm.enabled, m.intelligence_rank,
450
+ m.rpm_limit, m.rpd_limit, m.tpm_limit, m.tpd_limit
451
+ FROM profile_models pm
452
+ JOIN models m ON m.id = pm.model_db_id
453
+ WHERE pm.profile_id = ? AND m.enabled = 1
454
+ ORDER BY m.intelligence_rank ASC, pm.priority ASC
455
+ `).all(activeProfileId);
456
+ }
457
+ else {
458
+ // Default mode: use fallback_config (only include enabled models)
459
+ rawModels = db.prepare(`
460
+ SELECT m.id as model_db_id, m.platform, m.model_id, m.display_name, m.monthly_token_budget,
461
+ fc.priority, fc.enabled, m.intelligence_rank,
462
+ m.rpm_limit, m.rpd_limit, m.tpm_limit, m.tpd_limit
463
+ FROM fallback_config fc
464
+ JOIN models m ON m.id = fc.model_db_id
465
+ WHERE m.enabled = 1
466
+ ORDER BY m.intelligence_rank ASC, fc.priority ASC
467
+ `).all();
468
+ }
469
+ // Build per-model breakdown (only platforms with keys), preserving enabled state
470
+ const usageRows = db.prepare(`
471
+ SELECT platform, model_id, COALESCE(SUM(input_tokens + output_tokens), 0) AS used
472
+ FROM requests
473
+ WHERE created_at >= datetime('now', 'start of month')
474
+ AND request_type = 'chat'
475
+ GROUP BY platform, model_id
476
+ `).all();
477
+ const usageByModel = new Map(usageRows.map(r => [`${r.platform}:${r.model_id}`, r.used]));
478
+ const keyCountMap = new Map(db.prepare("SELECT platform, COUNT(*) as count FROM api_keys WHERE enabled = 1 AND status IN ('healthy', 'unknown') GROUP BY platform").all()
479
+ .map(k => [k.platform, k.count]));
480
+ const modelBudgets = rawModels
481
+ .filter(m => platformSet.has(m.platform))
482
+ .map(m => {
483
+ const keys = Math.max(1, keyCountMap.get(m.platform) ?? 1);
484
+ return {
485
+ modelDbId: m.model_db_id,
486
+ displayName: m.display_name,
487
+ platform: m.platform,
488
+ modelId: m.model_id,
489
+ intelligenceRank: m.intelligence_rank,
490
+ budget: parseBudget(m.monthly_token_budget) * keys,
491
+ used: usageByModel.get(`${m.platform}:${m.model_id}`) ?? 0,
492
+ enabled: m.enabled === 1,
493
+ rpmLimit: m.rpm_limit,
494
+ rpdLimit: m.rpd_limit,
495
+ tpmLimit: m.tpm_limit,
496
+ tpdLimit: m.tpd_limit,
497
+ };
498
+ });
499
+ // Total budget counts all models (both enabled and disabled — they contribute to the pool)
500
+ const totalBudget = modelBudgets.reduce((s, m) => s + m.budget, 0);
501
+ const totalUsed = modelBudgets.reduce((s, m) => s + m.used, 0);
502
+ res.json({
503
+ totalBudget,
504
+ totalUsed,
505
+ models: modelBudgets,
506
+ });
507
+ });
508
+ // Per-model time-window rate-limit usage (RPM/RPD/TPM: used vs limit), for the
509
+ // dashboard's remaining-quota display (#876). The monthly-budget metric says
510
+ // nothing about windowed limits, so this surfaces what the router actually
511
+ // enforces.
512
+ //
513
+ // Which key's numbers to report matters. The badge answers "how close is this
514
+ // model to being unroutable", so it has to follow the key the router would pick
515
+ // NEXT, not the worst key on the account: a platform with one exhausted key and
516
+ // one idle key routes fine, and reporting the exhausted one paints a red badge
517
+ // over a model that is wide open. So we mirror the router's key eligibility
518
+ // (`selectKeyForModel`) — enabled + healthy/unknown, model scope allows this
519
+ // model (#657), and for a custom model the key must belong to the model's own
520
+ // endpoint (#212, #619) — and then report the ELIGIBLE key with the most
521
+ // headroom (lowest used/limit ratio across its windows), which is the key the
522
+ // router lands on once the busier ones fail their gates.
523
+ //
524
+ // Cost: the naive shape is three SQL counts per model × key, which is thousands
525
+ // of statements on a real catalog. All of it comes from one table, so the whole
526
+ // page is a single grouped scan of `rate_limit_usage` over the last day.
527
+ const RATE_LIMIT_MINUTE_MS = 60 * 1000;
528
+ const RATE_LIMIT_DAY_MS = 24 * 60 * RATE_LIMIT_MINUTE_MS;
529
+ const NO_USAGE = { rpm: 0, rpd: 0, tpm: 0 };
530
+ /** used/limit for one window, or null when the model has no such limit. */
531
+ function windowRatio(used, limit) {
532
+ if (limit == null || limit <= 0)
533
+ return null;
534
+ return used / limit;
535
+ }
536
+ /** The busiest window of one key: what would reject this key's next request. */
537
+ function keyPressure(usage, limits) {
538
+ let worst = 0;
539
+ for (const r of [
540
+ windowRatio(usage.rpm, limits.rpm),
541
+ windowRatio(usage.rpd, limits.rpd),
542
+ windowRatio(usage.tpm, limits.tpm),
543
+ ]) {
544
+ if (r !== null && r > worst)
545
+ worst = r;
546
+ }
547
+ return worst;
548
+ }
549
+ fallbackRouter.get('/rate-limit-usage', (_req, res) => {
550
+ const db = getDb();
551
+ const now = Date.now();
552
+ const models = db.prepare(`
553
+ SELECT id AS model_db_id, platform, model_id, key_id, rpm_limit, rpd_limit, tpm_limit
554
+ FROM models
555
+ WHERE enabled = 1
556
+ `).all();
557
+ // Every key row once: the routable pool needs enabled+healthy rows, while the
558
+ // custom-endpoint pool is keyed on base_url and has to resolve a model's own
559
+ // key_id even when that row is disabled.
560
+ const allKeys = db.prepare(`
561
+ SELECT id, platform, base_url, model_scope_json, enabled, status FROM api_keys
562
+ `).all();
563
+ const baseUrlByKeyId = new Map(allKeys.map(k => [k.id, k.base_url]));
564
+ const routableByPlatform = new Map();
565
+ for (const k of allKeys) {
566
+ if (k.enabled !== 1 || (k.status !== 'healthy' && k.status !== 'unknown'))
567
+ continue;
568
+ const list = routableByPlatform.get(k.platform) ?? [];
569
+ list.push({ id: k.id, baseUrl: k.base_url, scope: parseModelScope(k.model_scope_json) });
570
+ routableByPlatform.set(k.platform, list);
571
+ }
572
+ // One grouped scan replaces three counts per model × key. Same windows the
573
+ // ratelimit service enforces: a sliding minute for RPM/TPM, a sliding day for
574
+ // RPD. Rows older than a day are pruned on write, but the WHERE keeps this
575
+ // correct even if a prune has not run yet.
576
+ const usageRows = db.prepare(`
577
+ SELECT platform, model_id, key_id,
578
+ SUM(CASE WHEN kind = 'request' AND created_at_ms > ? THEN 1 ELSE 0 END) AS rpm_used,
579
+ SUM(CASE WHEN kind = 'request' THEN 1 ELSE 0 END) AS rpd_used,
580
+ SUM(CASE WHEN kind = 'tokens' AND created_at_ms > ? THEN tokens ELSE 0 END) AS tpm_used
581
+ FROM rate_limit_usage
582
+ WHERE created_at_ms > ?
583
+ GROUP BY platform, model_id, key_id
584
+ `).all(now - RATE_LIMIT_MINUTE_MS, now - RATE_LIMIT_MINUTE_MS, now - RATE_LIMIT_DAY_MS);
585
+ const usageByKey = new Map();
586
+ for (const u of usageRows) {
587
+ usageByKey.set(`${u.platform}\u0000${u.model_id}\u0000${u.key_id}`, {
588
+ rpm: u.rpm_used, rpd: u.rpd_used, tpm: u.tpm_used,
589
+ });
590
+ }
591
+ const rows = models.map(m => {
592
+ const limits = { rpm: m.rpm_limit, rpd: m.rpd_limit, tpm: m.tpm_limit };
593
+ const pool = routableByPlatform.get(m.platform) ?? [];
594
+ // A custom model belongs to one endpoint; only that endpoint's credentials
595
+ // can serve it. Legacy rows (key_id NULL) keep the any-key match.
596
+ const endpointBaseUrl = m.platform === 'custom' && m.key_id != null
597
+ ? baseUrlByKeyId.get(m.key_id) ?? null
598
+ : null;
599
+ let best = null;
600
+ let bestPressure = Infinity;
601
+ for (const k of pool) {
602
+ if (!scopeAllows(k.scope, m.model_id))
603
+ continue;
604
+ if (m.platform === 'custom' && m.key_id != null) {
605
+ if (endpointBaseUrl == null ? k.id !== m.key_id : k.baseUrl !== endpointBaseUrl)
606
+ continue;
607
+ }
608
+ const usage = usageByKey.get(`${m.platform}\u0000${m.model_id}\u0000${k.id}`) ?? NO_USAGE;
609
+ const pressure = keyPressure(usage, limits);
610
+ if (pressure < bestPressure) {
611
+ bestPressure = pressure;
612
+ best = usage;
613
+ }
614
+ }
615
+ // No routable key at all: the model cannot be served, and a usage number
616
+ // would be fiction. Report no windows so the dashboard shows no badge.
617
+ if (!best) {
618
+ return { modelDbId: m.model_db_id, platform: m.platform, modelId: m.model_id, rpm: null, rpd: null, tpm: null };
619
+ }
620
+ return {
621
+ modelDbId: m.model_db_id,
622
+ platform: m.platform,
623
+ modelId: m.model_id,
624
+ rpm: m.rpm_limit != null ? { used: best.rpm, limit: m.rpm_limit } : null,
625
+ rpd: m.rpd_limit != null ? { used: best.rpd, limit: m.rpd_limit } : null,
626
+ tpm: m.tpm_limit != null ? { used: best.tpm, limit: m.tpm_limit } : null,
627
+ };
628
+ });
629
+ res.json({ generatedAtMs: now, rows });
630
+ });
631
+ //# sourceMappingURL=fallback.js.map