cartethyia 2.7.3 → 2.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/dist/dashboard/assets/{BannedPage-2TJD37Hb.js → BannedPage-ChG5svFb.js} +1 -1
  2. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  3. package/dist/dashboard/assets/{CliToolDetailPage-xefJNRmJ.js → CliToolDetailPage-BIcWQun7.js} +1 -1
  4. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolsPage-Rj9iHQ3F.js → CliToolsPage-Bf2VelDe.js} +1 -1
  6. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  7. package/dist/dashboard/assets/{CombosPage-JEbYJFxw.js → CombosPage-DCgm5g6g.js} +1 -1
  8. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  9. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +1 -0
  10. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  11. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +1 -0
  12. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  13. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +1 -0
  14. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  15. package/dist/dashboard/assets/{LoginPage-C4w7vea-.js → LoginPage-U6AKaJcF.js} +1 -1
  16. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  17. package/dist/dashboard/assets/{ModelPicker-BtPcAfot.js → ModelPicker-BMS2t8BA.js} +1 -1
  18. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  19. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +1 -0
  20. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  21. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +5 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  23. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +1 -0
  24. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  25. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js +9 -0
  26. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  27. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +1 -0
  28. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  29. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +1 -0
  30. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  31. package/dist/dashboard/assets/{SetupPage-BQS0Rx_u.js → SetupPage-f0DE1h0-.js} +1 -1
  32. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  33. package/dist/dashboard/assets/{SortableList-BAL5npBC.js → SortableList-ClzpwyET.js} +1 -1
  34. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  35. package/dist/dashboard/assets/{StudioPage-TP7voAQ0.js → StudioPage-Cq5tW7hW.js} +3 -3
  36. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  37. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +56 -0
  38. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  39. package/dist/dashboard/assets/api-keys-C38iXoO4.js +1 -0
  40. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  41. package/dist/dashboard/assets/app-a159k0ub.css +2 -0
  42. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  43. package/dist/dashboard/assets/assert-DbRA8EG2.js +15 -0
  44. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  45. package/dist/dashboard/assets/{badge-B_DMpMJN.js → badge-D9CS6dZk.js} +1 -1
  46. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  47. package/dist/dashboard/assets/{banner-DMrMPmth.js → banner-DympBNq4.js} +1 -1
  48. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  49. package/dist/dashboard/assets/{card-Be5Uzamx.js → card-ibRWU_uT.js} +1 -1
  50. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  51. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +1 -0
  52. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  53. package/dist/dashboard/assets/{clipboard-button-DOfrVmsi.js → clipboard-button-DJm-9pz7.js} +1 -1
  54. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  55. package/dist/dashboard/assets/{dialog-C9omdjQt.js → dialog-8fiE6tec.js} +1 -1
  56. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  57. package/dist/dashboard/assets/{drawer-Bm8WKaGY.js → drawer-CqGYeOrd.js} +1 -1
  58. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  59. package/dist/dashboard/assets/{entry-q5HwZ8nN.js → entry-BSAsYsmV.js} +1 -1
  60. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  61. package/dist/dashboard/assets/entry-CiIQULZD.js +4 -0
  62. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  63. package/dist/dashboard/assets/entry-Daz0lJ-W.js +1 -0
  64. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  65. package/dist/dashboard/assets/{formatters-BTScrQpe.js → formatters-D-MTJxMr.js} +1 -1
  66. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  67. package/dist/dashboard/assets/{github-badge-Orjuzemr.js → github-badge-CPK47xQx.js} +1 -1
  68. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  69. package/dist/dashboard/assets/{index-cPrX5vn6.js → index-DBNPOfhV.js} +2 -2
  70. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  71. package/dist/dashboard/assets/{inline-Dvux8w-0.js → inline-BT0zntEr.js} +1 -1
  72. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  73. package/dist/dashboard/assets/{input-CU1Rgf3p.js → input-Da2ZViWg.js} +1 -1
  74. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  75. package/dist/dashboard/assets/{layout-C_7A6H55.js → layout-BXNeLw6M.js} +1 -1
  76. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  77. package/dist/dashboard/assets/{list-row-CzFvogbj.js → list-row-BycOrrIV.js} +1 -1
  78. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  79. package/dist/dashboard/assets/live-DCQNZpF7.js +1 -0
  80. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  81. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +1 -0
  82. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  83. package/dist/dashboard/assets/{mutation-JJGQm8TD.js → mutation-Rr0TIvcj.js} +1 -1
  84. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  85. package/dist/dashboard/assets/network-9Yj2ZyLo.js +1 -0
  86. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  87. package/dist/dashboard/assets/{numbers-BNDZnsUE.js → numbers-CEagj6ZZ.js} +2 -2
  88. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-CLaNz8Xz.js → query-keys-BloKtaXJ.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  91. package/dist/dashboard/assets/quota-Caw7wqci.js +1 -0
  92. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  93. package/dist/dashboard/assets/routing-CO9zCUus.js +1 -0
  94. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  95. package/dist/dashboard/assets/{select-B3iTetHN.js → select-BIYIBkMU.js} +2 -2
  96. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  97. package/dist/dashboard/assets/settings-jS3-PNSA.js +1 -0
  98. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  99. package/dist/dashboard/assets/{stack-KrOrm7JZ.js → stack-DfgnFDWY.js} +1 -1
  100. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  101. package/dist/dashboard/assets/{state-DLS7IDMy.js → state-CkfdYWel.js} +1 -1
  102. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  103. package/dist/dashboard/assets/{switch-42ItvbAs.js → switch-SYm237HG.js} +1 -1
  104. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  105. package/dist/dashboard/assets/{useMutation-Dmnfh1Ue.js → useMutation-BQqCRNIi.js} +1 -1
  106. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  107. package/dist/dashboard/index.html +2 -2
  108. package/dist/dashboard/index.html.gz +0 -0
  109. package/dist/dashboard/precompressed-assets.json +55 -54
  110. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +9 -10
  111. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  112. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  113. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  114. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  115. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +9 -10
  116. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  117. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  118. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  119. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  120. package/package.json +2 -1
  121. package/src/boot/app.ts +9 -8
  122. package/src/config/network.ts +7 -3
  123. package/src/console/api-keys/contracts.ts +52 -0
  124. package/src/console/api-keys/routes.ts +93 -4
  125. package/src/console/audit/routes.ts +3 -3
  126. package/src/console/auth/account-reset.ts +4 -4
  127. package/src/console/auth/session.ts +3 -3
  128. package/src/console/backup/contracts.ts +2 -0
  129. package/src/console/backup/export-endpoint.ts +6 -6
  130. package/src/console/backup/routes.ts +3 -3
  131. package/src/console/cli-tools/routes.ts +3 -3
  132. package/src/console/console-router-guards.ts +2 -2
  133. package/src/console/console-router.ts +4 -4
  134. package/src/console/data-management/routes.ts +3 -3
  135. package/src/console/domain-registration.ts +2 -2
  136. package/src/console/observability/contracts.ts +4 -0
  137. package/src/console/observability/live.ts +3 -3
  138. package/src/console/observability/logs.ts +3 -3
  139. package/src/console/observability/performance.ts +3 -3
  140. package/src/console/observability/routes.ts +3 -3
  141. package/src/console/observability/store.ts +16 -16
  142. package/src/console/providers/catalog/contracts.ts +43 -22
  143. package/src/console/providers/catalog/provider-operations.ts +17 -2
  144. package/src/console/providers/catalog/routes.ts +3 -3
  145. package/src/console/providers/catalog/store-helpers.ts +349 -326
  146. package/src/console/providers/catalog/store.ts +1523 -1292
  147. package/src/console/providers/detail/routes.ts +3 -3
  148. package/src/console/providers/oauth/routes.ts +3 -3
  149. package/src/console/quota/account-quota-tenant.ts +26 -1
  150. package/src/console/quota/account-test-egress.ts +4 -4
  151. package/src/console/routing/model/routes.ts +3 -3
  152. package/src/console/routing/pools/contracts.ts +11 -8
  153. package/src/console/routing/pools/operations.ts +14 -7
  154. package/src/console/routing/pools/probe-verdict.ts +8 -3
  155. package/src/console/routing/pools/relay-deploy.ts +9 -9
  156. package/src/console/routing/pools/routes.ts +3 -3
  157. package/src/console/routing/pools/store.ts +21 -1
  158. package/src/console/settings/routes.ts +3 -3
  159. package/src/console/share/share-router.ts +12 -12
  160. package/src/console/share/share-stats.ts +105 -35
  161. package/src/console/shared/read-through-cache.ts +38 -2
  162. package/src/console/updates/routes.ts +7 -4
  163. package/src/network/outbound-fetch.ts +75 -4
  164. package/src/network/pool/resolver.ts +39 -39
  165. package/src/network/pool-cooldown-store.ts +71 -16
  166. package/src/network/pool-health-machine.ts +21 -1
  167. package/src/network/rate-limit-verdict.ts +68 -0
  168. package/src/network/ssrf.ts +4 -4
  169. package/src/observability/event-query.ts +320 -16
  170. package/src/observability/telemetry-status.ts +1 -1
  171. package/src/persistence/db-sqlite.ts +7 -2
  172. package/src/persistence/readiness.ts +18 -6
  173. package/src/persistence/schema.ts +66 -7
  174. package/src/persistence/stores/api-key-store.ts +99 -3
  175. package/src/persistence/stores/telemetry-store.ts +1 -1
  176. package/src/protocol/codecs.ts +6 -6
  177. package/src/protocol/gateway-error.ts +6 -3
  178. package/src/protocol/image-generation.ts +2 -2
  179. package/src/protocol/response/chat.ts +2 -2
  180. package/src/protocol/response/codex.ts +1 -1
  181. package/src/protocol/response/gemini.ts +1 -1
  182. package/src/protocol/response/messages.ts +5 -5
  183. package/src/protocol/response/responses.ts +2 -2
  184. package/src/protocol/sse-decoder.ts +14 -3
  185. package/src/protocol/translation/capabilities.ts +2 -2
  186. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  187. package/src/providers/adapters/base-adapter.ts +1 -1
  188. package/src/providers/adapters/compatible-adapter.ts +2 -2
  189. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  190. package/src/providers/configured-provider.ts +1 -1
  191. package/src/providers/discovery/probe-phases.ts +2 -2
  192. package/src/providers/discovery/probing-service.ts +12 -12
  193. package/src/providers/integrations/agentrouter/agentrouter.ts +2 -3
  194. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  195. package/src/providers/integrations/anthropic.ts +4 -11
  196. package/src/providers/integrations/antigravity/antigravity.ts +13 -24
  197. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  198. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  199. package/src/providers/integrations/buddy/buddy-identity.ts +22 -1
  200. package/src/providers/integrations/buddy/buddy-media.ts +16 -16
  201. package/src/providers/integrations/buddy/codebuddy/provider.ts +1 -1
  202. package/src/providers/integrations/buddy/workbuddy/provider.ts +1 -1
  203. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  204. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  205. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  206. package/src/providers/integrations/claude/claude.ts +3 -10
  207. package/src/providers/integrations/cline/cline.ts +1 -1
  208. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  209. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  210. package/src/providers/integrations/codex/codex.ts +14 -15
  211. package/src/providers/integrations/commandcode/commandcode.ts +4 -4
  212. package/src/providers/integrations/commandcode/quota.ts +5 -1
  213. package/src/providers/integrations/cursor/cursor-http2.ts +11 -11
  214. package/src/providers/integrations/cursor/cursor.ts +15 -15
  215. package/src/providers/integrations/factory/factory.ts +4 -4
  216. package/src/providers/integrations/gemini.ts +11 -11
  217. package/src/providers/integrations/github/github.ts +6 -6
  218. package/src/providers/integrations/grok/grok.ts +2 -6
  219. package/src/providers/integrations/inferhub.ts +4 -11
  220. package/src/providers/integrations/kimi/kimi.ts +4 -11
  221. package/src/providers/integrations/kiro/kiro.ts +10 -10
  222. package/src/providers/integrations/muse/muse.ts +6 -9
  223. package/src/providers/integrations/perplexity.ts +2 -2
  224. package/src/providers/integrations/qoder/qoder-catalog.ts +47 -9
  225. package/src/providers/integrations/qoder/qoder-checkin.ts +26 -8
  226. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +9 -8
  227. package/src/providers/integrations/qoder/qoder-realm.ts +15 -0
  228. package/src/providers/integrations/qoder/qoder-umid.ts +12 -13
  229. package/src/providers/integrations/qoder/qoder-virtual.ts +2 -2
  230. package/src/providers/integrations/qoder/qoder.ts +188 -22
  231. package/src/providers/integrations/tokenharbor.ts +2 -2
  232. package/src/providers/integrations/trae/trae.ts +6 -9
  233. package/src/providers/integrations/zcode/oauth.ts +1 -1
  234. package/src/providers/operations/provider-catalog-service.ts +4 -4
  235. package/src/providers/operations/provider-credential-service.ts +16 -4
  236. package/src/providers/operations/upstream-deadline.ts +3 -3
  237. package/src/providers/provider-contracts.ts +47 -3
  238. package/src/providers/provider-credential-resolver.ts +1 -1
  239. package/src/providers/provider-registry.ts +4 -4
  240. package/src/providers/quota/quota-contracts.ts +24 -10
  241. package/src/providers/quota/refresh.ts +2 -2
  242. package/src/providers/search/search-provider.ts +5 -5
  243. package/src/security/abuse.ts +4 -4
  244. package/src/security/admission/reasons.ts +17 -17
  245. package/src/security/api-key-auth.ts +4 -4
  246. package/src/shared/coerce.ts +19 -0
  247. package/src/transport/dispatch/attempt-finalize.ts +4 -3
  248. package/src/transport/dispatch/attempt-loop.ts +10 -7
  249. package/src/transport/dispatch/empty-stream.ts +6 -6
  250. package/src/transport/dispatch/generation.ts +9 -9
  251. package/src/transport/dispatch/leases.ts +8 -8
  252. package/src/transport/dispatch/proxy-request.ts +7 -7
  253. package/src/transport/dispatch/responses-compact.ts +11 -11
  254. package/src/transport/dispatch/retry-policy.ts +4 -67
  255. package/src/transport/dispatch/stream-bridge.ts +1 -1
  256. package/src/transport/dispatch/streaming/finalize.ts +9 -8
  257. package/src/transport/dispatch/systemone.ts +8 -8
  258. package/src/transport/dispatch/token-count.ts +9 -9
  259. package/src/transport/dispatch/websearch.ts +6 -6
  260. package/src/transport/drain-endpoint.ts +2 -2
  261. package/src/transport/failure-policy.ts +13 -6
  262. package/src/transport/guards/auth-guard.ts +6 -5
  263. package/src/transport/guards/body-policy.ts +4 -4
  264. package/src/transport/guards/error-lifecycle.ts +18 -3
  265. package/src/transport/guards/guard-errors.ts +7 -3
  266. package/src/transport/guards/headroom-guard.ts +1 -1
  267. package/src/transport/guards/pipeline.ts +6 -6
  268. package/src/transport/guards/readiness-guard.ts +16 -2
  269. package/src/transport/guards/request-context.ts +3 -3
  270. package/src/transport/request/preparer.ts +20 -20
  271. package/src/transport/request/state.ts +4 -7
  272. package/src/transport/routing/route-catalog.ts +97 -2
  273. package/src/transport/routing/route-model.ts +7 -7
  274. package/src/transport/routing/router.ts +2 -2
  275. package/src/transport/shutdown-notice.ts +19 -7
  276. package/src/transport/surface/completion.ts +1 -1
  277. package/src/transport/surface/messages/encode.ts +1 -1
  278. package/dist/dashboard/assets/BannedPage-2TJD37Hb.js.gz +0 -0
  279. package/dist/dashboard/assets/CliToolDetailPage-xefJNRmJ.js.gz +0 -0
  280. package/dist/dashboard/assets/CliToolsPage-Rj9iHQ3F.js.gz +0 -0
  281. package/dist/dashboard/assets/CombosPage-JEbYJFxw.js.gz +0 -0
  282. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js +0 -1
  283. package/dist/dashboard/assets/ConsoleLogPage-C3xx_inM.js.gz +0 -0
  284. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js +0 -1
  285. package/dist/dashboard/assets/CustomizationPage-Dw306gJU.js.gz +0 -0
  286. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js +0 -1
  287. package/dist/dashboard/assets/HealthEventsModal-jaBo1TWV.js.gz +0 -0
  288. package/dist/dashboard/assets/LoginPage-C4w7vea-.js.gz +0 -0
  289. package/dist/dashboard/assets/ModelPicker-BtPcAfot.js.gz +0 -0
  290. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js +0 -1
  291. package/dist/dashboard/assets/OverviewPage-CGC5gNs1.js.gz +0 -0
  292. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js +0 -4
  293. package/dist/dashboard/assets/ProviderDetailPage-DQcthNGt.js.gz +0 -0
  294. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js +0 -1
  295. package/dist/dashboard/assets/ProvidersPage-0OsXRGXe.js.gz +0 -0
  296. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js +0 -9
  297. package/dist/dashboard/assets/ProxyPage-DdPc8slb.js.gz +0 -0
  298. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js +0 -1
  299. package/dist/dashboard/assets/QuotaPage-Ci5O4BnH.js.gz +0 -0
  300. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js +0 -1
  301. package/dist/dashboard/assets/SettingsPage-CDZjTt87.js.gz +0 -0
  302. package/dist/dashboard/assets/SetupPage-BQS0Rx_u.js.gz +0 -0
  303. package/dist/dashboard/assets/SortableList-BAL5npBC.js.gz +0 -0
  304. package/dist/dashboard/assets/StudioPage-TP7voAQ0.js.gz +0 -0
  305. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js +0 -56
  306. package/dist/dashboard/assets/UsagePage-Cj_fEzhg.js.gz +0 -0
  307. package/dist/dashboard/assets/api-keys-MbI7e7rt.js +0 -1
  308. package/dist/dashboard/assets/api-keys-MbI7e7rt.js.gz +0 -0
  309. package/dist/dashboard/assets/app-B2vyPoII.css +0 -2
  310. package/dist/dashboard/assets/app-B2vyPoII.css.gz +0 -0
  311. package/dist/dashboard/assets/assert-C0YYuZJ4.js +0 -1
  312. package/dist/dashboard/assets/assert-C0YYuZJ4.js.gz +0 -0
  313. package/dist/dashboard/assets/badge-B_DMpMJN.js.gz +0 -0
  314. package/dist/dashboard/assets/banner-DMrMPmth.js.gz +0 -0
  315. package/dist/dashboard/assets/card-Be5Uzamx.js.gz +0 -0
  316. package/dist/dashboard/assets/cli-tools-muFRphDu.js +0 -1
  317. package/dist/dashboard/assets/cli-tools-muFRphDu.js.gz +0 -0
  318. package/dist/dashboard/assets/clipboard-button-DOfrVmsi.js.gz +0 -0
  319. package/dist/dashboard/assets/dialog-C9omdjQt.js.gz +0 -0
  320. package/dist/dashboard/assets/drawer-Bm8WKaGY.js.gz +0 -0
  321. package/dist/dashboard/assets/entry-DS90gUks.js +0 -1
  322. package/dist/dashboard/assets/entry-DS90gUks.js.gz +0 -0
  323. package/dist/dashboard/assets/entry-j40LJotO.js +0 -4
  324. package/dist/dashboard/assets/entry-j40LJotO.js.gz +0 -0
  325. package/dist/dashboard/assets/entry-q5HwZ8nN.js.gz +0 -0
  326. package/dist/dashboard/assets/formatters-BTScrQpe.js.gz +0 -0
  327. package/dist/dashboard/assets/github-badge-Orjuzemr.js.gz +0 -0
  328. package/dist/dashboard/assets/index-cPrX5vn6.js.gz +0 -0
  329. package/dist/dashboard/assets/inline-Dvux8w-0.js.gz +0 -0
  330. package/dist/dashboard/assets/input-CU1Rgf3p.js.gz +0 -0
  331. package/dist/dashboard/assets/layout-C_7A6H55.js.gz +0 -0
  332. package/dist/dashboard/assets/list-row-CzFvogbj.js.gz +0 -0
  333. package/dist/dashboard/assets/live-KaG15HLQ.js +0 -1
  334. package/dist/dashboard/assets/live-KaG15HLQ.js.gz +0 -0
  335. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  336. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  337. package/dist/dashboard/assets/mutation-JJGQm8TD.js.gz +0 -0
  338. package/dist/dashboard/assets/numbers-BNDZnsUE.js.gz +0 -0
  339. package/dist/dashboard/assets/query-keys-CLaNz8Xz.js.gz +0 -0
  340. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  341. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  342. package/dist/dashboard/assets/routing-BEH32QOC.js +0 -1
  343. package/dist/dashboard/assets/routing-BEH32QOC.js.gz +0 -0
  344. package/dist/dashboard/assets/select-B3iTetHN.js.gz +0 -0
  345. package/dist/dashboard/assets/settings-Dt3Eqbnq.js +0 -1
  346. package/dist/dashboard/assets/settings-Dt3Eqbnq.js.gz +0 -0
  347. package/dist/dashboard/assets/stack-KrOrm7JZ.js.gz +0 -0
  348. package/dist/dashboard/assets/state-DLS7IDMy.js.gz +0 -0
  349. package/dist/dashboard/assets/switch-42ItvbAs.js.gz +0 -0
  350. package/dist/dashboard/assets/useMutation-Dmnfh1Ue.js.gz +0 -0
  351. /package/dist/dashboard/assets/{app-wvwCi4Eh.js → app-BayTTy01.js} +0 -0
  352. /package/dist/dashboard/assets/{app-wvwCi4Eh.js.gz → app-BayTTy01.js.gz} +0 -0
@@ -16,6 +16,7 @@
16
16
  * protocol at the `/anthropic` path suffix, including `thinking_delta`
17
17
  * blocks, so the Messages leg is built directly.
18
18
  */
19
+ import { assertWireFamily } from "../../provider-contracts";
19
20
  import type {
20
21
  ProviderAdapter,
21
22
  ProviderDispatchContext,
@@ -57,7 +58,7 @@ function cloudflareEnvelope(context: ProviderDispatchContext): {
57
58
  } {
58
59
  const secret = context.credential.secret;
59
60
  if (secret === undefined || secret.length === 0) {
60
- throw new GatewayError("invalid_request", 400, "cloudflareai: credential is missing a secret value");
61
+ throw new GatewayError("invalid_request", 400, "cloudflareai: credential is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑");
61
62
  }
62
63
  let envelope: ReturnType<typeof decodeCloudflareAiGatewayCredential>;
63
64
  try {
@@ -66,7 +67,7 @@ function cloudflareEnvelope(context: ProviderDispatchContext): {
66
67
  throw new GatewayError(
67
68
  "invalid_request",
68
69
  400,
69
- `cloudflareai: ${error instanceof Error ? error.message : "stored credential is not a Cloudflare envelope"}`,
70
+ `cloudflareai: ${error instanceof Error ? error.message : "stored credential is not a Cloudflare envelope"} (request {requestId}). Wrong key, right door — check the credential 🔑`,
70
71
  );
71
72
  }
72
73
  return { token: envelope.token, baseUrl: cloudflareBaseUrl(envelope.accountId, envelope.gatewayId) };
@@ -93,11 +94,7 @@ class CloudflareAiGatewayAdapter implements ProviderAdapter {
93
94
  context: ProviderDispatchContext,
94
95
  ): AsyncIterable<CanonicalEvent> {
95
96
  if (candidate.wire_family !== "messages") {
96
- throw new GatewayError(
97
- "capability_unsupported",
98
- 400,
99
- `cloudflareai supports messages only, got ${candidate.wire_family}`,
100
- );
97
+ assertWireFamily(candidate, "messages", "cloudflareai");
101
98
  }
102
99
  const { token, baseUrl } = cloudflareEnvelope(context);
103
100
  const outbound = buildClaudeMessagesRequest({
@@ -167,7 +167,7 @@ export async function mapCodexErrorResponse(res: Response): Promise<never> {
167
167
  throw new GatewayError(
168
168
  classification.code,
169
169
  classification.status,
170
- friendlyMessage ?? sanitized,
170
+ `${friendlyMessage ?? sanitized} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
171
171
  details,
172
172
  classification.origin,
173
173
  );
@@ -22,7 +22,7 @@
22
22
  * OpenAI-compatible factory's reach — stays bespoke, never re-audit.
23
23
  */
24
24
  import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
25
- import { GatewayError, capabilityUnsupported } from "../../../protocol/gateway-error";
25
+ import { GatewayError } from "../../../protocol/gateway-error";
26
26
  import { getCodexVersion } from "../../operations/client-versions";
27
27
  import { buildCodexUserAgent } from "../../operations/cli-platform";
28
28
  import { randomUUID } from "node:crypto";
@@ -54,6 +54,7 @@ export function _setCodexRateLimitSleepForTesting(
54
54
  function sleep(ms: number, signal: AbortSignal): Promise<void> {
55
55
  return rateLimitSleep(ms, signal);
56
56
  }
57
+ import { assertWireFamily } from "../../provider-contracts";
57
58
  import type { ImageGenerationOutcome, ProviderDispatchTarget, ProviderAdapter, ProviderDispatchContext, ResolvedCredential, WebSearchOutcome, WebSearchResult } from "../../provider-contracts";
58
59
  import type { FetchLike } from "../../quota/quota-contracts";
59
60
  import { boundedUpstreamArray, boundedUpstreamNumber, sanitizeUpstreamLabel } from "../../provider-sanitize";
@@ -199,7 +200,7 @@ export function assertCodexOAuthCredential(
199
200
  throw new GatewayError(
200
201
  "invalid_request",
201
202
  400,
202
- `codex: ChatGPT OAuth credential required (got credential_kind=${credential.credential_kind})`,
203
+ `codex: ChatGPT OAuth credential required (got credential_kind=${credential.credential_kind}) (request {requestId}). Wrong key, right door — check the credential 🔑`,
203
204
  );
204
205
  }
205
206
  }
@@ -361,7 +362,7 @@ function authHeadersForCodex(
361
362
  throw new GatewayError(
362
363
  "invalid_request",
363
364
  400,
364
- "codex: OAuth credential is missing a bearer token",
365
+ "codex: OAuth credential is missing a bearer token (request {requestId}). Wrong key, right door — check the credential 🔑",
365
366
  );
366
367
  }
367
368
  const token = new TextDecoder().decode(credential.secret);
@@ -748,7 +749,7 @@ export function createCodexAdapter(
748
749
  context: ProviderDispatchContext,
749
750
  ): Promise<WebSearchOutcome> {
750
751
  const query = typeof body.query === "string" ? body.query.trim() : "";
751
- if (!query) throw new GatewayError("invalid_request", 400, "search query is required");
752
+ if (!query) throw new GatewayError("invalid_request", 400, "search query is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
752
753
  const requested = typeof body.model === "string" ? body.model.trim() : "";
753
754
  const model = requested.length > 0 && requested !== "codex" ? requested : CODEX_SEARCH_DEFAULT_MODEL;
754
755
  const request: CanonicalRequest = {
@@ -779,7 +780,7 @@ export function createCodexAdapter(
779
780
  }
780
781
  const results = normalizeCodexSearchCitations(citations, answerText);
781
782
  if (results.length === 0)
782
- throw new GatewayError("platform_unavailable", 502, "Codex search returned no citations");
783
+ throw new GatewayError("platform_unavailable", 502, "Codex search returned no citations (request {requestId}). The upstream came back empty-handed — retry 🌙");
783
784
  const rawMax = body.max_results;
784
785
  const maxResults =
785
786
  typeof rawMax === "number" && Number.isFinite(rawMax)
@@ -796,7 +797,7 @@ export function createCodexAdapter(
796
797
  const prompt = imagePrompt(body);
797
798
  const requested =
798
799
  candidate.model_id.length > 0 ? candidate.model_id : typeof body.model === "string" ? body.model : "";
799
- if (requested.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
800
+ if (requested.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
800
801
  // A `-image` id is the chat model with the suffix removed. Dedicated
801
802
  // image tools still need a chat carrier, and the account's visible 5.6
802
803
  // models are the current ones.
@@ -868,7 +869,7 @@ export function createCodexAdapter(
868
869
  try {
869
870
  parsed = JSON.parse(data);
870
871
  } catch {
871
- throw new GatewayError("platform_unavailable", 502, "Codex image stream returned malformed JSON", {}, "upstream");
872
+ throw new GatewayError("platform_unavailable", 502, "Codex image stream returned malformed JSON (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
872
873
  }
873
874
  if (isRecord(parsed) && (parsed.type === "error" || parsed.type === "response.failed")) {
874
875
  const message = isRecord(parsed.error) && typeof parsed.error.message === "string"
@@ -876,7 +877,7 @@ export function createCodexAdapter(
876
877
  : isRecord(parsed.response) && isRecord(parsed.response.error) && typeof parsed.response.error.message === "string"
877
878
  ? parsed.response.error.message
878
879
  : "Codex image generation failed";
879
- throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
880
+ throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
880
881
  }
881
882
  image = responsesImageResult(parsed) ?? image;
882
883
  }
@@ -903,19 +904,17 @@ export function createCodexAdapter(
903
904
  throw new GatewayError(
904
905
  "invalid_request",
905
906
  400,
906
- "codex adapter received non-codex candidate",
907
+ "codex adapter received non-codex candidate (request {requestId}). Even we have bad days — check the registry wiring 🐻",
907
908
  );
908
909
  }
909
910
  if (candidate.wire_family !== "responses") {
910
- throw capabilityUnsupported("responses", {
911
- wire_family: candidate.wire_family,
912
- });
911
+ assertWireFamily(candidate, "responses", "codex");
913
912
  }
914
913
  if (request.model.includes("?")) {
915
914
  throw new GatewayError(
916
915
  "invalid_request",
917
916
  400,
918
- "model must not contain query string",
917
+ "model must not contain query string (request {requestId}). Check the shape of what you sent — then resend 🪞",
919
918
  );
920
919
  }
921
920
 
@@ -1181,8 +1180,8 @@ export function createCodexAdapter(
1181
1180
  "platform_unavailable",
1182
1181
  502,
1183
1182
  error instanceof Error
1184
- ? `Malformed SSE event: ${error.message}`
1185
- : "Malformed SSE event",
1183
+ ? `Malformed SSE event: ${error.message} (request {requestId}). The upstream sent something we can't read — retry 🌙`
1184
+ : `Malformed SSE event (request {requestId}). The upstream sent something we can't read — retry 🌙`,
1186
1185
  {},
1187
1186
  "upstream",
1188
1187
  );
@@ -527,7 +527,7 @@ export function transformLine(line: string, state: StreamState, seqBase: number)
527
527
  const message =
528
528
  extractUpstreamMessage(raw) ||
529
529
  extractUpstreamMessage(event) ||
530
- "Command Code stream error";
530
+ "Command Code stream error (request {requestId}). The upstream came back empty-handed — retry 🌙";
531
531
  throw new GatewayError(
532
532
  classification.code,
533
533
  classification.status,
@@ -558,11 +558,11 @@ export async function* transformNdjson(body: ReadableStream<Uint8Array>, signal:
558
558
  yield { type: "response_start", sequence_number: seq++, model: "commandcode" } as CanonicalEvent;
559
559
 
560
560
  const readWithAbort = (): Promise<{ done: boolean; value?: Uint8Array }> => {
561
- if (signal.aborted) throw new GatewayError("transport_closed", 499, "Command Code stream aborted");
561
+ if (signal.aborted) throw new GatewayError("transport_closed", 499, "Command Code stream aborted (request {requestId}). Send it again whenever ready 🙃");
562
562
  const { promise, resolve, reject } = Promise.withResolvers<{ done: boolean; value?: Uint8Array }>() as unknown as { promise: Promise<{ done: boolean; value?: Uint8Array }>; resolve: (v: unknown) => void; reject: (e: unknown) => void };
563
563
  const onAbort = (): void => {
564
- if (signal.aborted) reject(new GatewayError("transport_closed", 499, "Command Code stream aborted"));
565
- else reject(new GatewayError("platform_unavailable", 502, "Command Code stream error", {}, "upstream"));
564
+ if (signal.aborted) reject(new GatewayError("transport_closed", 499, "Command Code stream aborted (request {requestId}). Send it again whenever ready 🙃"));
565
+ else reject(new GatewayError("platform_unavailable", 502, "Command Code stream error (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream"));
566
566
  };
567
567
  signal.addEventListener("abort", onAbort, { once: true });
568
568
  void reader.read().then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
@@ -72,7 +72,11 @@ function creditWindow(credits: Record<string, unknown>): ProviderQuotaWindow | n
72
72
  return {
73
73
  kind: "credits",
74
74
  label: "Credits",
75
- accounting: "independent",
75
+ // These are credits in one unit that can be spent interchangeably, so
76
+ // they are pooled like Qoder's plan/granted balances — not independent
77
+ // rate-limit lanes. The account-row pill and the Quota page both sum
78
+ // pooled windows, so this must be `pooled` or the balance never renders.
79
+ accounting: "pooled",
76
80
  usedPercent: null,
77
81
  remainingPercent: null,
78
82
  resetsAt: null,
@@ -46,7 +46,7 @@ function connectErrorEnvelope(payload: Uint8Array): GatewayError | undefined {
46
46
  return new GatewayError(
47
47
  "quota_exceeded",
48
48
  429,
49
- `Cursor refused the Run: ${detail}`,
49
+ `Cursor refused the Run: ${detail} (request {requestId}). You've maxed this window — pace yourself ⏳`,
50
50
  { providerId: "cursor", upstreamCode: code },
51
51
  "upstream",
52
52
  );
@@ -54,7 +54,7 @@ function connectErrorEnvelope(payload: Uint8Array): GatewayError | undefined {
54
54
  return new GatewayError(
55
55
  "platform_unavailable",
56
56
  502,
57
- `Cursor refused the Run: ${detail}`,
57
+ `Cursor refused the Run: ${detail} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
58
58
  { providerId: "cursor", upstreamCode: code },
59
59
  "upstream",
60
60
  );
@@ -126,7 +126,7 @@ export async function openCursorRun(input: {
126
126
  throw new GatewayError(
127
127
  "invalid_request",
128
128
  400,
129
- "Cursor Run requires an allowlisted Cursor agent origin",
129
+ "Cursor Run requires an allowlisted Cursor agent origin (request {requestId}). All roads blocked — time to find a new route 🗺️",
130
130
  { origin: input.origin },
131
131
  );
132
132
  }
@@ -153,7 +153,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
153
153
  return new GatewayError(
154
154
  "authentication_failed",
155
155
  401,
156
- `Cursor refused the credential${detail}`,
156
+ `Cursor refused the credential${detail} (request {requestId}). Wrong key, right door — check the credential 🔑`,
157
157
  { grpcStatus: status },
158
158
  "upstream",
159
159
  );
@@ -162,7 +162,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
162
162
  return new GatewayError(
163
163
  "quota_exceeded",
164
164
  429,
165
- `Cursor refused the Run${detail}`,
165
+ `Cursor refused the Run${detail} (request {requestId}). You've maxed this window — pace yourself ⏳`,
166
166
  { grpcStatus: status },
167
167
  "upstream",
168
168
  );
@@ -171,7 +171,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
171
171
  return new GatewayError(
172
172
  "deadline_exceeded",
173
173
  504,
174
- `Cursor Run ended before it finished${detail}`,
174
+ `Cursor Run ended before it finished${detail} (request {requestId}). Some things just take longer 🐢`,
175
175
  { grpcStatus: status },
176
176
  "upstream",
177
177
  );
@@ -179,7 +179,7 @@ function grpcError(status: string, message: string | undefined): GatewayError {
179
179
  return new GatewayError(
180
180
  "platform_unavailable",
181
181
  502,
182
- `Cursor Run failed (gRPC ${status})${detail}`,
182
+ `Cursor Run failed (gRPC ${status})${detail} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
183
183
  { grpcStatus: status },
184
184
  "upstream",
185
185
  );
@@ -205,7 +205,7 @@ export function cursorRunTerminationError(input: {
205
205
  : new GatewayError(
206
206
  "transport_unavailable",
207
207
  502,
208
- `Cursor Run transport interrupted: ${input.reason.error.message}`,
208
+ `Cursor Run transport interrupted: ${input.reason.error.message} (request {requestId}). The connection ghosted us — come back in a moment 👻`,
209
209
  {},
210
210
  "network",
211
211
  );
@@ -216,7 +216,7 @@ export function cursorRunTerminationError(input: {
216
216
  return new GatewayError(
217
217
  status === 401 || status === 403 ? "authentication_failed" : "platform_unavailable",
218
218
  status === 401 || status === 403 ? 401 : 502,
219
- `Cursor Run failed by remote: ${status}`,
219
+ `Cursor Run failed by remote: ${status} (request {requestId}). The upstream came back empty-handed — retry 🌙`,
220
220
  { httpStatus: status, ...(message === undefined ? {} : { upstreamMessage: message }) },
221
221
  "upstream",
222
222
  );
@@ -229,7 +229,7 @@ export function cursorRunTerminationError(input: {
229
229
  return new GatewayError(
230
230
  "platform_unavailable",
231
231
  502,
232
- "Cursor Run ended before turn_ended",
232
+ "Cursor Run ended before turn_ended (request {requestId}). The upstream came back empty-handed — retry 🌙",
233
233
  {},
234
234
  "upstream",
235
235
  );
@@ -253,7 +253,7 @@ export async function* decodeServerMessages(
253
253
  throw new GatewayError(
254
254
  "platform_unavailable",
255
255
  502,
256
- "Cursor Run exceeded the frame buffer bound",
256
+ "Cursor Run exceeded the frame buffer bound (request {requestId}). The upstream sent more than we can hold — retry 🌙",
257
257
  {},
258
258
  "upstream",
259
259
  );
@@ -152,14 +152,14 @@ function finishImage(bytes: Uint8Array): CursorImageInput {
152
152
  throw new GatewayError(
153
153
  "invalid_request",
154
154
  400,
155
- "Cursor accepts PNG, JPEG, WebP and GIF image input only",
155
+ "Cursor accepts PNG, JPEG, WebP and GIF image input only (request {requestId}). Check the shape of what you sent — then resend 🪞",
156
156
  );
157
157
  }
158
158
  if (bytes.byteLength > MAX_IMAGE_BYTES) {
159
159
  throw new GatewayError(
160
160
  "invalid_request",
161
161
  400,
162
- `Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit`,
162
+ `Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
163
163
  );
164
164
  }
165
165
  return { data: bytes, mimeType };
@@ -183,7 +183,7 @@ async function resolveImageInput(
183
183
  if (dataUrl !== undefined) {
184
184
  const bytes = base64ToBytes(dataUrl.data);
185
185
  if (bytes === undefined) {
186
- throw new GatewayError("invalid_request", 400, "Cursor image attachment is not valid base64");
186
+ throw new GatewayError("invalid_request", 400, "Cursor image attachment is not valid base64 (request {requestId}). Check the shape of what you sent — then resend 🪞");
187
187
  }
188
188
  return finishImage(bytes);
189
189
  }
@@ -192,7 +192,7 @@ async function resolveImageInput(
192
192
  throw new GatewayError(
193
193
  "invalid_request",
194
194
  400,
195
- "Cursor image URLs must be HTTPS; private and non-TLS sources are not fetched",
195
+ "Cursor image URLs must be HTTPS; private and non-TLS sources are not fetched (request {requestId}). Check the shape of what you sent — then resend 🪞",
196
196
  );
197
197
  }
198
198
  const fetcher = context.outbound_attachment_fetch;
@@ -200,7 +200,7 @@ async function resolveImageInput(
200
200
  throw new GatewayError(
201
201
  "invalid_request",
202
202
  400,
203
- "Cursor has no validated egress to fetch this image URL",
203
+ "Cursor has no validated egress to fetch this image URL (request {requestId}). All roads blocked — time to find a new route 🗺️",
204
204
  );
205
205
  }
206
206
  // Redirects are not followed: reject the response rather than letting a
@@ -222,7 +222,7 @@ async function resolveImageInput(
222
222
  throw new GatewayError(
223
223
  "invalid_request",
224
224
  400,
225
- `Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit`,
225
+ `Cursor image input exceeds the ${MAX_IMAGE_BYTES}-byte limit (request {requestId}). We love long reads, but not that long 📚`,
226
226
  );
227
227
  }
228
228
  return finishImage(body);
@@ -503,7 +503,7 @@ class CursorAdapter implements ProviderAdapter {
503
503
  throw new GatewayError(
504
504
  "invalid_request",
505
505
  400,
506
- "This tool result cannot be matched to a live Cursor Run; resend the complete conversation.",
506
+ "This tool result cannot be matched to a live Cursor Run (request {requestId}); resend the complete conversation. The session went cold — reconnect or resend 🔌",
507
507
  );
508
508
  }
509
509
  const resolvedAll = pending.map((item) => cursorRunSessions.resolveCall(item.callId, scope));
@@ -530,7 +530,7 @@ class CursorAdapter implements ProviderAdapter {
530
530
  throw new GatewayError(
531
531
  "invalid_request",
532
532
  400,
533
- "This tool result refers to a Cursor tool call that is no longer pending. Resend the complete conversation.",
533
+ "This tool result refers to a Cursor tool call that is no longer pending (request {requestId}). Resend the complete conversation. The session went cold — reconnect or resend 🔌",
534
534
  { callIds: pending.map((item) => item.callId) },
535
535
  );
536
536
  }
@@ -538,12 +538,12 @@ class CursorAdapter implements ProviderAdapter {
538
538
  throw new GatewayError(
539
539
  "invalid_request",
540
540
  400,
541
- "These tool results belong to different Cursor Runs; resend them one Run at a time.",
541
+ "These tool results belong to different Cursor Runs (request {requestId}); resend them one Run at a time. The session went cold — reconnect or resend 🔌",
542
542
  );
543
543
  }
544
544
  const session = cursorRunSessions.get(runId);
545
545
  if (session === undefined) {
546
- throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live");
546
+ throw new GatewayError("invalid_request", 400, "Cursor Run is no longer live (request {requestId}). The session went cold — reconnect or resend 🔌");
547
547
  }
548
548
  const handle = this.#handles.get(runId);
549
549
  if (handle === undefined) {
@@ -605,7 +605,7 @@ class CursorAdapter implements ProviderAdapter {
605
605
  throw new GatewayError(
606
606
  "admission_unavailable",
607
607
  503,
608
- "Cursor requires validated HTTP/2 egress; none is configured for this route",
608
+ "Cursor requires validated HTTP/2 egress (request {requestId}); none is configured for this route. No bridge to cross — configure a pool first 🏗️",
609
609
  { providerId: CURSOR_PROVIDER_ID },
610
610
  );
611
611
  }
@@ -784,7 +784,7 @@ class CursorAdapter implements ProviderAdapter {
784
784
  : new GatewayError(
785
785
  "platform_unavailable",
786
786
  502,
787
- `Cursor Run failed: ${error instanceof Error ? error.message : String(error)}`,
787
+ `Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
788
788
  { providerId: CURSOR_PROVIDER_ID },
789
789
  "upstream",
790
790
  );
@@ -828,7 +828,7 @@ class CursorAdapter implements ProviderAdapter {
828
828
  throw new GatewayError(
829
829
  "platform_unavailable",
830
830
  502,
831
- `Cursor Run origin could not be resolved: ${error instanceof Error ? error.message : String(error)}`,
831
+ `Cursor Run origin could not be resolved (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
832
832
  { providerId: CURSOR_PROVIDER_ID },
833
833
  "upstream",
834
834
  );
@@ -890,7 +890,7 @@ class CursorAdapter implements ProviderAdapter {
890
890
  }
891
891
  const message = item;
892
892
  if (context.abort_signal.aborted) {
893
- failure = new GatewayError("transport_closed", 499, "request was cancelled");
893
+ failure = new GatewayError("transport_closed", 499, "The request was cancelled (request {requestId}). Send it again whenever ready 🙃");
894
894
  break;
895
895
  }
896
896
  const execServer = recordOf(message["exec_server_message"]);
@@ -994,7 +994,7 @@ class CursorAdapter implements ProviderAdapter {
994
994
  : new GatewayError(
995
995
  "platform_unavailable",
996
996
  502,
997
- `Cursor Run failed: ${error instanceof Error ? error.message : String(error)}`,
997
+ `Cursor Run failed (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The upstream came back empty-handed — retry 🌙`,
998
998
  { providerId: CURSOR_PROVIDER_ID },
999
999
  "upstream",
1000
1000
  );
@@ -270,7 +270,7 @@ export function factoryRegionUnavailable(modelId: string, region: string): Gatew
270
270
  return new GatewayError(
271
271
  "capability_unsupported",
272
272
  400,
273
- `factory: ${modelId} is unavailable in this account region (${region})`,
273
+ `factory: ${modelId} is unavailable in this account region (${region}) (request {requestId}). Know your tools — this one just isn't in the box 🧰`,
274
274
  { model: modelId, region, reason: "Factory Droid model is unavailable in this account region." },
275
275
  );
276
276
  }
@@ -351,7 +351,7 @@ export function factoryRoutingHeaders(
351
351
  function factoryEnvelope(context: ProviderDispatchContext): { token: string; orgId: string } {
352
352
  const secret = context.credential.secret;
353
353
  if (secret === undefined || secret.length === 0) {
354
- throw new GatewayError("invalid_request", 400, "factory: credential is missing a secret value");
354
+ throw new GatewayError("invalid_request", 400, "factory: credential is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑");
355
355
  }
356
356
  try {
357
357
  const envelope = decodeFactoryDroidCredential(secret);
@@ -360,7 +360,7 @@ function factoryEnvelope(context: ProviderDispatchContext): { token: string; org
360
360
  throw new GatewayError(
361
361
  "invalid_request",
362
362
  400,
363
- `factory: ${error instanceof Error ? error.message : "stored credential is not a Factory Droid envelope"}`,
363
+ `factory: ${error instanceof Error ? error.message : "stored credential is not a Factory Droid envelope"} (request {requestId}). Wrong key, right door — check the credential 🔑`,
364
364
  );
365
365
  }
366
366
  }
@@ -523,7 +523,7 @@ class FactoryDroidAdapter implements ProviderAdapter {
523
523
  throw new GatewayError(
524
524
  "platform_unavailable",
525
525
  502,
526
- "factory gemini returned empty stream",
526
+ "factory gemini returned empty stream (request {requestId}). The upstream came back empty-handed — retry 🌙",
527
527
  {},
528
528
  "upstream",
529
529
  );
@@ -6,7 +6,7 @@ import { mapUpstreamHttpError } from "../../transport/failure-policy";
6
6
  import type { CanonicalEvent, CanonicalRequest, CanonicalStopReason } from "../../protocol/canonical-model";
7
7
  import { decodeSseEvents } from "../../protocol/sse-decoder";
8
8
  import { usageFromProvider } from "../provider-usage";
9
- import { readCredentialSecret, type ImageGenerationOutcome, type ProviderDispatchTarget, type ProviderAdapter, type ProviderDispatchContext, type WebSearchOutcome, type WebSearchResult } from "../provider-contracts";
9
+ import { readCredentialSecret, assertWireFamily, type ImageGenerationOutcome, type ProviderDispatchTarget, type ProviderAdapter, type ProviderDispatchContext, type WebSearchOutcome, type WebSearchResult } from "../provider-contracts";
10
10
  import type { ModelDefinition } from "../provider-model-definition";
11
11
  import { fetchOpenAICompatibleModels } from "../discovery/openai-model-discovery";
12
12
  import { isRecord } from "../../protocol/codecs";
@@ -181,7 +181,7 @@ class GeminiAdapter implements ProviderAdapter {
181
181
  context: ProviderDispatchContext,
182
182
  ): AsyncIterable<CanonicalEvent> {
183
183
  if (candidate.wire_family !== "chat" && candidate.wire_family !== "responses" && candidate.wire_family !== "messages") {
184
- throw new GatewayError("capability_unsupported", 400, `gemini supports chat/responses/messages, got ${candidate.wire_family}`);
184
+ assertWireFamily(candidate, ["chat", "responses", "messages"], "gemini");
185
185
  }
186
186
  const apiKey = readCredentialSecret(context.credential, "Gemini API key is required");
187
187
 
@@ -262,7 +262,7 @@ class GeminiAdapter implements ProviderAdapter {
262
262
  return;
263
263
  }
264
264
 
265
- if (!response.body) throw new GatewayError("platform_unavailable", 502, "Gemini returned empty stream", {}, "upstream");
265
+ if (!response.body) throw new GatewayError("platform_unavailable", 502, "Gemini returned empty stream (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
266
266
  let seq = 1;
267
267
  yield { type: "response_start", sequence_number: seq++, model: request.model } as CanonicalEvent;
268
268
  const state = { started: true, stopped: false, activeCalls: new Set<string>() };
@@ -339,7 +339,7 @@ class GeminiAdapter implements ProviderAdapter {
339
339
  context: ProviderDispatchContext,
340
340
  ): Promise<WebSearchOutcome> {
341
341
  const query = typeof body.query === "string" ? body.query.trim() : "";
342
- if (!query) throw new GatewayError("invalid_request", 400, "search query is required");
342
+ if (!query) throw new GatewayError("invalid_request", 400, "search query is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
343
343
  const rawMax = body.max_results;
344
344
  const maxResults =
345
345
  typeof rawMax === "number" && Number.isFinite(rawMax)
@@ -368,7 +368,7 @@ class GeminiAdapter implements ProviderAdapter {
368
368
  throw new GatewayError(
369
369
  "platform_unavailable",
370
370
  502,
371
- `Gemini search unreachable: ${error instanceof Error ? error.message : String(error)}`,
371
+ `Gemini search unreachable (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
372
372
  );
373
373
  }
374
374
  if (!response.ok) throw await mapUpstreamHttpError(response, "gemini search");
@@ -376,11 +376,11 @@ class GeminiAdapter implements ProviderAdapter {
376
376
  try {
377
377
  data = await response.json();
378
378
  } catch {
379
- throw new GatewayError("platform_unavailable", 502, "Gemini search returned invalid JSON");
379
+ throw new GatewayError("platform_unavailable", 502, "Gemini search returned invalid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙");
380
380
  }
381
381
  const results = normalizeGroundingResults(data, maxResults);
382
382
  if (results.length === 0)
383
- throw new GatewayError("platform_unavailable", 502, "Gemini search returned no grounded results");
383
+ throw new GatewayError("platform_unavailable", 502, "Gemini search returned no grounded results (request {requestId}). The upstream came back empty-handed — retry 🌙");
384
384
  return { results, total_results: results.length };
385
385
  }
386
386
 
@@ -391,7 +391,7 @@ class GeminiAdapter implements ProviderAdapter {
391
391
  ): Promise<ImageGenerationOutcome> {
392
392
  const prompt = imagePrompt(body);
393
393
  const model = candidate.model_id.length > 0 ? candidate.model_id : typeof body.model === "string" ? body.model : "";
394
- if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
394
+ if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
395
395
  const apiKey = readCredentialSecret(context.credential, "Gemini API key is required");
396
396
  const outboundFetch = context.outbound_fetch ?? this.fetchFn;
397
397
  const lifecycle = createUpstreamDeadlineLifecycle(context);
@@ -418,7 +418,7 @@ class GeminiAdapter implements ProviderAdapter {
418
418
  throw new GatewayError(
419
419
  "platform_unavailable",
420
420
  502,
421
- `Gemini image generation unreachable: ${error instanceof Error ? error.message : String(error)}`,
421
+ `Gemini image generation unreachable (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`,
422
422
  {},
423
423
  "upstream",
424
424
  );
@@ -430,11 +430,11 @@ class GeminiAdapter implements ProviderAdapter {
430
430
  try {
431
431
  data = await response.json();
432
432
  } catch {
433
- throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned invalid JSON", {}, "upstream");
433
+ throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned invalid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
434
434
  }
435
435
  const images = geminiInlineImages(data);
436
436
  if (images.length === 0) {
437
- throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned no image", {}, "upstream");
437
+ throw new GatewayError("platform_unavailable", 502, "Gemini image generation returned no image (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
438
438
  }
439
439
  return { created: imageCreatedSeconds(), data: images };
440
440
  }
@@ -411,7 +411,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
411
411
 
412
412
  const secret = context.credential.secret;
413
413
  if (secret === undefined || secret.length === 0) {
414
- throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing");
414
+ throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing (request {requestId}). Wrong key, right door — check the credential 🔑");
415
415
  }
416
416
  const credential = new TextDecoder().decode(secret);
417
417
  const autoInput = autoPrompt(request);
@@ -424,7 +424,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
424
424
  : this.#getCachedAutoDecision(cacheKey, autoInput.hasImage);
425
425
  if (autoDecision === undefined) {
426
426
  if (autoInput.prompt.length === 0) {
427
- throw new GatewayError("invalid_request", 400, "Copilot Auto requires a text prompt");
427
+ throw new GatewayError("invalid_request", 400, "Copilot Auto requires a text prompt (request {requestId}). Check the shape of what you sent — then resend 🪞");
428
428
  }
429
429
  autoDecision = await this.#selectAutoModel(
430
430
  autoInput.prompt,
@@ -462,7 +462,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
462
462
  throw new GatewayError(
463
463
  "upstream_unprocessable",
464
464
  502,
465
- "Copilot Auto selected a model without a discovered inference endpoint",
465
+ "Copilot Auto selected a model without a discovered inference endpoint (request {requestId}). The upstream came back empty-handed — retry 🌙",
466
466
  { selected_model: selectedModelId },
467
467
  "upstream",
468
468
  );
@@ -498,7 +498,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
498
498
  ? undefined
499
499
  : parseGithubCredential(new TextDecoder().decode(context.credential.secret));
500
500
  if (credential === undefined) {
501
- throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing");
501
+ throw new GatewayError("authentication_failed", 401, "GitHub Copilot credential is missing (request {requestId}). Wrong key, right door — check the credential 🔑");
502
502
  }
503
503
  const payload: Record<string, unknown> = { prompt, tier };
504
504
  if (hasImage) payload.has_image = true;
@@ -522,7 +522,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
522
522
  throw new GatewayError(
523
523
  "upstream_unprocessable",
524
524
  502,
525
- "Copilot Auto returned an invalid routing response",
525
+ "Copilot Auto returned an invalid routing response (request {requestId}). The upstream came back empty-handed — retry 🌙",
526
526
  {},
527
527
  "upstream",
528
528
  );
@@ -545,7 +545,7 @@ class GithubAdapter extends OpenAICompatibleAdapter {
545
545
  throw new GatewayError(
546
546
  "upstream_unprocessable",
547
547
  502,
548
- "Copilot Auto did not return a selected model",
548
+ "Copilot Auto did not return a selected model (request {requestId}). The upstream came back empty-handed — retry 🌙",
549
549
  {},
550
550
  "upstream",
551
551
  );
@@ -9,12 +9,12 @@
9
9
  * OpenAI-compatible adapter.
10
10
  */
11
11
  import { randomBytes, randomUUID } from "node:crypto";
12
- import { GatewayError } from "../../../protocol/gateway-error";
13
12
  import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
14
13
  import {
15
14
  OpenAICompatibleAdapter,
16
15
  withBearerAuthentication,
17
16
  } from "../../adapters/compatible-adapter";
17
+ import { assertCredentialKind } from "../../provider-contracts";
18
18
  import type { ProviderAdapter, ProviderDispatchTarget, ProviderDispatchContext } from "../../provider-contracts";
19
19
  import { providerBaseUrl } from "../../provider-metadata";
20
20
  import { boundedUpstreamArray, boundedUpstreamNumber, sanitizeUpstreamLabel } from "../../provider-sanitize";
@@ -526,11 +526,7 @@ class GrokAdapter extends OpenAICompatibleAdapter {
526
526
  context: ProviderDispatchContext,
527
527
  ): AsyncIterable<CanonicalEvent> {
528
528
  if (context.credential.credential_kind !== "oauth") {
529
- throw new GatewayError(
530
- "invalid_request",
531
- 400,
532
- "grok requires an xAI OAuth device credential",
533
- );
529
+ assertCredentialKind(context.credential, "oauth", "grok");
534
530
  }
535
531
  yield* super.dispatch(request, candidate, context);
536
532
  }