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
@@ -89,12 +89,15 @@ async function runReadinessChecks(
89
89
 
90
90
  // 1. Check database connectivity via simple query
91
91
  let dbOk = false;
92
+ let dbTimedOut = false;
92
93
  try {
93
94
  const result = await withTimeoutCheck(
94
95
  () => db.execute(sql`SELECT 1`),
95
96
  "Database connectivity check",
96
97
  );
97
- if (result !== "timeout") {
98
+ if (result === "timeout") {
99
+ dbTimedOut = true;
100
+ } else {
98
101
  dbOk = true;
99
102
  }
100
103
  } catch {
@@ -107,7 +110,10 @@ async function runReadinessChecks(
107
110
  db: "disconnected",
108
111
  migrations: "pending",
109
112
  redis: "disconnected",
110
- reason: "database not connected",
113
+ // A timed-out probe under load is not evidence the database is down —
114
+ // it is the probe itself failing to get a backend in time. The guard
115
+ // reads this to call it overload rather than a dependency failure.
116
+ reason: dbTimedOut ? "database probe timed out" : "database not connected",
111
117
  };
112
118
  }
113
119
 
@@ -115,13 +121,16 @@ async function runReadinessChecks(
115
121
  // Readiness requires every discovered migration to have a ledger row; a
116
122
  // reachable ledger alone is not proof the upgrade finished.
117
123
  let migrationsApplied = false;
124
+ let migrationsTimedOut = false;
118
125
  try {
119
126
  const result = await withTimeoutCheck(
120
127
  () => readMigrationLedgerStatus(db),
121
128
  "Migrations check",
122
129
  );
123
130
 
124
- if (result !== "timeout") {
131
+ if (result === "timeout") {
132
+ migrationsTimedOut = true;
133
+ } else {
125
134
  migrationsApplied = result.applied;
126
135
  }
127
136
  } catch {
@@ -134,18 +143,21 @@ async function runReadinessChecks(
134
143
  db: "connected",
135
144
  migrations: "pending",
136
145
  redis: "disconnected",
137
- reason: "migrations not yet applied",
146
+ reason: migrationsTimedOut ? "migrations probe timed out" : "migrations not yet applied",
138
147
  };
139
148
  }
140
149
 
141
150
  // 3. Check Redis. The memory backend is healthy by construction — there is
142
151
  // no connection to probe — so it passes without a round trip.
143
152
  let redisOk = redisBackend === "memory";
153
+ let redisTimedOut = false;
144
154
 
145
155
  if (redisBackend === "redis" && redis) {
146
156
  try {
147
157
  const result = await withTimeoutCheck(() => redis.ping(), "Redis connectivity check");
148
- if (result !== "timeout" && result === "PONG") {
158
+ if (result === "timeout") {
159
+ redisTimedOut = true;
160
+ } else if (result === "PONG") {
149
161
  redisOk = true;
150
162
  }
151
163
  } catch {
@@ -159,7 +171,7 @@ async function runReadinessChecks(
159
171
  db: "connected",
160
172
  migrations: "applied",
161
173
  redis: "disconnected",
162
- reason: "redis not connected",
174
+ reason: redisTimedOut ? "redis probe timed out" : "redis not connected",
163
175
  };
164
176
  }
165
177
 
@@ -2,7 +2,7 @@
2
2
  import { desc, sql } from "drizzle-orm";
3
3
  import {
4
4
  bigint, boolean, check, customType, index, integer, jsonb, numeric, pgEnum, pgTable,
5
- primaryKey, text, timestamp, uniqueIndex, uuid, type AnyPgColumn,
5
+ primaryKey, text, timestamp, unique, uniqueIndex, uuid, type AnyPgColumn,
6
6
  } from "drizzle-orm/pg-core";
7
7
 
8
8
  export const TENANT_STATUSES = ["active", "suspended", "deleted"] as const;
@@ -183,6 +183,32 @@ export const providers = pgTable(
183
183
  // tenant-owned/BYOK. The concurrency ceiling lives in provider routing
184
184
  // (`provider_routing_settings.max_inflight`) and network pools
185
185
  // (`network_pools.max_inflight`); there is no per-account override.
186
+ /**
187
+ * A Qoder native machine identity (UMID) bound to one account.
188
+ *
189
+ * The device identity is a deterministic function of a seed file
190
+ * (`~/.config/.locale_cfg`): the `runtime-info` bridge reads that seed and
191
+ * derives `machineToken`/`machineType`/`machineCode`. The daily 100-credit
192
+ * campaign does not gate grants on this identity. A persisted seed allows the
193
+ * vendor bridge to replay the same native identity where another Qoder surface
194
+ * requires it.
195
+ *
196
+ * `seed` is the exact seed-file content the identity was minted from, stored
197
+ * so the same device identity can be replayed (restore seed → bridge → same
198
+ * token). It is not a credential, but it is per-account device material and
199
+ * should not be shared between accounts. Campaign grant eligibility is
200
+ * independent of `machineToken`.
201
+ */
202
+ export interface NativeIdentityRecord {
203
+ readonly machineToken: string;
204
+ readonly machineType: string;
205
+ readonly machineCode: string;
206
+ /** The seed-file content this identity was minted from, if captured. */
207
+ readonly seed?: string;
208
+ /** How this identity was produced: the genuine SG bridge or the fallback. */
209
+ readonly source?: "runtime-info" | "generated";
210
+ }
211
+
186
212
  export const providerAccounts = pgTable("provider_accounts", {
187
213
  id: uuid("id").primaryKey().defaultRandom(),
188
214
  providerId: text("provider_id")
@@ -270,6 +296,18 @@ export const providerAccounts = pgTable("provider_accounts", {
270
296
  */
271
297
  quotaPlan: text("quota_plan"),
272
298
 
299
+ /**
300
+ * Qoder native machine identity bound to this account, as one JSON object
301
+ * (see {@link NativeIdentityRecord}). `null` means the account has no bound
302
+ * identity: the check-in mints one on first use.
303
+ *
304
+ * Deliberately a dedicated column, not a key inside `auth_state`: the
305
+ * device token is queryable ("which device is taken by whom") and enforced
306
+ * unique by the partial index below, and it must survive backup/restore
307
+ * like any other non-secret column.
308
+ */
309
+ nativeIdentity: jsonb("native_identity").$type<NativeIdentityRecord | null>(),
310
+
273
311
  },
274
312
  (table) => [
275
313
  uniqueIndex("provider_accounts_identity_uidx").on(
@@ -290,6 +328,17 @@ export const providerAccounts = pgTable("provider_accounts", {
290
328
  // predicate that does not constrain `provider_id`. This one matches the
291
329
  // hot listing path.
292
330
  index("provider_accounts_tenant_id_idx").on(table.tenantId),
331
+ // One Qoder device identity per account: the partial unique index on the
332
+ // extracted `machineToken` guarantees two accounts never share a device,
333
+ // which is what makes the daily 100-credit grant reusable per account
334
+ // instead of colliding on a device identity. `NULL` rows (unbound
335
+ // accounts) are excluded so the uniqueness only applies to bound
336
+ // identities. The Postgres migration spells the expression
337
+ // `(native_identity ->> 'machineToken')`; the SQLite migration spells it
338
+ // `json_extract(native_identity, '$.machineToken')`.
339
+ uniqueIndex("provider_accounts_native_identity_token_uidx")
340
+ .on(sql`(${table.nativeIdentity} ->> 'machineToken')`)
341
+ .where(sql`${table.nativeIdentity} IS NOT NULL`),
293
342
  ],
294
343
  );
295
344
 
@@ -521,6 +570,49 @@ export const networkPools = pgTable("network_pools", {
521
570
  ],
522
571
  );
523
572
 
573
+ /**
574
+ * A pool's account-equivalent routing entity for ip-scoped, credential-less
575
+ * providers (OpenCode Free today).
576
+ *
577
+ * These providers own no `provider_accounts` rows — the rate limit belongs to
578
+ * the egress address, not to a credential. Materializing one row per (pool,
579
+ * ip-scoped provider) lets the account health machine, routing eligibility, and
580
+ * the provider-detail accounts UI treat each egress like an account: the row
581
+ * carries the same health state machine and cooldown columns, so a spent egress
582
+ * is excluded from the plan the same way a cooling account is, and the operator
583
+ * sees it in the provider's Accounts card with a "Pool" badge.
584
+ *
585
+ * The row is an *account-equivalent*, not an account: it resolves no credential
586
+ * (`credential_kind` is fixed to `none`-style egress), is skipped by the quota
587
+ * refresh and identity sweeps (they filter on real credential kinds), and is
588
+ * owned by its pool — deleting the pool cascades the row.
589
+ */
590
+ export const providerPoolAccounts = pgTable(
591
+ "provider_pool_accounts",
592
+ {
593
+ id: uuid("id").primaryKey().defaultRandom(),
594
+ tenantId: tenantRefRequired(),
595
+ networkPoolId: uuid("network_pool_id")
596
+ .notNull()
597
+ .references(() => networkPools.id, { onDelete: "cascade" }),
598
+ providerId: text("provider_id").notNull(),
599
+ label: text("label").notNull(),
600
+ ...healthColumns(),
601
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
602
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
603
+ },
604
+ (table) => [
605
+ unique("provider_pool_accounts_pool_provider_uidx").on(
606
+ table.networkPoolId,
607
+ table.providerId,
608
+ table.tenantId,
609
+ ),
610
+ index("provider_pool_accounts_tenant_status_idx").on(table.tenantId, table.status),
611
+ index("provider_pool_accounts_provider_status_idx").on(table.providerId, table.status),
612
+ ],
613
+ );
614
+ export type ProviderPoolAccount = typeof providerPoolAccounts.$inferSelect;
615
+
524
616
 
525
617
  // Account and network-pool health events share one table. The entity kind
526
618
  // selects exactly one owner FK, and the CHECK constraint below preserves
@@ -766,6 +858,13 @@ export const apiKeys = pgTable(
766
858
  .notNull()
767
859
  .default(0),
768
860
  maxConcurrentRequests: integer("max_concurrent_requests"),
861
+ /**
862
+ * Slot cap for a share template: the maximum number of concurrently
863
+ * active child keys it may mint. `null` = unlimited (legacy behavior).
864
+ * Enforced at mint time in `issueSharedApiKey`; the console exposes it as
865
+ * the template's "slots".
866
+ */
867
+ maxChildren: integer("max_children"),
769
868
  /**
770
869
  * `whitelist` = only the names in `modelList` may be used (empty = all);
771
870
  * `blacklist` = the names in `modelList` are refused (empty = none). One
@@ -790,6 +889,21 @@ export const apiKeys = pgTable(
790
889
  createdAt: createdAtColumn(),
791
890
  enabled: boolean("enabled").notNull().default(true),
792
891
  revokedAt: timestamp("revoked_at", { withTimezone: true }),
892
+ /**
893
+ * Ban state. A ban is distinct from a revoke: it records the operator's
894
+ * reason (`banReason`) so the console can show it, and it is fully
895
+ * reversible — unban clears both columns, leaving no metadata behind.
896
+ * Banned keys are rejected by the auth path exactly like revoked keys.
897
+ */
898
+ bannedAt: timestamp("banned_at", { withTimezone: true }),
899
+ banReason: text("ban_reason"),
900
+ /**
901
+ * When the ban lifts on its own, if it is not permanent. `null` means the
902
+ * ban does not lapse (until an operator unbans it). The auth path treats a
903
+ * key as banned only while `banned_at` is set and `banned_until` is either
904
+ * null or in the future — so a timed ban expires without SQL.
905
+ */
906
+ bannedUntil: timestamp("banned_until", { withTimezone: true }),
793
907
  /**
794
908
  * The tenant's mandatory gateway key. Seeded at first boot whether or not
795
909
  * `CARTETHYIA_API_KEY` was configured, and the one key the console refuses
@@ -1126,6 +1240,26 @@ export const consoleSettings = pgTable("console_settings", {
1126
1240
  updatedAt: updatedAtColumn(),
1127
1241
  });
1128
1242
 
1243
+ // Tenant-scoped system prompt injection (append/override). One row per
1244
+ // tenant; `global` NULL means never configured, distinct from an explicit
1245
+ // disabled setting. Providers/models are JSON object maps keyed by
1246
+ // providerId and `providerId::modelId` respectively — see
1247
+ // `src/console/system-prompt/contracts.ts` for the value shapes and the
1248
+ // resolution rules implemented by the dispatch-path transform.
1249
+ export const tenantSystemPrompts = pgTable("tenant_system_prompts", {
1250
+ tenantId: tenantRefPrimaryKey(),
1251
+ global: jsonb("global").$type<import("../console/system-prompt/contracts").PromptSetting | null>(),
1252
+ providers: jsonb("providers")
1253
+ .notNull()
1254
+ .default({})
1255
+ .$type<Record<string, import("../console/system-prompt/contracts").ProviderPromptEntry>>(),
1256
+ models: jsonb("models")
1257
+ .notNull()
1258
+ .default({})
1259
+ .$type<Record<string, import("../console/system-prompt/contracts").PromptSetting>>(),
1260
+ updatedAt: updatedAtColumn(),
1261
+ });
1262
+
1129
1263
  // InferHub `config_read` key. One row for the whole deployment.
1130
1264
  //
1131
1265
  // Deliberately NOT `provider_accounts.auth_state`: that field is documented as
@@ -1229,6 +1363,14 @@ export const telemetryEvents = pgTable(
1229
1363
  networkPoolId: uuid("network_pool_id"),
1230
1364
  endpoint: text("endpoint"),
1231
1365
  apiKeyId: uuid("api_key_id"),
1366
+ /**
1367
+ * The share-template key this event belongs to (the template itself, or
1368
+ * the parent of the child key that carried the request). Denormalized at
1369
+ * write time so family rollups survive the key row being deleted — an
1370
+ * `EXISTS` join against `api_keys` tied history to key lifetime. NULL for
1371
+ * requests that ran under no share template.
1372
+ */
1373
+ familyTemplateKeyId: uuid("family_template_key_id"),
1232
1374
  userAgent: text("user_agent"),
1233
1375
  clientIp: text("client_ip"),
1234
1376
  latencyMs: integer("latency_ms"),
@@ -1317,6 +1459,14 @@ export const telemetryEvents = pgTable(
1317
1459
  desc(table.createdAt),
1318
1460
  desc(table.id),
1319
1461
  ),
1462
+ // Share-family rollup: equality on the denormalized template, keyset
1463
+ // range+order. Backs both the family totals and the hourly chart reads.
1464
+ index("telemetry_events_tenant_family_created_id_idx").on(
1465
+ table.tenantId,
1466
+ table.familyTemplateKeyId,
1467
+ desc(table.createdAt),
1468
+ desc(table.id),
1469
+ ),
1320
1470
  index("telemetry_events_request_id_idx").on(table.requestId),
1321
1471
  index("telemetry_events_tenant_account_created_idx").on(
1322
1472
  table.tenantId,
@@ -1373,6 +1523,13 @@ export const telemetryUsageTotals = pgTable(
1373
1523
  tenantId: tenantRefRequired(),
1374
1524
  identityType: text("identity_type").$type<TelemetryUsageIdentityType>().notNull(),
1375
1525
  entityId: uuid("entity_id").notNull(),
1526
+ /**
1527
+ * For `api_key` identities, the share-template key this key belongs to
1528
+ * (the template itself, or the parent of a minted child). Denormalized so
1529
+ * family reads do not depend on the key row surviving; NULL for `account`
1530
+ * identities and for keys outside a share family.
1531
+ */
1532
+ familyTemplateKeyId: uuid("family_template_key_id"),
1376
1533
  requests: bigint("requests", { mode: "number" }).notNull().default(0),
1377
1534
  errors: bigint("errors", { mode: "number" }).notNull().default(0),
1378
1535
  inputTokens: bigint("input_tokens", { mode: "number" }).notNull().default(0),
@@ -1389,6 +1546,10 @@ export const telemetryUsageTotals = pgTable(
1389
1546
  "telemetry_usage_totals_identity_type_check",
1390
1547
  sql`${table.identityType} IN ('account', 'api_key')`,
1391
1548
  ),
1549
+ index("telemetry_usage_totals_tenant_family_idx").on(
1550
+ table.tenantId,
1551
+ table.familyTemplateKeyId,
1552
+ ),
1392
1553
  ],
1393
1554
  );
1394
1555