cartethyia 2.7.2 → 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 (405) hide show
  1. package/.env.example +2 -0
  2. package/dist/dashboard/assets/{BannedPage-XaUmiBrC.js → BannedPage-ChG5svFb.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  4. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js +1 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  6. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js +1 -0
  7. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-CXGS_Ct-.js → CombosPage-DCgm5g6g.js} +1 -1
  9. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  10. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +1 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  12. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js +1 -0
  13. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  14. package/dist/dashboard/assets/{HealthEventsModal-BKtAPYVF.js → HealthEventsModal-DzSWzE_j.js} +1 -1
  15. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  16. package/dist/dashboard/assets/{LoginPage-BdmRLnq2.js → LoginPage-U6AKaJcF.js} +1 -1
  17. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  18. package/dist/dashboard/assets/{ModelPicker-BH8Tehdi.js → ModelPicker-BMS2t8BA.js} +1 -1
  19. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  20. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +1 -0
  21. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  22. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +5 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  24. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +1 -0
  25. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  26. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js +9 -0
  27. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  28. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +1 -0
  29. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  30. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +1 -0
  31. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  32. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js +1 -0
  33. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  34. package/dist/dashboard/assets/{SortableList-Dqf4zpS-.js → SortableList-ClzpwyET.js} +1 -1
  35. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  36. package/dist/dashboard/assets/{StudioPage-Byj2lAEm.js → StudioPage-Cq5tW7hW.js} +3 -3
  37. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  38. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +56 -0
  39. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  40. package/dist/dashboard/assets/api-keys-C38iXoO4.js +1 -0
  41. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  42. package/dist/dashboard/assets/app-a159k0ub.css +2 -0
  43. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  44. package/dist/dashboard/assets/arrow-up-59ms1iiT.js +1 -0
  45. package/dist/dashboard/assets/arrow-up-59ms1iiT.js.gz +0 -0
  46. package/dist/dashboard/assets/assert-DbRA8EG2.js +15 -0
  47. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-DC2L43Mj.js → badge-D9CS6dZk.js} +1 -1
  49. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-BBVcb0J3.js → banner-DympBNq4.js} +1 -1
  51. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-Cca1XC6G.js → card-ibRWU_uT.js} +1 -1
  53. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  54. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +1 -0
  55. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-DUzEbynq.js → clipboard-button-DJm-9pz7.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-DFvWhwTa.js → dialog-8fiE6tec.js} +1 -1
  59. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  60. package/dist/dashboard/assets/drawer-CqGYeOrd.js +1 -0
  61. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-Bqy8RFvM.js → entry-BSAsYsmV.js} +1 -1
  63. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  64. package/dist/dashboard/assets/entry-CiIQULZD.js +4 -0
  65. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-Daz0lJ-W.js +1 -0
  67. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  68. package/dist/dashboard/assets/{concurrency-BDF0ok7y.js → fingerprint-pattern-BWuHtbW4.js} +1 -1
  69. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  70. package/dist/dashboard/assets/{formatters-CWWZ-uCZ.js → formatters-D-MTJxMr.js} +1 -1
  71. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  72. package/dist/dashboard/assets/{github-badge-C9e8Ts7e.js → github-badge-CPK47xQx.js} +1 -1
  73. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  74. package/dist/dashboard/assets/{index-DFVFrnWW.js → index-DBNPOfhV.js} +2 -2
  75. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  76. package/dist/dashboard/assets/{inline-BFUcvllj.js → inline-BT0zntEr.js} +1 -1
  77. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  78. package/dist/dashboard/assets/{input-C_ILAvBb.js → input-Da2ZViWg.js} +1 -1
  79. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  80. package/dist/dashboard/assets/{layout-CBIyT6Rt.js → layout-BXNeLw6M.js} +1 -1
  81. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  82. package/dist/dashboard/assets/{list-row-ebJ_-Nsb.js → list-row-BycOrrIV.js} +1 -1
  83. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  84. package/dist/dashboard/assets/live-DCQNZpF7.js +1 -0
  85. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  86. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +1 -0
  87. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  88. package/dist/dashboard/assets/{mutation-sMD965oO.js → mutation-Rr0TIvcj.js} +1 -1
  89. package/dist/dashboard/assets/mutation-Rr0TIvcj.js.gz +0 -0
  90. package/dist/dashboard/assets/network-9Yj2ZyLo.js +1 -0
  91. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  92. package/dist/dashboard/assets/{numbers-BO9dKaFr.js → numbers-CEagj6ZZ.js} +2 -2
  93. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  94. package/dist/dashboard/assets/{query-keys-CfL_Zdoh.js → query-keys-BloKtaXJ.js} +1 -1
  95. package/dist/dashboard/assets/query-keys-BloKtaXJ.js.gz +0 -0
  96. package/dist/dashboard/assets/quota-Caw7wqci.js +1 -0
  97. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  98. package/dist/dashboard/assets/routing-CO9zCUus.js +1 -0
  99. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  100. package/dist/dashboard/assets/{select-DBNVLdUu.js → select-BIYIBkMU.js} +2 -2
  101. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  102. package/dist/dashboard/assets/settings-2-Ds9DQp0t.js +1 -0
  103. package/dist/dashboard/assets/settings-2-Ds9DQp0t.js.gz +0 -0
  104. package/dist/dashboard/assets/settings-jS3-PNSA.js +1 -0
  105. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  106. package/dist/dashboard/assets/{stack-EMrOMt4I.js → stack-DfgnFDWY.js} +1 -1
  107. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  108. package/dist/dashboard/assets/{state-CWoo7ty5.js → state-CkfdYWel.js} +1 -1
  109. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  110. package/dist/dashboard/assets/{switch-CCjT6IkF.js → switch-SYm237HG.js} +1 -1
  111. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  112. package/dist/dashboard/assets/{useMutation-DjkLHUcE.js → useMutation-BQqCRNIi.js} +1 -1
  113. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  114. package/dist/dashboard/index.html +3 -2
  115. package/dist/dashboard/index.html.gz +0 -0
  116. package/dist/dashboard/precompressed-assets.json +118 -115
  117. package/migrations/full-postgres/0026_add_qoder_native_identity.sql +20 -0
  118. package/migrations/full-postgres/0027_qoder_identity_genuine_seed.sql +21 -0
  119. package/migrations/full-postgres/0028_add_family_template_key_telemetry.sql +40 -0
  120. package/migrations/full-postgres/0029_null_share_child_policy_columns.sql +38 -0
  121. package/migrations/full-postgres/0030_add_api_key_max_children.sql +10 -0
  122. package/migrations/full-postgres/0031_tenant_system_prompts.sql +16 -0
  123. package/migrations/full-postgres/0032_add_provider_pool_accounts.sql +53 -0
  124. package/migrations/full-postgres/0033_add_api_key_ban.sql +9 -0
  125. package/migrations/full-postgres/0034_add_api_key_ban_until.sql +7 -0
  126. package/migrations/full-postgres/0035_align_pool_account_status_enum.sql +21 -0
  127. package/migrations/lite-sqlite3/0026_add_qoder_native_identity.sql +15 -0
  128. package/migrations/lite-sqlite3/0027_qoder_identity_genuine_seed.sql +21 -0
  129. package/migrations/lite-sqlite3/0028_add_family_template_key_telemetry.sql +40 -0
  130. package/migrations/lite-sqlite3/0029_null_share_child_policy_columns.sql +38 -0
  131. package/migrations/lite-sqlite3/0030_add_api_key_max_children.sql +10 -0
  132. package/migrations/lite-sqlite3/0031_tenant_system_prompts.sql +10 -0
  133. package/migrations/lite-sqlite3/0032_add_provider_pool_accounts.sql +44 -0
  134. package/migrations/lite-sqlite3/0033_add_api_key_ban.sql +8 -0
  135. package/migrations/lite-sqlite3/0034_add_api_key_ban_until.sql +5 -0
  136. package/migrations/lite-sqlite3/0035_align_pool_account_status_enum.sql +6 -0
  137. package/package.json +2 -1
  138. package/src/boot/app.ts +9 -8
  139. package/src/config/network.ts +7 -3
  140. package/src/console/api-keys/bucket-spend.ts +7 -7
  141. package/src/console/api-keys/contracts.ts +475 -410
  142. package/src/console/api-keys/routes.ts +211 -23
  143. package/src/console/audit/routes.ts +3 -3
  144. package/src/console/auth/account-reset.ts +4 -4
  145. package/src/console/auth/session.ts +3 -3
  146. package/src/console/backup/contracts.ts +2 -0
  147. package/src/console/backup/export-endpoint.ts +14 -17
  148. package/src/console/backup/routes.ts +43 -11
  149. package/src/console/backup/service.ts +11 -6
  150. package/src/console/backup/store.ts +384 -88
  151. package/src/console/cli-tools/routes.ts +3 -3
  152. package/src/console/console-router-guards.ts +2 -2
  153. package/src/console/console-router.ts +4 -4
  154. package/src/console/dashboard-assets.ts +16 -1
  155. package/src/console/data-management/routes.ts +3 -3
  156. package/src/console/domain-registration.ts +4 -2
  157. package/src/console/observability/contracts.ts +4 -0
  158. package/src/console/observability/live.ts +3 -3
  159. package/src/console/observability/logs.ts +3 -3
  160. package/src/console/observability/performance.ts +3 -3
  161. package/src/console/observability/routes.ts +3 -3
  162. package/src/console/observability/store.ts +16 -16
  163. package/src/console/providers/catalog/contracts.ts +43 -22
  164. package/src/console/providers/catalog/provider-operations.ts +17 -2
  165. package/src/console/providers/catalog/routes.ts +3 -3
  166. package/src/console/providers/catalog/store-helpers.ts +349 -326
  167. package/src/console/providers/catalog/store.ts +1523 -1292
  168. package/src/console/providers/detail/routes.ts +3 -3
  169. package/src/console/providers/oauth/routes.ts +3 -3
  170. package/src/console/quota/account-quota-tenant.ts +34 -2
  171. package/src/console/quota/account-quota.ts +4 -1
  172. package/src/console/quota/account-test-egress.ts +4 -4
  173. package/src/console/quota/native-identity.ts +189 -0
  174. package/src/console/remote-support/contracts.ts +12 -6
  175. package/src/console/remote-support/service.ts +2 -2
  176. package/src/console/routing/model/routes.ts +3 -3
  177. package/src/console/routing/pools/contracts.ts +11 -8
  178. package/src/console/routing/pools/operations.ts +14 -7
  179. package/src/console/routing/pools/probe-verdict.ts +8 -3
  180. package/src/console/routing/pools/relay-deploy.ts +9 -9
  181. package/src/console/routing/pools/routes.ts +3 -3
  182. package/src/console/routing/pools/store.ts +21 -1
  183. package/src/console/settings/routes.ts +3 -3
  184. package/src/console/share/share-router.ts +51 -18
  185. package/src/console/share/share-stats.ts +158 -49
  186. package/src/console/share/share-usage.ts +24 -7
  187. package/src/console/shared/read-through-cache.ts +38 -2
  188. package/src/console/system-prompt/contracts.ts +102 -0
  189. package/src/console/system-prompt/routes.ts +165 -0
  190. package/src/console/updates/routes.ts +7 -4
  191. package/src/main.ts +11 -0
  192. package/src/network/outbound-fetch.ts +75 -4
  193. package/src/network/pool/resolver.ts +39 -39
  194. package/src/network/pool-cooldown-store.ts +71 -16
  195. package/src/network/pool-health-machine.ts +21 -1
  196. package/src/network/rate-limit-verdict.ts +68 -0
  197. package/src/network/ssrf.ts +4 -4
  198. package/src/observability/event-query.ts +437 -22
  199. package/src/observability/telemetry-status.ts +1 -1
  200. package/src/persistence/db-pg.ts +42 -0
  201. package/src/persistence/db-sqlite.ts +7 -2
  202. package/src/persistence/readiness.ts +18 -6
  203. package/src/persistence/schema.ts +162 -1
  204. package/src/persistence/stores/api-key-store.ts +849 -581
  205. package/src/persistence/stores/share-store.ts +65 -13
  206. package/src/persistence/stores/telemetry-store.ts +58 -2
  207. package/src/persistence/system-prompt-store.ts +104 -0
  208. package/src/protocol/codecs.ts +6 -6
  209. package/src/protocol/gateway-error.ts +6 -3
  210. package/src/protocol/image-generation.ts +2 -2
  211. package/src/protocol/reasoning.ts +65 -1
  212. package/src/protocol/request/chat.ts +1 -0
  213. package/src/protocol/response/chat.ts +2 -2
  214. package/src/protocol/response/codex.ts +1 -1
  215. package/src/protocol/response/gemini.ts +1 -1
  216. package/src/protocol/response/messages.ts +5 -5
  217. package/src/protocol/response/responses.ts +2 -2
  218. package/src/protocol/sse-decoder.ts +14 -3
  219. package/src/protocol/translation/capabilities.ts +2 -2
  220. package/src/protocol/upstream/send-claude-messages.ts +3 -3
  221. package/src/providers/adapters/base-adapter.ts +1 -1
  222. package/src/providers/adapters/compatible-adapter.ts +2 -2
  223. package/src/providers/authentication/oauth-refresh-service.ts +2 -2
  224. package/src/providers/configured-provider.ts +1 -1
  225. package/src/providers/discovery/probe-phases.ts +2 -2
  226. package/src/providers/discovery/probing-service.ts +12 -12
  227. package/src/providers/integrations/agentrouter/agentrouter.ts +2 -3
  228. package/src/providers/integrations/alibabacp/alibabacp.ts +2 -2
  229. package/src/providers/integrations/anthropic.ts +4 -11
  230. package/src/providers/integrations/antigravity/antigravity.ts +33 -47
  231. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  232. package/src/providers/integrations/buddy/buddy-chat-shared.ts +30 -2
  233. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +37 -6
  234. package/src/providers/integrations/buddy/buddy-identity.ts +22 -1
  235. package/src/providers/integrations/buddy/buddy-media.ts +21 -17
  236. package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
  237. package/src/providers/integrations/buddy/workbuddy/provider.ts +6 -2
  238. package/src/providers/integrations/claude/claude-betas.ts +1 -1
  239. package/src/providers/integrations/claude/claude-credentials.ts +1 -1
  240. package/src/providers/integrations/claude/claude-slow-lane-retry.ts +1 -1
  241. package/src/providers/integrations/claude/claude.ts +3 -10
  242. package/src/providers/integrations/cline/cline.ts +8 -1
  243. package/src/providers/integrations/cloudflareai/cloudflareai.ts +4 -7
  244. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  245. package/src/providers/integrations/codex/codex.ts +14 -15
  246. package/src/providers/integrations/commandcode/commandcode.ts +4 -4
  247. package/src/providers/integrations/commandcode/quota.ts +5 -1
  248. package/src/providers/integrations/cursor/cursor-http2.ts +11 -11
  249. package/src/providers/integrations/cursor/cursor.ts +15 -15
  250. package/src/providers/integrations/factory/factory.ts +4 -4
  251. package/src/providers/integrations/gemini.ts +11 -11
  252. package/src/providers/integrations/github/github.ts +26 -7
  253. package/src/providers/integrations/grok/grok.ts +2 -6
  254. package/src/providers/integrations/hermes.ts +5 -1
  255. package/src/providers/integrations/inferhub.ts +4 -11
  256. package/src/providers/integrations/kilo/kilo.ts +4 -0
  257. package/src/providers/integrations/kimi/kimi.ts +4 -11
  258. package/src/providers/integrations/kiro/kiro.ts +10 -10
  259. package/src/providers/integrations/muse/muse.ts +6 -9
  260. package/src/providers/integrations/openrouter/provider.ts +4 -0
  261. package/src/providers/integrations/perplexity.ts +2 -2
  262. package/src/providers/integrations/qoder/qoder-catalog.ts +47 -9
  263. package/src/providers/integrations/qoder/qoder-checkin.ts +242 -51
  264. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +157 -0
  265. package/src/providers/integrations/qoder/qoder-oauth.ts +12 -3
  266. package/src/providers/integrations/qoder/qoder-realm.ts +15 -0
  267. package/src/providers/integrations/qoder/qoder-umid.ts +287 -0
  268. package/src/providers/integrations/qoder/qoder-virtual.ts +2 -2
  269. package/src/providers/integrations/qoder/qoder.ts +192 -24
  270. package/src/providers/integrations/tokenharbor.ts +2 -2
  271. package/src/providers/integrations/trae/trae.ts +6 -9
  272. package/src/providers/integrations/zcode/oauth.ts +1 -1
  273. package/src/providers/operations/account-error-classification.ts +6 -8
  274. package/src/providers/operations/account-health-service.ts +14 -16
  275. package/src/providers/operations/client-versions.ts +37 -22
  276. package/src/providers/operations/provider-catalog-service.ts +4 -4
  277. package/src/providers/operations/provider-credential-service.ts +16 -4
  278. package/src/providers/operations/upstream-deadline.ts +3 -3
  279. package/src/providers/provider-contracts.ts +55 -3
  280. package/src/providers/provider-credential-resolver.ts +1 -1
  281. package/src/providers/provider-registry.ts +4 -4
  282. package/src/providers/quota/quota-contracts.ts +24 -10
  283. package/src/providers/quota/refresh.ts +2 -2
  284. package/src/providers/search/search-provider.ts +5 -5
  285. package/src/security/abuse.ts +4 -4
  286. package/src/security/access-control.ts +19 -0
  287. package/src/security/admission/reasons.ts +17 -17
  288. package/src/security/api-key-auth.ts +18 -5
  289. package/src/shared/coerce.ts +19 -0
  290. package/src/transport/dispatch/attempt-finalize.ts +4 -3
  291. package/src/transport/dispatch/attempt-loop.ts +10 -7
  292. package/src/transport/dispatch/empty-stream.ts +6 -6
  293. package/src/transport/dispatch/generation.ts +9 -9
  294. package/src/transport/dispatch/leases.ts +8 -8
  295. package/src/transport/dispatch/proxy-request.ts +38 -9
  296. package/src/transport/dispatch/responses-compact.ts +11 -11
  297. package/src/transport/dispatch/retry-policy.ts +4 -67
  298. package/src/transport/dispatch/stream-bridge.ts +1 -1
  299. package/src/transport/dispatch/streaming/finalize.ts +9 -8
  300. package/src/transport/dispatch/streaming/stream.ts +16 -1
  301. package/src/transport/dispatch/systemone.ts +8 -8
  302. package/src/transport/dispatch/token-count.ts +9 -9
  303. package/src/transport/dispatch/upstream.ts +10 -0
  304. package/src/transport/dispatch/websearch.ts +6 -6
  305. package/src/transport/drain-endpoint.ts +2 -2
  306. package/src/transport/failure-policy.ts +13 -6
  307. package/src/transport/guards/auth-guard.ts +6 -5
  308. package/src/transport/guards/body-policy.ts +4 -4
  309. package/src/transport/guards/error-lifecycle.ts +18 -3
  310. package/src/transport/guards/guard-errors.ts +7 -3
  311. package/src/transport/guards/headroom-guard.ts +1 -1
  312. package/src/transport/guards/pipeline.ts +6 -6
  313. package/src/transport/guards/readiness-guard.ts +16 -2
  314. package/src/transport/guards/request-context.ts +3 -3
  315. package/src/transport/request/preparer.ts +37 -21
  316. package/src/transport/request/state.ts +4 -7
  317. package/src/transport/request/system-prompt-injection.ts +89 -0
  318. package/src/transport/request/tenant-preferences.ts +43 -0
  319. package/src/transport/routing/admission.ts +13 -3
  320. package/src/transport/routing/route-catalog.ts +104 -2
  321. package/src/transport/routing/route-model.ts +60 -7
  322. package/src/transport/routing/router.ts +306 -256
  323. package/src/transport/shutdown-notice.ts +19 -7
  324. package/src/transport/surface/completion.ts +1 -1
  325. package/src/transport/surface/messages/encode.ts +1 -1
  326. package/src/workers/daily-checkin.ts +2 -0
  327. package/dist/dashboard/assets/BannedPage-XaUmiBrC.js.gz +0 -0
  328. package/dist/dashboard/assets/CliToolDetailPage-CqD7QiLM.js +0 -1
  329. package/dist/dashboard/assets/CliToolDetailPage-CqD7QiLM.js.gz +0 -0
  330. package/dist/dashboard/assets/CliToolsPage-0XUo4UMn.js +0 -1
  331. package/dist/dashboard/assets/CliToolsPage-0XUo4UMn.js.gz +0 -0
  332. package/dist/dashboard/assets/CombosPage-CXGS_Ct-.js.gz +0 -0
  333. package/dist/dashboard/assets/ConsoleLogPage-DGnGNYnM.js +0 -1
  334. package/dist/dashboard/assets/ConsoleLogPage-DGnGNYnM.js.gz +0 -0
  335. package/dist/dashboard/assets/CustomizationPage-DAG5J9EY.js +0 -1
  336. package/dist/dashboard/assets/CustomizationPage-DAG5J9EY.js.gz +0 -0
  337. package/dist/dashboard/assets/HealthEventsModal-BKtAPYVF.js.gz +0 -0
  338. package/dist/dashboard/assets/LoginPage-BdmRLnq2.js.gz +0 -0
  339. package/dist/dashboard/assets/ModelPicker-BH8Tehdi.js.gz +0 -0
  340. package/dist/dashboard/assets/OverviewPage-CqMxibJB.js +0 -1
  341. package/dist/dashboard/assets/OverviewPage-CqMxibJB.js.gz +0 -0
  342. package/dist/dashboard/assets/ProviderDetailPage-CqMh2NRX.js +0 -4
  343. package/dist/dashboard/assets/ProviderDetailPage-CqMh2NRX.js.gz +0 -0
  344. package/dist/dashboard/assets/ProvidersPage-B9uWu4Nz.js +0 -1
  345. package/dist/dashboard/assets/ProvidersPage-B9uWu4Nz.js.gz +0 -0
  346. package/dist/dashboard/assets/ProxyPage-BoWOhpDO.js +0 -9
  347. package/dist/dashboard/assets/ProxyPage-BoWOhpDO.js.gz +0 -0
  348. package/dist/dashboard/assets/QuotaPage-7P2n--Fv.js +0 -1
  349. package/dist/dashboard/assets/QuotaPage-7P2n--Fv.js.gz +0 -0
  350. package/dist/dashboard/assets/SettingsPage-CxZ1fTkN.js +0 -1
  351. package/dist/dashboard/assets/SettingsPage-CxZ1fTkN.js.gz +0 -0
  352. package/dist/dashboard/assets/SetupPage-Co12Zzaw.js +0 -1
  353. package/dist/dashboard/assets/SetupPage-Co12Zzaw.js.gz +0 -0
  354. package/dist/dashboard/assets/SortableList-Dqf4zpS-.js.gz +0 -0
  355. package/dist/dashboard/assets/StudioPage-Byj2lAEm.js.gz +0 -0
  356. package/dist/dashboard/assets/UsagePage-CTkLAuRc.js +0 -56
  357. package/dist/dashboard/assets/UsagePage-CTkLAuRc.js.gz +0 -0
  358. package/dist/dashboard/assets/api-keys-CUi6UXsR.js +0 -1
  359. package/dist/dashboard/assets/api-keys-CUi6UXsR.js.gz +0 -0
  360. package/dist/dashboard/assets/app-KvsUJUMF.css +0 -2
  361. package/dist/dashboard/assets/app-KvsUJUMF.css.gz +0 -0
  362. package/dist/dashboard/assets/assert-67xXH5rf.js +0 -1
  363. package/dist/dashboard/assets/assert-67xXH5rf.js.gz +0 -0
  364. package/dist/dashboard/assets/badge-DC2L43Mj.js.gz +0 -0
  365. package/dist/dashboard/assets/banner-BBVcb0J3.js.gz +0 -0
  366. package/dist/dashboard/assets/card-Cca1XC6G.js.gz +0 -0
  367. package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js +0 -1
  368. package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js.gz +0 -0
  369. package/dist/dashboard/assets/clipboard-button-DUzEbynq.js.gz +0 -0
  370. package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
  371. package/dist/dashboard/assets/dialog-DFvWhwTa.js.gz +0 -0
  372. package/dist/dashboard/assets/drawer-CFM2sMX1.js +0 -1
  373. package/dist/dashboard/assets/drawer-CFM2sMX1.js.gz +0 -0
  374. package/dist/dashboard/assets/entry-Bqy8RFvM.js.gz +0 -0
  375. package/dist/dashboard/assets/entry-ClCMCWWQ.js +0 -4
  376. package/dist/dashboard/assets/entry-ClCMCWWQ.js.gz +0 -0
  377. package/dist/dashboard/assets/entry-_xHo5x6r.js +0 -1
  378. package/dist/dashboard/assets/entry-_xHo5x6r.js.gz +0 -0
  379. package/dist/dashboard/assets/formatters-CWWZ-uCZ.js.gz +0 -0
  380. package/dist/dashboard/assets/github-badge-C9e8Ts7e.js.gz +0 -0
  381. package/dist/dashboard/assets/index-DFVFrnWW.js.gz +0 -0
  382. package/dist/dashboard/assets/inline-BFUcvllj.js.gz +0 -0
  383. package/dist/dashboard/assets/input-C_ILAvBb.js.gz +0 -0
  384. package/dist/dashboard/assets/layout-CBIyT6Rt.js.gz +0 -0
  385. package/dist/dashboard/assets/list-row-ebJ_-Nsb.js.gz +0 -0
  386. package/dist/dashboard/assets/live-D0mm--ME.js +0 -1
  387. package/dist/dashboard/assets/live-D0mm--ME.js.gz +0 -0
  388. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +0 -1
  389. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  390. package/dist/dashboard/assets/mutation-sMD965oO.js.gz +0 -0
  391. package/dist/dashboard/assets/numbers-BO9dKaFr.js.gz +0 -0
  392. package/dist/dashboard/assets/query-keys-CfL_Zdoh.js.gz +0 -0
  393. package/dist/dashboard/assets/quota-DZGyp0N5.js +0 -1
  394. package/dist/dashboard/assets/quota-DZGyp0N5.js.gz +0 -0
  395. package/dist/dashboard/assets/routing-BnIpi1IJ.js +0 -1
  396. package/dist/dashboard/assets/routing-BnIpi1IJ.js.gz +0 -0
  397. package/dist/dashboard/assets/select-DBNVLdUu.js.gz +0 -0
  398. package/dist/dashboard/assets/settings-BAFhDgX8.js +0 -1
  399. package/dist/dashboard/assets/settings-BAFhDgX8.js.gz +0 -0
  400. package/dist/dashboard/assets/stack-EMrOMt4I.js.gz +0 -0
  401. package/dist/dashboard/assets/state-CWoo7ty5.js.gz +0 -0
  402. package/dist/dashboard/assets/switch-CCjT6IkF.js.gz +0 -0
  403. package/dist/dashboard/assets/useMutation-DjkLHUcE.js.gz +0 -0
  404. /package/dist/dashboard/assets/{app-BaWd0puM.js → app-BayTTy01.js} +0 -0
  405. /package/dist/dashboard/assets/{app-BaWd0puM.js.gz → app-BayTTy01.js.gz} +0 -0
@@ -108,7 +108,7 @@ export async function buddyGenerateImage(
108
108
  context: ProviderDispatchContext,
109
109
  ): Promise<ImageGenerationOutcome> {
110
110
  const model = modelOf(body, candidate);
111
- if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
111
+ if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
112
112
  const prompt = imagePrompt(body);
113
113
  if (config.imageGenerationPath !== undefined) {
114
114
  const requestBody: Record<string, unknown> = { model, prompt };
@@ -134,28 +134,28 @@ export async function buddyGenerateImage(
134
134
  release();
135
135
  }
136
136
  if (!isRecord(responseBody)) {
137
- throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned an invalid response", {}, "upstream");
137
+ throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned an invalid response (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
138
138
  }
139
139
  const providerError = buddyErrorOf(responseBody);
140
140
  if (providerError !== undefined) {
141
- throw new GatewayError("platform_unavailable", 502, providerError, {}, "upstream");
141
+ throw new GatewayError("platform_unavailable", 502, `${providerError} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
142
142
  }
143
143
  if (responseBody.code !== undefined && responseBody.code !== 0 && responseBody.code !== "0") {
144
144
  const message =
145
145
  typeof responseBody.msg === "string" && responseBody.msg.trim().length > 0
146
146
  ? responseBody.msg.trim()
147
147
  : `CodeBuddy image generation failed with code ${String(responseBody.code)}`;
148
- throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
148
+ throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
149
149
  }
150
150
  if (!isRecord(responseBody.data)) {
151
- throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned no image data", {}, "upstream");
151
+ throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned no image data (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
152
152
  }
153
153
  const result = responseBody.data;
154
154
  if (!Array.isArray(result.data) || result.data.some((image) => !isRecord(image))) {
155
- throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned malformed image data", {}, "upstream");
155
+ throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned malformed image data (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
156
156
  }
157
157
  if (result.data.length === 0) {
158
- throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned no images", {}, "upstream");
158
+ throw new GatewayError("platform_unavailable", 502, "CodeBuddy image generation returned no images (request {requestId}). The upstream came back empty-handed — retry 🌙", {}, "upstream");
159
159
  }
160
160
  return {
161
161
  ...(typeof result.created === "number" ? { created: result.created } : {}),
@@ -173,7 +173,11 @@ export async function buddyGenerateImage(
173
173
  buddyPrePayloadCommon(payload, undefined, "intl", context);
174
174
  const messages = payload["messages"];
175
175
  if (Array.isArray(messages)) {
176
- applyBuddySystemPrompt(messages as Array<Record<string, unknown>>, config.systemPrompt);
176
+ applyBuddySystemPrompt(
177
+ messages as Array<Record<string, unknown>>,
178
+ config.systemPrompt,
179
+ context?.tenant_system_prompt,
180
+ );
177
181
  }
178
182
  const headers: Record<string, string> = {
179
183
  "content-type": "application/json",
@@ -213,7 +217,7 @@ export async function buddyGenerateImage(
213
217
  if (!contentType.includes("text/event-stream")) {
214
218
  const parsed: unknown = await response.json().catch(() => null);
215
219
  const message = buddyErrorOf(parsed) ?? "CodeBuddy image generation returned a non-stream body";
216
- throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
220
+ throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
217
221
  }
218
222
  let content = "";
219
223
  for await (const event of decodeSseEvents(response.body, { signal: context.abort_signal })) {
@@ -228,7 +232,7 @@ export async function buddyGenerateImage(
228
232
  if (!isRecord(parsed)) continue;
229
233
  if (isRecord(parsed.error)) {
230
234
  const message = isRecord(parsed.error) && typeof parsed.error.message === "string" ? parsed.error.message : "CodeBuddy image generation failed";
231
- throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
235
+ throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
232
236
  }
233
237
  const choices = parsed.choices;
234
238
  if (!Array.isArray(choices) || !isRecord(choices[0])) continue;
@@ -240,7 +244,7 @@ export async function buddyGenerateImage(
240
244
  throw new GatewayError(
241
245
  "platform_unavailable",
242
246
  502,
243
- "CodeBuddy image generation returned no image in the chat stream",
247
+ "CodeBuddy image generation returned no image in the chat stream (request {requestId}). The upstream came back empty-handed — retry 🌙",
244
248
  {},
245
249
  "upstream",
246
250
  );
@@ -314,7 +318,7 @@ export async function buddyGenerateVideo(
314
318
  context: ProviderDispatchContext,
315
319
  ): Promise<Record<string, unknown>> {
316
320
  const model = modelOf(body, candidate);
317
- if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required");
321
+ if (model.length === 0) throw new GatewayError("invalid_request", 400, "model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
318
322
  const prompt = imagePrompt(body);
319
323
  const submitBody: Record<string, unknown> = { model, prompt };
320
324
  if (typeof body.n === "number" && Number.isFinite(body.n)) submitBody["n"] = Math.max(1, Math.floor(body.n));
@@ -350,14 +354,14 @@ export async function buddyGenerateVideo(
350
354
  if (url !== undefined) return { data: [{ url }] };
351
355
  // Otherwise cb refused (HTTP 200 error envelope) — surface its own reason.
352
356
  const message = buddyErrorOf(submitted) ?? "CodeBuddy video submit returned no task id";
353
- throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
357
+ throw new GatewayError("platform_unavailable", 502, `${message} (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
354
358
  }
355
359
  // Poll the sibling task endpoint until the clip is ready.
356
360
  const taskPath = `${submitUrl.replace(/\/+$/, "")}/${taskId}`;
357
361
  const deadline = Date.now() + VIDEO_POLL_TIMEOUT_MS;
358
362
  for (;;) {
359
363
  if (context.abort_signal?.aborted) {
360
- throw new GatewayError("transport_closed", 499, "video generation aborted");
364
+ throw new GatewayError("transport_closed", 499, "video generation aborted (request {requestId}). Send it again whenever ready 🙃");
361
365
  }
362
366
  const lifecycle = createUpstreamDeadlineLifecycle(context);
363
367
  let statusRes: Response;
@@ -370,7 +374,7 @@ export async function buddyGenerateVideo(
370
374
  } catch (error: unknown) {
371
375
  const abortError = abortGatewayError(lifecycle, error, context.abort_signal);
372
376
  if (abortError) throw abortError;
373
- throw new GatewayError("platform_unavailable", 502, `CodeBuddy video status unreachable: ${error instanceof Error ? error.message : String(error)}`, {}, "upstream");
377
+ throw new GatewayError("platform_unavailable", 502, `CodeBuddy video status unreachable (request {requestId}): ${error instanceof Error ? error.message : String(error)}. The connection ghosted us — come back in a moment 👻`, {}, "upstream");
374
378
  } finally {
375
379
  lifecycle.release();
376
380
  }
@@ -382,10 +386,10 @@ export async function buddyGenerateVideo(
382
386
  if (url !== undefined) return { data: [{ url }], task_id: taskId };
383
387
  const status = videoStatusOf(payload);
384
388
  if (status !== undefined && !VIDEO_PENDING.has(status)) {
385
- throw new GatewayError("platform_unavailable", 502, `CodeBuddy video task ended in state "${status}" with no clip`, {}, "upstream");
389
+ throw new GatewayError("platform_unavailable", 502, `CodeBuddy video task ended in state "${status}" with no clip (request {requestId}). The upstream came back empty-handed — retry 🌙`, {}, "upstream");
386
390
  }
387
391
  if (Date.now() > deadline) {
388
- throw new GatewayError("platform_unavailable", 504, `CodeBuddy video task ${taskId} did not finish within ${VIDEO_POLL_TIMEOUT_MS}ms`, {}, "upstream");
392
+ throw new GatewayError("platform_unavailable", 504, `CodeBuddy video task ${taskId} did not finish within ${VIDEO_POLL_TIMEOUT_MS}ms (request {requestId}). Some things just take longer 🐢`, {}, "upstream");
389
393
  }
390
394
  await new Promise((resolve) => setTimeout(resolve, VIDEO_POLL_INTERVAL_MS));
391
395
  }
@@ -81,10 +81,14 @@ function codeBuddyIntlPrePayload(
81
81
  typeof rawModel === "string" && rawModel.length > 0
82
82
  ? rawModel
83
83
  : candidate.model_id;
84
- if (!source) throw new GatewayError("invalid_request", 400, "CodeBuddy model is required");
84
+ if (!source) throw new GatewayError("invalid_request", 400, "CodeBuddy model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
85
85
  const messages = payload["messages"];
86
86
  if (Array.isArray(messages)) {
87
- applyBuddySystemPrompt(messages as Array<Record<string, unknown>>, CODEBUDDY_SYSTEM_PROMPT);
87
+ applyBuddySystemPrompt(
88
+ messages as Array<Record<string, unknown>>,
89
+ CODEBUDDY_SYSTEM_PROMPT,
90
+ context?.tenant_system_prompt,
91
+ );
88
92
  }
89
93
  normalizeBuddyToolNames(payload);
90
94
  injectBuddyParallelToolCalls(payload, request);
@@ -134,11 +134,15 @@ export function workbuddyPrePayload(
134
134
  const rawModel = payload["model"];
135
135
  const source =
136
136
  typeof rawModel === "string" && rawModel.length > 0 ? rawModel : candidate.model_id;
137
- if (!source) throw new GatewayError("invalid_request", 400, "WorkBuddy model is required");
137
+ if (!source) throw new GatewayError("invalid_request", 400, "WorkBuddy model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
138
138
  const messages = payload["messages"];
139
139
  if (Array.isArray(messages)) {
140
140
  const normalizedMessages = messages as Array<Record<string, unknown>>;
141
- applyBuddySystemPrompt(normalizedMessages, WORKBUDDY_SYSTEM_PROMPT);
141
+ applyBuddySystemPrompt(
142
+ normalizedMessages,
143
+ WORKBUDDY_SYSTEM_PROMPT,
144
+ context?.tenant_system_prompt,
145
+ );
142
146
  restoreHistoricalToolDefinitions(payload, normalizedMessages);
143
147
  }
144
148
  normalizeBuddyToolNames(payload);
@@ -67,7 +67,7 @@ export const ANTHROPIC_BETA_CAPABILITIES: Readonly<Record<string, readonly strin
67
67
  const BETA_TOKEN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
68
68
 
69
69
  function invalidBeta(message: string, value: unknown): GatewayError {
70
- return new GatewayError("invalid_request", 400, message, { field: "anthropic-beta", value });
70
+ return new GatewayError("invalid_request", 400, `${message} (request {requestId}). Check the shape of what you sent — then resend 🪞`, { field: "anthropic-beta", value });
71
71
  }
72
72
 
73
73
  /**
@@ -10,7 +10,7 @@ function invalidHeader(
10
10
  message: string,
11
11
  details: Readonly<Record<string, unknown>> = {},
12
12
  ): GatewayError {
13
- return new GatewayError("invalid_request", 400, message, details);
13
+ return new GatewayError("invalid_request", 400, `${message} (request {requestId}). Check the shape of what you sent — then resend 🪞`, details);
14
14
  }
15
15
 
16
16
  function decodeSecret(secret: Uint8Array | undefined): string | undefined {
@@ -96,5 +96,5 @@ export function planSlowLaneRetry(
96
96
 
97
97
  /** Typed error for a caller-aborted wait, so it is never read as a failure. */
98
98
  export function slowLaneAborted(): GatewayError {
99
- return new GatewayError("transport_closed", 499, "Aborted during slow-lane capacity wait");
99
+ return new GatewayError("transport_closed", 499, "The request was cancelled during the slow-lane capacity wait (request {requestId}). Send it again whenever ready 🙃");
100
100
  }
@@ -61,6 +61,7 @@ import {
61
61
  refusalCreditToken,
62
62
  sharedFallbackCreditCache,
63
63
  } from "./fallback-credit";
64
+ import { assertCredentialKind, assertWireFamily } from "../../provider-contracts";
64
65
  import type { ProviderDispatchTarget, ProviderAdapter, ProviderDispatchContext } from "../../provider-contracts";
65
66
  import { defineModel } from "../../provider-model-definition";
66
67
  import type { ModelDefinition } from "../../provider-model-definition";
@@ -185,21 +186,13 @@ export class ClaudeAdapter implements ProviderAdapter {
185
186
  context: ProviderDispatchContext,
186
187
  ): AsyncIterable<CanonicalEvent> {
187
188
  if (candidate.wire_family !== "messages") {
188
- throw new GatewayError(
189
- "capability_unsupported",
190
- 400,
191
- "claude supports messages only",
192
- );
189
+ assertWireFamily(candidate, "messages", "claude");
193
190
  }
194
191
  if (
195
192
  context.credential.credential_kind !== "oauth" &&
196
193
  context.credential.credential_kind !== "scoped_access_token"
197
194
  ) {
198
- throw new GatewayError(
199
- "invalid_request",
200
- 400,
201
- `claude: the assistant OAuth credential required (got credential_kind=${context.credential.credential_kind})`,
202
- );
195
+ assertCredentialKind(context.credential, ["oauth", "scoped_access_token"], "claude");
203
196
  }
204
197
  const customHeaders = filterClaudeCustomHeaders({
205
198
  ...this.customHeaders,
@@ -8,6 +8,7 @@ import { completeRequiredSchema, isRecord } from "../../../protocol/codecs";
8
8
  import { providerBaseUrl } from "../../provider-metadata";
9
9
  import { getCachedModelDiscovery } from "../../operations/model-discovery-cache";
10
10
  import { defineModel } from "../../provider-model-definition";
11
+ import { clineReasoningReplayPrepares } from "../buddy/buddy-chat-shared";
11
12
  import { clinePlatform, clinePlatformVersion } from "../../operations/cli-platform";
12
13
  import {
13
14
  getClineCliVersion,
@@ -133,6 +134,12 @@ function clinePrePayload(
133
134
  ? messages
134
135
  : [{ role: "system", content: "You are a helpful assistant." }, ...messages];
135
136
 
137
+ // 1.5) DeepSeek-replay backfill: Cline resells thinking models (deepseek,
138
+ // reflection/beam) whose upstream rejects the whole history when any prior
139
+ // assistant turn lacks `reasoning_content`. Same wire as OpenRouter/Hermes/
140
+ // Kilo, so the shared helper runs here too — it only mirrors a real trace.
141
+ for (const prepare of clineReasoningReplayPrepares) prepare(payload);
142
+
136
143
  // 2) Materialize deepseek-v4-flash non-stream quirk
137
144
  const model = typeof payload["model"] === "string" ? (payload["model"] as string) : candidate.model_id;
138
145
  const needsMaterialize = !request.stream && model.includes("deepseek-v4-flash");
@@ -143,7 +150,7 @@ function clinePrePayload(
143
150
  const cur = typeof payload["max_tokens"] === "number" ? (payload["max_tokens"] as number) : 0;
144
151
  payload["max_tokens"] = Math.max(cur, 256);
145
152
  // keep GatewayError reachable
146
- if (!model) throw new GatewayError("invalid_request", 400, "Cline model is required");
153
+ if (!model) throw new GatewayError("invalid_request", 400, "Cline model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
147
154
  }
148
155
  }
149
156
 
@@ -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
  );