@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,789 @@
1
+ import { z } from 'zod';
2
+ import { routePinnedModel, routeRequest, getOrderedFusionChain, resolveFusionCandidate, recordRateLimitHit, recordSuccess, } from './router.js';
3
+ import { recordRequest, recordTokens, setCooldown, getCooldownDurationForLimit, getCooldownDecisionForLimit, getPaymentRequiredCooldownMs, getModelForbiddenCooldownMs, } from './ratelimit.js';
4
+ import { logRequest } from '../lib/request-log.js';
5
+ import { isRetryableError, isRateLimitSignal, isPaymentRequiredError, isModelNotFoundError, isModelAccessForbiddenError, } from '../lib/error-classify.js';
6
+ import { contentToString, stripImagesFromMessages } from '../lib/content.js';
7
+ import { sanitizeProviderErrorMessage } from '../lib/error-redaction.js';
8
+ import { getSetting, setSetting } from '../db/index.js';
9
+ import { routeOutputBudget } from '../lib/output-cap.js';
10
+ // The virtual model id that triggers multi-model synthesis. Mirrors how
11
+ // `auto` is a virtual id the router intercepts (see routes/proxy.ts).
12
+ export const FUSION_MODEL_ID = 'fusion';
13
+ export function isFusionModel(modelId) {
14
+ if (!modelId)
15
+ return false;
16
+ const lower = modelId.toLowerCase();
17
+ return lower === FUSION_MODEL_ID || lower.startsWith(`${FUSION_MODEL_ID}:`);
18
+ }
19
+ // Tag every panel/judge sub-call with this in the request log so fusion traffic
20
+ // is attributable in analytics exactly like a pinned model would be.
21
+ const FUSION_TAG = 'fusion';
22
+ // Panel sizing. Default is deliberately ABOVE OpenRouter's 3-model default —
23
+ // the whole point of running on free tiers is we can afford a wider, more
24
+ // diverse panel. Both are operator-overridable via settings so a deployment
25
+ // can dial the token multiplier up or down without a code change.
26
+ const DEFAULT_PANEL_K = 4;
27
+ const HARD_MAX_PANEL_K = 8; // ceiling even an explicit panel can't exceed
28
+ // A panel of fewer than this many *successful* answers isn't worth a judge
29
+ // pass — with one survivor we just return it directly.
30
+ const SYNTHESIS_QUORUM = 2;
31
+ // Per-slot key-rotation budget: a slot tries at most this many keys of its
32
+ // pinned model before it's dropped. Small — a model with every key cooled down
33
+ // should fail fast, not stall the whole panel.
34
+ const MAX_SLOT_ATTEMPTS = 4;
35
+ // Judge dispatch walks the normal auto chain; give it room to fail over.
36
+ const MAX_JUDGE_ATTEMPTS = 6;
37
+ // Tool calls are actions, not independent prose. Running a whole Fusion panel
38
+ // for them is both unsafe (several models can propose the same side effect)
39
+ // and needlessly slow (one stalled provider holds Promise.allSettled open).
40
+ // Keep each sequential candidate bounded well below the provider's generous
41
+ // cold-start timeout; a slower candidate can still be reached through the
42
+ // normal ordered fallback list after this one is abandoned.
43
+ const DEFAULT_TOOL_CALL_TIMEOUT_MS = 12_000;
44
+ const MAX_TOOL_CALL_TIMEOUT_MS = 120_000;
45
+ function intSetting(key, fallback) {
46
+ const raw = getSetting(key);
47
+ if (!raw)
48
+ return fallback;
49
+ const n = parseInt(raw, 10);
50
+ return Number.isFinite(n) && n > 0 ? n : fallback;
51
+ }
52
+ function toolCallTimeoutMs() {
53
+ return Math.min(intSetting('fusion_tool_timeout_ms', DEFAULT_TOOL_CALL_TIMEOUT_MS), MAX_TOOL_CALL_TIMEOUT_MS);
54
+ }
55
+ /**
56
+ * Give one tool-bearing panel candidate its own deadline while preserving the
57
+ * caller's disconnect signal. The timer is cancelled as soon as the candidate
58
+ * settles; aborting a request is deliberately scoped to this candidate so a
59
+ * later fallback can still run.
60
+ */
61
+ function withToolCallDeadline(options) {
62
+ const controller = new AbortController();
63
+ const timeoutMs = toolCallTimeoutMs();
64
+ const timer = setTimeout(() => {
65
+ controller.abort(new Error(`fusion tool call timed out after ${timeoutMs}ms`));
66
+ }, timeoutMs);
67
+ timer.unref?.();
68
+ const signal = options.signal
69
+ ? AbortSignal.any([options.signal, controller.signal])
70
+ : controller.signal;
71
+ return {
72
+ options: { ...options, signal },
73
+ cancel: () => clearTimeout(timer),
74
+ };
75
+ }
76
+ function panelDefaultK() {
77
+ return Math.min(intSetting('fusion_default_k', DEFAULT_PANEL_K), panelMaxK());
78
+ }
79
+ function panelMaxK() {
80
+ return Math.min(intSetting('fusion_max_k', HARD_MAX_PANEL_K), HARD_MAX_PANEL_K);
81
+ }
82
+ export const fusionConfigSchema = z.object({
83
+ // Explicit panel: the exact model ids the client wants to fuse. Any unknown
84
+ // / disabled ids are dropped (and reported in x_fusion) rather than failing
85
+ // the whole request — a panel is robust to missing members by design.
86
+ models: z.array(z.string().min(1)).optional(),
87
+ // Auto-panel size when `models` is omitted. Clamped to [1, fusion_max_k].
88
+ k: z.number().int().positive().optional(),
89
+ // Judge/synthesizer model id. Omit → the top-ranked available model.
90
+ judge: z.string().min(1).optional(),
91
+ // 'synthesize' (default): one blended answer. 'best_of': skip the judge,
92
+ // return the longest single panel answer (cheaper; no +1 judge call).
93
+ strategy: z.enum(['synthesize', 'best_of']).optional(),
94
+ // Attach the per-model panel answers + judge metadata under `x_fusion`.
95
+ expose_panel: z.boolean().optional(),
96
+ });
97
+ export function getFusionMaxK() {
98
+ return panelMaxK();
99
+ }
100
+ // ── Saved fusion config (dashboard-managed default) ─────────────────────────
101
+ // Persisted in the settings table under `fusion_config`. A request's inline
102
+ // `fusion` field always overrides the saved default field-by-field, so the UI
103
+ // sets the baseline and any client can still tweak per call. `mode` is the
104
+ // "Both, user-toggleable" toggle: 'auto' picks a diverse panel off the
105
+ // Fallback Chain (ignoring `models`); 'explicit' uses the saved `models` list.
106
+ const SAVED_FUSION_KEY = 'fusion_config';
107
+ export const savedFusionConfigSchema = z.object({
108
+ mode: z.enum(['auto', 'explicit']),
109
+ models: z.array(z.string().min(1)).default([]),
110
+ judge: z.string().min(1).nullable().default(null),
111
+ k: z.number().int().positive(),
112
+ strategy: z.enum(['synthesize', 'best_of']),
113
+ expose_panel: z.boolean(),
114
+ });
115
+ function defaultSavedConfig() {
116
+ return { mode: 'auto', models: [], judge: null, k: panelDefaultK(), strategy: 'synthesize', expose_panel: false };
117
+ }
118
+ export function getSavedFusionConfig() {
119
+ const raw = getSetting(SAVED_FUSION_KEY);
120
+ if (raw) {
121
+ try {
122
+ const parsed = savedFusionConfigSchema.safeParse(JSON.parse(raw));
123
+ if (parsed.success)
124
+ return parsed.data;
125
+ }
126
+ catch { /* corrupt setting → fall through to default */ }
127
+ }
128
+ return defaultSavedConfig();
129
+ }
130
+ export function setSavedFusionConfig(input) {
131
+ const maxK = panelMaxK();
132
+ const normalized = {
133
+ mode: input.mode,
134
+ // De-dup the explicit panel and clamp to the operator cap.
135
+ models: [...new Set(input.models)].slice(0, maxK),
136
+ judge: input.judge && input.judge.trim() ? input.judge.trim() : null,
137
+ k: Math.min(Math.max(input.k, 1), maxK),
138
+ strategy: input.strategy,
139
+ expose_panel: input.expose_panel,
140
+ };
141
+ setSetting(SAVED_FUSION_KEY, JSON.stringify(normalized));
142
+ return normalized;
143
+ }
144
+ export function pruneUnavailableSavedFusionConfig() {
145
+ const raw = getSetting(SAVED_FUSION_KEY);
146
+ if (!raw)
147
+ return getSavedFusionConfig();
148
+ const saved = getSavedFusionConfig();
149
+ const models = saved.models.filter(savedModelId => resolveFusionCandidate(savedModelId) != null);
150
+ const judge = saved.judge && resolveFusionCandidate(saved.judge) != null ? saved.judge : null;
151
+ if (models.length === saved.models.length && judge === saved.judge)
152
+ return saved;
153
+ return setSavedFusionConfig({
154
+ ...saved,
155
+ models,
156
+ judge,
157
+ });
158
+ }
159
+ /**
160
+ * Merge a request's inline fusion config over the saved dashboard default.
161
+ * Each field present on the request wins; otherwise the saved default applies.
162
+ * An explicit panel only comes from the saved config when its mode is
163
+ * 'explicit' — in 'auto' mode the saved `models` are ignored so the panel is
164
+ * picked fresh off the Fallback Chain.
165
+ */
166
+ export function resolveEffectiveConfig(req) {
167
+ const saved = getSavedFusionConfig();
168
+ const models = (req.models && req.models.length > 0)
169
+ ? req.models
170
+ : (saved.mode === 'explicit' && saved.models.length > 0 ? saved.models : undefined);
171
+ return {
172
+ models,
173
+ k: req.k ?? saved.k,
174
+ judge: req.judge ?? saved.judge ?? undefined,
175
+ strategy: req.strategy ?? saved.strategy,
176
+ expose_panel: req.expose_panel ?? saved.expose_panel,
177
+ };
178
+ }
179
+ const ZERO_USAGE = { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
180
+ function addUsage(a, b) {
181
+ if (!b)
182
+ return a;
183
+ return {
184
+ prompt_tokens: a.prompt_tokens + (b.prompt_tokens ?? 0),
185
+ completion_tokens: a.completion_tokens + (b.completion_tokens ?? 0),
186
+ total_tokens: a.total_tokens + (b.total_tokens ?? 0),
187
+ };
188
+ }
189
+ /**
190
+ * Run one model call with retry across keys/models, doing the same accounting
191
+ * (request counts, token usage, success/penalty, cooldowns, request log) the
192
+ * normal proxy path does — just tagged as fusion traffic. `getRoute` decides
193
+ * WHICH model is tried: a pinned-model closure for a panel slot (never
194
+ * substitutes), or the auto-router for the judge (falls over across the chain).
195
+ */
196
+ async function runModelCall(getRoute, messages, options, estimatedTokens, maxAttempts) {
197
+ const skipKeys = new Set();
198
+ const skipModels = new Set();
199
+ let lastError;
200
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
201
+ let route;
202
+ try {
203
+ route = getRoute(skipKeys, skipModels);
204
+ }
205
+ catch (err) {
206
+ // routeRequest throws when the whole chain is exhausted (judge path).
207
+ lastError = sanitizeProviderErrorMessage(err?.message);
208
+ break;
209
+ }
210
+ if (!route)
211
+ break;
212
+ const startedAt = Date.now();
213
+ const routeOpts = { ...options, contextBudget: routeOutputBudget(route, estimatedTokens) };
214
+ try {
215
+ const result = await route.provider.chatCompletion(route.apiKey, messages, route.modelId, routeOpts);
216
+ const choice = result.choices?.[0];
217
+ const text = contentToString(choice?.message?.content ?? '');
218
+ const toolCalls = choice?.message?.tool_calls;
219
+ const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
220
+ if (!text && !hasToolCalls) {
221
+ // Empty completion — fail over like the main proxy path does.
222
+ logRequest(route.platform, route.modelId, route.keyId, 'error', 0, 0, Date.now() - startedAt, 'empty completion (fusion)', null, FUSION_TAG, null, 'http');
223
+ skipKeys.add(`${route.platform}:${route.modelId}:${route.keyId}`);
224
+ setCooldown(route.platform, route.modelId, route.keyId, getCooldownDurationForLimit(route.platform, route.modelId, route.keyId, { rpd: route.rpdLimit, tpd: route.tpdLimit }));
225
+ recordRateLimitHit(route.modelDbId);
226
+ lastError = `empty completion from ${route.displayName}`;
227
+ continue;
228
+ }
229
+ const usage = result.usage ?? ZERO_USAGE;
230
+ recordRequest(route.platform, route.modelId, route.keyId);
231
+ recordTokens(route.platform, route.modelId, route.keyId, usage.total_tokens);
232
+ recordSuccess(route.modelDbId);
233
+ logRequest(route.platform, route.modelId, route.keyId, 'success', usage.prompt_tokens ?? 0, usage.completion_tokens ?? 0, Date.now() - startedAt, null, null, FUSION_TAG, null, 'http');
234
+ return {
235
+ ok: true,
236
+ route,
237
+ text,
238
+ toolCalls: hasToolCalls ? toolCalls : undefined,
239
+ rawChoice: hasToolCalls ? choice : undefined,
240
+ usage,
241
+ };
242
+ }
243
+ catch (err) {
244
+ const safe = sanitizeProviderErrorMessage(err?.message);
245
+ logRequest(route.platform, route.modelId, route.keyId, 'error', 0, 0, Date.now() - startedAt, safe, null, FUSION_TAG, null, 'http');
246
+ lastError = safe;
247
+ if (isRetryableError(err)) {
248
+ if (isModelNotFoundError(err) || isModelAccessForbiddenError(err))
249
+ skipModels.add(route.modelDbId);
250
+ skipKeys.add(`${route.platform}:${route.modelId}:${route.keyId}`);
251
+ // Provenance mirrors cooldownDecisionForError (lib/fallback-loop.ts):
252
+ // credit/tier benches are never probe-recovered, Retry-After-backed
253
+ // ones only when our heuristic outlasted the provider's own retry time.
254
+ const decision = isPaymentRequiredError(err)
255
+ ? { durationMs: getPaymentRequiredCooldownMs(), source: 'credit' }
256
+ : isModelAccessForbiddenError(err)
257
+ ? { durationMs: getModelForbiddenCooldownMs(), source: 'tier' }
258
+ : getCooldownDecisionForLimit(route.platform, route.modelId, route.keyId, { rpd: route.rpdLimit, tpd: route.tpdLimit }, err.retryAfterMs, { quotaSignal: isRateLimitSignal(err) });
259
+ setCooldown(route.platform, route.modelId, route.keyId, decision.durationMs, decision.source);
260
+ recordRateLimitHit(route.modelDbId);
261
+ continue;
262
+ }
263
+ // Non-retryable (auth, validation) — this slot/judge is done.
264
+ break;
265
+ }
266
+ finally {
267
+ // Panel slots run concurrently, so a leaked lease here would starve the
268
+ // rest of the panel of its own keys' concurrency budget. The route object
269
+ // stays usable as a data carrier after release.
270
+ route.release?.();
271
+ }
272
+ }
273
+ return { ok: false, error: lastError ?? 'no available key for model' };
274
+ }
275
+ /**
276
+ * Like runModelCall, but STREAMS the judge's answer so the client sees it
277
+ * written live instead of waiting for the whole synthesis. Failover only works
278
+ * before the first byte (`started`): once we've forwarded text to the client we
279
+ * can't cleanly switch models, so a mid-stream error returns the partial answer.
280
+ * Usage is estimated (streaming rarely echoes a usage block).
281
+ */
282
+ async function runJudgeStreaming(getRoute, messages, options, estimatedTokens, maxAttempts, cb) {
283
+ const skipKeys = new Set();
284
+ const skipModels = new Set();
285
+ let lastError;
286
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
287
+ let route;
288
+ try {
289
+ route = getRoute(skipKeys, skipModels);
290
+ }
291
+ catch (err) {
292
+ lastError = sanitizeProviderErrorMessage(err?.message);
293
+ break;
294
+ }
295
+ if (!route)
296
+ break;
297
+ const startedAt = Date.now();
298
+ const routeOpts = { ...options, contextBudget: routeOutputBudget(route, estimatedTokens) };
299
+ let text = '';
300
+ let started = false;
301
+ try {
302
+ for await (const chunk of route.provider.streamChatCompletion(route.apiKey, messages, route.modelId, routeOpts)) {
303
+ const delta = chunk?.choices?.[0]?.delta?.content;
304
+ if (typeof delta === 'string' && delta.length > 0) {
305
+ if (!started) {
306
+ started = true;
307
+ cb.onStart?.({ platform: route.platform, model: route.modelId });
308
+ }
309
+ text += delta;
310
+ cb.onDelta?.(delta);
311
+ }
312
+ }
313
+ if (!text) {
314
+ logRequest(route.platform, route.modelId, route.keyId, 'error', 0, 0, Date.now() - startedAt, 'empty completion (fusion judge)', null, FUSION_TAG, null, 'http');
315
+ skipKeys.add(`${route.platform}:${route.modelId}:${route.keyId}`);
316
+ setCooldown(route.platform, route.modelId, route.keyId, getCooldownDurationForLimit(route.platform, route.modelId, route.keyId, { rpd: route.rpdLimit, tpd: route.tpdLimit }));
317
+ recordRateLimitHit(route.modelDbId);
318
+ lastError = `empty judge completion from ${route.displayName}`;
319
+ continue;
320
+ }
321
+ const out = Math.ceil(text.length / 4);
322
+ const usage = { prompt_tokens: estimatedTokens, completion_tokens: out, total_tokens: estimatedTokens + out };
323
+ recordRequest(route.platform, route.modelId, route.keyId);
324
+ recordTokens(route.platform, route.modelId, route.keyId, usage.total_tokens);
325
+ recordSuccess(route.modelDbId);
326
+ logRequest(route.platform, route.modelId, route.keyId, 'success', estimatedTokens, out, Date.now() - startedAt, null, null, FUSION_TAG, null, 'http');
327
+ return { ok: true, route, text, usage };
328
+ }
329
+ catch (err) {
330
+ const safe = sanitizeProviderErrorMessage(err?.message);
331
+ logRequest(route.platform, route.modelId, route.keyId, 'error', 0, 0, Date.now() - startedAt, safe, null, FUSION_TAG, null, 'http');
332
+ lastError = safe;
333
+ // Already streamed bytes — can't fail over without duplicating output.
334
+ // Keep whatever the client already received.
335
+ if (started) {
336
+ if (text) {
337
+ const out = Math.ceil(text.length / 4);
338
+ return { ok: true, route, text, usage: { prompt_tokens: estimatedTokens, completion_tokens: out, total_tokens: estimatedTokens + out } };
339
+ }
340
+ break;
341
+ }
342
+ if (isRetryableError(err)) {
343
+ if (isModelNotFoundError(err) || isModelAccessForbiddenError(err))
344
+ skipModels.add(route.modelDbId);
345
+ skipKeys.add(`${route.platform}:${route.modelId}:${route.keyId}`);
346
+ // Same provenance mapping as the non-stream path above.
347
+ const decision = isPaymentRequiredError(err)
348
+ ? { durationMs: getPaymentRequiredCooldownMs(), source: 'credit' }
349
+ : isModelAccessForbiddenError(err)
350
+ ? { durationMs: getModelForbiddenCooldownMs(), source: 'tier' }
351
+ : getCooldownDecisionForLimit(route.platform, route.modelId, route.keyId, { rpd: route.rpdLimit, tpd: route.tpdLimit }, err.retryAfterMs, { quotaSignal: isRateLimitSignal(err) });
352
+ setCooldown(route.platform, route.modelId, route.keyId, decision.durationMs, decision.source);
353
+ recordRateLimitHit(route.modelDbId);
354
+ continue;
355
+ }
356
+ break;
357
+ }
358
+ finally {
359
+ route.release?.();
360
+ }
361
+ }
362
+ return { ok: false, error: lastError ?? 'no available key for judge' };
363
+ }
364
+ /**
365
+ * Collapse a provider-specific model id to its rough model FAMILY: drop the
366
+ * provider prefix (everything up to the last '/') and any ':tag'/':free' suffix,
367
+ * so e.g. `qwen/qwen3-coder:free` and `qwen3-coder:480b` map to one family.
368
+ * Deliberately a SIMPLE heuristic, not a maintained alias map — cross-provider
369
+ * id naming drifts constantly, so we only want a good-enough signal to avoid
370
+ * stacking the panel with the same model served under two providers.
371
+ */
372
+ export function familyKey(modelId) {
373
+ return modelId.toLowerCase().replace(/^.*\//, '').replace(/:.*$/, '');
374
+ }
375
+ /**
376
+ * Order a strategy-sorted servable chain for panel diversity along TWO axes:
377
+ * provider (platform) AND model family. Fusion's value comes from genuinely
378
+ * DIFFERENT perspectives (issue #326 spike: a panel only beats the best single
379
+ * model when its members actually disagree); the same model family served by
380
+ * two providers is platform-distinct but perspective-redundant — one viewpoint
381
+ * filling two slots.
382
+ *
383
+ * Two stable passes, each preserving the routing-strategy order it's handed:
384
+ * 1. Provider-first (the existing invariant): one model per distinct platform
385
+ * before doubling up, so the panel spans different backends / failure
386
+ * domains.
387
+ * 2. Family-dedup: within that provider-diverse order, demote any model whose
388
+ * family already appeared — a fresh family takes the slot first, and the
389
+ * redundant copy sinks to the refill tail rather than being dropped.
390
+ * Pure function of its input (unit-tested directly).
391
+ */
392
+ export function diversifyChain(ordered) {
393
+ // Pass 1 — provider diversity first, strategy order within.
394
+ const seenPlatform = new Set();
395
+ const platformFirst = [];
396
+ const platformRest = [];
397
+ for (const c of ordered) {
398
+ if (seenPlatform.has(c.platform))
399
+ platformRest.push(c);
400
+ else {
401
+ seenPlatform.add(c.platform);
402
+ platformFirst.push(c);
403
+ }
404
+ }
405
+ // Pass 2 — demote same-family duplicates so a fresh perspective wins the slot.
406
+ const seenFamily = new Set();
407
+ const fresh = [];
408
+ const dupFamily = [];
409
+ for (const c of [...platformFirst, ...platformRest]) {
410
+ const fam = familyKey(c.modelId);
411
+ if (seenFamily.has(fam))
412
+ dupFamily.push(c);
413
+ else {
414
+ seenFamily.add(fam);
415
+ fresh.push(c);
416
+ }
417
+ }
418
+ return [...fresh, ...dupFamily];
419
+ }
420
+ /**
421
+ * Build the panel plus a refill queue:
422
+ * - `panel` — the K models to run first (explicit list, or provider-diverse
423
+ * picks off the strategy-sorted chain).
424
+ * - `overflow` — the next servable models from the chain, used to refill a slot
425
+ * when a panel model fails outright (auto mode only; an explicit
426
+ * panel is run as-is with no substitution).
427
+ * Diversity = distinct provider AND model family first (see diversifyChain), so
428
+ * both the panel and its refills span genuinely different perspectives before
429
+ * doubling up on either axis.
430
+ */
431
+ export function selectPanel(config, requirements) {
432
+ const maxK = panelMaxK();
433
+ if (config.models && config.models.length > 0) {
434
+ const panel = [];
435
+ const dropped = [];
436
+ const seen = new Set();
437
+ for (const id of config.models) {
438
+ if (panel.length >= maxK) {
439
+ dropped.push(`${id} (over cap of ${maxK})`);
440
+ continue;
441
+ }
442
+ const cand = resolveFusionCandidate(id);
443
+ if (!cand) {
444
+ dropped.push(`${id} (unknown or disabled)`);
445
+ continue;
446
+ }
447
+ if (requirements.requireTools && !cand.supportsTools) {
448
+ dropped.push(`${id} (no tool-calling support)`);
449
+ continue;
450
+ }
451
+ if (requirements.requireVision && !cand.supportsVision) {
452
+ dropped.push(`${id} (no vision support)`);
453
+ continue;
454
+ }
455
+ if (seen.has(cand.modelDbId))
456
+ continue; // de-dup repeats
457
+ seen.add(cand.modelDbId);
458
+ panel.push(cand);
459
+ }
460
+ // Explicit panel: the user named exact models, so don't substitute others.
461
+ return { panel, overflow: [], dropped };
462
+ }
463
+ const k = Math.min(Math.max(config.k ?? panelDefaultK(), 1), maxK);
464
+ // Size-aware: the chain excludes models that cannot hold a prompt this large,
465
+ // so a too-small model never claims a slot it is guaranteed to fail.
466
+ const ordered = getOrderedFusionChain(requirements.estimatedTokens)
467
+ .filter(c => !requirements.requireTools || c.supportsTools)
468
+ .filter(c => !requirements.requireVision || c.supportsVision);
469
+ // Diversity-first ordering of the whole servable chain along provider AND
470
+ // model family (see diversifyChain). The first K are the panel; the rest are
471
+ // refill candidates that stay as diverse as possible.
472
+ const full = diversifyChain(ordered);
473
+ const panel = full.slice(0, k);
474
+ // Cap refills so a run of failures can't sweep the entire catalog: try at most
475
+ // K extra models (≤ 2K dispatches total).
476
+ const overflow = full.slice(k, k * 2);
477
+ return { panel, overflow, dropped: [] };
478
+ }
479
+ // Synthesis judge instructions. Anonymized "Response N" so the judge weighs
480
+ // content, not model reputation; told to produce the final answer directly with
481
+ // no meta-commentary about merging.
482
+ const JUDGE_SYSTEM_PROMPT = 'You are the final author of a single answer. Several AI assistants each independently answered the user\'s most recent message; their answers are provided below, anonymized as "Response 1", "Response 2", etc. ' +
483
+ 'IMPORTANT: the user will NEVER see any of those individual responses — they only ever see what you write — so your answer must be COMPLETE and fully STAND-ALONE on its own. ' +
484
+ 'Take the best parts of every response, combine the correct and most useful ideas into one coherent whole, resolve any contradictions by reasoning about which is actually right (do not just average or list options), and fill in anything they all missed. ' +
485
+ 'Then REWRITE it all from scratch, in your own words, as one clear, well-structured, self-contained answer that makes complete sense by itself. ' +
486
+ 'Do not mention that other answers exist, do not refer to "Response 1/2/3", do not compare the responses, and do not describe your process — just deliver the final, authoritative answer directly to the user.';
487
+ export function buildJudgeMessages(original, answers, stripImages = false) {
488
+ const ok = answers.filter(a => a.status === 'ok' && a.content);
489
+ const panelBlock = ok
490
+ .map((a, i) => `--- Response ${i + 1} ---\n${a.content}`)
491
+ .join('\n\n');
492
+ // Keep the full original conversation for context, then append the candidate
493
+ // answers + synthesis instruction as a final user turn. The judge system
494
+ // prompt leads so it frames everything that follows.
495
+ return [
496
+ { role: 'system', content: JUDGE_SYSTEM_PROMPT },
497
+ ...(stripImages ? stripImagesFromMessages(original) : original),
498
+ {
499
+ role: 'user',
500
+ content: `Here are ${ok.length} independent answers to my most recent message:\n\n${panelBlock}\n\n` +
501
+ 'Take the best parts of these, then rewrite one complete, self-contained answer to my most recent message in your own words. ' +
502
+ 'I will only see your answer — not these — so do not reference them.',
503
+ },
504
+ ];
505
+ }
506
+ /**
507
+ * Orchestrate a fusion request end to end: select the panel, fan out in
508
+ * parallel, then synthesize survivors with a judge (or best-of). Throws a
509
+ * FusionError when nothing usable comes back so the route can map it to an
510
+ * HTTP status.
511
+ */
512
+ export class FusionError extends Error {
513
+ status;
514
+ constructor(message, status) {
515
+ super(message);
516
+ this.status = status;
517
+ }
518
+ }
519
+ export async function runFusion(params) {
520
+ const { messages, options, estimatedTokens, hooks, vision = false } = params;
521
+ // Apply the dashboard-saved default; the request's inline fusion field (if
522
+ // any) has already-merged precedence field-by-field.
523
+ const config = resolveEffectiveConfig(params.config);
524
+ const strategy = config.strategy ?? 'synthesize';
525
+ const requireTools = (options.tools?.length ?? 0) > 0;
526
+ const requiresToolCall = options.tool_choice === 'required'
527
+ || (typeof options.tool_choice === 'object' && options.tool_choice !== null);
528
+ const requiredToolName = typeof options.tool_choice === 'object'
529
+ ? options.tool_choice.function.name
530
+ : undefined;
531
+ // `tool_choice=auto` (or an omitted choice) still allows a model to emit a
532
+ // structured call. Continue past a prose-only candidate so a later capable
533
+ // model gets a chance; `none` is the explicit opt-out and may stop at prose.
534
+ const acceptsToolCall = options.tool_choice !== 'none';
535
+ const { panel, overflow, dropped } = selectPanel(config, { requireTools, requireVision: vision, estimatedTokens });
536
+ if (panel.length === 0) {
537
+ const hint = vision
538
+ ? 'No vision-capable model is servable for the panel. Enable a vision model in the Fallback Chain or pass `fusion.models` with vision-capable model ids.'
539
+ : 'Provide `fusion.models` with enabled model ids, or enable models in the Fallback Chain.';
540
+ throw new FusionError(`fusion: no usable models for the panel. ${hint}`, 400);
541
+ }
542
+ // Dispatch ONE panel slot: hard-pinned to its model, rotating only that
543
+ // model's keys (so a key 429 doesn't collapse the slot onto a duplicate
544
+ // backend — issue #326). Returns its answer and fires onPanel the moment it
545
+ // settles so a streaming client sees answers arrive one by one.
546
+ const runSlot = (cand, slotOptions = options) => runModelCall((skipKeys) => routePinnedModel(cand.modelDbId, estimatedTokens, skipKeys), messages, slotOptions, estimatedTokens, MAX_SLOT_ATTEMPTS).then((outcome) => {
547
+ const returnedToolCalls = outcome.toolCalls;
548
+ const forbiddenToolCall = options.tool_choice === 'none' && !!returnedToolCalls?.length;
549
+ const wrongNamedTool = !!requiredToolName
550
+ && !!returnedToolCalls?.length
551
+ && returnedToolCalls.some(tc => tc.function?.name !== requiredToolName);
552
+ const answer = outcome.ok && !wrongNamedTool && !forbiddenToolCall
553
+ ? {
554
+ modelDbId: cand.modelDbId,
555
+ platform: cand.platform,
556
+ modelId: cand.modelId,
557
+ displayName: cand.displayName,
558
+ status: 'ok',
559
+ content: outcome.text,
560
+ toolCalls: outcome.toolCalls,
561
+ rawChoice: outcome.rawChoice,
562
+ usage: outcome.usage,
563
+ }
564
+ : {
565
+ modelDbId: cand.modelDbId,
566
+ platform: cand.platform,
567
+ modelId: cand.modelId,
568
+ displayName: cand.displayName,
569
+ status: 'failed',
570
+ error: wrongNamedTool
571
+ ? `provider returned a tool call other than required function '${requiredToolName}'`
572
+ : forbiddenToolCall
573
+ ? 'provider returned a tool call despite tool_choice=none'
574
+ : outcome.error,
575
+ };
576
+ hooks?.onPanel?.({ platform: answer.platform, model: answer.modelId, status: answer.status, content: answer.content, tool_calls: answer.toolCalls, error: answer.error });
577
+ return answer;
578
+ });
579
+ // Run the panel in waves, REFILLING failed slots from the fallback chain:
580
+ // we aim for `target` successful answers. Wave 1 is the K-model panel; if some
581
+ // fail (a model 429s/413s/aborts), the next wave pulls that many more models
582
+ // from `overflow` (the next servable models in your chain). A slot is never
583
+ // substituted mid-model — we move to a DIFFERENT chain model — so diversity
584
+ // holds while transient failures don't shrink the panel. Bounded by the
585
+ // candidate pool (≤ 2K dispatches), so it can't sweep the whole catalog.
586
+ const target = panel.length;
587
+ const candidates = [...panel, ...overflow];
588
+ const answers = [];
589
+ let okCount = 0;
590
+ let cursor = 0;
591
+ if (requireTools) {
592
+ // Tool calls are not safely mergeable: the client may execute the returned
593
+ // action, so asking several models in parallel can produce duplicate or
594
+ // contradictory side effects. Walk the ordered candidates one at a time,
595
+ // stopping at the first structured call (or the target number of prose
596
+ // survivors when the model declines to call). Each candidate gets a bounded signal so a slow
597
+ // provider cannot hold the Responses stream open for its full 180s
598
+ // cold-start budget. This also makes fallback deterministic and releases
599
+ // the provider lease before the next candidate starts.
600
+ while (cursor < candidates.length) {
601
+ const cand = candidates[cursor++];
602
+ const deadline = withToolCallDeadline(options);
603
+ let answer;
604
+ try {
605
+ answer = await runSlot(cand, deadline.options);
606
+ }
607
+ finally {
608
+ deadline.cancel();
609
+ }
610
+ answers.push(answer);
611
+ const usable = answer.status === 'ok' && (answer.content || (answer.toolCalls?.length ?? 0) > 0);
612
+ if (usable) {
613
+ okCount++;
614
+ if (answer.toolCalls?.length && acceptsToolCall)
615
+ break;
616
+ if (!acceptsToolCall || (!requiresToolCall && okCount >= target))
617
+ break;
618
+ }
619
+ }
620
+ }
621
+ else {
622
+ while (okCount < target && cursor < candidates.length) {
623
+ const wave = candidates.slice(cursor, cursor + (target - okCount));
624
+ cursor += wave.length;
625
+ const settled = await Promise.allSettled(wave.map(cand => runSlot(cand)));
626
+ settled.forEach((s, i) => {
627
+ const a = s.status === 'fulfilled'
628
+ ? s.value
629
+ : { modelDbId: wave[i].modelDbId, platform: wave[i].platform, modelId: wave[i].modelId, displayName: wave[i].displayName, status: 'failed', error: sanitizeProviderErrorMessage(s.reason?.message) };
630
+ answers.push(a);
631
+ if (a.status === 'ok' && (a.content || (a.toolCalls?.length ?? 0) > 0))
632
+ okCount++;
633
+ });
634
+ }
635
+ }
636
+ const survivors = answers.filter(a => a.status === 'ok' && (a.content || (a.toolCalls?.length ?? 0) > 0));
637
+ let totalUsage = { ...ZERO_USAGE };
638
+ for (const a of survivors)
639
+ totalUsage = addUsage(totalUsage, a.usage);
640
+ if (survivors.length === 0) {
641
+ throw new FusionError('fusion: every panel model failed or was rate-limited. Try again shortly or pick different `fusion.models`.', 429);
642
+ }
643
+ // Tool calls are actions, not prose. They cannot be safely synthesized across
644
+ // models, so the first panel survivor that returned structured tool_calls
645
+ // wins and the judge is skipped.
646
+ const toolCallWinner = survivors.find(a => (a.toolCalls?.length ?? 0) > 0 && a.rawChoice);
647
+ if (toolCallWinner) {
648
+ const choice = {
649
+ index: 0,
650
+ message: toolCallWinner.rawChoice.message,
651
+ finish_reason: 'tool_calls',
652
+ };
653
+ const response = {
654
+ id: `fusion-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
655
+ object: 'chat.completion',
656
+ created: Math.floor(Date.now() / 1000),
657
+ model: FUSION_MODEL_ID,
658
+ choices: [choice],
659
+ usage: totalUsage,
660
+ };
661
+ const winner = { platform: toolCallWinner.platform, model: toolCallWinner.modelId };
662
+ response._fusion = {
663
+ panel: survivors.map(a => ({ platform: a.platform, model: a.modelId })),
664
+ judge: null,
665
+ synthesized: false,
666
+ tool_call_winner: winner,
667
+ };
668
+ if (config.expose_panel) {
669
+ response.x_fusion = {
670
+ strategy,
671
+ synthesized: false,
672
+ judge: null,
673
+ panel_requested: panel.map(p => p.modelId),
674
+ dropped,
675
+ tool_call_winner: winner,
676
+ panel: answers.map(a => ({
677
+ model: a.modelId,
678
+ platform: a.platform,
679
+ status: a.status,
680
+ ...(a.status === 'ok'
681
+ ? { content: a.content, tool_calls: a.toolCalls }
682
+ : { error: a.error }),
683
+ })),
684
+ };
685
+ }
686
+ return {
687
+ response,
688
+ routedVia: `fusion(${survivors.map(a => a.modelId).join('+')} -> tool_call:${toolCallWinner.modelId})`,
689
+ };
690
+ }
691
+ if (requiresToolCall) {
692
+ // `tool_choice=required` (or a named function choice) is a contract with
693
+ // the caller. Returning prose after every candidate ignored that contract
694
+ // would leave an agent waiting for a tool result that can never arrive.
695
+ throw new FusionError('fusion: no panel model returned the required tool call. Try again or pick a tool-capable `fusion.models` entry.', 502);
696
+ }
697
+ const textSurvivors = survivors.filter(a => a.content);
698
+ // Decide the final answer.
699
+ let finalText;
700
+ let judgeModelLabel = null;
701
+ let judgeRoute = null;
702
+ let synthesized = false;
703
+ if (textSurvivors.length < SYNTHESIS_QUORUM || strategy === 'best_of') {
704
+ // One survivor, or best-of requested: return the strongest single answer
705
+ // (longest as a cheap proxy for completeness) — no judge call.
706
+ finalText = textSurvivors.slice().sort((a, b) => (b.content.length - a.content.length))[0].content;
707
+ }
708
+ else {
709
+ const judgeMessages = buildJudgeMessages(messages, textSurvivors, vision);
710
+ // The judge prompt carries every panel answer, so its input is much larger
711
+ // than the original — size the routing estimate accordingly.
712
+ const judgeEstimate = estimatedTokens + textSurvivors.reduce((n, a) => n + Math.ceil((a.content?.length ?? 0) / 4), 0);
713
+ const judgeOptions = requireTools
714
+ ? { ...options, tools: undefined, tool_choice: undefined, parallel_tool_calls: undefined }
715
+ : options;
716
+ const getJudgeRoute = config.judge
717
+ ? (skipKeys) => {
718
+ const cand = resolveFusionCandidate(config.judge);
719
+ return cand ? routePinnedModel(cand.modelDbId, judgeEstimate, skipKeys) : null;
720
+ }
721
+ : (skipKeys, skipModels) => routeRequest(judgeEstimate, skipKeys.size ? skipKeys : undefined, undefined, false, false, skipModels.size ? skipModels : undefined, undefined,
722
+ // The judge writes the final answer the client receives, so a
723
+ // structured-output request must not land it on a platform whose
724
+ // policy drops response_format (kilo) — the schema would never even
725
+ // reach the model. Mirrors the non-fusion routing (#516).
726
+ options.response_format !== undefined);
727
+ // Stream the judge when the caller wants live tokens (Playground); otherwise
728
+ // a single buffered call (plain API clients hitting fusion non-streaming).
729
+ const judge = hooks?.onJudgeDelta
730
+ ? await runJudgeStreaming(getJudgeRoute, judgeMessages, judgeOptions, judgeEstimate, MAX_JUDGE_ATTEMPTS, {
731
+ // Surface the judge model the moment it starts emitting, so the trace
732
+ // shows it while the answer is still streaming.
733
+ onStart: (r) => { judgeRoute = r; judgeModelLabel = `${r.platform}/${r.model}`; hooks.onJudge?.(r); },
734
+ onDelta: hooks.onJudgeDelta,
735
+ })
736
+ : await runModelCall(getJudgeRoute, judgeMessages, judgeOptions, judgeEstimate, MAX_JUDGE_ATTEMPTS);
737
+ if (judge.ok && judge.text) {
738
+ finalText = judge.text;
739
+ synthesized = true;
740
+ // For the streaming path judgeRoute was set in onStart; set it here for the
741
+ // buffered path (and as a fallback).
742
+ if (!judgeRoute && judge.route)
743
+ judgeRoute = { platform: judge.route.platform, model: judge.route.modelId };
744
+ judgeModelLabel = judgeRoute ? `${judgeRoute.platform}/${judgeRoute.model}` : null;
745
+ if (!hooks?.onJudgeDelta && judgeRoute)
746
+ hooks?.onJudge?.(judgeRoute);
747
+ totalUsage = addUsage(totalUsage, judge.usage);
748
+ }
749
+ else {
750
+ // Judge failed → best-of fallback rather than erroring the whole request.
751
+ finalText = textSurvivors.slice().sort((a, b) => (b.content.length - a.content.length))[0].content;
752
+ }
753
+ }
754
+ const routedModels = textSurvivors.map(a => a.modelId);
755
+ const routedVia = `fusion(${routedModels.join('+')}${synthesized && judgeModelLabel ? ` -> ${judgeModelLabel}` : ''})`;
756
+ const response = {
757
+ id: `fusion-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
758
+ object: 'chat.completion',
759
+ created: Math.floor(Date.now() / 1000),
760
+ model: FUSION_MODEL_ID,
761
+ choices: [{ index: 0, message: { role: 'assistant', content: finalText }, finish_reason: 'stop' }],
762
+ usage: totalUsage,
763
+ };
764
+ // Lightweight, always-on routing summary so a client (e.g. the Playground
765
+ // footer) can show exactly which panel models replied and which judge
766
+ // synthesized — without the heavier per-answer `x_fusion` payload.
767
+ response._fusion = {
768
+ panel: survivors.map(a => ({ platform: a.platform, model: a.modelId })),
769
+ judge: synthesized ? judgeRoute : null,
770
+ synthesized,
771
+ };
772
+ if (config.expose_panel) {
773
+ response.x_fusion = {
774
+ strategy,
775
+ synthesized,
776
+ judge: judgeModelLabel,
777
+ panel_requested: panel.map(p => p.modelId),
778
+ dropped,
779
+ panel: answers.map(a => ({
780
+ model: a.modelId,
781
+ platform: a.platform,
782
+ status: a.status,
783
+ ...(a.status === 'ok' ? { content: a.content } : { error: a.error }),
784
+ })),
785
+ };
786
+ }
787
+ return { response, routedVia };
788
+ }
789
+ //# sourceMappingURL=fusion.js.map