cartethyia 2.7.3 → 2.7.5

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 (625) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-2TJD37Hb.js → BannedPage-Cj15GsMp.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  5. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
  6. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolDetailPage-xefJNRmJ.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.js → CliToolsPage-BIccZmeL.js} +1 -1
  10. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  11. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
  12. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
  14. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  15. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js +1 -0
  16. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-C4w7vea-.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BtPcAfot.js → ModelPicker-DnQPSIA8.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  31. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js +9 -0
  32. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-BQS0Rx_u.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-TP7voAQ0.js → StudioPage-BfAb5-o_.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
  44. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  45. package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
  46. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-C0YYuZJ4.js → assert-C0K-c4eo.js} +1 -1
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DMrMPmth.js → banner-BllT4LcF.js} +1 -1
  52. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  53. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  54. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  55. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  56. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  57. package/dist/dashboard/assets/{card-Be5Uzamx.js → card-CtkX66Wd.js} +1 -1
  58. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  59. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
  60. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
  61. package/dist/dashboard/assets/{cli-tools-muFRphDu.js → cli-tools-CQXVMn4P.js} +1 -1
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-BQqBQd2n.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  65. package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-Bm8WKaGY.js → drawer-BrTEZ8zu.js} +1 -1
  68. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
  70. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  71. package/dist/dashboard/assets/{entry-q5HwZ8nN.js → entry-EBHJ3DrE.js} +1 -1
  72. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
  74. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  75. package/dist/dashboard/assets/{formatters-BTScrQpe.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-YSCE4UC2.js} +1 -1
  78. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-cPrX5vn6.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-BHHX_Tmm.js} +1 -1
  84. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/{layout-C_7A6H55.js.gz → layout-CajrYUnD.js.gz} +0 -0
  87. package/dist/dashboard/assets/{list-row-CzFvogbj.js → list-row-Bx2I7XUe.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  89. package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
  90. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  91. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +1 -0
  92. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
  94. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  95. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  96. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  97. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  98. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  99. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  100. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  101. package/dist/dashboard/assets/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
  102. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  103. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  104. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  105. package/dist/dashboard/assets/{routing-BEH32QOC.js → routing-in0f_IfK.js} +1 -1
  106. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  107. package/dist/dashboard/assets/{select-B3iTetHN.js → select-BLULNqTp.js} +2 -2
  108. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  109. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  110. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  111. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  112. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  113. package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-D2lIR0tg.js} +1 -1
  114. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  115. package/dist/dashboard/assets/{state-DLS7IDMy.js → state-DTARjfiW.js} +1 -1
  116. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  117. package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-c0oPSnqW.js} +1 -1
  118. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  119. package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-m8WGNPrz.js} +1 -1
  120. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  121. package/dist/dashboard/console-backgrounds.jpg +0 -0
  122. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  123. package/dist/dashboard/index.html +2 -2
  124. package/dist/dashboard/index.html.gz +0 -0
  125. package/dist/dashboard/precompressed-assets.json +59 -57
  126. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
  127. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  128. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  129. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  130. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  131. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  132. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  133. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  134. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  135. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  136. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  137. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +9 -10
  138. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  139. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  140. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  141. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  142. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  143. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  144. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  145. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  146. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  147. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  148. package/package.json +4 -5
  149. package/scripts/cli/update.ts +15 -41
  150. package/src/boot/app.ts +67 -10
  151. package/src/boot/dependencies.ts +786 -732
  152. package/src/boot/lifecycle.ts +11 -12
  153. package/src/config/cooldowns.ts +34 -55
  154. package/src/config/network.ts +8 -4
  155. package/src/config/package-paths.ts +1 -1
  156. package/src/config/providers.ts +13 -14
  157. package/src/config/resources.ts +0 -5
  158. package/src/config/runtime.ts +2 -5
  159. package/src/config/spec.ts +26 -6
  160. package/src/console/api-keys/ban-constants.ts +38 -0
  161. package/src/console/api-keys/contracts.ts +92 -31
  162. package/src/console/api-keys/routes.ts +131 -6
  163. package/src/console/audit/routes.ts +3 -3
  164. package/src/console/auth/access.ts +4 -4
  165. package/src/console/auth/account-reset.ts +5 -5
  166. package/src/console/auth/audit-recorder.ts +1 -1
  167. package/src/console/auth/lockout.ts +7 -3
  168. package/src/console/auth/row-coercion.ts +57 -12
  169. package/src/console/auth/session-resolver.ts +1 -1
  170. package/src/console/auth/session-service.ts +8 -2
  171. package/src/console/auth/session.ts +40 -34
  172. package/src/console/auth/setup-service.ts +4 -3
  173. package/src/console/auth/user-store.ts +1 -1
  174. package/src/console/backup/9router-map.ts +0 -3
  175. package/src/console/backup/contracts.ts +11 -9
  176. package/src/console/backup/export-endpoint.ts +11 -12
  177. package/src/console/backup/nine-router.ts +1 -7
  178. package/src/console/backup/routes.ts +32 -36
  179. package/src/console/backup/service.ts +468 -468
  180. package/src/console/backup/store.ts +47 -29
  181. package/src/console/backup/validate.ts +11 -1
  182. package/src/console/cli-tools/contracts.ts +7 -7
  183. package/src/console/cli-tools/injectors/cline.ts +110 -110
  184. package/src/console/cli-tools/injectors/codex.ts +181 -181
  185. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  186. package/src/console/cli-tools/injectors/driver.ts +247 -247
  187. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  188. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  189. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  190. package/src/console/cli-tools/routes.ts +4 -4
  191. package/src/console/cli-tools/service.ts +1 -1
  192. package/src/console/cli-tools/store.ts +2 -2
  193. package/src/console/console-router-guards.ts +2 -2
  194. package/src/console/console-router.ts +36 -4
  195. package/src/console/dashboard-assets.ts +9 -9
  196. package/src/console/data-management/routes.ts +3 -3
  197. package/src/console/domain-registration.ts +18 -4
  198. package/src/console/inferhub/client.ts +0 -7
  199. package/src/console/inferhub/key-store.ts +1 -1
  200. package/src/console/inferhub/normalize.ts +2 -2
  201. package/src/console/inferhub/routes.ts +1 -1
  202. package/src/console/inferhub/types.ts +1 -1
  203. package/src/console/observability/contracts.ts +5 -1
  204. package/src/console/observability/live.ts +34 -21
  205. package/src/console/observability/logs.ts +4 -4
  206. package/src/console/observability/performance.ts +3 -3
  207. package/src/console/observability/routes.ts +3 -3
  208. package/src/console/observability/sse.ts +62 -8
  209. package/src/console/observability/store.ts +36 -20
  210. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  211. package/src/console/providers/catalog/contracts.ts +82 -22
  212. package/src/console/providers/catalog/model-operations.ts +1 -1
  213. package/src/console/providers/catalog/provider-operations.ts +110 -17
  214. package/src/console/providers/catalog/public-model-store.ts +0 -0
  215. package/src/console/providers/catalog/routes.ts +30 -6
  216. package/src/console/providers/catalog/store-helpers.ts +349 -326
  217. package/src/console/providers/catalog/store.ts +1662 -1292
  218. package/src/console/providers/detail/routes.ts +4 -4
  219. package/src/console/providers/oauth/callback-listener.ts +100 -18
  220. package/src/console/providers/oauth/routes.ts +95 -16
  221. package/src/console/quota/account-quota-global.ts +41 -3
  222. package/src/console/quota/account-quota-shared.ts +10 -3
  223. package/src/console/quota/account-quota-tenant.ts +285 -67
  224. package/src/console/quota/account-test-egress.ts +4 -4
  225. package/src/console/quota/daily-growth-job.ts +308 -0
  226. package/src/console/quota/native-identity.ts +2 -2
  227. package/src/console/quota/quota-view.ts +1 -1
  228. package/src/console/remote-support/routes.ts +1 -1
  229. package/src/console/remote-support/service.ts +2 -2
  230. package/src/console/routing/model/contracts.ts +1 -1
  231. package/src/console/routing/model/routes.ts +3 -3
  232. package/src/console/routing/pools/contracts.ts +13 -10
  233. package/src/console/routing/pools/import-parse.ts +3 -3
  234. package/src/console/routing/pools/operations.ts +14 -7
  235. package/src/console/routing/pools/probe-verdict.ts +8 -3
  236. package/src/console/routing/pools/relay-deploy.ts +12 -12
  237. package/src/console/routing/pools/routes.ts +3 -3
  238. package/src/console/routing/pools/store.ts +21 -1
  239. package/src/console/settings/contracts.ts +29 -2
  240. package/src/console/settings/routes.ts +3 -3
  241. package/src/console/settings/store.ts +20 -0
  242. package/src/console/share/share-router.ts +112 -44
  243. package/src/console/share/share-stats.ts +109 -39
  244. package/src/console/share/share-usage.ts +1 -1
  245. package/src/console/shared/errors.ts +2 -2
  246. package/src/console/shared/object.ts +18 -0
  247. package/src/console/shared/read-through-cache.ts +42 -6
  248. package/src/console/shared/transaction.ts +14 -0
  249. package/src/console/system-prompt/contracts.ts +89 -12
  250. package/src/console/system-prompt/routes.ts +98 -45
  251. package/src/console/updates/apply-update.ts +244 -0
  252. package/src/console/updates/routes.ts +256 -98
  253. package/src/main.ts +11 -5
  254. package/src/network/http2-bidi.ts +1 -1
  255. package/src/network/ip-utils.ts +298 -0
  256. package/src/network/outbound-fetch.ts +76 -5
  257. package/src/network/pool/agent.ts +7 -6
  258. package/src/network/pool/byte-accounting.ts +1 -1
  259. package/src/network/pool/resolver.ts +55 -51
  260. package/src/network/pool/selector.ts +150 -136
  261. package/src/network/pool-cooldown-store.ts +71 -16
  262. package/src/network/pool-health-machine.ts +22 -2
  263. package/src/network/rate-limit-verdict.ts +68 -0
  264. package/src/network/retry.ts +1 -1
  265. package/src/network/ssrf.ts +24 -75
  266. package/src/observability/event-log.ts +2 -2
  267. package/src/observability/event-query.ts +286 -214
  268. package/src/observability/log-sanitize.ts +1 -1
  269. package/src/observability/metrics.ts +4 -4
  270. package/src/observability/payload-capture.ts +6 -5
  271. package/src/observability/payload-store.ts +1 -1
  272. package/src/observability/runtime-metrics.ts +1 -1
  273. package/src/observability/telemetry-buffer.ts +12 -3
  274. package/src/observability/telemetry-reconciliation.ts +3 -3
  275. package/src/observability/telemetry-status.ts +1 -1
  276. package/src/observability/token-speed.ts +1 -1
  277. package/src/persistence/connection-url.ts +1 -1
  278. package/src/persistence/db-handle.ts +1 -1
  279. package/src/persistence/db-pg.ts +2 -2
  280. package/src/persistence/db-sqlite.ts +10 -5
  281. package/src/persistence/dialect.ts +5 -1
  282. package/src/persistence/readiness.ts +19 -7
  283. package/src/persistence/redis.ts +1 -1
  284. package/src/persistence/schema.ts +177 -45
  285. package/src/persistence/shared-cache.ts +2 -2
  286. package/src/persistence/sort-order.ts +1 -1
  287. package/src/persistence/stores/api-key-store.ts +109 -4
  288. package/src/persistence/stores/share-store.ts +20 -8
  289. package/src/persistence/stores/telemetry-store.ts +1 -1
  290. package/src/persistence/system-prompt-store.ts +63 -18
  291. package/src/persistence/tenant-preferences.ts +1 -1
  292. package/src/persistence/ttl-cache.ts +3 -3
  293. package/src/persistence/usage-flush.ts +7 -2
  294. package/src/protocol/canonical-model.ts +1 -1
  295. package/src/protocol/codecs.ts +12 -16
  296. package/src/protocol/dsml.ts +3 -49
  297. package/src/protocol/gateway-error.ts +6 -3
  298. package/src/protocol/image-clamp.ts +2 -2
  299. package/src/protocol/image-generation.ts +2 -2
  300. package/src/protocol/reasoning-text.ts +1 -1
  301. package/src/protocol/reasoning.ts +7 -52
  302. package/src/protocol/registry.ts +50 -15
  303. package/src/protocol/request/chat.ts +46 -19
  304. package/src/protocol/request/codex.ts +1 -1
  305. package/src/protocol/request/messages.ts +46 -14
  306. package/src/protocol/request/responses.ts +19 -10
  307. package/src/protocol/response/chat.ts +27 -12
  308. package/src/protocol/response/codex.ts +2 -2
  309. package/src/protocol/response/gemini.ts +1 -1
  310. package/src/protocol/response/messages.ts +6 -6
  311. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  312. package/src/protocol/response/responses.ts +3 -3
  313. package/src/protocol/sse-decoder.ts +64 -4
  314. package/src/protocol/stop-reason.ts +2 -2
  315. package/src/protocol/think-split.ts +347 -0
  316. package/src/protocol/translation/attachment-integrity.ts +3 -3
  317. package/src/protocol/translation/cache-controls.ts +8 -20
  318. package/src/protocol/translation/capabilities.ts +8 -8
  319. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  320. package/src/protocol/translation/dialect/inband.ts +39 -0
  321. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  322. package/src/protocol/translation/dialect/qwen.ts +114 -0
  323. package/src/protocol/translation/dialect/resolver.ts +83 -0
  324. package/src/protocol/translation/dialect/rules.ts +93 -0
  325. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  326. package/src/protocol/translation/dialect/types.ts +58 -0
  327. package/src/protocol/translation/quirks.ts +18 -4
  328. package/src/protocol/translation/thinking.ts +12 -252
  329. package/src/protocol/translation/tool-id.ts +3 -3
  330. package/src/protocol/translation/tool-repair.ts +1 -1
  331. package/src/protocol/upstream/post-json.ts +6 -1
  332. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  333. package/src/providers/adapters/base-adapter.ts +1 -1
  334. package/src/providers/adapters/compatible-adapter.ts +44 -5
  335. package/src/providers/authentication/jwt-validator.ts +0 -5
  336. package/src/providers/authentication/oauth-client.ts +254 -253
  337. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  338. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  339. package/src/providers/bundled-discovery-providers.ts +6 -30
  340. package/src/providers/configured-openai-providers.ts +82 -97
  341. package/src/providers/configured-provider.ts +1 -1
  342. package/src/providers/default-registry.ts +23 -35
  343. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  344. package/src/providers/discovery/discovery-types.ts +0 -1
  345. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  346. package/src/providers/discovery/probe-phases.ts +50 -15
  347. package/src/providers/discovery/probing-service.ts +18 -20
  348. package/src/providers/integrations/agentrouter/agentrouter.ts +14 -5
  349. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  350. package/src/providers/integrations/anthropic.ts +4 -11
  351. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  352. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  353. package/src/providers/integrations/antigravity/antigravity.ts +15 -26
  354. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +2 -2
  355. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  356. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  357. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  358. package/src/providers/integrations/buddy/buddy-identity.ts +108 -1
  359. package/src/providers/integrations/buddy/buddy-media.ts +16 -16
  360. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  361. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  362. package/src/providers/integrations/buddy/codebuddy/provider.ts +5 -16
  363. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  364. package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -10
  365. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  366. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  367. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  368. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  369. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  370. package/src/providers/integrations/claude/claude.ts +3 -10
  371. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  372. package/src/providers/integrations/cline/cline.ts +2 -2
  373. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  374. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  375. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  376. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  377. package/src/providers/integrations/codex/codex.ts +14 -15
  378. package/src/providers/integrations/commandcode/commandcode.ts +76 -116
  379. package/src/providers/integrations/commandcode/quota.ts +132 -48
  380. package/src/providers/integrations/cursor/cursor-http2.ts +11 -14
  381. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  382. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  383. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  384. package/src/providers/integrations/cursor/cursor.ts +53 -20
  385. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  386. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  387. package/src/providers/integrations/factory/factory.ts +13 -13
  388. package/src/providers/integrations/gemini.ts +11 -11
  389. package/src/providers/integrations/github/github-discovery.ts +55 -10
  390. package/src/providers/integrations/github/github-oauth.ts +6 -5
  391. package/src/providers/integrations/github/github.ts +47 -20
  392. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  393. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  394. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  395. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  396. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  397. package/src/providers/integrations/grok/grok.ts +88 -42
  398. package/src/providers/integrations/inferhub.ts +4 -11
  399. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  400. package/src/providers/integrations/kimi/kimi.ts +4 -11
  401. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  402. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  403. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  404. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  405. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  406. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  407. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  408. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  409. package/src/providers/integrations/kiro/kiro.ts +91 -78
  410. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  411. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  412. package/src/providers/integrations/muse/muse.ts +6 -9
  413. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  414. package/src/providers/integrations/opencode/provider.ts +17 -24
  415. package/src/providers/integrations/perplexity.ts +2 -2
  416. package/src/providers/integrations/qoder/qoder-catalog.ts +132 -17
  417. package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
  418. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -8
  419. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  420. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  421. package/src/providers/integrations/qoder/qoder-realm.ts +22 -28
  422. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  423. package/src/providers/integrations/qoder/qoder-umid.ts +33 -38
  424. package/src/providers/integrations/qoder/qoder-virtual.ts +14 -2
  425. package/src/providers/integrations/qoder/qoder.ts +521 -63
  426. package/src/providers/integrations/shared/connect.ts +0 -54
  427. package/src/providers/integrations/shared/hash.ts +15 -0
  428. package/src/providers/integrations/shared/session-cache.ts +136 -0
  429. package/src/providers/integrations/tokenharbor.ts +2 -2
  430. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  431. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  432. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  433. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  434. package/src/providers/integrations/trae/trae.ts +59 -19
  435. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  436. package/src/providers/integrations/zcode/oauth.ts +1 -1
  437. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  438. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  439. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  440. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  441. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  442. package/src/providers/operations/account-error-classification.ts +131 -116
  443. package/src/providers/operations/account-health-service.ts +31 -39
  444. package/src/providers/operations/account-reset-service.ts +58 -1
  445. package/src/providers/operations/cli-platform.ts +31 -5
  446. package/src/providers/operations/client-version-resolver.ts +4 -6
  447. package/src/providers/operations/client-versions.ts +10 -7
  448. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  449. package/src/providers/operations/provider-catalog-service.ts +22 -6
  450. package/src/providers/operations/provider-credential-service.ts +35 -6
  451. package/src/providers/operations/upstream-deadline.ts +3 -3
  452. package/src/providers/provider-contracts.ts +65 -10
  453. package/src/providers/provider-credential-resolver.ts +1 -1
  454. package/src/providers/provider-metadata.ts +17 -2
  455. package/src/providers/provider-model-definition.ts +22 -1
  456. package/src/providers/provider-probe.ts +4 -2
  457. package/src/providers/provider-registry.ts +4 -4
  458. package/src/providers/provider-usage.ts +81 -16
  459. package/src/providers/quota/cache.ts +29 -0
  460. package/src/providers/quota/quota-contracts.ts +28 -10
  461. package/src/providers/quota/refresh.ts +29 -6
  462. package/src/providers/quota/snapshot.ts +94 -0
  463. package/src/providers/search/search-provider.ts +6 -8
  464. package/src/providers/search/search-providers.ts +2 -1
  465. package/src/security/abuse.ts +8 -8
  466. package/src/security/admission/reasons.ts +17 -17
  467. package/src/security/admission/service.ts +2 -2
  468. package/src/security/admission/ttl.ts +61 -61
  469. package/src/security/api-key-auth.ts +20 -8
  470. package/src/security/client-router-fingerprint.ts +4 -4
  471. package/src/security/credential-codec.ts +3 -3
  472. package/src/security/csrf.ts +2 -2
  473. package/src/security/ip-boundary.ts +16 -189
  474. package/src/security/model-access-rule.ts +1 -1
  475. package/src/security/outbound-headers.ts +18 -0
  476. package/src/shared/coerce.ts +19 -0
  477. package/src/shared/invoke-guard.ts +47 -0
  478. package/src/transport/contracts.ts +13 -4
  479. package/src/transport/dispatch/attempt-finalize.ts +5 -4
  480. package/src/transport/dispatch/attempt-loop.ts +10 -7
  481. package/src/transport/dispatch/capture-policy.ts +34 -37
  482. package/src/transport/dispatch/empty-stream.ts +28 -25
  483. package/src/transport/dispatch/generation.ts +33 -53
  484. package/src/transport/dispatch/leases.ts +8 -8
  485. package/src/transport/dispatch/native-shared.ts +127 -0
  486. package/src/transport/dispatch/proxy-request.ts +10 -8
  487. package/src/transport/dispatch/responses-compact.ts +35 -56
  488. package/src/transport/dispatch/retry-policy.ts +4 -67
  489. package/src/transport/dispatch/stream-bridge.ts +1 -1
  490. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  491. package/src/transport/dispatch/streaming/finalize.ts +11 -10
  492. package/src/transport/dispatch/streaming/stream.ts +7 -3
  493. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  494. package/src/transport/dispatch/systemone.ts +27 -55
  495. package/src/transport/dispatch/token-count.ts +49 -46
  496. package/src/transport/dispatch/websearch.ts +24 -50
  497. package/src/transport/drain-endpoint.ts +3 -3
  498. package/src/transport/failure-policy.ts +19 -6
  499. package/src/transport/guards/auth-guard.ts +6 -11
  500. package/src/transport/guards/body-policy.ts +7 -7
  501. package/src/transport/guards/error-lifecycle.ts +18 -3
  502. package/src/transport/guards/guard-errors.ts +7 -3
  503. package/src/transport/guards/headroom-guard.ts +2 -2
  504. package/src/transport/guards/pipeline.ts +7 -7
  505. package/src/transport/guards/readiness-guard.ts +16 -2
  506. package/src/transport/guards/request-context.ts +15 -20
  507. package/src/transport/request/preparer.ts +306 -27
  508. package/src/transport/request/rtk/compress-request.ts +3 -3
  509. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  510. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  511. package/src/transport/request/state.ts +5 -20
  512. package/src/transport/request/system-prompt-injection.ts +74 -11
  513. package/src/transport/request/tenant-preferences.ts +22 -0
  514. package/src/transport/routing/candidate-index.ts +2 -2
  515. package/src/transport/routing/round-robin.ts +1 -1
  516. package/src/transport/routing/route-catalog.ts +113 -19
  517. package/src/transport/routing/route-model.ts +131 -38
  518. package/src/transport/routing/router.ts +154 -39
  519. package/src/transport/shutdown-notice.ts +21 -9
  520. package/src/transport/surface/adapters.ts +3 -3
  521. package/src/transport/surface/chat/encode.ts +7 -7
  522. package/src/transport/surface/chat/parse.ts +7 -7
  523. package/src/transport/surface/completion.ts +3 -3
  524. package/src/transport/surface/content-parts.ts +1 -1
  525. package/src/transport/surface/dialects.ts +2 -2
  526. package/src/transport/surface/messages/encode.ts +1 -1
  527. package/src/transport/surface/messages/parse.ts +3 -3
  528. package/src/transport/surface/responses/adapter.ts +1 -1
  529. package/src/transport/surface/responses/errors.ts +0 -9
  530. package/src/transport/vision-handoff-cache.ts +58 -0
  531. package/src/transport/vision-handoff.ts +376 -0
  532. package/src/workers/account-identity-sweep.ts +2 -2
  533. package/src/workers/buddy-growth-tasks.ts +392 -346
  534. package/src/workers/daily-checkin.ts +102 -49
  535. package/src/workers/maintenance-lease.ts +2 -35
  536. package/src/workers/oauth-refresh-sweep.ts +8 -1
  537. package/src/workers/quota-refresh-sweep.ts +120 -82
  538. package/src/workers/scheduler.ts +67 -4
  539. package/src/workers/sweep-runner.ts +24 -5
  540. package/src/workers/zcode-gift-claim.ts +108 -0
  541. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  542. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  543. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  544. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  545. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  546. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js +0 -1
  547. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  548. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
  549. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  550. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
  551. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  552. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
  553. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  554. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  555. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  556. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
  557. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  558. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
  559. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  560. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  561. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  562. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +0 -1
  563. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  564. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
  565. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  566. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
  567. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  568. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
  569. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  570. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  571. package/dist/dashboard/assets/SortableList-BAL5npBC.js +0 -1
  572. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  573. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  574. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
  575. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  576. package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
  577. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  578. package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
  579. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  580. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  581. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  582. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  583. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  584. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  585. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  586. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  587. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  588. package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
  589. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  590. package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
  591. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  592. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  593. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  594. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  595. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  596. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  597. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  598. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  599. package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
  600. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  601. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  602. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  603. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  604. package/dist/dashboard/assets/numbers-BNDZnsUE.js +0 -2
  605. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  606. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  607. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  608. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  609. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  610. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  611. package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
  612. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  613. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  614. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  615. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  616. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  617. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  618. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  619. package/src/network/response-headers.ts +0 -39
  620. package/src/protocol/response/dsml.ts +0 -38
  621. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  622. /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-Bgd3zANQ.js} +0 -0
  623. /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  624. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  625. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -156,10 +156,9 @@ export interface ProxyRequestState {
156
156
  */
157
157
  extendDeadline(ms: number): void;
158
158
  cleanup(): void;
159
- addCleanup(cleanup: () => void): void;
160
159
  }
161
160
 
162
- export interface RequestTracker {
161
+ interface RequestTracker {
163
162
  track(id: string): void;
164
163
  untrack(id: string): void;
165
164
  }
@@ -191,15 +190,12 @@ function subscribeInFlightSnapshot(
191
190
  store: { inFlightSnapshot(): InFlightSnapshot },
192
191
  listener: (snapshot: InFlightSnapshot) => void,
193
192
  ): () => void {
194
- const timers = new Set<ReturnType<typeof setTimeout>>();
195
193
  const push = (): void => listener(store.inFlightSnapshot());
196
194
  push();
197
195
  const handle = setInterval(push, 1_000);
198
196
  (handle as unknown as { unref?: () => void })?.unref?.();
199
197
  return () => {
200
198
  clearInterval(handle);
201
- for (const t of timers) clearTimeout(t);
202
- timers.clear();
203
199
  };
204
200
  }
205
201
 
@@ -259,7 +255,7 @@ export class ProxyRequestStateStore {
259
255
  try {
260
256
  if (controller && !controller.signal.aborted) {
261
257
  controller.abort(
262
- new GatewayError("deadline_exceeded", 504, "in-flight request exceeded its deadline"),
258
+ new GatewayError("deadline_exceeded", 504, "in-flight request exceeded its deadline (request {requestId}). Some things just take longer 🐢"),
263
259
  );
264
260
  }
265
261
  } catch {
@@ -292,7 +288,7 @@ export class ProxyRequestStateStore {
292
288
  const abortReason =
293
289
  reason instanceof Error || reason instanceof DOMException
294
290
  ? reason
295
- : new GatewayError("shutting_down", 503, "The gateway is shutting down, so this request cannot be served. Retry against a live instance.");
291
+ : new GatewayError("shutting_down", 503, "The gateway is shutting down, so this request cannot be served (request {requestId}). Retry against a live instance. Maintenance mode — back in a minute 🧘");
296
292
  for (const controller of controllers) {
297
293
  try {
298
294
  if (!controller.signal.aborted) controller.abort(abortReason);
@@ -319,7 +315,6 @@ export class ProxyRequestStateStore {
319
315
  else request.signal.addEventListener("abort", onAbort, { once: true });
320
316
  let cleaned = false;
321
317
  let providerFlightStarted = false;
322
- const cleanups: Array<() => void> = [];
323
318
  const armDeadline = (ms: number): void => {
324
319
  clearTimeout(timer);
325
320
  timer = setTimeout(() => {
@@ -330,7 +325,7 @@ export class ProxyRequestStateStore {
330
325
  new GatewayError(
331
326
  "deadline_exceeded",
332
327
  504,
333
- "request deadline exceeded",
328
+ "request deadline exceeded (request {requestId}). Some things just take longer 🐢",
334
329
  {},
335
330
  "cartethyia",
336
331
  ),
@@ -393,22 +388,12 @@ export class ProxyRequestStateStore {
393
388
  request.signal.removeEventListener("abort", onAbort);
394
389
  } catch {
395
390
  }
396
- for (const cleanup of cleanups.splice(0)) {
397
- try {
398
- cleanup();
399
- } catch {
400
- }
401
- }
402
391
  try {
403
392
  abortController.abort(new DOMException("request complete", "AbortError"));
404
393
  } catch {
405
394
  }
406
395
  this.states.delete(request);
407
396
  },
408
- addCleanup: (cleanup) => {
409
- if (cleaned) cleanup();
410
- else cleanups.push(cleanup);
411
- },
412
397
  };
413
398
  this.liveControllers.set(state.requestId, abortController);
414
399
  this.tracker?.track(state.requestId);
@@ -418,7 +403,7 @@ export class ProxyRequestStateStore {
418
403
  require(request: Request): ProxyRequestState {
419
404
  const state = this.states.get(request);
420
405
  if (!state)
421
- throw new GatewayError("admission_unavailable", 503, "The request was never registered, so it cannot be served. Resend the request.");
406
+ throw new GatewayError("route_unavailable", 503, "The request was never registered, so it cannot be served (request {requestId}). Resend the request. The bouncer stepped out — resend shortly 🚪");
422
407
  return state;
423
408
  }
424
409
 
@@ -8,8 +8,9 @@
8
8
  * injection (Claude identity/billing prepend, buddy fixed system turn,
9
9
  * antigravity identity) happens later, in the adapters, and is untouched.
10
10
  *
11
- * Resolution is most-specific-wins: model > provider > global, where a
12
- * provider either follows the tenant's global prompt or carries a custom one.
11
+ * Resolution is most-specific-wins: alias/combo (when the caller's requested
12
+ * name matches one) > model > provider > global. A scope either references a
13
+ * named preset, carries a custom setting, or follows the global prompt.
13
14
  * Failure is non-fatal — an unusable configuration must not fail a
14
15
  * dispatchable request.
15
16
  */
@@ -17,6 +18,7 @@ import type { CanonicalRequest } from "../../protocol/canonical-model";
17
18
  import type { ServiceKind } from "../../protocol/canonical-model";
18
19
  import type {
19
20
  PromptSetting,
21
+ ScopePromptRef,
20
22
  TenantSystemPrompts,
21
23
  } from "../../console/system-prompt/contracts";
22
24
  import {
@@ -28,28 +30,89 @@ export interface SystemPromptRoute {
28
30
  readonly providerId: string;
29
31
  readonly modelId: string;
30
32
  readonly serviceKind: ServiceKind;
33
+ /** The model name the client asked for (pre-alias/combo resolution), when
34
+ * it differs from the resolved `modelId` — lets a combo/alias carry its
35
+ * own injection reference. */
36
+ readonly requestedModel?: string;
37
+ }
38
+
39
+ /**
40
+ * Resolves one scope reference to a concrete prompt setting. Returns
41
+ * `undefined` when the scope has nothing to say (no entry, preset
42
+ * missing/disabled, custom disabled). `undefined` here means "skip this
43
+ * scope" — the caller decides the final global fallback.
44
+ *
45
+ * `global` is itself a `ScopePromptRef | null`, so the `{ kind: "global" }`
46
+ * marker resolves through the global ref — which may be a preset, a custom
47
+ * setting, or `null` (nothing). An explicit `{ kind: "off" }` is handled by
48
+ * the caller before this function runs.
49
+ */
50
+ function resolveRef(
51
+ prompts: TenantSystemPrompts,
52
+ ref: ScopePromptRef | undefined,
53
+ ): PromptSetting | undefined {
54
+ if (ref === undefined || ref.kind === "off" || ref.kind === "global") return undefined;
55
+ if (ref.kind === "preset") {
56
+ const preset = prompts.presets[ref.presetId];
57
+ if (preset === undefined || !preset.enabled) return undefined;
58
+ return { enabled: true, mode: preset.mode, text: preset.text };
59
+ }
60
+ return ref.setting.enabled ? ref.setting : undefined;
61
+ }
62
+
63
+ /**
64
+ * Whether a scope entry explicitly stops injection. An explicit `off` is
65
+ * terminal — it does NOT fall through to the global prompt.
66
+ */
67
+ function isExplicitOff(ref: ScopePromptRef | undefined): boolean {
68
+ return ref?.kind === "off";
31
69
  }
32
70
 
33
71
  /**
34
72
  * Resolves the effective prompt for a route: the most-specific enabled scope
35
- * wins. A provider scope honours its `followGlobal` toggle; model scope is
36
- * always explicit. Returns `undefined` when nothing applies.
73
+ * wins. Alias/combo scopes (keyed by the requested name) beat the model scope;
74
+ * a provider scope honours its reference; model scope is always explicit. An
75
+ * explicit `off` at any scope stops injection for that request — it does not
76
+ * fall through to the global prompt. Returns `undefined` when nothing applies.
37
77
  */
38
78
  export function resolveTenantSystemPrompt(
39
79
  prompts: TenantSystemPrompts | undefined,
40
- route: Pick<SystemPromptRoute, "providerId" | "modelId">,
80
+ route: Pick<SystemPromptRoute, "providerId" | "modelId" | "requestedModel">,
41
81
  ): PromptSetting | undefined {
42
82
  if (prompts === undefined) return undefined;
83
+ const global = prompts.global;
84
+
85
+ const requested = route.requestedModel;
86
+ if (requested !== undefined && requested.length > 0 && requested !== route.modelId) {
87
+ const aliasRef = prompts.aliases[requested];
88
+ if (aliasRef !== undefined) {
89
+ if (isExplicitOff(aliasRef)) return undefined;
90
+ const aliasSetting = resolveRef(prompts, aliasRef);
91
+ if (aliasSetting !== undefined) return aliasSetting;
92
+ }
93
+ const comboRef = prompts.combos[requested];
94
+ if (comboRef !== undefined) {
95
+ if (isExplicitOff(comboRef)) return undefined;
96
+ const comboSetting = resolveRef(prompts, comboRef);
97
+ if (comboSetting !== undefined) return comboSetting;
98
+ }
99
+ }
100
+
43
101
  const model = prompts.models[systemPromptModelKey(route.providerId, route.modelId)];
44
- if (model !== undefined && model.enabled) return model;
102
+ if (model !== undefined) {
103
+ if (isExplicitOff(model)) return undefined;
104
+ const modelSetting = resolveRef(prompts, model);
105
+ if (modelSetting !== undefined) return modelSetting;
106
+ }
107
+
45
108
  const provider = prompts.providers[route.providerId];
46
109
  if (provider !== undefined) {
47
- if (provider.followGlobal) {
48
- return prompts.global !== null && prompts.global.enabled ? prompts.global : undefined;
49
- }
50
- if (provider.setting !== undefined && provider.setting.enabled) return provider.setting;
110
+ if (isExplicitOff(provider)) return undefined;
111
+ const providerSetting = resolveRef(prompts, provider);
112
+ if (providerSetting !== undefined) return providerSetting;
51
113
  }
52
- return prompts.global !== null && prompts.global.enabled ? prompts.global : undefined;
114
+
115
+ return resolveRef(prompts, global ?? undefined);
53
116
  }
54
117
 
55
118
  /** Marker text guard so retries never double-inject. */
@@ -107,6 +107,27 @@ export async function resolveTenantImageClampMaxBytes(
107
107
  }
108
108
  }
109
109
 
110
+ /**
111
+ * The tenant's ordered vision-handoff model list, or `[]` when none is
112
+ * configured (legacy `[image]` placeholder behavior). Read through the shared
113
+ * revision-keyed preference reader; a settings outage yields an empty list,
114
+ * which is the safe direction (handoff is an upgrade, never a prerequisite).
115
+ */
116
+ export async function resolveTenantVisionHandoffModels(
117
+ db: CartethyiaDatabase,
118
+ tenantId: string | undefined,
119
+ ): Promise<readonly string[]> {
120
+ if (tenantId === undefined) return [];
121
+ try {
122
+ const prefs = await preferencesReaderFor(db).readPreferences(tenantId);
123
+ const models = prefs?.visionHandoffModels;
124
+ if (!Array.isArray(models)) return [];
125
+ return models.filter((model): model is string => typeof model === "string" && model.trim().length > 0);
126
+ } catch {
127
+ return [];
128
+ }
129
+ }
130
+
110
131
  /**
111
132
  * Applies request shaping owned by tenant preferences and deployment config:
112
133
  * thinking normalization and the Responses reasoning summary override.
@@ -133,6 +154,7 @@ export async function applyTenantPreferences(
133
154
  providerId: candidate.provider_id,
134
155
  modelId: candidate.model_id,
135
156
  serviceKind: candidate.service_kind ?? "llm",
157
+ requestedModel: prepared.plan?.requested_model ?? candidate.model_id,
136
158
  });
137
159
  if (prefs) {
138
160
  // When the routed model is Responses (codex/openai/muse-spark) and the
@@ -2,7 +2,7 @@
2
2
  import type { RouteCandidate, RouteSnapshot } from "./route-model";
3
3
 
4
4
  /** One parsed model reference: `provider/model` or a bare `model`. */
5
- export interface ParsedModel {
5
+ interface ParsedModel {
6
6
  readonly providerId: string | null;
7
7
  readonly modelId: string;
8
8
  }
@@ -24,7 +24,7 @@ export function parseModelReference(model: string): ParsedModel {
24
24
  * candidates cost K×C `candidateMatches` calls (each re-parsing the model
25
25
  * string), repeated on every request.
26
26
  */
27
- export interface RouteCandidateIndex {
27
+ interface RouteCandidateIndex {
28
28
  /** Candidates keyed by `provider_id/model_id`, snapshot order preserved. */
29
29
  readonly qualified: ReadonlyMap<string, readonly RouteCandidate[]>;
30
30
  /** Candidates keyed by bare `model_id`, snapshot order preserved. */
@@ -23,7 +23,7 @@ export class RoundRobinState {
23
23
  * combinations would retain one entry forever. 1000 is far above the working
24
24
  * set of any real catalog, so eviction only ever targets genuinely cold keys.
25
25
  */
26
- export const MAX_ROUND_ROBIN_ENTRIES = 1000;
26
+ const MAX_ROUND_ROBIN_ENTRIES = 1000;
27
27
 
28
28
  /**
29
29
  * Creates the bounded LRU map the router keeps round-robin state in.
@@ -10,6 +10,7 @@ import {
10
10
  networkPools,
11
11
  poolRoutingSettings,
12
12
  providerAccounts,
13
+ providerPoolAccounts,
13
14
  providerRoutingSettings,
14
15
  providers,
15
16
  tenantDisabledModels,
@@ -19,12 +20,12 @@ import {
19
20
  import { DEFAULT_PROVIDER_MAX_INFLIGHT } from "../../persistence/schema";
20
21
  import { resolveTenantOverride } from "../../persistence/tenant-scope";
21
22
  import {
22
- type RouteCandidate,
23
23
  type ComboDefinition,
24
24
  type PoolRoutingSetting,
25
25
  type ProviderRoutingMap,
26
26
  type RouteSnapshot,
27
27
  type SnapshotBuilder,
28
+ type RoutedCandidate,
28
29
  } from "./route-model";
29
30
  import { DEFAULT_PROXY_SKIP_PROVIDER_IDS } from "../../providers/provider-metadata";
30
31
  import { buildClaudeCliUserAgent } from "../../providers/operations/custom-cli-headers";
@@ -83,18 +84,6 @@ export function cliMappingSourceKeys(toolId: string, sourceModel: string): reado
83
84
  * — `RoutingEngine.plan()` filters candidates by the requesting tenant.
84
85
  */
85
86
 
86
- type RouteCandidateWithHealth = RouteCandidate & {
87
- health_status?: "cooldown" | "model_cooldown" | "disabled";
88
- cooldown_kind?: "hard" | "soft";
89
- /**
90
- * Epoch milliseconds at which this candidate's cooling window ends, when one
91
- * is in force. Routing-internal: it is what lets `plan()` report a real reset
92
- * on the all-accounts-cooling answer, and it never reaches a client verbatim —
93
- * only the derived `retry-after` does.
94
- */
95
- cooldown_until?: number;
96
- };
97
-
98
87
  const HARD_COOLDOWN_CATEGORIES: Readonly<Record<string, true>> = {
99
88
  quota_exhausted: true,
100
89
  policy_blocked: true,
@@ -245,6 +234,7 @@ interface MergedModelRow {
245
234
  providerId: string;
246
235
  modelId: string;
247
236
  wireFamily: WireFamily;
237
+ dialect?: string | null;
248
238
  serviceKind: ServiceKind;
249
239
  endpointPath: string;
250
240
  modalities: unknown;
@@ -269,6 +259,7 @@ function mergeModelCatalog(
269
259
  providerId: row.providerId,
270
260
  modelId: row.modelId,
271
261
  wireFamily: row.wireFamily as WireFamily,
262
+ ...(row.dialect === null ? {} : { dialect: row.dialect }),
272
263
  serviceKind: row.serviceKind as ServiceKind,
273
264
  endpointPath: row.endpointPath,
274
265
  modalities: row.modalities,
@@ -308,6 +299,7 @@ const MODEL_COLUMNS = {
308
299
  providerId: models.providerId,
309
300
  modelId: models.modelId,
310
301
  wireFamily: models.wireFamily,
302
+ dialect: models.dialect,
311
303
  serviceKind: models.serviceKind,
312
304
  endpointPath: models.endpointPath,
313
305
  modalities: models.modalities,
@@ -372,6 +364,17 @@ const POOL_COLUMNS = {
372
364
  weight: networkPools.weight,
373
365
  } as const;
374
366
 
367
+ const POOL_ACCOUNT_COLUMNS = {
368
+ id: providerPoolAccounts.id,
369
+ tenantId: providerPoolAccounts.tenantId,
370
+ networkPoolId: providerPoolAccounts.networkPoolId,
371
+ providerId: providerPoolAccounts.providerId,
372
+ label: providerPoolAccounts.label,
373
+ status: providerPoolAccounts.status,
374
+ cooldownUntil: providerPoolAccounts.cooldownUntil,
375
+ lastErrorCategory: providerPoolAccounts.lastErrorCategory,
376
+ } as const;
377
+
375
378
  const DISABLED_MODEL_COLUMNS = {
376
379
  tenantId: tenantDisabledModels.tenantId,
377
380
  providerId: tenantDisabledModels.providerId,
@@ -414,7 +417,7 @@ class RouteCatalogRepository {
414
417
  constructor(private readonly db: CartethyiaDatabase) {}
415
418
 
416
419
  async loadRouteCatalogSnapshot(tenantId?: string): Promise<RouteCatalogSnapshotResult> {
417
- const [providerRows, modelRows, accountRows, aliasRows, comboRows, routingRows, poolRows, disabledModelRows, cliMappingRows, cliMappingSettingRows, poolSettingRows, settingsRows] =
420
+ const [providerRows, modelRows, accountRows, aliasRows, comboRows, routingRows, poolRows, poolAccountRows, disabledModelRows, cliMappingRows, cliMappingSettingRows, poolSettingRows, settingsRows] =
418
421
  await Promise.all([
419
422
  this.db.select(PROVIDER_COLUMNS).from(providers).where(eq(providers.enabled, true)),
420
423
  this.db.select(MODEL_COLUMNS).from(models),
@@ -427,6 +430,7 @@ class RouteCatalogRepository {
427
430
  this.db.select(COMBO_COLUMNS).from(modelCombos),
428
431
  this.db.select(ROUTING_COLUMNS).from(providerRoutingSettings),
429
432
  this.db.select(POOL_COLUMNS).from(networkPools),
433
+ this.db.select(POOL_ACCOUNT_COLUMNS).from(providerPoolAccounts),
430
434
  this.db.select(DISABLED_MODEL_COLUMNS).from(tenantDisabledModels),
431
435
  this.db.select(CLI_MAPPING_COLUMNS).from(cliToolMappings),
432
436
  this.db.select(CLI_MAPPING_SETTING_COLUMNS).from(cliToolSettings),
@@ -500,6 +504,28 @@ class RouteCatalogRepository {
500
504
  activePoolsByTenant.set(pool.tenantId, list);
501
505
  }
502
506
 
507
+ // Pool-as-account rows, grouped by tenant: one per (pool × ip-scoped
508
+ // provider). For a credential-less ip-scoped provider these are the
509
+ // account-equivalent routing entities — a spent egress is excluded from
510
+ // the plan exactly like a cooling account, and the candidate carries the
511
+ // pool-account's health (see the public-candidate fan-out below).
512
+ const poolAccountsByTenant = new Map<
513
+ string,
514
+ Array<{
515
+ id: string;
516
+ networkPoolId: string;
517
+ providerId: string;
518
+ status: string;
519
+ cooldownUntil: Date | null;
520
+ lastErrorCategory: string | null;
521
+ }>
522
+ >();
523
+ for (const poolAccount of poolAccountRows) {
524
+ const list = poolAccountsByTenant.get(poolAccount.tenantId) ?? [];
525
+ list.push(poolAccount);
526
+ poolAccountsByTenant.set(poolAccount.tenantId, list);
527
+ }
528
+
503
529
  // Per-tenant pool selection strategy; an absent row reads as the
504
530
  // `least_loaded` default at selection time.
505
531
  const poolRouting: Record<string, PoolRoutingSetting> = {};
@@ -643,7 +669,7 @@ class RouteCatalogRepository {
643
669
  accountsByProvider.set(account.providerId, list);
644
670
  }
645
671
 
646
- const candidates: RouteCandidateWithHealth[] = [];
672
+ const candidates: RoutedCandidate[] = [];
647
673
  for (const model of mergedModelRows) {
648
674
  const providerTenantId = providerTenantById.get(model.providerId);
649
675
  if (providerTenantId === undefined) continue;
@@ -657,19 +683,83 @@ class RouteCatalogRepository {
657
683
  if (accounts.length === 0) {
658
684
  const providerRequiresAccount = requiresAccountById.get(model.providerId) ?? true;
659
685
  if (!providerRequiresAccount) {
660
- // Public models inherit active pools for each tenant that has active pools
686
+ // Public models inherit active pools for each tenant that has active pools.
687
+ // When the provider is ip-scoped (limits follow the egress address), the
688
+ // tenant's pool-account rows are the account-equivalent routing entities:
689
+ // one candidate per pool, carrying that pool-account's health, so a spent
690
+ // egress is excluded from the plan exactly like a cooling account.
691
+ const ownedTenantIds = [...poolAccountsByTenant.keys()].filter((tid) =>
692
+ (poolAccountsByTenant.get(tid) ?? []).some((pa) => pa.providerId === model.providerId),
693
+ );
694
+ let emittedPoolAccount = false;
695
+ for (const tenantOwnerId of ownedTenantIds) {
696
+ const poolAccounts = poolAccountsByTenant.get(tenantOwnerId) ?? [];
697
+ const tenantPoolAccounts = new Map<string, typeof poolAccounts>();
698
+ for (const pa of poolAccounts) {
699
+ if (pa.providerId !== model.providerId) continue;
700
+ const list = tenantPoolAccounts.get(pa.networkPoolId) ?? [];
701
+ list.push(pa);
702
+ tenantPoolAccounts.set(pa.networkPoolId, list);
703
+ }
704
+ if (tenantPoolAccounts.size === 0) continue;
705
+ for (const [poolId, pas] of tenantPoolAccounts) {
706
+ const first = pas[0];
707
+ if (!first) continue;
708
+ const tenantPools = resolveNetworkPools(model.providerId, tenantOwnerId);
709
+ if (!tenantPools) continue;
710
+ emittedPoolAccount = true;
711
+ const tenantCandidate: RoutedCandidate = {
712
+ provider_id: model.providerId,
713
+ model_id: model.modelId,
714
+ wire_family: model.wireFamily as WireFamily,
715
+ ...(model.dialect == null ? {} : { dialect: model.dialect }),
716
+ service_kind: model.serviceKind,
717
+ endpoint: model.endpointPath,
718
+ ...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
719
+ capability_profile: capabilityProfile,
720
+ tenant_id: tenantOwnerId,
721
+ ...(model.freeTier === true ? { free_tier: true } : {}),
722
+ // Public credential-less candidates have no account to own them.
723
+ owner_tenant_id: null,
724
+ requires_account: false as const,
725
+ network_pool_ids: [poolId],
726
+ network_pool_required: true,
727
+ network_pool_limits: tenantPools.limits,
728
+ network_pool_weights: tenantPools.weights,
729
+ ...(tenantPools.routing ? { network_pool_routing: tenantPools.routing } : {}),
730
+ ...providerLimitFor(model.providerId, tenantOwnerId),
731
+ ...(first.status === "disabled"
732
+ ? { health_status: "disabled" as const }
733
+ : first.status === "cooldown"
734
+ ? {
735
+ health_status: "cooldown" as const,
736
+ cooldown_kind: hardCooldownCategory(first.lastErrorCategory) ? "hard" : "soft",
737
+ ...(first.cooldownUntil && first.cooldownUntil.getTime() > Date.now()
738
+ ? { cooldown_until: first.cooldownUntil.getTime() }
739
+ : {}),
740
+ }
741
+ : {}),
742
+ };
743
+ if (tenantId === undefined || tenantId === tenantOwnerId) {
744
+ candidates.push(tenantCandidate);
745
+ }
746
+ }
747
+ }
748
+ if (emittedPoolAccount) continue;
661
749
  for (const tId of configuredPoolTenants) {
662
750
  const tenantPools = resolveNetworkPools(model.providerId, tId);
663
751
  if (tenantPools) {
664
- const tenantCandidate: RouteCandidateWithHealth = {
752
+ const tenantCandidate: RoutedCandidate = {
665
753
  provider_id: model.providerId,
666
754
  model_id: model.modelId,
667
755
  wire_family: model.wireFamily as WireFamily,
756
+ ...(model.dialect == null ? {} : { dialect: model.dialect }),
668
757
  service_kind: model.serviceKind,
669
758
  endpoint: model.endpointPath,
670
759
  ...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
671
760
  capability_profile: capabilityProfile,
672
761
  tenant_id: tId,
762
+ ...(model.freeTier === true ? { free_tier: true } : {}),
673
763
  // Public credential-less candidates have no account to own them.
674
764
  owner_tenant_id: null,
675
765
  requires_account: false as const,
@@ -689,15 +779,17 @@ class RouteCatalogRepository {
689
779
  const networkPools = providerRequiresAccount
690
780
  ? undefined
691
781
  : resolveNetworkPools(model.providerId, providerTenantId);
692
- const candidate: RouteCandidateWithHealth = {
782
+ const candidate: RoutedCandidate = {
693
783
  provider_id: model.providerId,
694
784
  model_id: model.modelId,
695
785
  wire_family: model.wireFamily as WireFamily,
786
+ ...(model.dialect == null ? {} : { dialect: model.dialect }),
696
787
  service_kind: model.serviceKind,
697
788
  endpoint: model.endpointPath,
698
789
  ...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
699
790
  capability_profile: capabilityProfile,
700
791
  tenant_id: providerTenantId,
792
+ ...(model.freeTier === true ? { free_tier: true } : {}),
701
793
  // Public credential-less candidates have no account to own them.
702
794
  owner_tenant_id: null,
703
795
  ...(providerRequiresAccount
@@ -731,15 +823,17 @@ class RouteCatalogRepository {
731
823
  }
732
824
  const networkPools = resolveNetworkPools(model.providerId, rowTenantId);
733
825
  const routeUserAgent = resolveUserAgent(model.providerId, rowTenantId);
734
- const candidate: RouteCandidateWithHealth = {
826
+ const candidate: RoutedCandidate = {
735
827
  provider_id: model.providerId,
736
828
  model_id: model.modelId,
737
829
  wire_family: model.wireFamily as WireFamily,
830
+ ...(model.dialect == null ? {} : { dialect: model.dialect }),
738
831
  service_kind: model.serviceKind,
739
832
  endpoint: model.endpointPath,
740
833
  ...(model.outputLimit == null ? {} : { output_limit: model.outputLimit }),
741
834
  capability_profile: capabilityProfile,
742
835
  ...(routeUserAgent === undefined ? {} : { user_agent: routeUserAgent }),
836
+ ...(model.freeTier === true ? { free_tier: true } : {}),
743
837
  tenant_id: rowTenantId,
744
838
  provider_account_id: account.id,
745
839
  // The account's owning tenant (null = shared pool-wide) — the bucket