cartethyia 2.6.7 → 2.7.1

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 (335) hide show
  1. package/.env.example +1 -7
  2. package/README.md +25 -2
  3. package/dist/dashboard/assets/{BannedPage-Dskhyp0l.js → BannedPage-D-J75hBM.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-D-J75hBM.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage--SJhk7qQ.js → CliToolDetailPage-CVe6RaBH.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-CVe6RaBH.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-C203VT-c.js → CliToolsPage-Dd8ZSamp.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-Dd8ZSamp.js.gz +0 -0
  9. package/dist/dashboard/assets/{CombosPage-BcS7kGG1.js → CombosPage-QoJ6foxo.js} +1 -1
  10. package/dist/dashboard/assets/CombosPage-QoJ6foxo.js.gz +0 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js +1 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-DpNRay4C.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-uujbBYwC.js → CustomizationPage-CKUFTcW4.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-CKUFTcW4.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-CzSLiDzr.js.gz +0 -0
  17. package/dist/dashboard/assets/LoginPage-DubdQcvX.js +1 -0
  18. package/dist/dashboard/assets/LoginPage-DubdQcvX.js.gz +0 -0
  19. package/dist/dashboard/assets/{ModelPicker-CA1kLs45.js → ModelPicker-BH8Tehdi.js} +1 -1
  20. package/dist/dashboard/assets/ModelPicker-BH8Tehdi.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-DuWzAQFL.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js +4 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-BKEKe2Fm.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +1 -0
  26. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  27. package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js +1 -0
  28. package/dist/dashboard/assets/ProvidersPage-Bwotu8UJ.js.gz +0 -0
  29. package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js +9 -0
  30. package/dist/dashboard/assets/ProxyPage-D7hpWbg9.js.gz +0 -0
  31. package/dist/dashboard/assets/{QuotaPage-BueSWX5D.js → QuotaPage-ATpaxrbl.js} +1 -1
  32. package/dist/dashboard/assets/QuotaPage-ATpaxrbl.js.gz +0 -0
  33. package/dist/dashboard/assets/SettingsPage-CETophpx.js +1 -0
  34. package/dist/dashboard/assets/SettingsPage-CETophpx.js.gz +0 -0
  35. package/dist/dashboard/assets/SetupPage-BdgECjqq.js +1 -0
  36. package/dist/dashboard/assets/SetupPage-BdgECjqq.js.gz +0 -0
  37. package/dist/dashboard/assets/{SortableList-DrKeMcGN.js → SortableList-CAK-EN9z.js} +1 -1
  38. package/dist/dashboard/assets/SortableList-CAK-EN9z.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-qjuYtccc.js → StudioPage-B7W2_RhT.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-B7W2_RhT.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-6T4EFDjW.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-6T4EFDjW.js.gz +0 -0
  43. package/dist/dashboard/assets/{api-keys-C23S9sgp.js → api-keys-CUi6UXsR.js} +1 -1
  44. package/dist/dashboard/assets/api-keys-CUi6UXsR.js.gz +0 -0
  45. package/dist/dashboard/assets/app-KvsUJUMF.css +2 -0
  46. package/dist/dashboard/assets/app-KvsUJUMF.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-DU6qrMA_.js → assert-67xXH5rf.js} +1 -1
  48. package/dist/dashboard/assets/assert-67xXH5rf.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-Bkz_-RrM.js → badge-DC2L43Mj.js} +1 -1
  50. package/dist/dashboard/assets/badge-DC2L43Mj.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-C-7y3VKV.js → banner-BBVcb0J3.js} +1 -1
  52. package/dist/dashboard/assets/banner-BBVcb0J3.js.gz +0 -0
  53. package/dist/dashboard/assets/{card-BOPBuBzD.js → card-Cca1XC6G.js} +1 -1
  54. package/dist/dashboard/assets/card-Cca1XC6G.js.gz +0 -0
  55. package/dist/dashboard/assets/{cli-tools-BaFUuFFF.js → cli-tools-KvsWa1Jl.js} +1 -1
  56. package/dist/dashboard/assets/cli-tools-KvsWa1Jl.js.gz +0 -0
  57. package/dist/dashboard/assets/{clipboard-button-e-Mlk0FH.js → clipboard-button-DUzEbynq.js} +1 -1
  58. package/dist/dashboard/assets/clipboard-button-DUzEbynq.js.gz +0 -0
  59. package/dist/dashboard/assets/{dialog-Iec_ywbD.js → dialog-DFvWhwTa.js} +1 -1
  60. package/dist/dashboard/assets/dialog-DFvWhwTa.js.gz +0 -0
  61. package/dist/dashboard/assets/{drawer-Bs8MIIHc.js → drawer-CFM2sMX1.js} +1 -1
  62. package/dist/dashboard/assets/drawer-CFM2sMX1.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-DOddwoc0.js → entry-BLBLxX0h.js} +3 -3
  64. package/dist/dashboard/assets/entry-BLBLxX0h.js.gz +0 -0
  65. package/dist/dashboard/assets/{entry-DcobaKFu.js → entry-Bqy8RFvM.js} +1 -1
  66. package/dist/dashboard/assets/entry-Bqy8RFvM.js.gz +0 -0
  67. package/dist/dashboard/assets/{entry-BRszm4_Z.js → entry-_xHo5x6r.js} +1 -1
  68. package/dist/dashboard/assets/entry-_xHo5x6r.js.gz +0 -0
  69. package/dist/dashboard/assets/formatters-mpBPqAQ8.js +1 -0
  70. package/dist/dashboard/assets/formatters-mpBPqAQ8.js.gz +0 -0
  71. package/dist/dashboard/assets/{github-badge-BuDsrsPn.js → github-badge-C9e8Ts7e.js} +1 -1
  72. package/dist/dashboard/assets/github-badge-C9e8Ts7e.js.gz +0 -0
  73. package/dist/dashboard/assets/{index-BeLRhsmt.js → index-D6QzEC_n.js} +2 -2
  74. package/dist/dashboard/assets/index-D6QzEC_n.js.gz +0 -0
  75. package/dist/dashboard/assets/{inline-DToMICwl.js → inline-BFUcvllj.js} +1 -1
  76. package/dist/dashboard/assets/inline-BFUcvllj.js.gz +0 -0
  77. package/dist/dashboard/assets/{input-WlyHWeG2.js → input-C_ILAvBb.js} +1 -1
  78. package/dist/dashboard/assets/input-C_ILAvBb.js.gz +0 -0
  79. package/dist/dashboard/assets/{layout-DaJ5baJr.js → layout-CBIyT6Rt.js} +1 -1
  80. package/dist/dashboard/assets/layout-CBIyT6Rt.js.gz +0 -0
  81. package/dist/dashboard/assets/{list-row-B3oSK13z.js → list-row-ebJ_-Nsb.js} +1 -1
  82. package/dist/dashboard/assets/list-row-ebJ_-Nsb.js.gz +0 -0
  83. package/dist/dashboard/assets/{live-ta6GMb-8.js → live-D0mm--ME.js} +1 -1
  84. package/dist/dashboard/assets/live-D0mm--ME.js.gz +0 -0
  85. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +1 -0
  86. package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
  87. package/dist/dashboard/assets/{mutation-g_fduiNw.js → mutation-sMD965oO.js} +1 -1
  88. package/dist/dashboard/assets/mutation-sMD965oO.js.gz +0 -0
  89. package/dist/dashboard/assets/{numbers-Dulqgys5.js → numbers-BO9dKaFr.js} +1 -1
  90. package/dist/dashboard/assets/numbers-BO9dKaFr.js.gz +0 -0
  91. package/dist/dashboard/assets/providers/inception.svg +5 -0
  92. package/dist/dashboard/assets/providers/inception.svg.gz +0 -0
  93. package/dist/dashboard/assets/{query-keys-UETqfytp.js → query-keys-CfL_Zdoh.js} +1 -1
  94. package/dist/dashboard/assets/query-keys-CfL_Zdoh.js.gz +0 -0
  95. package/dist/dashboard/assets/{routing-BPUo-W8d.js → routing-BnIpi1IJ.js} +1 -1
  96. package/dist/dashboard/assets/routing-BnIpi1IJ.js.gz +0 -0
  97. package/dist/dashboard/assets/{select-BfZ3SCTM.js → select-Cj5Nw43g.js} +1 -1
  98. package/dist/dashboard/assets/select-Cj5Nw43g.js.gz +0 -0
  99. package/dist/dashboard/assets/settings-BAFhDgX8.js +1 -0
  100. package/dist/dashboard/assets/settings-BAFhDgX8.js.gz +0 -0
  101. package/dist/dashboard/assets/{stack-B1w5BM0u.js → stack-EMrOMt4I.js} +1 -1
  102. package/dist/dashboard/assets/stack-EMrOMt4I.js.gz +0 -0
  103. package/dist/dashboard/assets/{state-DhZBfWgx.js → state-CWoo7ty5.js} +1 -1
  104. package/dist/dashboard/assets/state-CWoo7ty5.js.gz +0 -0
  105. package/dist/dashboard/assets/{switch-yD7D99Lg.js → switch-CCjT6IkF.js} +1 -1
  106. package/dist/dashboard/assets/switch-CCjT6IkF.js.gz +0 -0
  107. package/dist/dashboard/assets/{useMutation-EDFRkn1i.js → useMutation-DjkLHUcE.js} +1 -1
  108. package/dist/dashboard/assets/useMutation-DjkLHUcE.js.gz +0 -0
  109. package/dist/dashboard/index.html +1 -1
  110. package/dist/dashboard/index.html.gz +0 -0
  111. package/dist/dashboard/precompressed-assets.json +55 -54
  112. package/migrations/full-postgres/0024_add_pool_provider_cooldowns.sql +12 -0
  113. package/migrations/full-postgres/0025_add_pool_random_strategy.sql +3 -0
  114. package/migrations/lite-sqlite3/0024_add_pool_provider_cooldowns.sql +12 -0
  115. package/migrations/lite-sqlite3/0025_add_pool_random_strategy.sql +20 -0
  116. package/package.json +1 -1
  117. package/scripts/cli/console-menu.ts +5 -2
  118. package/scripts/cli/tray.ts +21 -6
  119. package/src/boot/app.ts +24 -62
  120. package/src/boot/dependencies.ts +732 -750
  121. package/src/config/cooldowns.ts +16 -0
  122. package/src/config/providers.ts +13 -1
  123. package/src/config/resources.ts +13 -80
  124. package/src/config/security.ts +2 -38
  125. package/src/config/spec.ts +16 -23
  126. package/src/console/console-router.ts +7 -7
  127. package/src/console/domain-registration.ts +19 -12
  128. package/src/console/providers/catalog/catalog-projections.ts +2 -6
  129. package/src/console/providers/catalog/contracts.ts +19 -0
  130. package/src/console/providers/catalog/provider-operations.ts +38 -0
  131. package/src/console/providers/catalog/routes.ts +14 -0
  132. package/src/console/providers/catalog/store-helpers.ts +326 -0
  133. package/src/console/providers/catalog/store.ts +1292 -1563
  134. package/src/console/quota/account-quota-global.ts +2 -2
  135. package/src/console/quota/account-quota-shared.ts +1 -1
  136. package/src/console/quota/account-quota-tenant.ts +35 -12
  137. package/src/console/quota/quota-view.ts +2 -2
  138. package/src/console/remote-support/contracts.ts +3 -1
  139. package/src/console/remote-support/service.ts +115 -6
  140. package/src/console/routing/pools/contracts.ts +41 -1
  141. package/src/console/routing/pools/operations.ts +183 -4
  142. package/src/console/routing/pools/relay-deploy.ts +17 -4
  143. package/src/console/routing/pools/routes.ts +30 -0
  144. package/src/console/routing/pools/store.ts +98 -8
  145. package/src/main.ts +16 -2
  146. package/src/network/outbound-fetch.ts +226 -365
  147. package/src/network/pool/agent.ts +8 -0
  148. package/src/network/pool/pool-state.ts +7 -0
  149. package/src/network/pool/selector.ts +110 -2
  150. package/src/network/pool-cooldown-store.ts +252 -0
  151. package/src/network/pool-health-machine.ts +5 -3
  152. package/src/network/pool-health.ts +36 -9
  153. package/src/observability/event-query.ts +57 -0
  154. package/src/observability/metrics.ts +15 -5
  155. package/src/observability/runtime-metrics.ts +30 -15
  156. package/src/persistence/health-event-flush.ts +2 -0
  157. package/src/persistence/schema.ts +19 -0
  158. package/src/persistence/usage-flush.ts +8 -3
  159. package/src/protocol/canonical-model.ts +1 -1
  160. package/src/protocol/dsml.ts +377 -0
  161. package/src/protocol/gateway-error.ts +0 -1
  162. package/src/{providers/provider-reasoning.ts → protocol/reasoning.ts} +10 -9
  163. package/src/protocol/request/chat.ts +7 -7
  164. package/src/protocol/request/codex.ts +2 -2
  165. package/src/protocol/request/gemini.ts +1 -1
  166. package/src/protocol/request/messages.ts +6 -6
  167. package/src/protocol/request/responses.ts +7 -7
  168. package/src/protocol/response/dsml.ts +12 -133
  169. package/src/{transport → protocol}/translation/attachment-integrity.ts +2 -2
  170. package/src/{transport → protocol}/translation/cache-controls.ts +1 -1
  171. package/src/{transport → protocol}/translation/capabilities.ts +2 -2
  172. package/src/{transport → protocol}/translation/normalize.ts +1 -1
  173. package/src/{transport → protocol}/translation/quirks.ts +1 -1
  174. package/src/{transport → protocol}/translation/search.ts +1 -1
  175. package/src/{transport → protocol}/translation/thinking.ts +23 -1
  176. package/src/{transport → protocol}/translation/tool-id.ts +1 -1
  177. package/src/{transport → protocol}/translation/tool-repair.ts +2 -2
  178. package/src/protocol/upstream-parsing.ts +176 -0
  179. package/src/providers/adapters/compatible-adapter.ts +11 -2
  180. package/src/providers/authentication/oauth-refresh-service.ts +9 -5
  181. package/src/providers/default-registry.ts +21 -5
  182. package/src/providers/discovery/probe-phases.ts +16 -3
  183. package/src/providers/discovery/probing-service.ts +4 -1
  184. package/src/providers/integrations/anthropic.ts +1 -1
  185. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -4
  186. package/src/providers/integrations/buddy/buddy-chat-shared.ts +141 -8
  187. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -1
  188. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -82
  189. package/src/providers/integrations/buddy/buddy-identity.ts +25 -0
  190. package/src/providers/integrations/buddy/buddy-server-tools.ts +240 -0
  191. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +36 -0
  192. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +6 -31
  193. package/src/providers/integrations/buddy/codebuddy/provider.ts +2 -0
  194. package/src/providers/integrations/buddy/codebuddy/shared.ts +19 -4
  195. package/src/providers/integrations/buddy/turing-device-token.ts +262 -0
  196. package/src/providers/integrations/buddy/workbuddy/provider.ts +2 -0
  197. package/src/providers/integrations/buddy/workbuddy/shared.ts +56 -3
  198. package/src/providers/integrations/claude/claude.ts +1 -1
  199. package/src/providers/integrations/cloudflareai/cloudflareai.ts +1 -1
  200. package/src/providers/integrations/codex/codex-errors.ts +1 -1
  201. package/src/providers/integrations/codex/codex.ts +1 -1
  202. package/src/providers/integrations/commandcode/commandcode.ts +134 -104
  203. package/src/providers/integrations/commandcode/discovery.ts +6 -5
  204. package/src/providers/integrations/factory/factory.ts +1 -1
  205. package/src/providers/integrations/github/github.ts +1 -1
  206. package/src/providers/integrations/grok/grok.ts +1 -1
  207. package/src/providers/integrations/inception/provider.ts +91 -0
  208. package/src/providers/integrations/inferhub.ts +1 -1
  209. package/src/providers/integrations/kiro/kiro-request.ts +1 -1
  210. package/src/providers/integrations/mistral.ts +193 -19
  211. package/src/providers/integrations/opencode/fingerprint.ts +19 -2
  212. package/src/providers/integrations/opencode/prompt.ts +111 -0
  213. package/src/providers/integrations/opencode/provider.ts +101 -23
  214. package/src/providers/integrations/opencode/tool-definitions.ts +4 -4
  215. package/src/providers/integrations/qoder/qoder-checkin.ts +303 -0
  216. package/src/providers/integrations/qoder/qoder.ts +1641 -884
  217. package/src/providers/integrations/shared/install-id.ts +2 -1
  218. package/src/providers/integrations/trae/trae-cache.ts +110 -0
  219. package/src/providers/integrations/trae/trae-oauth.ts +29 -4
  220. package/src/providers/integrations/trae/trae-protocol.ts +2 -1
  221. package/src/providers/integrations/trae/trae.ts +106 -23
  222. package/src/providers/operations/account-error-classification.ts +1660 -0
  223. package/src/providers/operations/account-health-service.ts +621 -2097
  224. package/src/providers/operations/account-reset-service.ts +2 -0
  225. package/src/providers/provider-contracts.ts +0 -2
  226. package/src/providers/provider-metadata.ts +25 -4
  227. package/src/providers/provider-probe.ts +2 -2
  228. package/src/{console → providers}/quota/cache.ts +1 -1
  229. package/src/{console → providers}/quota/refresh.ts +5 -5
  230. package/src/security/abuse.ts +17 -0
  231. package/src/transport/dispatch/attempt-finalize.ts +114 -12
  232. package/src/transport/dispatch/attempt-loop.ts +3 -0
  233. package/src/transport/dispatch/empty-stream.ts +224 -217
  234. package/src/transport/dispatch/generation.ts +37 -55
  235. package/src/transport/dispatch/handler-deps.ts +32 -0
  236. package/src/transport/dispatch/leases.ts +9 -4
  237. package/src/transport/dispatch/proxy-request.ts +6 -30
  238. package/src/transport/dispatch/responses-compact.ts +22 -43
  239. package/src/transport/dispatch/streaming/finalize.ts +3 -0
  240. package/src/transport/dispatch/streaming/stream.ts +0 -8
  241. package/src/transport/dispatch/systemone.ts +22 -42
  242. package/src/transport/dispatch/token-count.ts +23 -39
  243. package/src/transport/dispatch/upstream.ts +1 -3
  244. package/src/transport/dispatch/websearch.ts +22 -41
  245. package/src/transport/failure-policy.ts +59 -178
  246. package/src/transport/guards/abuse-guard.ts +10 -0
  247. package/src/transport/guards/auth-guard.ts +0 -18
  248. package/src/transport/guards/error-lifecycle.ts +1 -1
  249. package/src/transport/guards/pipeline.ts +0 -6
  250. package/src/transport/guards/request-context.ts +18 -91
  251. package/src/transport/request/degradation.ts +20 -1
  252. package/src/transport/request/inflight.ts +4 -95
  253. package/src/transport/request/preparer.ts +6 -6
  254. package/src/transport/request/state.ts +66 -38
  255. package/src/transport/request/tenant-preferences.ts +1 -1
  256. package/src/transport/routing/route-catalog.ts +41 -31
  257. package/src/transport/routing/router.ts +2 -2
  258. package/src/transport/surface/messages/parse.ts +1 -1
  259. package/src/workers/buddy-growth-tasks.ts +346 -425
  260. package/src/workers/daily-checkin.ts +17 -6
  261. package/src/workers/quota-refresh-sweep.ts +2 -2
  262. package/src/workers/scheduler.ts +17 -1
  263. package/dist/dashboard/assets/BannedPage-Dskhyp0l.js.gz +0 -0
  264. package/dist/dashboard/assets/CliToolDetailPage--SJhk7qQ.js.gz +0 -0
  265. package/dist/dashboard/assets/CliToolsPage-C203VT-c.js.gz +0 -0
  266. package/dist/dashboard/assets/CombosPage-BcS7kGG1.js.gz +0 -0
  267. package/dist/dashboard/assets/ConsoleLogPage-ChmiSLwO.js +0 -1
  268. package/dist/dashboard/assets/ConsoleLogPage-ChmiSLwO.js.gz +0 -0
  269. package/dist/dashboard/assets/CustomizationPage-uujbBYwC.js.gz +0 -0
  270. package/dist/dashboard/assets/HealthEventsModal-fKAWd-OQ.js +0 -1
  271. package/dist/dashboard/assets/HealthEventsModal-fKAWd-OQ.js.gz +0 -0
  272. package/dist/dashboard/assets/LoginPage-DoOUthbG.js +0 -1
  273. package/dist/dashboard/assets/LoginPage-DoOUthbG.js.gz +0 -0
  274. package/dist/dashboard/assets/ModelPicker-CA1kLs45.js.gz +0 -0
  275. package/dist/dashboard/assets/OverviewPage-C5Z-UBz1.js +0 -1
  276. package/dist/dashboard/assets/OverviewPage-C5Z-UBz1.js.gz +0 -0
  277. package/dist/dashboard/assets/ProviderDetailPage-CFu1qGcT.js +0 -3
  278. package/dist/dashboard/assets/ProviderDetailPage-CFu1qGcT.js.gz +0 -0
  279. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js +0 -1
  280. package/dist/dashboard/assets/ProviderIcon-CmfzxpVM.js.gz +0 -0
  281. package/dist/dashboard/assets/ProvidersPage-CnlJZbxF.js +0 -1
  282. package/dist/dashboard/assets/ProvidersPage-CnlJZbxF.js.gz +0 -0
  283. package/dist/dashboard/assets/ProxyPage-B9mBTweh.js +0 -7
  284. package/dist/dashboard/assets/ProxyPage-B9mBTweh.js.gz +0 -0
  285. package/dist/dashboard/assets/QuotaPage-BueSWX5D.js.gz +0 -0
  286. package/dist/dashboard/assets/SettingsPage-B0x00MVY.js +0 -1
  287. package/dist/dashboard/assets/SettingsPage-B0x00MVY.js.gz +0 -0
  288. package/dist/dashboard/assets/SetupPage-DQ9oDRpi.js +0 -1
  289. package/dist/dashboard/assets/SetupPage-DQ9oDRpi.js.gz +0 -0
  290. package/dist/dashboard/assets/SortableList-DrKeMcGN.js.gz +0 -0
  291. package/dist/dashboard/assets/StudioPage-qjuYtccc.js.gz +0 -0
  292. package/dist/dashboard/assets/UsagePage-Be7aNviQ.js +0 -56
  293. package/dist/dashboard/assets/UsagePage-Be7aNviQ.js.gz +0 -0
  294. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  295. package/dist/dashboard/assets/app-BUSiYL6F.css +0 -2
  296. package/dist/dashboard/assets/app-BUSiYL6F.css.gz +0 -0
  297. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  298. package/dist/dashboard/assets/badge-Bkz_-RrM.js.gz +0 -0
  299. package/dist/dashboard/assets/banner-C-7y3VKV.js.gz +0 -0
  300. package/dist/dashboard/assets/card-BOPBuBzD.js.gz +0 -0
  301. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  302. package/dist/dashboard/assets/clipboard-button-e-Mlk0FH.js.gz +0 -0
  303. package/dist/dashboard/assets/cog-CdWhsajs.js +0 -1
  304. package/dist/dashboard/assets/cog-CdWhsajs.js.gz +0 -0
  305. package/dist/dashboard/assets/dialog-Iec_ywbD.js.gz +0 -0
  306. package/dist/dashboard/assets/drawer-Bs8MIIHc.js.gz +0 -0
  307. package/dist/dashboard/assets/entry-BRszm4_Z.js.gz +0 -0
  308. package/dist/dashboard/assets/entry-DOddwoc0.js.gz +0 -0
  309. package/dist/dashboard/assets/entry-DcobaKFu.js.gz +0 -0
  310. package/dist/dashboard/assets/github-badge-BuDsrsPn.js.gz +0 -0
  311. package/dist/dashboard/assets/index-BeLRhsmt.js.gz +0 -0
  312. package/dist/dashboard/assets/inline-DToMICwl.js.gz +0 -0
  313. package/dist/dashboard/assets/input-WlyHWeG2.js.gz +0 -0
  314. package/dist/dashboard/assets/layout-DaJ5baJr.js.gz +0 -0
  315. package/dist/dashboard/assets/list-row-B3oSK13z.js.gz +0 -0
  316. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  317. package/dist/dashboard/assets/model-bans-BmYTmbAk.js +0 -1
  318. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  319. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  320. package/dist/dashboard/assets/numbers-Dulqgys5.js.gz +0 -0
  321. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  322. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  323. package/dist/dashboard/assets/select-BfZ3SCTM.js.gz +0 -0
  324. package/dist/dashboard/assets/settings--3hxSyry.js +0 -1
  325. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  326. package/dist/dashboard/assets/stack-B1w5BM0u.js.gz +0 -0
  327. package/dist/dashboard/assets/state-DhZBfWgx.js.gz +0 -0
  328. package/dist/dashboard/assets/switch-yD7D99Lg.js.gz +0 -0
  329. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  330. package/src/console/admin/model-abuse/contracts.ts +0 -38
  331. package/src/console/admin/model-abuse/routes.ts +0 -97
  332. package/src/security/model-abuse.ts +0 -704
  333. package/src/transport/guards/concurrency-guard.ts +0 -125
  334. /package/dist/dashboard/assets/{app-MdVfwraB.js → app-BaWd0puM.js} +0 -0
  335. /package/dist/dashboard/assets/{app-MdVfwraB.js.gz → app-BaWd0puM.js.gz} +0 -0
@@ -642,6 +642,7 @@ async function recordResetActivity(
642
642
  })
643
643
  .where(eq(providerAccounts.id, accountId));
644
644
  await db.insert(healthEvents).values({
645
+ id: randomUUID(),
645
646
  entityKind: "account",
646
647
  accountId,
647
648
  fromStatus: currentStatus,
@@ -655,6 +656,7 @@ async function recordResetActivity(
655
656
  }
656
657
 
657
658
  await db.insert(healthEvents).values({
659
+ id: randomUUID(),
658
660
  entityKind: "account",
659
661
  accountId,
660
662
  fromStatus: currentStatus,
@@ -134,8 +134,6 @@ export interface ProviderDispatchContext {
134
134
  readonly outbound_fetch?: ValidatedOutboundFetch | undefined;
135
135
  /** Validated image/attachment egress; deliberately excluded from payload capture. */
136
136
  readonly outbound_attachment_fetch?: ValidatedOutboundFetch | undefined;
137
- /** Validated WSS egress bound to the same selected network pool as HTTP. */
138
- readonly outbound_websocket?: ValidatedOutboundWebSocket | undefined;
139
137
  /** Validated bidirectional HTTP/2 egress bound to the same selected network pool. */
140
138
  readonly outbound_http2?: ValidatedOutboundHttp2Bidi | undefined;
141
139
  /** Built-in API-key route-selected fallback User-Agent; custom providers leave this unset. */
@@ -15,6 +15,15 @@ export interface CompatibilityProfile {
15
15
  }>;
16
16
  /** Whether requests to OpenAI/Anthropic-compatible upstream should send official CLI headers. Defaults to true. */
17
17
  readonly cli_identity?: boolean;
18
+ /**
19
+ * Direct egress for this provider uses the runtime-native fetch instead of
20
+ * the Node-stack pinned agent. Some upstreams meter per client transport
21
+ * fingerprint — OpenCode's anonymous free tier refuses the Node agent with
22
+ * 429 FreeUsageLimitError while accepting the native fetch byte-for-byte
23
+ * (verified live). The SSRF resolve/validate pass still runs for every hop;
24
+ * only the socket-level address pin is traded away.
25
+ */
26
+ readonly preferNativeFetch?: boolean;
18
27
  /**
19
28
  * Opts this provider into the gateway identity (`user-agent:
20
29
  * `Cartethyia/<version>`) instead of official CLI cloaking. Explicit only:
@@ -322,6 +331,14 @@ const RAW_BUNDLED_PROVIDER_METADATA = [
322
331
  hasAdapterUserAgent: true,
323
332
  },
324
333
  { id: "bai", displayName: "B.AI", baseUrl: "https://api.b.ai/v1", credentialUrl: "https://b.ai" },
334
+ {
335
+ id: "inception",
336
+ displayName: "Inception Labs",
337
+ // Version-rooted: the chat wire lives below the `/v1` root, so the
338
+ // declared path is `/chat/completions` (same rule as Groq/DeepInfra).
339
+ baseUrl: "https://api.inceptionlabs.ai/v1",
340
+ credentialUrl: "https://platform.inceptionlabs.ai/dashboard/api-keys",
341
+ },
325
342
  {
326
343
  id: "larprouter",
327
344
  displayName: "LarRouter",
@@ -630,16 +647,20 @@ export function providerBaseUrl(providerId: string): string {
630
647
  export const PROVIDER_COMPATIBILITY_PROFILES: Record<string, CompatibilityProfile> = {
631
648
  opencode: {
632
649
  endpoint_paths_by_wire_family: {
633
- chat: "/inference/v1/chat/completions",
634
- responses: "/inference/v1/responses",
650
+ chat: "/inference/openai/v1/chat/completions",
651
+ responses: "/inference/openai/v1/responses",
635
652
  },
653
+ // Direct egress must use the native fetch: the anonymous free tier refuses
654
+ // the Node-stack agent with 429 FreeUsageLimitError (verified live).
655
+ preferNativeFetch: true,
636
656
  model_wire_families: [{ pattern: "^muse-spark", wire_family: "responses" }],
637
657
  },
638
658
  "opencode-zen": {
639
659
  endpoint_paths_by_wire_family: {
640
- chat: "/inference/v1/chat/completions",
641
- responses: "/inference/v1/responses",
660
+ chat: "/inference/openai/v1/chat/completions",
661
+ responses: "/inference/openai/v1/responses",
642
662
  },
663
+ preferNativeFetch: true,
643
664
  model_wire_families: [{ pattern: "^muse-spark", wire_family: "responses" }],
644
665
  },
645
666
  "opencode-go": {
@@ -110,13 +110,13 @@ export async function buildProviderProbeRequest(
110
110
  provider_id: providerId,
111
111
  model_id: PROBE_MODEL,
112
112
  wire_family: "chat",
113
- endpoint_path: "/inference/v1/chat/completions",
113
+ endpoint_path: "/inference/openai/v1/chat/completions",
114
114
  capabilities: {},
115
115
  } as ProviderDispatchTarget,
116
116
  );
117
117
  const headers = (await spec.buildExtraHeaders?.(probeContext(providerId), source)) ?? {};
118
118
  return {
119
- url: `${providerBaseUrl(providerId).replace(/\/+$/, "")}/inference/v1/chat/completions`,
119
+ url: `${providerBaseUrl(providerId).replace(/\/+$/, "")}/inference/openai/v1/chat/completions`,
120
120
  headers: { "content-type": "application/json", ...headers },
121
121
  body: payload,
122
122
  };
@@ -6,7 +6,7 @@
6
6
  // Reads the pre-envelope bare result and v2-v4 envelopes during upgrade;
7
7
  // writes use v5, which records attempt time, retained-refresh errors, and
8
8
  // forces a one-time refresh for required quota accounting metadata.
9
- import type { ProviderQuotaResult } from "../../providers/quota/quota-contracts";
9
+ import type { ProviderQuotaResult } from "./quota-contracts";
10
10
  import type { RedisClient } from "../../persistence/redis";
11
11
  import { TtlCache } from "../../persistence/ttl-cache";
12
12
  import { log } from "../../observability/logger";
@@ -11,12 +11,12 @@ import type { CartethyiaDatabase } from "../../persistence/db-handle";
11
11
  import { providerAccounts } from "../../persistence/schema";
12
12
  import type { RedisClient } from "../../persistence/redis";
13
13
  import { log } from "../../observability/logger";
14
- import { fetchProviderQuota } from "../../providers/quota/quota-support";
15
- import { type FetchLike, type ProviderQuotaResult } from "../../providers/quota/quota-contracts";
16
- import type { ProviderId } from "../../providers/provider-contracts";
17
- import type { ProviderRegistry } from "../../providers/provider-registry";
14
+ import { fetchProviderQuota } from "./quota-support";
15
+ import { type FetchLike, type ProviderQuotaResult } from "./quota-contracts";
16
+ import type { ProviderId } from "../provider-contracts";
17
+ import type { ProviderRegistry } from "../provider-registry";
18
18
  import { GLOBAL_QUOTA_LENS, setCachedQuota } from "./cache";
19
- import { record } from "../../providers/authentication/oauth-flow-store";
19
+ import { record } from "../authentication/oauth-flow-store";
20
20
 
21
21
  /** Why an account quota refresh failed; `null` means the fetch succeeded. */
22
22
  export type QuotaRefreshFailureCode = "missing_credential" | "quota_fetch_failed";
@@ -1,4 +1,6 @@
1
1
  import { GatewayError } from "../protocol/gateway-error";
2
+ import { log } from "../observability/logger";
3
+ import { metrics } from "../observability/metrics";
2
4
  import { redisEvalTuple, type RedisClient } from "../persistence/redis";
3
5
 
4
6
  export interface ClientIdentity {
@@ -419,7 +421,21 @@ export class IpAbuseProtectionService {
419
421
  banDurationMs: this.banDurationMs,
420
422
  });
421
423
 
424
+ // Logged once, at the transition. A ban is the one state here the
425
+ // operator cannot see from a metric and cannot wait out by guessing:
426
+ // every request afterwards answers 429 with the same message, whether
427
+ // the address is banned or merely over the window. Naming the address,
428
+ // the count that tripped it, and how long it lasts is what turns
429
+ // "429, sometimes" into something to act on.
430
+ if (outcome.bannedNow) {
431
+ log.warn(
432
+ `ip abuse: banned ${ip} for ${Math.round(this.banDurationMs / 60_000)}min` +
433
+ ` (route ${input.route}, ceiling ${this.banThreshold})`,
434
+ );
435
+ }
436
+
422
437
  if (outcome.banned) {
438
+ metrics.cartethyia_ip_abuse_refusals_total.inc(1, { reason: "ip-banned" });
423
439
  throw new GatewayError("quota_exceeded", 429, "This address is temporarily banned for too many failed requests. Wait for the ban to lift, then slow down.", {
424
440
  // Distinguishes this from the rate-limited 429 below and from an API
425
441
  // key's own budget. It used to be "admission-unavailable", which is
@@ -437,6 +453,7 @@ export class IpAbuseProtectionService {
437
453
  }
438
454
 
439
455
  if (outcome.count > this.maxRequestsPerWindow) {
456
+ metrics.cartethyia_ip_abuse_refusals_total.inc(1, { reason: "ip-rate-limited" });
440
457
  throw new GatewayError("quota_exceeded", 429, "This address is sending requests faster than the abuse limit allows. Back off and retry after the window rolls over.", {
441
458
  reason: "ip-rate-limited",
442
459
  ip,
@@ -13,7 +13,7 @@ import type { TelemetryBatchBuffer } from "../../observability/telemetry-buffer"
13
13
  import type { ProxyRequestOutcome, ProxyRequestState } from "../request/state";
14
14
  import type { PayloadCaptureState } from "../../observability/payload-capture";
15
15
  import { finalizeRequestTelemetry } from "../guards/error-lifecycle";
16
- import { debitCachedQuota, quotaLens } from "../../console/quota/cache";
16
+ import { debitCachedQuota, quotaLens } from "../../providers/quota/cache";
17
17
  import { BUDDY_PROVIDER_IDS } from "../../providers/provider-metadata";
18
18
  import { log } from "../../observability/logger";
19
19
  import {
@@ -195,6 +195,43 @@ export function providerRequestMetadataOnly(request: unknown): unknown {
195
195
  return Object.keys(metadata).length === 0 ? null : metadata;
196
196
  }
197
197
 
198
+ /**
199
+ * Captures one provider request body into the stored provider-request panel.
200
+ *
201
+ * Providers send bodies in several shapes: a plain string (the common case), a
202
+ * `Uint8Array`/Buffer (Qoder's custom cosy encoding), or another BodyInit
203
+ * type (URLSearchParams, Blob, FormData) that cannot be sliced safely here.
204
+ * Strings and byte arrays are decoded and stored; anything else is recorded as
205
+ * present-but-opaque, same as the metadata path.
206
+ */
207
+ function captureRequestBodyBody(
208
+ body: BodyInit,
209
+ maxBytes: number,
210
+ ): { body: unknown } | { body_present: true; body_bytes: number } {
211
+ if (typeof body === "string") {
212
+ return { body: parseCapturedBody(truncateUtf8(body, maxBytes)) };
213
+ }
214
+ if (body instanceof Uint8Array) {
215
+ return { body: parseCapturedBody(truncateUtf8(new TextDecoder().decode(body), maxBytes)) };
216
+ }
217
+ return { body_present: true, body_bytes: capturedBodyByteLength(body) };
218
+ }
219
+
220
+ /** Byte length of a request body in whatever shape the provider sent it. */
221
+ function capturedBodyByteLength(body: BodyInit): number {
222
+ if (typeof body === "string") return Buffer.byteLength(body, "utf8");
223
+ if (body instanceof Uint8Array) return body.byteLength;
224
+ if (typeof body === "object" && body !== null && "size" in body) {
225
+ const size = (body as { size?: unknown }).size;
226
+ if (typeof size === "number" && Number.isFinite(size)) return Math.round(size);
227
+ }
228
+ if (typeof body === "object" && body !== null && "byteLength" in body) {
229
+ const byteLength = (body as { byteLength?: unknown }).byteLength;
230
+ if (typeof byteLength === "number" && Number.isFinite(byteLength)) return Math.round(byteLength);
231
+ }
232
+ return 0;
233
+ }
234
+
198
235
  /**
199
236
  * Wraps a validated outbound fetch to tee the provider request/response.
200
237
  *
@@ -216,7 +253,7 @@ export function captureProviderExchange(
216
253
  : input instanceof URL
217
254
  ? input.toString()
218
255
  : input.url;
219
- const rawBody = typeof init?.body === "string" ? init.body : null;
256
+ const rawBody = init?.body;
220
257
  const headers = selectCapturedHeaders(init);
221
258
  sink.request = {
222
259
  method: init?.method ?? "GET",
@@ -227,11 +264,11 @@ export function captureProviderExchange(
227
264
  // shape sliced up to `maxBytes` of the translated body and ran it through
228
265
  // `JSON.parse` for every attempt — content a metadata-mode tenant had
229
266
  // explicitly declined to retain, paid on every dispatch.
230
- ...(rawBody === null
267
+ ...(rawBody === null || rawBody === undefined
231
268
  ? {}
232
269
  : captureBody
233
- ? { body: parseCapturedBody(truncateUtf8(rawBody, maxBytes)) }
234
- : { body_present: true, body_bytes: Buffer.byteLength(rawBody, "utf8") }),
270
+ ? captureRequestBodyBody(rawBody, maxBytes)
271
+ : { body_present: true, body_bytes: capturedBodyByteLength(rawBody) }),
235
272
  };
236
273
  const response = await inner(input, init);
237
274
  sink.response =
@@ -463,6 +500,13 @@ export function estimatedUsage(inputTokens: number, outputTokens: number): Usage
463
500
  export interface AttemptCompletion extends ProxyRequestOutcome {
464
501
  readonly modelId?: string;
465
502
  readonly error?: unknown;
503
+ /**
504
+ * The HTTP status the terminal classifier derived for a raw (non-GatewayError)
505
+ * failure — an upstream socket drop is 502, not the 500 the fallback implied.
506
+ * Only consulted when the error carries no status of its own and no wire
507
+ * response named one.
508
+ */
509
+ readonly terminalHttpStatus?: number;
466
510
  readonly lease?: AdmissionLease;
467
511
  /** Usage to reconcile, or undefined when this attempt consumed nothing billable. */
468
512
  readonly commitUsage?: UsageRecord;
@@ -538,6 +582,63 @@ export function completionContext(input: {
538
582
  };
539
583
  }
540
584
 
585
+ /**
586
+ * The terminal-completion base the native routes (generation, responses
587
+ * compact, system one, web search, token count) all assemble. The proxy and
588
+ * streaming paths use `completionContext`; these routes previously spelled
589
+ * the same twelve fields by hand in six places. Callers spread this and add
590
+ * only what differs: status, response body, error classification.
591
+ */
592
+ export function nativeCompletionBase(input: {
593
+ readonly providerId: string;
594
+ readonly modelId: string;
595
+ readonly tenantId: string | null;
596
+ readonly ingressBody: unknown;
597
+ readonly accountId?: string;
598
+ readonly accountLabel?: string;
599
+ readonly networkPoolId?: string;
600
+ readonly lease?: AdmissionLease;
601
+ readonly db: CartethyiaDatabase;
602
+ readonly telemetryBuffer?: TelemetryBatchBuffer;
603
+ readonly snapshotService?: { invalidate(): unknown };
604
+ readonly providerCapture?: ProviderExchangeCapture;
605
+ readonly usage?: AttemptCompletion["usage"];
606
+ readonly commitUsage?: AttemptCompletion["commitUsage"];
607
+ }): Omit<
608
+ AttemptCompletion,
609
+ | "status"
610
+ | "responseBody"
611
+ | "httpStatus"
612
+ | "terminalHttpStatus"
613
+ | "error"
614
+ | "clientResponseText"
615
+ | "firstContentDeltaAtMs"
616
+ | "lastEventAtMs"
617
+ | "reportedModel"
618
+ | "errorCategory"
619
+ | "errorOrigin"
620
+ | "ttfbMs"
621
+ | "tokensPerSec"
622
+ > {
623
+ return {
624
+ providerId: input.providerId,
625
+ modelId: input.modelId,
626
+ tenantId: input.tenantId,
627
+ ingressBody: input.ingressBody,
628
+ terminal: true,
629
+ ...(input.accountId === undefined ? {} : { accountId: input.accountId }),
630
+ ...(input.accountLabel === undefined ? {} : { accountLabel: input.accountLabel }),
631
+ ...(input.networkPoolId === undefined ? {} : { networkPoolId: input.networkPoolId }),
632
+ ...(input.lease === undefined ? {} : { lease: input.lease }),
633
+ db: input.db,
634
+ ...(input.telemetryBuffer === undefined ? {} : { telemetryBuffer: input.telemetryBuffer }),
635
+ ...(input.snapshotService === undefined ? {} : { snapshotService: input.snapshotService }),
636
+ ...(input.providerCapture === undefined ? {} : { providerCapture: input.providerCapture }),
637
+ ...(input.usage === undefined ? {} : { usage: input.usage }),
638
+ ...(input.commitUsage === undefined ? {} : { commitUsage: input.commitUsage }),
639
+ };
640
+ }
641
+
541
642
  /**
542
643
  * Decides whether a failed attempt proves *the pool* is unusable, and which
543
644
  * HTTP status that verdict rests on.
@@ -639,13 +740,14 @@ export async function completeAttempt(
639
740
  completion.httpStatus ??
640
741
  (completion.error instanceof GatewayError
641
742
  ? completion.error.status
642
- : completion.status === "completed"
643
- ? 200
644
- : completion.status === "cancelled"
645
- ? 499
646
- : completion.status === "truncated"
647
- ? 502
648
- : 500),
743
+ : completion.terminalHttpStatus ??
744
+ (completion.status === "completed"
745
+ ? 200
746
+ : completion.status === "cancelled"
747
+ ? 499
748
+ : completion.status === "truncated"
749
+ ? 502
750
+ : 500)),
649
751
  ...(completion.providerId === undefined ? {} : { providerId: completion.providerId }),
650
752
  ...(completion.accountId === undefined ? {} : { accountId: completion.accountId }),
651
753
  ...(completion.accountLabel === undefined ? {} : { accountLabel: completion.accountLabel }),
@@ -288,6 +288,7 @@ export async function runAttemptLoop<TResult, TAdapter>(
288
288
  status: terminal.status,
289
289
  errorCategory: terminal.errorCategory,
290
290
  errorOrigin: terminal.errorOrigin,
291
+ ...(terminal.httpStatus === undefined ? {} : { terminalHttpStatus: terminal.httpStatus }),
291
292
  error: lastError,
292
293
  tenantId: input.tenantId,
293
294
  terminal: true,
@@ -419,6 +420,7 @@ export async function runAttemptLoop<TResult, TAdapter>(
419
420
  status: terminal.status,
420
421
  errorCategory: terminal.errorCategory,
421
422
  errorOrigin: terminal.errorOrigin,
423
+ ...(terminal.httpStatus === undefined ? {} : { terminalHttpStatus: terminal.httpStatus }),
422
424
  error,
423
425
  tenantId: input.tenantId,
424
426
  terminal: terminalAttempt,
@@ -539,6 +541,7 @@ export async function runAttemptLoop<TResult, TAdapter>(
539
541
  status: terminal.status,
540
542
  errorCategory: terminal.errorCategory,
541
543
  errorOrigin: terminal.errorOrigin,
544
+ ...(terminal.httpStatus === undefined ? {} : { terminalHttpStatus: terminal.httpStatus }),
542
545
  error: lastError,
543
546
  terminal: true,
544
547
  tenantId: input.tenantId,