cartethyia 2.5.4 → 2.5.6

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 (395) hide show
  1. package/.env.example +13 -4
  2. package/README.md +2 -2
  3. package/dist/dashboard/assets/{BannedPage-C2orBsI2.js → BannedPage-CADDq4IU.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-CADDq4IU.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js +1 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-DuO1Z7dq.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-DuO1Z7dq.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-BVdpfiz1.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-BVdpfiz1.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-BR5HHvbi.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-BR5HHvbi.js.gz +0 -0
  15. package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-mUfcknqm.js} +1 -1
  16. package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-V5faV9V2.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-V5faV9V2.js.gz +0 -0
  19. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js +1 -0
  20. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-uPiGVTTK.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js.gz +0 -0
  27. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js +7 -0
  28. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-UB690SE2.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-UB690SE2.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-BLujdX7N.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-BLujdX7N.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-D5C2raAc.js} +3 -3
  38. package/dist/dashboard/assets/StudioPage-D5C2raAc.js.gz +0 -0
  39. package/dist/dashboard/assets/UsagePage-8uIcxa1W.js +56 -0
  40. package/dist/dashboard/assets/UsagePage-8uIcxa1W.js.gz +0 -0
  41. package/dist/dashboard/assets/api-keys-DQYLQxpW.js +1 -0
  42. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  43. package/dist/dashboard/assets/app-CX_Z8cMs.css +2 -0
  44. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  45. package/dist/dashboard/assets/{assert-Chi7pCnt.js → assert-C9FD_JwJ.js} +1 -1
  46. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  47. package/dist/dashboard/assets/{badge-D4pQapKj.js → badge-CR72dasT.js} +1 -1
  48. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  49. package/dist/dashboard/assets/{banner-DH6cg-_B.js → banner-CI9_eSfO.js} +1 -1
  50. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  51. package/dist/dashboard/assets/{card-BKqlUOe4.js → card-DS7CQEsO.js} +1 -1
  52. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  53. package/dist/dashboard/assets/{cli-tools-fTgljTGA.js → cli-tools-CNqzrfdb.js} +1 -1
  54. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  55. package/dist/dashboard/assets/{clipboard-button-D5Ys_sM0.js → clipboard-button-611pSsaX.js} +1 -1
  56. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  57. package/dist/dashboard/assets/{fingerprint-pattern-BWuHtbW4.js → concurrency-BDF0ok7y.js} +1 -1
  58. package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
  59. package/dist/dashboard/assets/dialog-k37exjNt.js +1 -0
  60. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  61. package/dist/dashboard/assets/drawer-CX7N8ucR.js +1 -0
  62. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CQBr6U9c.js → entry-B9Xvtnfj.js} +1 -1
  64. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
  66. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-DxBHnauy.js +4 -0
  68. package/dist/dashboard/assets/entry-DxBHnauy.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-BlptL8Uf.js → github-badge-sltk1qUi.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-js6TJvdr.js → index-CmxZr14F.js} +2 -2
  72. package/dist/dashboard/assets/index-CmxZr14F.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-DUWDSmDV.js → inline-BhY2sSnO.js} +1 -1
  74. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-LVjgZq4f.js → input-V1umFiBk.js} +1 -1
  76. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  77. package/dist/dashboard/assets/layout-BBOYycyS.js +1 -0
  78. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-DupvLfDx.js → list-row-1zzZYM0B.js} +1 -1
  80. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-C4pEJUqI.js → live-BivGfuUs.js} +1 -1
  82. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-BRiuufkB.js → model-bans-CmffjLuG.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-B4ROwk8L.js → mutation-46P0oWMe.js} +1 -1
  86. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  87. package/dist/dashboard/assets/numbers-DkfMR5Qs.js +2 -0
  88. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-gmjzC3RS.js → query-keys-BFhGpwR1.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-C7tBT5o-.js → routing-CAb4F37R.js} +1 -1
  92. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-WUCXorXw.js → select-BYR_5K2c.js} +1 -1
  94. package/dist/dashboard/assets/select-BYR_5K2c.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-C_zKl1GS.js → settings-DNX9sydi.js} +1 -1
  96. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-_3O0F8Xn.js → stack-BHTfXdz_.js} +1 -1
  98. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-BgTxHcJS.js → state-mPDRlQkl.js} +1 -1
  100. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DEjTtOWf.js → switch-DOmJxg7H.js} +1 -1
  102. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  103. package/dist/dashboard/assets/tokens-COzario9.js +1 -0
  104. package/dist/dashboard/assets/tokens-COzario9.js.gz +0 -0
  105. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js +1 -0
  106. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js.gz +0 -0
  107. package/dist/dashboard/assets/{useMutation-BWSC0UAS.js → useMutation-Dem0lXQj.js} +1 -1
  108. package/dist/dashboard/assets/useMutation-Dem0lXQj.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 +54 -54
  112. package/migrations/README.md +52 -52
  113. package/migrations/lite-sqlite3/0000_baseline.sql +2 -2
  114. package/package.json +96 -95
  115. package/scripts/cli/admin.ts +125 -0
  116. package/scripts/cli/{ui/background.ts → background.ts} +1 -1
  117. package/scripts/cli/{command/console-menu.ts → console-menu.ts} +275 -244
  118. package/scripts/cli/doctor.ts +37 -0
  119. package/scripts/cli/{support/env.ts → env.ts} +99 -99
  120. package/scripts/cli/{gateway/spawn.ts → gateway.ts} +112 -24
  121. package/scripts/cli/instance.ts +224 -0
  122. package/scripts/cli/main.ts +61 -18
  123. package/scripts/cli/{support/platform.ts → platform.ts} +64 -64
  124. package/scripts/cli/port.ts +100 -0
  125. package/scripts/cli/{support/services.ts → services.ts} +88 -88
  126. package/scripts/cli/{command/setup.ts → setup.ts} +35 -34
  127. package/scripts/cli/{command/start.ts → start.ts} +10 -5
  128. package/scripts/cli/{support/startup-signal.ts → startup-signal.ts} +23 -23
  129. package/scripts/cli/tray/index.ts +62 -12
  130. package/scripts/cli/{command/tray.ts → tray.ts} +208 -208
  131. package/scripts/cli/{command/update.ts → update.ts} +39 -39
  132. package/scripts/cli/version.ts +67 -0
  133. package/scripts/cli/{ui/wordmark.ts → wordmark.ts} +58 -58
  134. package/src/boot/app.ts +697 -693
  135. package/src/boot/dependencies.ts +647 -646
  136. package/src/boot/timeout.ts +2 -13
  137. package/src/config/cooldowns.ts +186 -138
  138. package/src/config/network.ts +8 -14
  139. package/src/config/providers.ts +7 -10
  140. package/src/config/runtime.ts +76 -76
  141. package/src/config/security.ts +15 -0
  142. package/src/config/spec.ts +20 -30
  143. package/src/config/telemetry.ts +0 -20
  144. package/src/config/timeouts.ts +0 -6
  145. package/src/console/admin/model-abuse/contracts.ts +28 -6
  146. package/src/console/admin/model-abuse/routes.ts +56 -3
  147. package/src/console/api-keys/contracts.ts +410 -414
  148. package/src/console/api-keys/routes.ts +881 -880
  149. package/src/console/auth/credentials.ts +3 -3
  150. package/src/console/auth/setup-service.ts +2 -2
  151. package/src/console/backup/export-endpoint.ts +6 -2
  152. package/src/console/backup/nine-router.ts +2 -5
  153. package/src/console/backup/service.ts +4 -0
  154. package/src/console/backup/store.ts +192 -29
  155. package/src/console/backup/validate.ts +3 -45
  156. package/src/console/cli-tools/fs-ops.ts +487 -487
  157. package/src/console/console-router-guards.ts +1 -1
  158. package/src/console/data-management/contracts.ts +13 -6
  159. package/src/console/data-management/operations.ts +23 -18
  160. package/src/console/data-management/routes.ts +0 -1
  161. package/src/console/domain-registration.ts +10 -5
  162. package/src/console/observability/live.ts +22 -0
  163. package/src/console/observability/store.ts +39 -16
  164. package/src/console/observability/usage-dimensions.ts +4 -4
  165. package/src/console/providers/catalog/catalog-projections.ts +6 -7
  166. package/src/console/providers/catalog/model-operations.ts +5 -2
  167. package/src/console/providers/catalog/provider-operations.ts +4 -4
  168. package/src/console/providers/catalog/public-model-store.ts +8 -11
  169. package/src/console/providers/catalog/store.ts +1553 -1553
  170. package/src/console/providers/oauth/routes.ts +8 -12
  171. package/src/console/quota/account-quota-tenant.ts +6 -6
  172. package/src/console/quota/quota-view.ts +1 -1
  173. package/src/console/remote-support/contracts.ts +61 -0
  174. package/src/console/remote-support/routes.ts +65 -0
  175. package/src/console/remote-support/service.ts +207 -0
  176. package/src/console/response-compression.ts +0 -3
  177. package/src/console/routing/pools/probe-result.ts +3 -2
  178. package/src/console/routing/pools/probe-verdict.ts +132 -132
  179. package/src/console/routing/pools/store.ts +8 -8
  180. package/src/console/settings/contracts.ts +58 -2
  181. package/src/console/settings/store.ts +30 -3
  182. package/src/console/shared/cursor.ts +8 -8
  183. package/src/console/shared/errors.ts +1 -3
  184. package/src/network/http2-bidi.ts +2 -4
  185. package/src/network/pool/agent.ts +478 -478
  186. package/src/network/pool/selector.ts +5 -4
  187. package/src/network/retry.ts +1 -2
  188. package/src/network/ssrf.ts +5 -4
  189. package/src/observability/event-compaction.ts +80 -78
  190. package/src/observability/event-day-index.ts +13 -15
  191. package/src/observability/event-log.ts +4 -4
  192. package/src/observability/logger.ts +6 -6
  193. package/src/observability/payload-capture.ts +151 -33
  194. package/src/observability/payload-store.ts +397 -440
  195. package/src/observability/redaction.ts +5 -6
  196. package/src/observability/request-notify.ts +43 -0
  197. package/src/observability/telemetry-status.ts +8 -9
  198. package/src/observability/token-speed.ts +5 -4
  199. package/src/persistence/db-mode.ts +7 -7
  200. package/src/persistence/readiness.ts +1 -1
  201. package/src/persistence/schema.ts +1406 -1402
  202. package/src/persistence/shared-cache.ts +1 -2
  203. package/src/persistence/stores/api-key-store.ts +18 -6
  204. package/src/persistence/stores/share-store.ts +4 -3
  205. package/src/persistence/stores/telemetry-store.ts +236 -237
  206. package/src/protocol/canonical-model.ts +11 -3
  207. package/src/protocol/codecs.ts +138 -4
  208. package/src/protocol/gateway-error.ts +6 -4
  209. package/src/protocol/request/chat.ts +21 -1
  210. package/src/protocol/request/codex.ts +10 -1
  211. package/src/protocol/request/messages.ts +4 -5
  212. package/src/protocol/request/responses.ts +9 -1
  213. package/src/protocol/response/chat.ts +34 -4
  214. package/src/protocol/response/codex.ts +7 -4
  215. package/src/protocol/response/dsml.ts +140 -28
  216. package/src/protocol/response/responses.ts +11 -5
  217. package/src/protocol/stream-error-frames.ts +4 -5
  218. package/src/providers/authentication/jwt-validator.ts +9 -10
  219. package/src/providers/authentication/oauth-refresh-service.ts +9 -11
  220. package/src/providers/configured-openai-providers.ts +134 -136
  221. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  222. package/src/providers/discovery/catalog/catalog-format.ts +3 -6
  223. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  224. package/src/providers/discovery/probe-phases.ts +4 -4
  225. package/src/providers/discovery/probe-wire.ts +6 -13
  226. package/src/providers/discovery/probing-service.ts +1117 -1045
  227. package/src/providers/integrations/alibabacp/alibabacp.ts +1 -1
  228. package/src/providers/integrations/antigravity/antigravity-quota.ts +5 -7
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +23 -2
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +1 -4
  231. package/src/providers/integrations/buddy/buddy-cli-headers.ts +23 -6
  232. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -1
  233. package/src/providers/integrations/buddy/buddy-identity.ts +52 -0
  234. package/src/providers/integrations/buddy/buddy-media.ts +2 -2
  235. package/src/providers/integrations/buddy/buddy-usage-store.ts +3 -4
  236. package/src/providers/integrations/buddy/codebuddy/quota.ts +2 -13
  237. package/src/providers/integrations/buddy/codebuddy/shared.ts +118 -115
  238. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -11
  239. package/src/providers/integrations/buddy/workbuddy/shared.ts +5 -2
  240. package/src/providers/integrations/claude/claude.ts +608 -608
  241. package/src/providers/integrations/cline/cline-quota.ts +132 -132
  242. package/src/providers/integrations/cline/cline.ts +537 -539
  243. package/src/providers/integrations/codex/codex-oauth.ts +1 -1
  244. package/src/providers/integrations/commandcode/commandcode.ts +674 -675
  245. package/src/providers/integrations/commandcode/discovery.ts +117 -116
  246. package/src/providers/integrations/cursor/cursor-auth.ts +418 -418
  247. package/src/providers/integrations/cursor/cursor-quota.ts +309 -310
  248. package/src/providers/integrations/cursor/cursor.ts +11 -163
  249. package/src/providers/integrations/factory/factory-models.ts +3 -5
  250. package/src/providers/integrations/grok/grok-install-id.ts +2 -3
  251. package/src/providers/integrations/grok/grok.ts +6 -7
  252. package/src/providers/integrations/hermes.ts +14 -18
  253. package/src/providers/integrations/kiro/kiro-discovery.ts +1 -1
  254. package/src/providers/integrations/kiro/kiro.ts +1 -1
  255. package/src/providers/integrations/mistral.ts +6 -6
  256. package/src/providers/integrations/opencode/fingerprint.ts +3 -3
  257. package/src/providers/integrations/opencode/provider.ts +8 -8
  258. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -450
  259. package/src/providers/integrations/qoder/qoder-oauth.ts +388 -310
  260. package/src/providers/integrations/qoder/qoder.ts +884 -865
  261. package/src/providers/integrations/shared/connect.ts +6 -6
  262. package/src/providers/integrations/trae/trae-catalog.ts +1 -2
  263. package/src/providers/integrations/trae/trae.ts +2 -2
  264. package/src/providers/integrations/zcode/oauth.ts +6 -1
  265. package/src/providers/operations/account-health-service.ts +1528 -1523
  266. package/src/providers/operations/account-reset-service.ts +1 -1
  267. package/src/providers/operations/client-versions.ts +6 -6
  268. package/src/providers/operations/custom-cli-headers.ts +3 -4
  269. package/src/providers/operations/provider-catalog-seeder.ts +95 -95
  270. package/src/providers/operations/provider-catalog-service.ts +3 -4
  271. package/src/providers/provider-metadata.ts +4 -8
  272. package/src/providers/provider-registry.ts +6 -7
  273. package/src/providers/provider-usage.ts +1 -1
  274. package/src/security/abuse.ts +15 -10
  275. package/src/security/access-control.ts +144 -146
  276. package/src/security/admission/contracts.ts +11 -0
  277. package/src/security/admission/in-memory-store.ts +4 -3
  278. package/src/security/admission/lease-sweep.ts +6 -6
  279. package/src/security/admission/reasons.ts +5 -1
  280. package/src/security/admission/redis-store.ts +211 -210
  281. package/src/security/admission/service.ts +4 -0
  282. package/src/security/api-key-auth.ts +504 -504
  283. package/src/security/ip-boundary.ts +155 -15
  284. package/src/security/model-abuse.ts +366 -94
  285. package/src/security/outbound-headers.ts +3 -4
  286. package/src/shared/sleep.ts +4 -0
  287. package/src/transport/dispatch/attempt-finalize.ts +47 -5
  288. package/src/transport/dispatch/attempt-loop.ts +531 -530
  289. package/src/transport/dispatch/stream-bridge.ts +1 -3
  290. package/src/transport/dispatch/streaming/finalize.ts +1 -1
  291. package/src/transport/dispatch/streaming/stream.ts +5 -6
  292. package/src/transport/failure-policy.ts +162 -8
  293. package/src/transport/guards/auth-guard.ts +7 -4
  294. package/src/transport/guards/concurrency-guard.ts +0 -5
  295. package/src/transport/guards/error-lifecycle.ts +13 -6
  296. package/src/transport/guards/pipeline.ts +15 -3
  297. package/src/transport/guards/request-context.ts +8 -2
  298. package/src/transport/request/inflight.ts +5 -6
  299. package/src/transport/request/preparer.ts +2 -2
  300. package/src/transport/request/state.ts +12 -8
  301. package/src/transport/routing/admission.ts +4 -0
  302. package/src/transport/routing/route-catalog.ts +8 -1
  303. package/src/transport/routing/route-model.ts +46 -14
  304. package/src/transport/routing/router.ts +21 -14
  305. package/src/transport/surface/completion.ts +2 -3
  306. package/src/transport/surface/dialects.ts +5 -6
  307. package/src/transport/surface/responses/encode.ts +38 -0
  308. package/src/transport/surface/responses/parse.ts +4 -0
  309. package/src/transport/translation/capabilities.ts +2 -3
  310. package/src/transport/translation/quirks.ts +3 -3
  311. package/src/workers/buddy-growth-tasks.ts +5 -10
  312. package/src/workers/daily-checkin.ts +17 -23
  313. package/src/workers/quota-refresh-sweep.ts +26 -26
  314. package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
  315. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +0 -1
  316. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
  317. package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
  318. package/dist/dashboard/assets/CombosPage-Bsan4679.js +0 -1
  319. package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
  320. package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
  321. package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
  322. package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
  323. package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
  324. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js +0 -1
  325. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
  326. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +0 -1
  327. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
  328. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +0 -3
  329. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
  330. package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
  331. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +0 -7
  332. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
  333. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +0 -1
  334. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
  335. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +0 -1
  336. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
  337. package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
  338. package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
  339. package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
  340. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js +0 -56
  341. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
  342. package/dist/dashboard/assets/api-keys-VY68Mhd1.js +0 -1
  343. package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
  344. package/dist/dashboard/assets/app-COlK95oi.css +0 -2
  345. package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
  346. package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
  347. package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
  348. package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
  349. package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
  350. package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
  351. package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
  352. package/dist/dashboard/assets/dialog-BYj-8WuK.js +0 -1
  353. package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
  354. package/dist/dashboard/assets/drawer-CmXIZ6H1.js +0 -1
  355. package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
  356. package/dist/dashboard/assets/entry-CBg5zeu8.js +0 -1
  357. package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
  358. package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-CgdSAzEV.js +0 -4
  360. package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
  361. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
  363. package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
  365. package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-CPfxpsfy.js +0 -1
  367. package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
  368. package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
  369. package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
  370. package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
  371. package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
  372. package/dist/dashboard/assets/numbers-YNcHvRY7.js +0 -2
  373. package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
  374. package/dist/dashboard/assets/query-keys-gmjzC3RS.js.gz +0 -0
  375. package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
  376. package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
  377. package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
  378. package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
  379. package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
  380. package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
  381. package/dist/dashboard/assets/tokens-DDxMbSRL.js +0 -1
  382. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  383. package/dist/dashboard/assets/use-presence-BSZEBx7U.js +0 -1
  384. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  385. package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
  386. package/scripts/cli/command/admin.ts +0 -65
  387. package/scripts/cli/command/doctor.ts +0 -257
  388. package/scripts/cli/gateway/drain-token.ts +0 -78
  389. package/scripts/cli/gateway/instance-lock.ts +0 -105
  390. package/scripts/cli/gateway/stop.ts +0 -51
  391. package/scripts/cli/support/bun.ts +0 -27
  392. package/scripts/cli/support/version.ts +0 -37
  393. /package/dist/dashboard/assets/{app-DCQZRmHY.js → app-BIt446yE.js} +0 -0
  394. /package/dist/dashboard/assets/{app-DCQZRmHY.js.gz → app-BIt446yE.js.gz} +0 -0
  395. /package/scripts/cli/{ui/prompt.ts → prompt.ts} +0 -0
@@ -278,7 +278,7 @@ export class NetworkPoolSelector {
278
278
  // One script, not `SET` then `SADD`: a crash between the two left the
279
279
  // marker unindexed (invisible to the pool listing) or the index
280
280
  // pointing at a marker that expired. The script also arms the index
281
- // set's own TTL, which previously had none and so grew without bound.
281
+ // set's own TTL, which must be armed or the index grows without bound.
282
282
  await redisEvalNumber(
283
283
  this.redis,
284
284
  COOLDOWN_FLAG_SCRIPT,
@@ -458,9 +458,10 @@ export class NetworkPoolSelector {
458
458
  /**
459
459
  * Removes one cooldown marker and its index entry in one atomic step.
460
460
  *
461
- * The two writes used to be separate `DEL` + `SREM`, so a crash between them
462
- * left the index listing a provider whose marker was gone — a pool would
463
- * report a cooldown that no longer applied until the index entry expired.
461
+ * The two writes must not be separate `DEL` + `SREM`: a crash between them
462
+ * would leave the index listing a provider whose marker is gone — a pool
463
+ * would report a cooldown that no longer applies until the index entry
464
+ * expires.
464
465
  */
465
466
  private async clearRedisCooldown(poolId: string, providerId: string): Promise<void> {
466
467
  if (!this.redis) return;
@@ -7,6 +7,7 @@
7
7
  */
8
8
 
9
9
  import { exponentialBackoff, type BackoffOptions } from "./backoff";
10
+ import { sleep as defaultSleep } from "../shared/sleep";
10
11
 
11
12
  export interface RetryOptions {
12
13
  readonly maxRetries?: number;
@@ -18,8 +19,6 @@ export interface RetryOptions {
18
19
  readonly shouldRetry?: (error: unknown, attempt: number) => boolean;
19
20
  }
20
21
 
21
- const defaultSleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
22
-
23
22
  /**
24
23
  * Runs `fn`, retrying on failure with exponential backoff (100 ms, 200 ms,
25
24
  * 400 ms, …) capped at `maxDelayMs` and jittered by up to 25% to avoid a
@@ -73,10 +73,11 @@ function cidrContains(address: string, cidr: string): boolean {
73
73
  const [network, prefixText] = cidr.split("/");
74
74
  if (!network || prefixText === undefined) return false;
75
75
  // A present-but-blank prefix (`"10.0.0.0/"`) must be refused, not coerced.
76
- // `Number("")` is 0 and `""` is not `undefined`, so the guard below used to fall
77
- // through with `prefix = 0` — and a /0 admits every address of its family. An
78
- // operator's typo therefore silently widened the allowlist to the whole IPv4
79
- // space, including the link-local metadata endpoint this guard exists to refuse.
76
+ // `Number("")` is 0 and `""` is not `undefined`, so a plain truthiness check
77
+ // here would leave `prefix = 0` — and a /0 admits every address of its family.
78
+ // An operator's typo would therefore silently widen the allowlist to the whole
79
+ // IPv4 space, including the link-local metadata endpoint this guard exists to
80
+ // refuse.
80
81
  //
81
82
  // Requiring a run of digits (after trimming) also refuses the exotic spellings
82
83
  // `Number` accepts for zero — `-0`, `+0`, `0x0`, `0b0`, `0o0`, `0.0` — all of
@@ -1,70 +1,13 @@
1
1
  /**
2
- * Compaction for hourly telemetry files: old per-request rows become one
3
- * summary row per (tenant, API key, day).
2
+ * Bucket primitives for the per-day telemetry index.
4
3
  *
5
- * The problem this solves is growth, and growth alone. Hourly JSONL files were
6
- * never deleted, so every read of the usage list scanned every file ever
7
- * written — the cost grew with total volume, not with the number of users. An
8
- * install serving 20 users got slower purely by serving them longer.
9
- *
10
- * Compaction is **accumulation, not sampling**. A compacted row carries the
11
- * running sums of everything it replaced, so a total that read 2B tokens
12
- * before compaction still reads 2B after it. Nothing is estimated and nothing
13
- * is averaged away — the per-request rows are gone, their totals are not.
14
- *
15
- * What compaction cannot preserve is anything that needs the individual row:
16
- * the request list, per-request filters, and the detail drawer. Latency is the
17
- * interesting middle case — a percentile needs every sample, so compaction
18
- * keeps a fixed histogram instead. P50 stays available as an approximation and
19
- * is marked as one rather than silently reported as exact.
20
- *
21
- * Retention becomes tiered:
22
- *
23
- * 0 .. N days hourly files, complete
24
- * N .. M days compacted daily summary
25
- * beyond M deleted
4
+ * Each day's events are folded into a `CompactedBucket` via `accumulate()` and
5
+ * stored as a `.index.json` file alongside the source `.events.jsonl`. Buckets
6
+ * are pure accumulators: every field is a running sum, min, or max — nothing
7
+ * is averaged or estimated away. `mergeBucketsInternal` adds two buckets so
8
+ * partial indexes can be merged without re-reading source files.
26
9
  */
27
10
  import type { TelemetryEventRecord } from "./event-log";
28
- import type { CartethyiaDatabase } from "../persistence/db-handle";
29
- import { consoleSettings } from "../persistence/schema";
30
- import { resolveTelemetryWindowMinutes } from "../config/telemetry";
31
-
32
- /**
33
- * The compaction age to apply on a pass with no explicit age given.
34
- *
35
- * Hourly files are **not** partitioned per tenant — one file per hour holds
36
- * every tenant's rows — so a per-tenant age cannot be honoured per file. The
37
- * safest reading of several tenants' preferences is the **largest**: compacting
38
- * smaller than one tenant asked for moves its requests into the summary before
39
- * that tenant expected, losing the per-request view of them, while keeping them
40
- * longer than another wanted only costs disk and a slower scan. Losing detail
41
- * is not reversible; using more disk is.
42
- *
43
- * Falls back to the deployment default when no tenant overrides, and never
44
- * exceeds the retention window (compacting at or past the delete age would
45
- * fold a file and discard it in the same pass).
46
- */
47
- export async function resolveEffectiveWindowMinutes(db: CartethyiaDatabase): Promise<number> {
48
- const fallback = resolveTelemetryWindowMinutes();
49
- try {
50
- const rows = await db
51
- .select({ preferences: consoleSettings.preferences })
52
- .from(consoleSettings);
53
- let widest = fallback;
54
- for (const row of rows) {
55
- const minutes = row.preferences?.telemetryWindowMinutes;
56
- if (typeof minutes === "number" && Number.isFinite(minutes) && minutes > widest) {
57
- widest = minutes;
58
- }
59
- }
60
- return Math.floor(widest);
61
- } catch {
62
- return fallback;
63
- }
64
- }
65
-
66
- /** Discriminator so a reader can tell a summary from a request row at a glance. */
67
- const COMPACTED_KIND = "compacted" as const;
68
11
 
69
12
  /**
70
13
  * Histogram bucket edges in milliseconds.
@@ -112,23 +55,53 @@ export interface CompactedBucket {
112
55
  readonly byProvider: Readonly<Record<string, number>>;
113
56
  readonly byClient: Readonly<Record<string, number>>;
114
57
  readonly byClientIp: Readonly<Record<string, number>>;
58
+ /**
59
+ * Requests per HTTP status, keyed by the status as a decimal string.
60
+ *
61
+ * Kept as counts for the same reason the other dimensions are: the Usage
62
+ * summary's status chips and the request-list filters read these, and without
63
+ * them every chip reads zero once the day's events have been folded — the
64
+ * numbers were on the source events, which no longer exist.
65
+ */
66
+ readonly byStatus: Readonly<Record<string, number>>;
67
+ /**
68
+ * Sum and count of gateway routing delay, so `avgResolveMs` survives
69
+ * compaction. Kept as a sum rather than an average of averages for the same
70
+ * reason the latency sum is: an average of per-file averages drifts as soon
71
+ * as the files hold different request counts.
72
+ */
73
+ readonly resolveSumMs: number;
74
+ readonly resolveCount: number;
115
75
  }
116
76
 
117
- /** One compacted row: the totals of everything it replaced, for one key/day. */
118
- export interface CompactedRow extends CompactedBucket {
119
- readonly kind: typeof COMPACTED_KIND;
120
- /** ISO day (UTC) this row summarises. */
121
- readonly day: string;
122
- readonly tenantId: string;
123
- readonly apiKeyId: string | null;
124
- }
125
-
126
- /** A number from a value that may be a numeric string; 0 when unusable. */
127
- function numeric(value: unknown): number {
77
+ /**
78
+ * A number from a value that may be a numeric string; 0 when unusable.
79
+ *
80
+ * Exported so readers of a compacted bucket coerce its fields the same way the
81
+ * fold does: a second local copy of "is this a number" is how one caller ends
82
+ * up summing `undefined` into NaN while another reads it as zero.
83
+ */
84
+ export function numeric(value: unknown): number {
128
85
  const asNumber = typeof value === "number" ? value : Number(value);
129
86
  return Number.isFinite(asNumber) ? asNumber : 0;
130
87
  }
131
88
 
89
+ /**
90
+ * The two fields added after the first index format, read defensively.
91
+ *
92
+ * An index file written before they existed carries neither, and `undefined +
93
+ 0` is `NaN` — which then propagates straight through every later fold and
94
+ * merge, so one old day turns the whole period's `avgResolveMs` into `NaN`.
95
+ * Reading them as 0/{} is the same answer an empty day gives, and a folded
96
+ * day that predates the field genuinely has no resolve measurement to report.
97
+ */
98
+ function readResolveSum(bucket: CompactedBucket): number {
99
+ return numeric(bucket.resolveSumMs);
100
+ }
101
+ function readResolveCount(bucket: CompactedBucket): number {
102
+ return numeric(bucket.resolveCount);
103
+ }
104
+
132
105
  /** Adds one occurrence to a count map, ignoring an absent key. */
133
106
  function bump(
134
107
  counts: Readonly<Record<string, number>> | undefined,
@@ -156,6 +129,9 @@ export function emptyBucket(): CompactedBucket {
156
129
  byProvider: {},
157
130
  byClient: {},
158
131
  byClientIp: {},
132
+ byStatus: {},
133
+ resolveSumMs: 0,
134
+ resolveCount: 0,
159
135
  requests: 0,
160
136
  inputTokens: 0,
161
137
  cachedTokens: 0,
@@ -207,11 +183,18 @@ export function accumulate(
207
183
  // summing, which turned a cost of 0.000966 into "00.000966". Coerced here so
208
184
  // every downstream sum is arithmetic.
209
185
  const priced = numeric(event.estimatedCostUsd);
186
+ const resolve = event.resolveMs;
187
+ const hasResolve = resolve !== null && resolve !== undefined && Number.isFinite(resolve);
210
188
  return {
211
189
  byModel: bump(into.byModel, event.requestedModel ?? event.reportedModel),
212
190
  byProvider: bump(into.byProvider, event.providerId),
213
191
  byClient: bump(into.byClient, event.sourceSurface),
214
192
  byClientIp: bump(into.byClientIp, event.clientIp),
193
+ // Keyed on the HTTP status, not the internal one: the chips and the filters
194
+ // are the status the client was given.
195
+ byStatus: bump(into.byStatus, event.httpStatus?.toString()),
196
+ resolveSumMs: readResolveSum(into) + (hasResolve ? resolve : 0),
197
+ resolveCount: readResolveCount(into) + (hasResolve ? 1 : 0),
215
198
  requests: into.requests + 1,
216
199
  inputTokens: into.inputTokens + (event.inputTokens ?? 0),
217
200
  cachedTokens: into.cachedTokens + (event.cachedInputTokens ?? 0),
@@ -251,13 +234,20 @@ export function accumulate(
251
234
  *
252
235
  * Returns the upper edge of the bucket that contains it — never a value
253
236
  * between edges, because a histogram cannot be more precise than the bucket
254
- * that holds the sample. `null` when there are no samples, and `null` when the
255
- * percentile falls in the overflow bucket, whose upper edge is unbounded.
237
+ * that holds the sample. `null` when there are no samples.
238
+ *
239
+ * The overflow bucket is the last one and has no upper edge, so it returns
240
+ * {@link HISTOGRAM_OVERFLOW_MS} — the top edge of the last real bucket — rather
241
+ * than `null`. Returning `null` there was read as "no data" by every caller,
242
+ * which collapsed a P95 of 40 s to `0 ms`: the slowest, most interesting
243
+ * percentiles were the ones reported as zero. Callers that can do better pass
244
+ * the period's `latencyMaxMs` as `overflowMs` and get that instead.
256
245
  */
257
246
  export function percentileFromHistogram(
258
247
  histogram: readonly number[],
259
248
  percentile: number,
260
- ): (typeof LATENCY_BUCKETS_MS)[number] | null {
249
+ overflowMs?: number | null,
250
+ ): number | null {
261
251
  const total = histogram.reduce((sum, count) => sum + count, 0);
262
252
  if (total === 0) return null;
263
253
  const target = Math.ceil((percentile / 100) * total);
@@ -267,12 +257,21 @@ export function percentileFromHistogram(
267
257
  if (seen >= target) {
268
258
  // The bucket's upper edge: a percentile from a histogram can never be
269
259
  // more precise than the bucket that contains it.
270
- return index < LATENCY_BUCKETS_MS.length ? LATENCY_BUCKETS_MS[index]! : null;
260
+ if (index < LATENCY_BUCKETS_MS.length) return LATENCY_BUCKETS_MS[index]!;
261
+ // Above the last edge. `latencyMaxMs` is the honest answer when the
262
+ // caller has it — it is the real slowest request in the period, so a
263
+ // percentile past the last edge is at most that. Falling back to the
264
+ // last edge rather than 0 keeps the figure in the right order of
265
+ // magnitude even when no max was recorded.
266
+ return overflowMs ?? HISTOGRAM_OVERFLOW_MS;
271
267
  }
272
268
  }
273
269
  return null;
274
270
  }
275
271
 
272
+ /** Top edge of the last real latency bucket; the floor for an overflow answer. */
273
+ export const HISTOGRAM_OVERFLOW_MS = LATENCY_BUCKETS_MS[LATENCY_BUCKETS_MS.length - 1]!;
274
+
276
275
  /** Newline count of a file, so a torn or unparsable line is detectable. */
277
276
  /** Adds two buckets. Exported so the day index can merge without duplicating it. */
278
277
  export function mergeBucketsInternal(a: CompactedBucket, b: CompactedBucket): CompactedBucket {
@@ -282,6 +281,9 @@ export function mergeBucketsInternal(a: CompactedBucket, b: CompactedBucket): Co
282
281
  byProvider: mergeCounts(a.byProvider, b.byProvider),
283
282
  byClient: mergeCounts(a.byClient, b.byClient),
284
283
  byClientIp: mergeCounts(a.byClientIp, b.byClientIp),
284
+ byStatus: mergeCounts(a.byStatus, b.byStatus),
285
+ resolveSumMs: readResolveSum(a) + readResolveSum(b),
286
+ resolveCount: readResolveCount(a) + readResolveCount(b),
285
287
  requests: a.requests + b.requests,
286
288
  inputTokens: a.inputTokens + b.inputTokens,
287
289
  cachedTokens: a.cachedTokens + b.cachedTokens,
@@ -12,17 +12,15 @@ import { TELEMETRY_EVENT_DIR, type TelemetryEventRecord } from "./event-log";
12
12
  * One sidecar index per day, beside that day's append-only event file.
13
13
  *
14
14
  * The event file grows all day and is never rewritten while it is open. The
15
- * index is the thing the dashboard reads: it holds the same totals and the same
16
- * breakdown counts the old per-day compaction produced, but they are maintained
17
- * incrementally from a byte watermark rather than rebuilt by folding and
18
- * deleting source files.
15
+ * index is the thing the dashboard reads: it holds the totals and the breakdown
16
+ * counts, maintained incrementally from a byte watermark rather than rebuilt by
17
+ * folding and deleting source files.
19
18
  *
20
- * That watermark is the whole reason this replaces the old scheme. Which file
21
- * was still being written used to be decided by comparing file *names*, so the
22
- * open file was periodically folded and unlinked mid-write, and its requests
23
- * never reached the summary. A byte offset has no such ambiguity: everything
24
- * below it is counted, everything above it is not, and re-reading the tail is
25
- * idempotent.
19
+ * The watermark is what makes that possible. Deciding which file was still
20
+ * being written by comparing file *names* lets the open file be folded and
21
+ * unlinked mid-write, so its requests never reach the summary. A byte offset
22
+ * has no such ambiguity: everything below it is counted, everything above it is
23
+ * not, and re-reading the tail is idempotent.
26
24
  */
27
25
 
28
26
  /**
@@ -58,16 +56,16 @@ export function utcDay(at: Date): string {
58
56
  * One hour's share of a bucket.
59
57
  *
60
58
  * The Traffic chart asks how a day was spent, which the totals alone cannot
61
- * answer. Twenty-four slots per bucket is small — four numbers each — and is
62
- * held *inside* the index rather than as the per-hour files this replaced.
59
+ * answer. Twenty-four slots per bucket is small — four numbers each — so it is
60
+ * held *inside* the index rather than as separate per-hour files.
63
61
  */
64
62
  /**
65
63
  * One named dimension's share of a bucket.
66
64
  *
67
65
  * The breakdown asks for tokens, errors and cost per model/provider/client/IP,
68
- * not merely how many requests each took. Counts alone were enough for the old
69
- * per-day totals, but the breakdown columns would all have read zero, so each
70
- * named entry carries the same running sums the bucket does.
66
+ * not merely how many requests each took. Counts alone would leave every
67
+ * breakdown column reading zero, so each named entry carries the same running
68
+ * sums the bucket does.
71
69
  */
72
70
  export interface IndexedDimension {
73
71
  readonly requests: number;
@@ -5,9 +5,9 @@ import { resolveDataDir } from "../persistence/db-mode";
5
5
 
6
6
  /**
7
7
  * Per-request telemetry lives in hourly JSONL files, not in Postgres. The
8
- * database keeps only the durable aggregate. Every reader that used to query
9
- * `telemetry_events` reads through here, so the file is the single source for
10
- * recent requests and the table is no longer written.
8
+ * database keeps only the durable aggregate; the files are the single source
9
+ * for recent requests and readers must go through this module, not a
10
+ * `telemetry_events` table.
11
11
  */
12
12
  /**
13
13
  * Where hourly event files and their compacted summaries live.
@@ -325,7 +325,7 @@ export async function queryTelemetryEvents(query: EventQuery): Promise<Telemetry
325
325
  //
326
326
  // The lower bound is the retention window, not just `since`: a caller that
327
327
  // asks for all time still must not scan files that have already been aged
328
- // out, and one that passes no `since` at all used to read every file ever
328
+ // out, and one that passes no `since` at all must not read every file ever
329
329
  // written. Files older than retention are gone or compacted; either way they
330
330
  // are not here.
331
331
  const retentionFloor = hourStamp(
@@ -115,12 +115,12 @@ function logArgs(
115
115
  msg: string,
116
116
  args: readonly unknown[],
117
117
  ): void {
118
- // The level is consulted first. Building the safe copy used to happen
119
- // unconditionally, so a `debug` call at the production `info` default still
120
- // paid a depth-capped deep copy plus a JSON.stringify of every argument, on
121
- // every request that reached it — the surface-detection debug line fires on
122
- // almost every chat request. Pino's own level check happens inside `write`,
123
- // which is already too late to skip the work.
118
+ // The level is consulted first. Building the safe copy unconditionally would
119
+ // make a `debug` call at the production `info` default still pay a
120
+ // depth-capped deep copy plus a JSON.stringify of every argument, on every
121
+ // request that reaches it — the surface-detection debug line fires on almost
122
+ // every chat request. Pino's own level check happens inside `write`, which is
123
+ // already too late to skip the work.
124
124
  if (!logger.isLevelEnabled(level)) return;
125
125
  const safeArgs = safeLogArgs(args);
126
126
  ring(level, msg, safeArgs);