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
@@ -123,42 +123,42 @@ const ADAPTER_OWNED: Record<string, true> = {
123
123
  export function validateCompatibilityProfile(profile: CompatibilityProfile): void {
124
124
  if (profile.cli_identity !== undefined) {
125
125
  if (typeof profile.cli_identity !== "boolean") {
126
- throw new GatewayError("invalid_request", 400, "cli_identity must be boolean");
126
+ throw new GatewayError("invalid_request", 400, "cli_identity must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
127
127
  }
128
128
  }
129
129
  if (profile.gateway_user_agent !== undefined) {
130
130
  if (typeof profile.gateway_user_agent !== "boolean") {
131
- throw new GatewayError("invalid_request", 400, "gateway_user_agent must be boolean");
131
+ throw new GatewayError("invalid_request", 400, "gateway_user_agent must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
132
132
  }
133
133
  }
134
134
  if (profile.extra_headers) {
135
135
  for (const [rawName, rawValue] of Object.entries(profile.extra_headers)) {
136
136
  const name = rawName.toLowerCase();
137
137
  if (name.length < 1 || name.length > 64 || !TOKEN_REGEX.test(name)) {
138
- throw new GatewayError("invalid_request", 400, `invalid header name ${rawName}`);
138
+ throw new GatewayError("invalid_request", 400, `invalid header name ${rawName} (request {requestId}). Check the shape of what you sent — then resend 🪞`);
139
139
  }
140
140
  if (isProtectedHeader(name, ADAPTER_OWNED)) {
141
141
  throw new GatewayError(
142
142
  "invalid_request",
143
143
  400,
144
- `header ${rawName} is not allowed as custom header`,
144
+ `header ${rawName} is not allowed as custom header (request {requestId}). Check the shape of what you sent — then resend 🪞`,
145
145
  );
146
146
  }
147
147
  if (typeof rawValue !== "string") {
148
148
  throw new GatewayError(
149
149
  "invalid_request",
150
150
  400,
151
- `header value for ${rawName} must be string`,
151
+ `header value for ${rawName} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`,
152
152
  );
153
153
  }
154
154
  if (Buffer.byteLength(rawValue, "utf8") > 4096) {
155
- throw new GatewayError("invalid_request", 400, `header value for ${rawName} exceeds 4KiB`);
155
+ throw new GatewayError("invalid_request", 400, `header value for ${rawName} exceeds 4KiB (request {requestId}). We love long reads, but not that long 📚`);
156
156
  }
157
157
  if (/[\r\n\x00-\x1f\x7f]/.test(rawValue)) {
158
158
  throw new GatewayError(
159
159
  "invalid_request",
160
160
  400,
161
- `header value for ${rawName} contains control characters`,
161
+ `header value for ${rawName} contains control characters (request {requestId}). Check the shape of what you sent — then resend 🪞`,
162
162
  );
163
163
  }
164
164
  }
@@ -166,9 +166,9 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
166
166
  if (profile.extra_query_params) {
167
167
  for (const [k, v] of Object.entries(profile.extra_query_params)) {
168
168
  if (typeof v !== "string")
169
- throw new GatewayError("invalid_request", 400, `query param ${k} must be string`);
169
+ throw new GatewayError("invalid_request", 400, `query param ${k} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`);
170
170
  if (/[\r\n]/.test(k) || /[\r\n]/.test(v))
171
- throw new GatewayError("invalid_request", 400, `query param contains CRLF`);
171
+ throw new GatewayError("invalid_request", 400, `query param contains CRLF (request {requestId}). Check the shape of what you sent — then resend 🪞`);
172
172
  }
173
173
  }
174
174
  if (profile.endpoint_paths_by_wire_family) {
@@ -177,56 +177,56 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
177
177
  throw new GatewayError(
178
178
  "invalid_request",
179
179
  400,
180
- `endpoint_paths_by_wire_family: unknown wire family ${wf}`,
180
+ `endpoint_paths_by_wire_family: unknown wire family ${wf} (request {requestId}). Check the shape of what you sent — then resend 🪞`,
181
181
  );
182
182
  }
183
183
  if (typeof path !== "string") {
184
184
  throw new GatewayError(
185
185
  "invalid_request",
186
186
  400,
187
- `endpoint_paths_by_wire_family.${wf} must be string`,
187
+ `endpoint_paths_by_wire_family.${wf} must be string (request {requestId}). Check the shape of what you sent — then resend 🪞`,
188
188
  );
189
189
  }
190
190
  if (path.length === 0 || path.length > 256) {
191
191
  throw new GatewayError(
192
192
  "invalid_request",
193
193
  400,
194
- `endpoint_paths_by_wire_family.${wf} path length must be 1-256 chars`,
194
+ `endpoint_paths_by_wire_family.${wf} path length must be 1-256 chars (request {requestId}). Check the shape of what you sent — then resend 🪞`,
195
195
  );
196
196
  }
197
197
  if (!path.startsWith("/")) {
198
198
  throw new GatewayError(
199
199
  "invalid_request",
200
200
  400,
201
- `endpoint_paths_by_wire_family.${wf} path must start with /`,
201
+ `endpoint_paths_by_wire_family.${wf} path must start with / (request {requestId}). Check the shape of what you sent — then resend 🪞`,
202
202
  );
203
203
  }
204
204
  if (/[\s\r\n\x00-\x1f\x7f]/.test(path)) {
205
205
  throw new GatewayError(
206
206
  "invalid_request",
207
207
  400,
208
- `endpoint_paths_by_wire_family.${wf} path contains invalid characters`,
208
+ `endpoint_paths_by_wire_family.${wf} path contains invalid characters (request {requestId}). Check the shape of what you sent — then resend 🪞`,
209
209
  );
210
210
  }
211
211
  }
212
212
  }
213
213
  if (profile.model_wire_families) {
214
214
  if (!Array.isArray(profile.model_wire_families)) {
215
- throw new GatewayError("invalid_request", 400, "model_wire_families must be an array");
215
+ throw new GatewayError("invalid_request", 400, "model_wire_families must be an array (request {requestId}). Check the shape of what you sent — then resend 🪞");
216
216
  }
217
217
  for (const rule of profile.model_wire_families) {
218
218
  if (typeof rule?.pattern !== "string" || rule.pattern.length === 0) {
219
219
  throw new GatewayError(
220
220
  "invalid_request",
221
221
  400,
222
- "model_wire_families[].pattern must be a non-empty string",
222
+ "model_wire_families[].pattern must be a non-empty string (request {requestId}). Check the shape of what you sent — then resend 🪞",
223
223
  );
224
224
  }
225
225
  if (rule.pattern.length > 256) {
226
226
  throw new GatewayError(
227
227
  "invalid_request",
228
228
  400,
229
- "model_wire_families[].pattern must be at most 256 chars",
229
+ "model_wire_families[].pattern must be at most 256 chars (request {requestId}). Check the shape of what you sent — then resend 🪞",
230
230
  );
231
231
  }
232
232
  try {
@@ -235,14 +235,14 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
235
235
  throw new GatewayError(
236
236
  "invalid_request",
237
237
  400,
238
- `model_wire_families[].pattern ${rule.pattern} is not a valid regular expression`,
238
+ `model_wire_families[].pattern ${rule.pattern} is not a valid regular expression (request {requestId}). Check the shape of what you sent — then resend 🪞`,
239
239
  );
240
240
  }
241
241
  if (!isWireFamily(rule.wire_family)) {
242
242
  throw new GatewayError(
243
243
  "invalid_request",
244
244
  400,
245
- `model_wire_families[].wire_family: unknown wire family ${String(rule.wire_family)}`,
245
+ `model_wire_families[].wire_family: unknown wire family ${String(rule.wire_family)} (request {requestId}). Check the shape of what you sent — then resend 🪞`,
246
246
  );
247
247
  }
248
248
  }
@@ -251,10 +251,10 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
251
251
  profile.streaming_usage_mode &&
252
252
  !["include_usage", "none"].includes(profile.streaming_usage_mode)
253
253
  ) {
254
- throw new GatewayError("invalid_request", 400, "invalid streaming_usage_mode");
254
+ throw new GatewayError("invalid_request", 400, "invalid streaming_usage_mode (request {requestId}). Check the shape of what you sent — then resend 🪞");
255
255
  }
256
256
  if (profile.structured_output && typeof profile.structured_output.enabled !== "boolean") {
257
- throw new GatewayError("invalid_request", 400, "structured_output.enabled must be boolean");
257
+ throw new GatewayError("invalid_request", 400, "structured_output.enabled must be boolean (request {requestId}). Check the shape of what you sent — then resend 🪞");
258
258
  }
259
259
  // If any field is present but has no runtime reader, our current reader set covers all fields above.
260
260
  const allowed: Record<string, true> = {
@@ -281,7 +281,7 @@ export function validateCompatibilityProfile(profile: CompatibilityProfile): voi
281
281
  throw new GatewayError(
282
282
  "invalid_request",
283
283
  400,
284
- `unknown compatibility_profile field ${k} has no runtime reader`,
284
+ `unknown compatibility_profile field ${k} has no runtime reader (request {requestId}). Check the shape of what you sent — then resend 🪞`,
285
285
  );
286
286
  }
287
287
  }
@@ -508,6 +508,13 @@ export interface ProviderAccountResponse {
508
508
  label: string;
509
509
  credentialKind: CredentialKind;
510
510
  credentialMode?: CredentialMode;
511
+ /**
512
+ * Which sign-in family issued this credential, read from the account's
513
+ * `auth_state` (e.g. `social`/`oidc`/`api_key` for Kiro). Surfaced so the
514
+ * console can badge an account by how it logged in without shipping the
515
+ * whole auth state to the browser.
516
+ */
517
+ authMethod?: string;
511
518
  tokenExpiresAt?: string;
512
519
  /**
513
520
  * Who issued this credential, read from the JWT `iss` claim at registration
@@ -539,6 +546,27 @@ export interface ProviderAccountResponse {
539
546
  staticToken?: boolean;
540
547
  /** Stable list position within this provider; the console's "Added" order. */
541
548
  sortIndex: number;
549
+ /**
550
+ * Row flavor. `"pool"` marks a pool-as-account entity (see
551
+ * `provider_pool_accounts`): it is an account-equivalent for an
552
+ * ip-scoped, credential-less provider, resolves no credential, and is
553
+ * owned by its pool. Absent means a real `provider_accounts` row.
554
+ */
555
+ kind?: "pool";
556
+ /** The owning pool row (present for `kind: "pool"`). */
557
+ networkPoolId?: string;
558
+ /**
559
+ * Provider-scoped rate-limit markers on the owning pool, when this is a
560
+ * pool-as-account row. Mirrors `NetworkPoolResponse.providerCooldowns`: a
561
+ * 429 cooldown refills, a block means the upstream retired the egress
562
+ * address. Absent for real accounts and for pools with no markers.
563
+ */
564
+ providerCooldowns?: Array<{
565
+ providerId: string;
566
+ until: string;
567
+ reason: string;
568
+ blocked: boolean;
569
+ }>;
542
570
  }
543
571
  /**
544
572
  * Plaintext export of one account's decrypted provider tokens.
@@ -632,6 +660,18 @@ export interface ProviderResponse {
632
660
  isBuiltIn: boolean;
633
661
  /** True when this tenant has any persisted account for the provider. */
634
662
  configured?: boolean;
663
+ /**
664
+ * Number of provider accounts this tenant has for the provider. Present on
665
+ * list items (the Providers page overview); absent elsewhere.
666
+ */
667
+ accountCount?: number;
668
+ /**
669
+ * Accounts whose status is not disabled/revoked — an account parked by the
670
+ * health machine (`cooldown`) still counts. Present on list items.
671
+ */
672
+ activeAccountCount?: number;
673
+ /** Enabled model rows the tenant can see for the provider. Present on list items. */
674
+ modelCount?: number;
635
675
  /** `false` only for a genuinely credential-less provider (OpenCode Free) —
636
676
  * the dashboard hides account creation for it since none is usable. */
637
677
  requiresAccount: boolean;
@@ -779,6 +819,26 @@ export interface ProviderCatalogStore {
779
819
  syncModels(tenantId: string, providerId: string): Promise<{ synced: number }>;
780
820
  listAccounts(tenantId: string, providerId: string): Promise<readonly ProviderAccountResponse[]>;
781
821
  listAllAccounts(tenantId: string): Promise<readonly ProviderAccountResponse[]>;
822
+ /**
823
+ * Provider-id + status only, for every account the tenant can see. Much
824
+ * cheaper than `listAllAccounts` (which also fetches today/lifetime usage,
825
+ * inflight, pool rows): used by the provider list's "configured" marker and
826
+ * the flat model picker's active-account counts, neither of which reads
827
+ * usage.
828
+ */
829
+ listAllAccountSummaries(tenantId: string): Promise<readonly { providerId: string; status: string }[]>;
830
+ /**
831
+ * Per-provider account totals for the tenant, from one grouped read. Used by
832
+ * the provider list overview (`accountCount` / `activeAccountCount`).
833
+ */
834
+ providerAccountCounts(
835
+ tenantId: string,
836
+ ): Promise<readonly { providerId: string; total: number; active: number }[]>;
837
+ /**
838
+ * Per-provider enabled model-row counts for the tenant, from one grouped read.
839
+ * Used by the provider list overview (`modelCount`).
840
+ */
841
+ providerModelCounts(tenantId: string): Promise<readonly { providerId: string; count: number }[]>;
782
842
  /**
783
843
  * Non-secret upstream auth configuration for the given owned accounts,
784
844
  * keyed by account id. Used by the account-export route so a re-import can
@@ -62,7 +62,7 @@ export function createModelCatalogOperations(config: ProviderCatalogConfig) {
62
62
  const a = requireTenantAnyScope(access, MODEL_READ_SCOPES);
63
63
  const [providers, allAccounts] = await Promise.all([
64
64
  config.store.list(a.tenantId),
65
- config.store.listAllAccounts(a.tenantId),
65
+ config.store.listAllAccountSummaries(a.tenantId),
66
66
  ]);
67
67
  const accountsByProvider = new Map<string, number>();
68
68
  for (const account of allAccounts) {
@@ -16,6 +16,8 @@ import {
16
16
  requireGlobalAdmin,
17
17
  requireTenantAnyScope,
18
18
  } from "../../shared/errors";
19
+ import { cachedReadWithEtag, conditionalResponse } from "../../shared/read-through-cache";
20
+ import type { RedisClient } from "../../../persistence/redis";
19
21
  import type { AccessDecision } from "../../../security/access-control";
20
22
  import type { ProviderUsageDayRow } from "../../../observability/event-query";
21
23
  import { isBundledProviderId } from "../../../providers/provider-contracts";
@@ -128,7 +130,22 @@ export interface ProviderCatalogConfig {
128
130
  readonly auditSink?: AuditSink;
129
131
  /** Registry-backed OAuth login clients; used to compute `oauthFlows` on responses. */
130
132
  readonly providerRegistry: ProviderRegistry;
131
- readonly snapshotInvalidator?: { invalidate(): Promise<number> };
133
+ /**
134
+ * Shared Redis client for the provider-list read-through cache. Omitted in
135
+ * lite mode / tests, where `cachedReadWithEtag` falls back to its bounded
136
+ * in-process TTL store; the ETag/304 semantics are identical either way.
137
+ */
138
+ readonly redis?: RedisClient | undefined;
139
+ /**
140
+ * Drops the cached route snapshot after a catalog write. `currentRevision`
141
+ * (when the host exposes it) is folded into the provider-list cache key, so
142
+ * every mutation that already bumps the snapshot — provider, account, and
143
+ * model writes — rotates the cached overview without a per-path delete.
144
+ */
145
+ readonly snapshotInvalidator?: {
146
+ invalidate(): Promise<number>;
147
+ currentRevision?(): number;
148
+ };
132
149
  /**
133
150
  * Re-applies one provider's BYOK adapter registration after a create/update
134
151
  * so a custom provider is dispatchable without a restart. Optional: tests
@@ -232,23 +249,81 @@ function toProviderLoginField(field: OAuthLoginField): ProviderLoginField {
232
249
  : { options: field.options.map((option) => ({ value: option.value, label: option.label })) }),
233
250
  };
234
251
  }
252
+ /** Provider-list cache TTL: short enough that a 60s poll re-checks the DB
253
+ * occasionally, long enough that a warm page does zero per-card work. */
254
+ const PROVIDER_LIST_CACHE_TTL_SECONDS = 20;
255
+
256
+ /** Cache key namespace + shape version for the provider-list overview. */
257
+ const PROVIDER_LIST_CACHE_SHAPE = "providers:v1:list";
258
+
259
+ /** Version of the read-through cache backend, so a bump is a key rotation. */
260
+ const PROVIDER_LIST_CACHE_REVISION = 1;
261
+
262
+ /** The list projection shared by `listProviders` and its cached wrapper. */
263
+ async function computeProviderList(
264
+ config: ProviderCatalogConfig,
265
+ tenantId: string,
266
+ ): Promise<ProviderResponse[]> {
267
+ const [records, accountCounts, modelCounts] = await Promise.all([
268
+ config.store.list(tenantId),
269
+ config.store.providerAccountCounts(tenantId),
270
+ config.store.providerModelCounts(tenantId),
271
+ ]);
272
+ const accountsByProvider = new Map(accountCounts.map((row) => [row.providerId, row]));
273
+ const modelsByProvider = new Map(modelCounts.map((row) => [row.providerId, row.count]));
274
+ return Promise.all(
275
+ records.map((r) => {
276
+ const counts = accountsByProvider.get(r.providerId);
277
+ return attachProviderCapabilities(
278
+ {
279
+ ...sanitizeProviderResponse(r),
280
+ // A provider with no persisted accounts is not "configured"; the
281
+ // count fields are still present (zero) so the card renders the
282
+ // empty state instead of a loading placeholder.
283
+ configured: counts !== undefined,
284
+ accountCount: counts?.total ?? 0,
285
+ activeAccountCount: counts?.active ?? 0,
286
+ modelCount: modelsByProvider.get(r.providerId) ?? 0,
287
+ },
288
+ config.providerRegistry,
289
+ );
290
+ }),
291
+ );
292
+ }
293
+
235
294
  export function createProviderCatalogOperations(config: ProviderCatalogConfig) {
236
295
  const operations = {
237
296
  async listProviders(access: AccessDecision | undefined): Promise<ProviderResponse[]> {
238
297
  const a = requireTenantAnyScope(access, PROVIDER_READ_SCOPES);
239
- const [records, accounts] = await Promise.all([
240
- config.store.list(a.tenantId),
241
- config.store.listAllAccounts(a.tenantId),
242
- ]);
243
- const configured = new Set(accounts.map((account) => account.providerId));
244
- return Promise.all(
245
- records.map((r) =>
246
- attachProviderCapabilities(
247
- { ...sanitizeProviderResponse(r), configured: configured.has(r.providerId) },
248
- config.providerRegistry,
249
- ),
250
- ),
298
+ return computeProviderList(config, a.tenantId);
299
+ },
300
+ /**
301
+ * The full provider list with overview counts, served through the
302
+ * read-through cache (P-04). A repeated poll answers `304` with the ETag
303
+ * instead of recomputing the two grouped count queries.
304
+ *
305
+ * Returning a `Response` rather than a plain array is what makes the ETag
306
+ * conditional branch possible: a `304` has no body to serialize. The cache
307
+ * key is tenant-scoped and carries the routing revision, so a provider /
308
+ * account / model mutation that bumps the snapshot rotates the key and the
309
+ * next read recomputes fresh counts.
310
+ */
311
+ async listProvidersCached(
312
+ access: AccessDecision | undefined,
313
+ ifNoneMatch: string | null,
314
+ ): Promise<Response> {
315
+ const a = requireTenantAnyScope(access, PROVIDER_READ_SCOPES);
316
+ const revision = config.snapshotInvalidator?.currentRevision?.() ?? 0;
317
+ const key =
318
+ `cartethyia:${PROVIDER_LIST_CACHE_SHAPE}:v${PROVIDER_LIST_CACHE_REVISION}:` +
319
+ `${a.tenantId}:${revision}`;
320
+ const result = await cachedReadWithEtag(
321
+ config.redis,
322
+ key,
323
+ () => computeProviderList(config, a.tenantId),
324
+ PROVIDER_LIST_CACHE_TTL_SECONDS,
251
325
  );
326
+ return conditionalResponse(ifNoneMatch, result, result.value);
252
327
  },
253
328
  async getProviderDetail(
254
329
  access: AccessDecision | undefined,
@@ -693,12 +768,30 @@ export function createProviderCatalogOperations(config: ProviderCatalogConfig) {
693
768
  // Non-secret auth state is part of the credential export: without
694
769
  // it a re-import loses the upstream user id and region that Trae
695
770
  // refresh and dispatch are addressed by.
696
- ...(() => {
771
+ ...(await (async () => {
697
772
  const authState = authStates[account.id];
698
- return authState !== undefined && Object.keys(authState).length > 0
699
- ? { authState }
773
+ // Buddy providers bind a per-account device identity
774
+ // (qimei36) that is normally derived from the INTERNAL account
775
+ // id. Export must materialize that raw binding into the
776
+ // exported auth state — otherwise a re-import mints a new
777
+ // account id, the derived binding changes, and the upstream
778
+ // channel check (11128) rejects the imported account.
779
+ const materialized =
780
+ account.providerId === "cb" ||
781
+ account.providerId === "cbcn" ||
782
+ account.providerId === "workbuddy" ||
783
+ account.providerId === "workbuddycn"
784
+ // dynamic-import: B-02 lazy graph — buddy device-binding materializer, buddy-family only.
785
+ // The buddy-identity graph is lazy-loaded: the device-binding
786
+ // materializer only runs for buddy-family accounts (B-02).
787
+ ? (await import("../../../providers/integrations/buddy/buddy-identity"))
788
+ .materializeBuddyDeviceBinding(account.id, authState)
789
+ : undefined;
790
+ const effectiveAuthState = materialized ?? authState;
791
+ return effectiveAuthState !== undefined && Object.keys(effectiveAuthState).length > 0
792
+ ? { authState: effectiveAuthState }
700
793
  : {};
701
- })(),
794
+ })()),
702
795
  ...(account.inflight === undefined ? {} : { inflight: account.inflight }),
703
796
  createdAt: account.createdAt,
704
797
  ...(account.cooldownUntil ? { cooldownUntil: account.cooldownUntil } : {}),
@@ -1,6 +1,6 @@
1
1
  import { consoleErrorHandler } from "../../shared/errors";
2
2
  import { literalUnion } from "../../shared/elysia-schema";
3
- import { Elysia, t } from "elysia";
3
+ import { Elysia, t, type AnyElysia } from "elysia";
4
4
  import { SERVICE_KINDS, WIRE_FAMILIES } from "../../../protocol/canonical-model";
5
5
  import { PROBE_REASONING_EFFORTS } from "../../../providers/discovery/discovery-types";
6
6
  import {
@@ -150,13 +150,37 @@ const bulkDeleteModelsBody = t.Object({
150
150
  const usageMatrixQuery = t.Object({
151
151
  days: t.Optional(t.Integer({ minimum: 1, maximum: 366 })),
152
152
  });
153
- export function createProviderCatalogRoutes(config: ProviderCatalogConfig): Elysia {
154
- const factory = createProviderCatalogOperations(config);
155
- const modelFactory = createModelCatalogOperations(config);
153
+ export function createProviderCatalogRoutes(config: ProviderCatalogConfig): AnyElysia {
154
+ // One provider-list cache revision shared by both operation factories. Every
155
+ // provider/account/model mutation already funnels through the snapshot
156
+ // invalidator; wrapping it here means any of those writes bumps the revision
157
+ // folded into the provider-list cache key, so the cached overview (P-04)
158
+ // recomputes on the next read without a per-path cache delete. The revision
159
+ // stays per route-group, so a mutation handled by a peer process still
160
+ // converges when its own entry's TTL lapses.
161
+ const underlyingInvalidator = config.snapshotInvalidator;
162
+ let providerListCacheRevision = 0;
163
+ const catalogSnapshotInvalidator = underlyingInvalidator
164
+ ? {
165
+ invalidate: async () => {
166
+ providerListCacheRevision += 1;
167
+ return underlyingInvalidator.invalidate();
168
+ },
169
+ currentRevision: () => providerListCacheRevision,
170
+ }
171
+ : undefined;
172
+ const effectiveConfig = catalogSnapshotInvalidator
173
+ ? { ...config, snapshotInvalidator: catalogSnapshotInvalidator }
174
+ : config;
175
+ const factory = createProviderCatalogOperations(effectiveConfig);
176
+ const modelFactory = createModelCatalogOperations(effectiveConfig);
156
177
  return new Elysia({ prefix: "/providers" })
157
178
  .error(consoleErrorHandler("Provider catalog operation failed"))
158
179
  .get("/", async ({ request }) => {
159
- return await factory.listProviders(config.accessResolver(request));
180
+ return await factory.listProvidersCached(
181
+ config.accessResolver(request),
182
+ request.headers.get("if-none-match"),
183
+ );
160
184
  })
161
185
  .patch(
162
186
  "/platform/global/:providerId",
@@ -394,5 +418,5 @@ export function createProviderCatalogRoutes(config: ProviderCatalogConfig): Elys
394
418
  body.accountIds,
395
419
  );
396
420
  },
397
- ) as unknown as Elysia;
421
+ );
398
422
  }