cartethyia 2.5.4 → 2.5.7

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-DE2607Tb.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-DE2607Tb.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-Duv6mfrl.js +1 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-Duv6mfrl.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-C2PNYWzk.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-C2PNYWzk.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-TXP9OfAM.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-TXP9OfAM.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-B-9xnAQN.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-B-9xnAQN.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-xeax9nJt.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-xeax9nJt.js.gz +0 -0
  15. package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-Df4jjaHJ.js} +1 -1
  16. package/dist/dashboard/assets/HealthEventsModal-Df4jjaHJ.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-Dyojsm84.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-Dyojsm84.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-BJfg4ow6.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-BJfg4ow6.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-ChCX1gmT.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-ChCX1gmT.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-DeWSOEUO.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-DeWSOEUO.js.gz +0 -0
  27. package/dist/dashboard/assets/ProxyPage-CkpWln2S.js +7 -0
  28. package/dist/dashboard/assets/ProxyPage-CkpWln2S.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-B3VOgQmt.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-B3VOgQmt.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-C_klIZom.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-C_klIZom.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-BYph-InK.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-BYph-InK.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-CvyQCYWJ.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-CvyQCYWJ.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-Cm1JYilI.js} +3 -3
  38. package/dist/dashboard/assets/StudioPage-Cm1JYilI.js.gz +0 -0
  39. package/dist/dashboard/assets/UsagePage-DlFnc3_S.js +56 -0
  40. package/dist/dashboard/assets/UsagePage-DlFnc3_S.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-Bog0p925.js +4 -0
  66. package/dist/dashboard/assets/entry-Bog0p925.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
  68. package/dist/dashboard/assets/entry-CTP8AyiS.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-CZQIrdoX.js} +2 -2
  72. package/dist/dashboard/assets/index-CZQIrdoX.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-BPpSsBgL.js} +1 -1
  94. package/dist/dashboard/assets/select-BPpSsBgL.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 +95 -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
@@ -608,7 +608,7 @@ function describeResetCode(code: string): string {
608
608
  /**
609
609
  * Writes the outcome to `health_events` and, on success, restores the account to
610
610
  * `active` so it rejoins dispatch rotation immediately rather than waiting out a
611
- * cooldown that no longer reflects reality.
611
+ * cooldown that the reset has already cleared.
612
612
  */
613
613
  async function recordResetActivity(
614
614
  db: CartethyiaDatabase,
@@ -332,9 +332,9 @@ export const VERSION_SOURCES = {
332
332
  fallback: "1.3.11",
333
333
  sources: [
334
334
  {
335
- // Kiro's downloads page no longer exposes a stable version string.
336
- // Homebrew tracks the official installer URL and exposes its version
337
- // as JSON; keep the product page parser as a fallback.
335
+ // Kiro's downloads page exposes no stable version string. Homebrew
336
+ // tracks the official installer URL and exposes its version as JSON;
337
+ // keep the product page parser as a fallback.
338
338
  url: "https://formulae.brew.sh/api/cask/kiro.json",
339
339
  extract: kiroCaskVersion,
340
340
  },
@@ -488,8 +488,8 @@ const PROVIDER_VERSION_RESOLVERS: Readonly<Record<string, ClientVersionResolver>
488
488
  "opencode-zen": resolvers.opencode,
489
489
  "opencode-go": resolvers.opencode,
490
490
  // The identity this provider is dispatched under is the CLI's, so the route
491
- // identity reports the CLI version. `clineClient` (the VS Code extension
492
- // manifest) is no longer the client this provider claims to be.
491
+ // identity reports the CLI version, not the VS Code extension manifest
492
+ // (`clineClient`).
493
493
  cline: resolvers.clineCli,
494
494
  codex: resolvers.codex,
495
495
  qoder: resolvers.qoder,
@@ -670,7 +670,7 @@ export function buildCodeBuddyUserAgent(
670
670
  ): string {
671
671
  // 1:1 with codebuddy2api's identity_headers(): the CLI profile uses ONE version
672
672
  // (the npm CLI package pin) for both halves, and the IDE profile uses the other
673
- // product's version. This previously always used `version`, so "CLI" produced
673
+ // product's version. Using `version` for both would make "CLI" produce
674
674
  // `CLI/<ide> CodeBuddy/<ide>` — a CLI claiming the desktop build.
675
675
  const resolved = identity === "CLI" ? cnVersion : version;
676
676
  return `${identity}/${resolved} CodeBuddy/${resolved}`;
@@ -34,10 +34,9 @@ export function buildCustomCodexCliHeaders(): Record<string, string> {
34
34
  *
35
35
  * This is the route-level default for a provider whose operator set no client
36
36
  * identity of their own: a bare API key identifies as the Claude Code CLI
37
- * rather than as nothing. It used to be the Codex CLI identity
38
- * (`codex_cli_rs/…`), which named a different vendor's client on requests that
39
- * most often reached neither — an upstream that keys on the client string
40
- * would act on it.
37
+ * rather than as nothing. The Codex CLI identity (`codex_cli_rs/…`) would name
38
+ * a different vendor's client on requests that most often reach neither — an
39
+ * upstream that keys on the client string would act on it.
41
40
  *
42
41
  * The version comes from the live getter for the same reason
43
42
  * {@link buildCustomClaudeCliHeaders} does: the pinned `claude-fingerprint`
@@ -1,95 +1,95 @@
1
- /** Durable materialization of bundled provider model metadata. */
2
- import { and, eq, sql } from "drizzle-orm";
3
- import type { CartethyiaDatabase } from "../../persistence/db-handle";
4
- import { models } from "../../persistence/schema";
5
- import type { ModelDefinition } from "../provider-model-definition";
6
-
7
- /** Persists compiled provider model metadata and reconciles drifted capability flags. */
8
- export async function seedBundledModels(
9
- db: CartethyiaDatabase,
10
- builtinModels: ReadonlyMap<string, readonly ModelDefinition[]>,
11
- ): Promise<void> {
12
- for (const [providerId, definitions] of builtinModels) {
13
- if (definitions.length === 0) continue;
14
- // Drop builtin rows the current catalog no longer declares, including rows
15
- // whose model id is still present but whose endpoint path drifted (e.g. a
16
- // provider that moved from `/chat/completions` to `/v2/chat/completions`).
17
- // The unique key is (provider, model, endpoint), so a changed endpoint
18
- // would otherwise insert a second row and leave the stale route behind —
19
- // the model list would then show duplicates and probes could hit the dead
20
- // path. Composite `NOT IN` keeps exactly the (model, endpoint) pairs the
21
- // catalog owns.
22
- const pairs = definitions.map(
23
- (definition) => sql`(${definition.modelId}, ${definition.endpointPath})`,
24
- );
25
- await db
26
- .delete(models)
27
- .where(
28
- and(
29
- eq(models.providerId, providerId),
30
- eq(models.source, "builtin"),
31
- sql`(${models.modelId}, ${models.endpointPath}) NOT IN (${sql.join(pairs, sql`, `)})`,
32
- ),
33
- );
34
- }
35
- const now = new Date();
36
- const seen = new Set<string>();
37
- const rows = [...builtinModels.entries()].flatMap(([providerId, definitions]) =>
38
- definitions.flatMap((definition) => {
39
- const key = `${providerId}\u0000${definition.modelId}\u0000${definition.endpointPath}`;
40
- if (seen.has(key)) return [];
41
- seen.add(key);
42
- return [
43
- {
44
- providerId,
45
- modelId: definition.modelId,
46
- wireFamily: definition.wireFamily,
47
- serviceKind: definition.serviceKind ?? "llm",
48
- endpointPath: definition.endpointPath,
49
- contextLimit: definition.contextLimit,
50
- outputLimit: definition.outputLimit,
51
- modalities: definition.modalities,
52
- reasoning: definition.reasoning,
53
- toolCall: definition.toolCall,
54
- cost: definition.cost,
55
- // A static row either knows it is refused on a free plan or says
56
- // nothing. Never coerced to false: the column is three-valued, and
57
- // "nobody established it" is not the same claim as "served on free".
58
- proOnly: definition.proOnly ?? null,
59
- // Same three-valued rule for the inverse: the provider's directory
60
- // states the tier, so the flag is carried rather than derived.
61
- freeTier: definition.freeTier ?? null,
62
- source: "builtin",
63
- sourceUpdatedAt: now,
64
- enabled: true,
65
- },
66
- ];
67
- }),
68
- );
69
- if (rows.length === 0) return;
70
- // Reconcile static metadata on conflict rather than skipping: capability
71
- // flags (toolCall/reasoning/webSearch), wire family, limits, and cost can
72
- // drift on a pre-existing row (e.g. a discovery seeded `tool_call=false`
73
- // before the static catalog was corrected). `source` is forced back to
74
- // `builtin`: a fetch upsert may have flipped a builtin row to `discovered`,
75
- // and the static catalog owns these ids. `enabled` is operator-owned and
76
- // must never be reset here.
77
- await db.insert(models).values(rows).onConflictDoUpdate({
78
- target: [models.providerId, models.modelId, models.endpointPath],
79
- set: {
80
- wireFamily: sql`excluded.wire_family`,
81
- serviceKind: sql`excluded.service_kind`,
82
- endpointPath: sql`excluded.endpoint_path`,
83
- contextLimit: sql`excluded.context_limit`,
84
- outputLimit: sql`excluded.output_limit`,
85
- modalities: sql`excluded.modalities`,
86
- reasoning: sql`excluded.reasoning`,
87
- toolCall: sql`excluded.tool_call`,
88
- cost: sql`excluded.cost`,
89
- proOnly: sql`excluded.pro_only`,
90
- freeTier: sql`excluded.free_tier`,
91
- source: sql`'builtin'`,
92
- sourceUpdatedAt: sql`excluded.source_updated_at`,
93
- },
94
- });
95
- }
1
+ /** Durable materialization of bundled provider model metadata. */
2
+ import { and, eq, sql } from "drizzle-orm";
3
+ import type { CartethyiaDatabase } from "../../persistence/db-handle";
4
+ import { models } from "../../persistence/schema";
5
+ import type { ModelDefinition } from "../provider-model-definition";
6
+
7
+ /** Persists compiled provider model metadata and reconciles drifted capability flags. */
8
+ export async function seedBundledModels(
9
+ db: CartethyiaDatabase,
10
+ builtinModels: ReadonlyMap<string, readonly ModelDefinition[]>,
11
+ ): Promise<void> {
12
+ for (const [providerId, definitions] of builtinModels) {
13
+ if (definitions.length === 0) continue;
14
+ // Drop builtin rows the current catalog no longer declares, including rows
15
+ // whose model id is still present but whose endpoint path drifted (e.g. a
16
+ // provider that moved from `/chat/completions` to `/v2/chat/completions`).
17
+ // The unique key is (provider, model, endpoint), so a changed endpoint
18
+ // would otherwise insert a second row and leave the stale route behind —
19
+ // the model list then shows duplicates and probes can hit the dead path.
20
+ // Composite `NOT IN` keeps exactly the (model, endpoint) pairs the catalog
21
+ // owns.
22
+ const pairs = definitions.map(
23
+ (definition) => sql`(${definition.modelId}, ${definition.endpointPath})`,
24
+ );
25
+ await db
26
+ .delete(models)
27
+ .where(
28
+ and(
29
+ eq(models.providerId, providerId),
30
+ eq(models.source, "builtin"),
31
+ sql`(${models.modelId}, ${models.endpointPath}) NOT IN (${sql.join(pairs, sql`, `)})`,
32
+ ),
33
+ );
34
+ }
35
+ const now = new Date();
36
+ const seen = new Set<string>();
37
+ const rows = [...builtinModels.entries()].flatMap(([providerId, definitions]) =>
38
+ definitions.flatMap((definition) => {
39
+ const key = `${providerId}\u0000${definition.modelId}\u0000${definition.endpointPath}`;
40
+ if (seen.has(key)) return [];
41
+ seen.add(key);
42
+ return [
43
+ {
44
+ providerId,
45
+ modelId: definition.modelId,
46
+ wireFamily: definition.wireFamily,
47
+ serviceKind: definition.serviceKind ?? "llm",
48
+ endpointPath: definition.endpointPath,
49
+ contextLimit: definition.contextLimit,
50
+ outputLimit: definition.outputLimit,
51
+ modalities: definition.modalities,
52
+ reasoning: definition.reasoning,
53
+ toolCall: definition.toolCall,
54
+ cost: definition.cost,
55
+ // A static row either knows it is refused on a free plan or says
56
+ // nothing. Never coerced to false: the column is three-valued, and
57
+ // "nobody established it" is not the same claim as "served on free".
58
+ proOnly: definition.proOnly ?? null,
59
+ // Same three-valued rule for the inverse: the provider's directory
60
+ // states the tier, so the flag is carried rather than derived.
61
+ freeTier: definition.freeTier ?? null,
62
+ source: "builtin",
63
+ sourceUpdatedAt: now,
64
+ enabled: true,
65
+ },
66
+ ];
67
+ }),
68
+ );
69
+ if (rows.length === 0) return;
70
+ // Reconcile static metadata on conflict rather than skipping: capability
71
+ // flags (toolCall/reasoning/webSearch), wire family, limits, and cost can
72
+ // drift on a pre-existing row (e.g. a discovery seeded `tool_call=false`
73
+ // before the static catalog was corrected). `source` is forced back to
74
+ // `builtin`: a fetch upsert may have flipped a builtin row to `discovered`,
75
+ // and the static catalog owns these ids. `enabled` is operator-owned and
76
+ // must never be reset here.
77
+ await db.insert(models).values(rows).onConflictDoUpdate({
78
+ target: [models.providerId, models.modelId, models.endpointPath],
79
+ set: {
80
+ wireFamily: sql`excluded.wire_family`,
81
+ serviceKind: sql`excluded.service_kind`,
82
+ endpointPath: sql`excluded.endpoint_path`,
83
+ contextLimit: sql`excluded.context_limit`,
84
+ outputLimit: sql`excluded.output_limit`,
85
+ modalities: sql`excluded.modalities`,
86
+ reasoning: sql`excluded.reasoning`,
87
+ toolCall: sql`excluded.tool_call`,
88
+ cost: sql`excluded.cost`,
89
+ proOnly: sql`excluded.pro_only`,
90
+ freeTier: sql`excluded.free_tier`,
91
+ source: sql`'builtin'`,
92
+ sourceUpdatedAt: sql`excluded.source_updated_at`,
93
+ },
94
+ });
95
+ }
@@ -134,7 +134,7 @@ export async function seedBundledProviders(db: CartethyiaDatabase): Promise<void
134
134
  * console-created provider carries a tenant — so an unowned id absent from the
135
135
  * bundle is an orphan by construction, and a tenant-owned BYOK row is never in
136
136
  * scope. The model seeder prunes its retired rows the same way; this is the
137
- * provider-level half that was missing.
137
+ * provider-level half.
138
138
  *
139
139
  * Separate from {@link seedBundledProviders} rather than folded into it: the
140
140
  * harness calls that seeder on import to converge a shared database, and a
@@ -226,9 +226,8 @@ export async function bundledModelCatalog(
226
226
 
227
227
  /**
228
228
  * Re-seeds the compiled catalogs, called when a provider gains an account after
229
- * boot. Seeding is no longer account-gated, so this is now simply the same walk
230
- * as at boot; it exists because an account makes the rows routable and the
231
- * snapshot must reflect that without waiting for a restart.
229
+ * boot. It runs the same walk as at boot: an account makes the rows routable and
230
+ * the snapshot must reflect that without waiting for a restart.
232
231
  *
233
232
  * Gated on {@link currentCatalogRevision}: this is the seeder the snapshot
234
233
  * builder calls on every rebuild, and the invalidation that triggers it is a
@@ -415,18 +415,14 @@ const RAW_BUNDLED_PROVIDER_METADATA = [
415
415
  /**
416
416
  * Web search is a route of its own, never a model capability.
417
417
  *
418
- * There used to be a manual list of providers "whose hosted search had been
419
- * proven", and a `providerSupportsWebSearch` helper that consulted it. Both are
420
- * gone. A model row no longer advertises search, and a provider serves search
418
+ * A model row does not advertise search, and a provider serves search
421
419
  * purely by declaring a `serviceKind: "websearch"` catalog row — which is what
422
420
  * Exa, Parallel, and Gemini do. Those rows answer `POST /v1/search` and are
423
421
  * never reached from a chat turn.
424
422
  *
425
- * The reason is that the flag was never a capability gate: `deriveRequiredCapabilities`
426
- * deliberately does not derive `web_search`, so no chat request was ever
427
- * filtered or degraded by it. Its only real effect was to smuggle `llm` rows
428
- * (Codex, Antigravity) into the fallback candidate list as if they were search
429
- * routes, and to show a badge in the console. The fallback is gone too: a chat
423
+ * A search flag is not a capability gate: `deriveRequiredCapabilities`
424
+ * deliberately does not derive `web_search`, so no chat request is
425
+ * filtered or degraded by it. A chat
430
426
  * turn is dispatched once to the route its model selects, and a hosted search
431
427
  * declaration is answered by that upstream, not executed by the gateway.
432
428
  */
@@ -38,8 +38,8 @@ export interface ProviderModule {
38
38
  * `upstream_host` is the SSRF-validated network-binding target for this
39
39
  * provider — carried on the same registration object as the adapter loader
40
40
  * so adding a provider touches one call-site instead of a second map kept
41
- * in sync by hand elsewhere (`transport/dispatch/proxy-request.ts` used to hardcode this
42
- * separately; `providers/operations/provider-catalog-service.ts` now derives it from here).
41
+ * in sync by hand elsewhere; `providers/operations/provider-catalog-service.ts`
42
+ * derives it from here.
43
43
  */
44
44
  export interface ProviderRegistration {
45
45
  readonly provider_id: ProviderId;
@@ -240,11 +240,10 @@ export class ProviderRegistry {
240
240
  * check — no module is loaded — for list projections that must hide the
241
241
  * "Fetch models" control from providers with no discovery endpoint.
242
242
  *
243
- * This is the question the projection should be asking. "Is this a builtin?"
244
- * was a proxy for it that was true for every provider when the catalog had no
245
- * discovery-backed builtins, and wrong for every one added since: a builtin
246
- * that registers a resolver cannot list any model until an operator runs a
247
- * sync, so hiding the control leaves it permanently empty.
243
+ * This is the question the projection should be asking; "is this a builtin?"
244
+ * is not a proxy for it. A builtin that registers a resolver cannot list any
245
+ * model until an operator runs a sync, so hiding the control on the strength
246
+ * of builtin status alone leaves it permanently empty.
248
247
  */
249
248
  hasModelDiscovery(providerId: string): boolean {
250
249
  return this.#registrations.get(parseProviderId(providerId))?.loadModelDiscovery !== undefined;
@@ -195,7 +195,7 @@ export function normalizeUsage(input: Record<string, unknown>): UsageRecord {
195
195
  // the zeroed `*_tokens_details.cached_tokens` those bridges also emit.
196
196
  // Flat `cached_tokens` is the intermediate shape `mapGeminiUsage`
197
197
  // (Gemini/Antigravity) and CommandCode emit; `cachedContentTokenCount` is
198
- // Gemini's raw `usageMetadata` field. Both were previously dropped.
198
+ // Gemini's raw `usageMetadata` field. Both are consumed here.
199
199
  if (
200
200
  cached_input_tokens === "unavailable" &&
201
201
  typeof input.cached_tokens === "number"
@@ -78,10 +78,10 @@ export interface IpAbuseOutcome {
78
78
  *
79
79
  * The store is the only component that knows this: a ban's remainder is its
80
80
  * marker's TTL, and a rate-limited window's remainder is the age of its
81
- * oldest attempt. Both are server state. The middleware used to answer every
82
- * 429 with a fixed `retry-after: 3600`, which told a client hitting a 60-second
83
- * window to wait sixty times longer than it had to — and told a client whose
84
- * ban had nearly elapsed to wait the full hour again.
81
+ * oldest attempt. Both are server state. Answering every 429 with a fixed
82
+ * `retry-after: 3600` would tell a client hitting a 60-second window to wait
83
+ * sixty times longer than it had to — and tell a client whose ban had nearly
84
+ * elapsed to wait the full hour again.
85
85
  */
86
86
  readonly retryAfterMs: number;
87
87
  }
@@ -224,7 +224,7 @@ export class InMemoryIpAbuseStore implements IpAbuseStore {
224
224
 
225
225
  /** Evicts the oldest entries of `map` down to `maxKeys` in a single pass so
226
226
  * an adversarial fan-out over unique identities cannot pin memory. Deleting
227
- * one entry at a time was O(1) but starved reclaim. */
227
+ * one entry at a time is O(1) but starves reclaim. */
228
228
  private evictOldest<K, V>(map: Map<K, V>): void {
229
229
  if (map.size < this.maxKeys) return;
230
230
  let toEvict = map.size - this.maxKeys + 1;
@@ -251,10 +251,10 @@ export class InMemoryIpAbuseStore implements IpAbuseStore {
251
251
  /**
252
252
  * Outage injection for tests, mirroring the store's own reachability.
253
253
  *
254
- * The service no longer probes the store before using it: every method below
254
+ * The service does not probe the store before using it: every method below
255
255
  * throws when the store is unreachable, and the service's catch maps that to
256
- * a bounded `admission_unavailable`. Keeping a separate probe would only add
257
- * a round trip to every request on the Redis store.
256
+ * a bounded `admission_unavailable`. A separate probe would only add a round
257
+ * trip to every request on the Redis store.
258
258
  */
259
259
  private assertAvailable(): void {
260
260
  if (this.failing) throw new Error("ip store unavailable");
@@ -421,7 +421,12 @@ export class IpAbuseProtectionService {
421
421
 
422
422
  if (outcome.banned) {
423
423
  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
- reason: "admission-unavailable",
424
+ // Distinguishes this from the rate-limited 429 below and from an API
425
+ // key's own budget. It used to be "admission-unavailable", which is
426
+ // the label for an *unreachable* store — so every refusal from this
427
+ // layer claimed an outage that had not happened, and a client could
428
+ // not tell "banned" from "over the window" from "store is down".
429
+ reason: "ip-banned",
425
430
  ip,
426
431
  route: input.route,
427
432
  // Measured by the store: the ban marker's remaining TTL. Carried as
@@ -433,7 +438,7 @@ export class IpAbuseProtectionService {
433
438
 
434
439
  if (outcome.count > this.maxRequestsPerWindow) {
435
440
  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.", {
436
- reason: "admission-unavailable",
441
+ reason: "ip-rate-limited",
437
442
  ip,
438
443
  route: input.route,
439
444
  count: outcome.count,