cartethyia 2.5.9 → 2.6.0

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 (386) hide show
  1. package/.env.example +15 -42
  2. package/README.md +11 -10
  3. package/dist/dashboard/assets/{BannedPage-Brvuj_Eb.js → BannedPage-l6XMnfr9.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-CqfXtI3y.js → CliToolDetailPage-DwOzAW45.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-GQeS91bg.js → CliToolsPage-BT3Up3QA.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
  9. package/dist/dashboard/assets/{CombosPage-BDRsTXBB.js → CombosPage-6kYIUpzR.js} +1 -1
  10. package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-zP8AFHX0.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-BmfrNZ14.js → CustomizationPage-C7m-H1Rz.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-C7m-H1Rz.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-DoreIgm8.js → LoginPage-CbphLvjg.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
  19. package/dist/dashboard/assets/{ModelPicker-C7pDb41R.js → ModelPicker-DVny4S5_.js} +1 -1
  20. package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-BnoPgA7w.js → ProvidersPage-Dfb2896L.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
  27. package/dist/dashboard/assets/{ProxyPage-Bq_TGgdb.js → ProxyPage-BaCIdAUt.js} +1 -1
  28. package/dist/dashboard/assets/ProxyPage-BaCIdAUt.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-Day3mCOn.js → SetupPage-D4g6vOGc.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-DQxllnB5.js → SortableList-C93i14BD.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js → StudioPage-SgQpymjm.js} +1 -1
  38. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
  39. package/dist/dashboard/assets/{UsagePage-DXa1oR-4.js → UsagePage-BFME-eba.js} +2 -2
  40. package/dist/dashboard/assets/UsagePage-BFME-eba.js.gz +0 -0
  41. package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
  42. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  43. package/dist/dashboard/assets/{app-BIt446yE.js → app-2KhtHCv9.js} +1 -1
  44. package/dist/dashboard/assets/{app-BIt446yE.js.gz → app-2KhtHCv9.js.gz} +0 -0
  45. package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
  46. package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
  48. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-CR72dasT.js → badge-CKsF123d.js} +1 -1
  50. package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-CI9_eSfO.js → banner-8j7uChA9.js} +1 -1
  52. package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
  53. package/dist/dashboard/assets/{card-DS7CQEsO.js → card-CdsSlWA3.js} +1 -1
  54. package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
  55. package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
  56. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  57. package/dist/dashboard/assets/{clipboard-button-611pSsaX.js → clipboard-button-uL5aYLfW.js} +1 -1
  58. package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
  59. package/dist/dashboard/assets/{dialog-k37exjNt.js → dialog-C07hr5_G.js} +1 -1
  60. package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
  61. package/dist/dashboard/assets/{drawer-CX7N8ucR.js → drawer-BPO1TcKH.js} +1 -1
  62. package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CTP8AyiS.js → entry-Bz_CtDfC.js} +1 -1
  64. package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CwPRKk0d.js +4 -0
  66. package/dist/dashboard/assets/entry-CwPRKk0d.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
  68. package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-sltk1qUi.js → github-badge-DmQreSDd.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-z3zDOSMM.js → index-Bblu6erR.js} +2 -2
  72. package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-BhY2sSnO.js → inline-C9dCYaBZ.js} +1 -1
  74. package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-V1umFiBk.js → input-CjCnXweJ.js} +1 -1
  76. package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
  77. package/dist/dashboard/assets/{layout-BBOYycyS.js → layout-V6y8DAkl.js} +1 -1
  78. package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-1zzZYM0B.js → list-row-CM1AaG_y.js} +1 -1
  80. package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
  82. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
  86. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  87. package/dist/dashboard/assets/{numbers-DkfMR5Qs.js → numbers-BOevJzdz.js} +1 -1
  88. package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
  92. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-C6MMiaio.js → select-C980c4cz.js} +1 -1
  94. package/dist/dashboard/assets/select-C980c4cz.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
  96. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-BHTfXdz_.js → stack-_gfTdLVB.js} +1 -1
  98. package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-mPDRlQkl.js → state-2c5V4zo7.js} +1 -1
  100. package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DOmJxg7H.js → switch-Dkke7Naf.js} +1 -1
  102. package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
  103. package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
  104. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  105. package/dist/dashboard/index.html +1 -1
  106. package/dist/dashboard/index.html.gz +0 -0
  107. package/dist/dashboard/precompressed-assets.json +51 -51
  108. package/migrations/README.md +52 -52
  109. package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
  110. package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
  111. package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
  112. package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  113. package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
  114. package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
  115. package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
  116. package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  117. package/package.json +96 -97
  118. package/scripts/cli/admin.ts +126 -125
  119. package/scripts/cli/autostart.ts +237 -237
  120. package/scripts/cli/background.ts +120 -110
  121. package/scripts/cli/bin/carte.cjs +8 -8
  122. package/scripts/cli/bin/cartethyia.cjs +167 -167
  123. package/scripts/cli/console-menu.ts +308 -275
  124. package/scripts/cli/controller.ts +145 -0
  125. package/scripts/cli/doctor.ts +1 -1
  126. package/scripts/cli/env.ts +99 -99
  127. package/scripts/cli/gateway.ts +264 -261
  128. package/scripts/{health.ts → cli/health.ts} +4 -4
  129. package/scripts/cli/instance.ts +234 -224
  130. package/scripts/cli/main.ts +188 -164
  131. package/scripts/cli/platform.ts +64 -64
  132. package/scripts/cli/prompt.ts +275 -107
  133. package/scripts/cli/services.ts +88 -88
  134. package/scripts/cli/setup.ts +445 -445
  135. package/scripts/cli/start.ts +85 -82
  136. package/scripts/cli/startup-signal.ts +23 -23
  137. package/scripts/cli/telemetry.ts +70 -0
  138. package/scripts/cli/tray/index.ts +263 -263
  139. package/scripts/cli/tray/windows.ps1 +107 -107
  140. package/scripts/cli/tray.ts +192 -208
  141. package/scripts/cli/update.ts +39 -39
  142. package/scripts/cli/version.ts +67 -67
  143. package/scripts/cli/wordmark.ts +58 -58
  144. package/src/boot/app.ts +16 -1
  145. package/src/boot/dependencies.ts +128 -25
  146. package/src/config/package-paths.ts +24 -0
  147. package/src/config/resources.ts +137 -0
  148. package/src/config/runtime.ts +133 -76
  149. package/src/config/spec.ts +30 -29
  150. package/src/config/telemetry.ts +0 -25
  151. package/src/console/api-keys/bucket-spend.ts +14 -17
  152. package/src/console/api-keys/contracts.ts +410 -410
  153. package/src/console/api-keys/routes.ts +12 -0
  154. package/src/console/audit/store.ts +2 -3
  155. package/src/console/auth/setup-service.ts +8 -1
  156. package/src/console/backup/routes.ts +7 -0
  157. package/src/console/backup/service.ts +463 -463
  158. package/src/console/backup/store.ts +16 -11
  159. package/src/console/backup/validate.ts +1 -4
  160. package/src/console/cli-tools/fs-ops.ts +18 -2
  161. package/src/console/data-management/contracts.ts +1 -8
  162. package/src/console/data-management/operations.ts +61 -48
  163. package/src/console/data-management/routes.ts +4 -2
  164. package/src/console/domain-registration.ts +25 -3
  165. package/src/console/inferhub/client.ts +139 -0
  166. package/src/console/inferhub/key-store.ts +129 -0
  167. package/src/console/inferhub/normalize.ts +347 -0
  168. package/src/console/inferhub/routes.ts +411 -0
  169. package/src/console/inferhub/store.ts +109 -0
  170. package/src/console/inferhub/types.ts +183 -0
  171. package/src/console/observability/contracts.ts +2 -41
  172. package/src/console/observability/store.ts +176 -371
  173. package/src/console/providers/catalog/public-model-store.ts +0 -0
  174. package/src/console/providers/catalog/store.ts +23 -36
  175. package/src/console/quota/account-quota-shared.ts +52 -52
  176. package/src/console/quota/account-quota-tenant.ts +16 -24
  177. package/src/console/quota/refresh.ts +441 -441
  178. package/src/console/remote-support/service.ts +270 -114
  179. package/src/console/routing/pools/import-parse.ts +206 -206
  180. package/src/console/routing/pools/operations.ts +543 -543
  181. package/src/console/routing/pools/probe-verdict.ts +132 -132
  182. package/src/console/routing/pools/routes.ts +181 -181
  183. package/src/console/routing/pools/store.ts +1 -1
  184. package/src/console/settings/contracts.ts +42 -40
  185. package/src/console/settings/store.ts +25 -25
  186. package/src/console/share/share-stats.ts +22 -4
  187. package/src/console/share/share-usage.ts +30 -4
  188. package/src/console/shared/cursor.ts +15 -0
  189. package/src/console/updates/repository-updates.ts +40 -39
  190. package/src/console/updates/routes.ts +12 -0
  191. package/src/main.ts +13 -5
  192. package/src/network/pool/resolver.ts +1104 -1104
  193. package/src/observability/client-name.ts +22 -0
  194. package/src/observability/event-log.ts +5 -29
  195. package/src/observability/event-query.ts +690 -0
  196. package/src/observability/log-ring.ts +26 -2
  197. package/src/observability/log-sanitize.ts +118 -0
  198. package/src/observability/logger.ts +17 -13
  199. package/src/observability/metrics.ts +35 -0
  200. package/src/observability/payload-capture.ts +114 -41
  201. package/src/observability/payload-store.ts +249 -24
  202. package/src/observability/raw-event-writer.ts +118 -0
  203. package/src/observability/runtime-metrics.ts +71 -1
  204. package/src/observability/telemetry-buffer.ts +100 -17
  205. package/src/observability/telemetry-reconciliation.ts +417 -0
  206. package/src/persistence/boot.ts +20 -9
  207. package/src/persistence/db-pg.ts +13 -0
  208. package/src/persistence/db-sqlite.ts +569 -497
  209. package/src/persistence/dialect.ts +3 -2
  210. package/src/persistence/migrate.ts +181 -181
  211. package/src/persistence/schema.ts +1496 -1406
  212. package/src/persistence/shared-cache.ts +5 -1
  213. package/src/persistence/stores/api-key-store.ts +581 -581
  214. package/src/persistence/stores/telemetry-store.ts +124 -63
  215. package/src/protocol/reasoning-text.ts +30 -0
  216. package/src/protocol/registry.ts +2 -0
  217. package/src/protocol/response/chat.ts +33 -7
  218. package/src/protocol/response/codex.ts +14 -2
  219. package/src/protocol/response/messages.ts +5 -2
  220. package/src/providers/authentication/oauth-flow-store.ts +3 -10
  221. package/src/providers/bundled-discovery-providers.ts +122 -122
  222. package/src/providers/default-registry.ts +14 -0
  223. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  224. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  225. package/src/providers/discovery/probe-phases.ts +43 -7
  226. package/src/providers/discovery/probing-service.ts +70 -32
  227. package/src/providers/integrations/antigravity/antigravity.ts +9 -2
  228. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
  231. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
  232. package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
  233. package/src/providers/integrations/buddy/capabilities.ts +4 -0
  234. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
  235. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
  236. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
  237. package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
  238. package/src/providers/integrations/claude/claude-quota.ts +2 -2
  239. package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
  240. package/src/providers/integrations/claude/claude.ts +3 -4
  241. package/src/providers/integrations/cline/cline.ts +94 -8
  242. package/src/providers/integrations/codex/codex.ts +61 -37
  243. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
  244. package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
  245. package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
  246. package/src/providers/integrations/cursor/cursor-request.ts +11 -0
  247. package/src/providers/integrations/cursor/cursor.ts +29 -17
  248. package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
  249. package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
  250. package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
  251. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
  252. package/src/providers/integrations/github/github.ts +3 -1
  253. package/src/providers/integrations/grok/grok-quota.ts +279 -279
  254. package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
  255. package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
  256. package/src/providers/integrations/hermes.ts +7 -1
  257. package/src/providers/integrations/inferhub.ts +201 -73
  258. package/src/providers/integrations/kilo/kilo.ts +152 -152
  259. package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
  260. package/src/providers/integrations/opencode/provider.ts +2 -0
  261. package/src/providers/integrations/openrouter/provider.ts +129 -129
  262. package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
  263. package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
  264. package/src/providers/integrations/trae/trae-headers.ts +17 -48
  265. package/src/providers/integrations/trae/trae-oauth.ts +4 -26
  266. package/src/providers/integrations/trae/trae-quota.ts +389 -384
  267. package/src/providers/integrations/trae/trae-realm.ts +15 -2
  268. package/src/providers/integrations/trae/trae.ts +22 -24
  269. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
  270. package/src/providers/integrations/zcode/oauth.ts +1 -1
  271. package/src/providers/operations/account-health-service.ts +605 -279
  272. package/src/providers/provider-metadata.ts +12 -1
  273. package/src/providers/provider-model-definition.ts +373 -373
  274. package/src/providers/provider-probe.ts +3 -0
  275. package/src/providers/quota/quota-contracts.ts +3 -7
  276. package/src/providers/search/search-provider.ts +2 -6
  277. package/src/security/admission/contracts.ts +10 -0
  278. package/src/security/admission/in-memory-store.ts +89 -14
  279. package/src/security/admission/lua.ts +191 -182
  280. package/src/security/admission/redis-store.ts +30 -0
  281. package/src/security/admission/service.ts +18 -0
  282. package/src/security/api-key-auth-cache.ts +96 -0
  283. package/src/security/api-key-auth.ts +11 -100
  284. package/src/security/client-router-fingerprint.ts +3 -7
  285. package/src/security/ip-boundary.ts +7 -3
  286. package/src/shared/coerce.ts +67 -0
  287. package/src/shared/hash.ts +6 -0
  288. package/src/shared/time.ts +7 -0
  289. package/src/transport/dispatch/attempt-finalize.ts +26 -138
  290. package/src/transport/dispatch/attempt-loop.ts +103 -81
  291. package/src/transport/dispatch/capture-policy.ts +78 -0
  292. package/src/transport/dispatch/proxy-request.ts +4 -2
  293. package/src/transport/dispatch/streaming/encoder.ts +111 -5
  294. package/src/transport/dispatch/streaming/stream.ts +19 -2
  295. package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
  296. package/src/transport/failure-policy.ts +27 -0
  297. package/src/transport/guards/abuse-guard.ts +2 -2
  298. package/src/transport/guards/auth-guard.ts +17 -0
  299. package/src/transport/guards/body-policy.ts +3 -2
  300. package/src/transport/guards/concurrency-guard.ts +89 -13
  301. package/src/transport/guards/early-rejection-capture.ts +43 -3
  302. package/src/transport/guards/error-lifecycle.ts +10 -2
  303. package/src/transport/guards/guard-errors.ts +23 -0
  304. package/src/transport/guards/headroom-guard.ts +41 -7
  305. package/src/transport/guards/pipeline.ts +24 -0
  306. package/src/transport/guards/request-context.ts +2 -1
  307. package/src/transport/routing/admission.ts +51 -9
  308. package/src/transport/routing/bounded-lru.ts +49 -0
  309. package/src/transport/routing/candidate-index.ts +88 -0
  310. package/src/transport/routing/reservations.ts +121 -7
  311. package/src/transport/routing/round-robin.ts +10 -22
  312. package/src/transport/routing/route-catalog.ts +26 -13
  313. package/src/transport/routing/route-model.ts +22 -2
  314. package/src/transport/routing/router.ts +53 -31
  315. package/src/transport/surface/chat/encode.ts +2 -3
  316. package/src/transport/surface/chat/parse.ts +2 -1
  317. package/src/transport/surface/dialects.ts +11 -3
  318. package/src/transport/surface/messages/encode.ts +2 -1
  319. package/src/transport/surface/messages/parse.ts +3 -1
  320. package/src/transport/surface/messages/stream.ts +2 -6
  321. package/src/workers/maintenance-lease.ts +200 -0
  322. package/src/workers/scheduler.ts +101 -1
  323. package/dist/dashboard/assets/BannedPage-Brvuj_Eb.js.gz +0 -0
  324. package/dist/dashboard/assets/CliToolDetailPage-CqfXtI3y.js.gz +0 -0
  325. package/dist/dashboard/assets/CliToolsPage-GQeS91bg.js.gz +0 -0
  326. package/dist/dashboard/assets/CombosPage-BDRsTXBB.js.gz +0 -0
  327. package/dist/dashboard/assets/ConsoleLogPage-zP8AFHX0.js.gz +0 -0
  328. package/dist/dashboard/assets/CustomizationPage-BmfrNZ14.js.gz +0 -0
  329. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js +0 -1
  330. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js.gz +0 -0
  331. package/dist/dashboard/assets/LoginPage-DoreIgm8.js.gz +0 -0
  332. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  333. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js +0 -1
  334. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js.gz +0 -0
  335. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js +0 -3
  336. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js.gz +0 -0
  337. package/dist/dashboard/assets/ProvidersPage-BnoPgA7w.js.gz +0 -0
  338. package/dist/dashboard/assets/ProxyPage-Bq_TGgdb.js.gz +0 -0
  339. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js +0 -1
  340. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js.gz +0 -0
  341. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js +0 -1
  342. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js.gz +0 -0
  343. package/dist/dashboard/assets/SetupPage-Day3mCOn.js.gz +0 -0
  344. package/dist/dashboard/assets/SortableList-DQxllnB5.js.gz +0 -0
  345. package/dist/dashboard/assets/UsagePage-DXa1oR-4.js.gz +0 -0
  346. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  347. package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
  348. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  349. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  350. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  351. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  352. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  353. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  354. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  355. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  356. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  357. package/dist/dashboard/assets/entry-B9Xvtnfj.js +0 -1
  358. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-ByMGkR3C.js +0 -4
  360. package/dist/dashboard/assets/entry-ByMGkR3C.js.gz +0 -0
  361. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  363. package/dist/dashboard/assets/index-z3zDOSMM.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  365. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  367. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  368. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  369. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  370. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  371. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  372. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  373. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  374. package/dist/dashboard/assets/select-C6MMiaio.js.gz +0 -0
  375. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  376. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  377. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  378. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  379. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  380. package/scripts/build/aot.ts +0 -143
  381. package/scripts/build/build.ts +0 -24
  382. package/scripts/build/compile.ts +0 -88
  383. package/scripts/build/restart.ts +0 -120
  384. package/scripts/build/start.ts +0 -25
  385. package/src/observability/event-compaction.ts +0 -317
  386. package/src/observability/event-day-index.ts +0 -440
@@ -0,0 +1,275 @@
1
+ // Cursor-native tool calls, unified into one canonical shape.
2
+ //
3
+ // Cursor's `agent.v1.ToolCall` is a oneof of ~30 variants spanning three
4
+ // unrelated generations: the legacy natives (`ReadToolCall` 8, `ShellToolCall`
5
+ // 1, `EditToolCall` 12, …), the modern exec family (`PiReadToolCall` 61 …
6
+ // `PiLsToolCall` 67), and MCP (`McpToolCall` 15). Each carries its own args
7
+ // message and its own `*ToolResult` oneof of `success`/`error`, so handling
8
+ // them individually meant a decoder and a builder per variant — most of them
9
+ // saying the same thing.
10
+ //
11
+ // This module is the single join point. One table maps a wire variant to a
12
+ // canonical tool identity, and the decode/encode paths below are written once
13
+ // against that table rather than once per variant.
14
+ //
15
+ // **Variants stay separate.** `ReadToolCall` and `PiReadToolCall` are two tools,
16
+ // not one tool seen twice: their args and their result shapes genuinely differ,
17
+ // and folding them would mean picking one shape and lying about the other. A
18
+ // new variant is one table row, not a new converter.
19
+ //
20
+ // **Cursor-scoped on purpose.** Nothing here is shared with the other provider
21
+ // integrations. The canonical vocabulary is Cursor's own (`read`, `pi_read`,
22
+ // `shell`, …), so a tool named `read` on Cursor and a `read` on some other
23
+ // provider are unrelated and cannot collide through a shared registry.
24
+ import type { ToolDefinition } from "../../../../protocol/canonical-model";
25
+
26
+ /**
27
+ * One `ToolCall` oneof arm, as it exists on the wire.
28
+ *
29
+ * `field` is the oneof number from `agent.proto` — the only stable identity a
30
+ * variant has. `wireType` and `argsType` name the protobuf messages so a
31
+ * decoder can resolve them against the type registry without this file
32
+ * importing the registry (and without the registry growing a second notion of
33
+ * which variants exist).
34
+ */
35
+ export interface CursorToolVariant {
36
+ readonly field: number;
37
+ readonly wireType: string;
38
+ readonly argsType: string;
39
+ /** Result message carrying the `success`/`error` oneof. */
40
+ readonly resultType: string;
41
+ /**
42
+ * Canonical tool name for this variant.
43
+ *
44
+ * Deliberately not shared across generations: `read` and `pi_read` are two
45
+ * names because they are two tools. A caller that wants both treats them as
46
+ * both; a caller that wants one filters on one.
47
+ */
48
+ readonly name: string;
49
+ }
50
+
51
+ const VARIANT = (
52
+ field: number,
53
+ wireType: string,
54
+ argsType: string,
55
+ resultType: string,
56
+ name: string,
57
+ ): CursorToolVariant => ({ field, wireType, argsType, resultType, name });
58
+
59
+ /**
60
+ * Every Cursor-native tool variant this layer speaks, keyed by oneof field.
61
+ *
62
+ * `McpToolCall` is absent on purpose: client-declared tools have no native
63
+ * slot anywhere in `agent.proto` — `RequestContext.tools` (#7) is
64
+ * `repeated McpToolDefinition` and `AgentRunRequest.mcp_tools` (#4) is the only
65
+ * other place tools travel — so those stay on the MCP meta-tool path. This
66
+ * table is for the arms Cursor itself owns.
67
+ */
68
+ export const CURSOR_TOOL_VARIANTS: ReadonlyMap<number, CursorToolVariant> = new Map([
69
+ VARIANT(1, "ShellToolCall", "ShellArgs", "ShellResult", "shell"),
70
+ VARIANT(3, "DeleteToolCall", "DeleteArgs", "DeleteResult", "delete"),
71
+ VARIANT(4, "GlobToolCall", "GlobArgs", "GlobResult", "glob"),
72
+ VARIANT(5, "GrepToolCall", "GrepArgs", "GrepResult", "grep"),
73
+ VARIANT(8, "ReadToolCall", "ReadToolArgs", "ReadToolResult", "read"),
74
+ VARIANT(9, "UpdateTodosToolCall", "UpdateTodosArgs", "UpdateTodosResult", "update_todos"),
75
+ VARIANT(10, "ReadTodosToolCall", "ReadTodosArgs", "ReadTodosResult", "read_todos"),
76
+ VARIANT(12, "EditToolCall", "EditToolArgs", "EditToolResult", "edit"),
77
+ VARIANT(13, "LsToolCall", "LsArgs", "LsResult", "ls"),
78
+ VARIANT(14, "ReadLintsToolCall", "ReadLintsToolArgs", "ReadLintsToolResult", "read_lints"),
79
+ VARIANT(16, "SemSearchToolCall", "SemSearchToolArgs", "SemSearchToolResult", "sem_search"),
80
+ VARIANT(17, "CreatePlanToolCall", "CreatePlanArgs", "CreatePlanResult", "create_plan"),
81
+ VARIANT(18, "WebSearchToolCall", "WebSearchToolArgs", "WebSearchToolResult", "web_search"),
82
+ VARIANT(19, "TaskToolCall", "TaskToolArgs", "TaskToolResult", "task"),
83
+ VARIANT(22, "ApplyAgentDiffToolCall", "ApplyAgentDiffArgs", "ApplyAgentDiffResult", "apply_agent_diff"),
84
+ VARIANT(23, "AskQuestionToolCall", "AskQuestionArgs", "AskQuestionResult", "ask_question"),
85
+ VARIANT(24, "FetchToolCall", "FetchToolArgs", "FetchToolResult", "fetch"),
86
+ VARIANT(25, "SwitchModeToolCall", "SwitchModeArgs", "SwitchModeResult", "switch_mode"),
87
+ VARIANT(26, "ExaSearchToolCall", "ExaSearchArgs", "ExaSearchResult", "exa_search"),
88
+ VARIANT(27, "ExaFetchToolCall", "ExaFetchArgs", "ExaFetchResult", "exa_fetch"),
89
+ VARIANT(28, "GenerateImageToolCall", "GenerateImageArgs", "GenerateImageResult", "generate_image"),
90
+ VARIANT(29, "RecordScreenToolCall", "RecordScreenArgs", "RecordScreenResult", "record_screen"),
91
+ VARIANT(30, "ComputerUseToolCall", "ComputerUseArgs", "ComputerUseResult", "computer_use"),
92
+ VARIANT(31, "WriteShellStdinToolCall", "WriteShellStdinArgs", "WriteShellStdinResult", "write_shell_stdin"),
93
+ VARIANT(32, "ReflectToolCall", "ReflectArgs", "ReflectResult", "reflect"),
94
+ VARIANT(33, "SetupVmEnvironmentToolCall", "SetupVmEnvironmentArgs", "SetupVmEnvironmentResult", "setup_vm_environment"),
95
+ VARIANT(34, "TruncatedToolCall", "TruncatedArgs", "TruncatedResult", "truncated"),
96
+ // The modern exec family. Same join point, separate identities.
97
+ VARIANT(61, "PiReadToolCall", "PiReadToolArgs", "PiReadExecResult", "pi_read"),
98
+ VARIANT(62, "PiBashToolCall", "PiBashToolArgs", "PiBashExecResult", "pi_bash"),
99
+ VARIANT(63, "PiEditToolCall", "PiEditToolArgs", "PiEditExecResult", "pi_edit"),
100
+ VARIANT(64, "PiWriteToolCall", "PiWriteToolArgs", "PiWriteExecResult", "pi_write"),
101
+ VARIANT(65, "PiGrepToolCall", "PiGrepToolArgs", "PiGrepExecResult", "pi_grep"),
102
+ VARIANT(66, "PiFindToolCall", "PiFindToolArgs", "PiFindExecResult", "pi_find"),
103
+ VARIANT(67, "PiLsToolCall", "PiLsToolArgs", "PiLsExecResult", "pi_ls"),
104
+ ].map((entry) => [entry.field, entry]));
105
+
106
+ /**
107
+ * A decoded Cursor-native tool call, in the same shape the rest of the gateway
108
+ * already reasons about.
109
+ *
110
+ * `variant` is carried rather than discarded so a result can be encoded back
111
+ * into the wire arm it came from. Dropping it would mean `pi_read` in and
112
+ * `read` out, which silently breaks the client's own tool loop.
113
+ */
114
+ export interface CursorNativeToolCall {
115
+ readonly variant: CursorToolVariant;
116
+ readonly name: string;
117
+ readonly callId: string;
118
+ readonly arguments: Record<string, unknown>;
119
+ }
120
+
121
+ /** Which oneof arm a `ToolCall` message carries, as `(field, message)`. */
122
+ type OneofArm = { readonly field: number; readonly payload: Record<string, unknown> };
123
+
124
+ /**
125
+ * Reads the single arm a `ToolCall` is holding.
126
+ *
127
+ * A oneof has exactly one populated field; a message with none is not a tool
128
+ * call at all and is reported as `undefined` rather than guessed at. An arm
129
+ * this layer does not know is also `undefined` — that is what leaves room for
130
+ * MCP to claim it.
131
+ */
132
+ export function cursorToolArm(
133
+ toolCall: Record<string, unknown>,
134
+ ): OneofArm | undefined {
135
+ for (const [key, value] of Object.entries(toolCall)) {
136
+ if (value === null || value === undefined) continue;
137
+ const variant = [...CURSOR_TOOL_VARIANTS.values()].find(
138
+ (entry) => entry.wireType.toLowerCase() === key.toLowerCase(),
139
+ );
140
+ if (variant === undefined) continue;
141
+ return { field: variant.field, payload: value as Record<string, unknown> };
142
+ }
143
+ return undefined;
144
+ }
145
+
146
+ /**
147
+ * Decodes one `ToolCall` into a canonical call, or `undefined` when the arm is
148
+ * not a Cursor-native tool.
149
+ *
150
+ * Arguments come off the variant's `args` sub-message and are normalised to
151
+ * canonical OpenAI-style tool arguments: snake_case keys, all the way down.
152
+ * Cursor's own arms disagree with each other and with the OpenAI spelling, and
153
+ * this is the gateway's translation boundary — the point where a Cursor call
154
+ * becomes a tool call every other protocol can read. Leaving the keys as the
155
+ * wire sent them would make the same tool mean different things depending on
156
+ * which arm happened to carry it.
157
+ */
158
+ export function decodeCursorNativeToolCall(
159
+ callId: string,
160
+ toolCall: Record<string, unknown>,
161
+ ): CursorNativeToolCall | undefined {
162
+ const arm = cursorToolArm(toolCall);
163
+ if (arm === undefined) return undefined;
164
+ const variant = CURSOR_TOOL_VARIANTS.get(arm.field);
165
+ if (variant === undefined) return undefined;
166
+ const args = arm.payload["args"];
167
+ return {
168
+ variant,
169
+ name: variant.name,
170
+ callId,
171
+ arguments: canonicalToolArguments(args),
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Recursive snake_case normalisation of a tool-argument value.
177
+ *
178
+ * OpenAI-style tool arguments are snake_case throughout, nested values
179
+ * included, so the conversion has to walk the whole tree rather than the top
180
+ * level — a Cursor `EditToolArgs` can carry nested objects whose keys would
181
+ * otherwise stay camelCase and be invisible to a client reading the canonical
182
+ * spelling. Array elements are walked for the same reason; a scalar is
183
+ * returned untouched because there is no key to convert.
184
+ */
185
+ export function canonicalToolArguments(value: unknown): Record<string, unknown> {
186
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
187
+ return Object.fromEntries(
188
+ Object.entries(value as Record<string, unknown>).map(([key, child]) => [
189
+ snakeCaseKey(key),
190
+ canonicalToolValue(child),
191
+ ]),
192
+ );
193
+ }
194
+
195
+ function canonicalToolValue(value: unknown): unknown {
196
+ if (Array.isArray(value)) return value.map(canonicalToolValue);
197
+ if (value !== null && typeof value === "object") return canonicalToolArguments(value);
198
+ return value;
199
+ }
200
+
201
+ /** `someKeyName` → `some_key_name`; already-snake keys come back unchanged. */
202
+ function snakeCaseKey(key: string): string {
203
+ return key
204
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
205
+ .replace(/[\s-]+/g, "_")
206
+ .toLowerCase();
207
+ }
208
+
209
+ /**
210
+ * The variant whose args a host-exec frame is carrying.
211
+ *
212
+ * Exec frames name their payload after the args message — `read_args`,
213
+ * `shell_args`, `pi_read_args` — not after the `ToolCall` arm, so the lookup
214
+ * runs off `argsType`. Anything not ending in `_args` is not a tool payload
215
+ * (`id`, `exec_id`, `request_context_args`, …) and is reported as `undefined`.
216
+ */
217
+ export function cursorVariantForExecArgs(
218
+ execServer: Record<string, unknown>,
219
+ ): { readonly variant: CursorToolVariant; readonly args: Record<string, unknown> } | undefined {
220
+ for (const [key, value] of Object.entries(execServer)) {
221
+ if (value === null || value === undefined || !key.endsWith("_args")) continue;
222
+ const wanted = key.slice(0, -"_args".length);
223
+ const variant = [...CURSOR_TOOL_VARIANTS.values()].find((entry) =>
224
+ entry.argsType.toLowerCase().startsWith(wanted.toLowerCase()),
225
+ );
226
+ if (variant === undefined) continue;
227
+ return {
228
+ variant,
229
+ args: canonicalToolArguments(value),
230
+ };
231
+ }
232
+ return undefined;
233
+ }
234
+
235
+ /**
236
+ * The variant an inbound result must be encoded back into.
237
+ *
238
+ * Keyed by `call_id`, which is what the response carries and what the client
239
+ * echoes on the result. Consulted before encoding so a result for a tool this
240
+ * layer never decoded is not invented into some other variant's shape.
241
+ */
242
+ export class CursorToolCallProvenance {
243
+ readonly #byCallId = new Map<string, CursorToolVariant>();
244
+
245
+ record(callId: string, variant: CursorToolVariant): void {
246
+ this.#byCallId.set(callId, variant);
247
+ }
248
+
249
+ lookup(callId: string): CursorToolVariant | undefined {
250
+ return this.#byCallId.get(callId);
251
+ }
252
+
253
+ /** Drops one call's provenance once its result has been encoded. */
254
+ complete(callId: string): void {
255
+ this.#byCallId.delete(callId);
256
+ }
257
+ }
258
+
259
+ /**
260
+ * A tool declaration the gateway can advertise for Cursor-native tools.
261
+ *
262
+ * Kept separate from `ToolDefinition`'s own name on purpose: the canonical name
263
+ * (`pi_read`) is not the name a client's schema would use, so advertising one
264
+ * under the other would make the call/result round trip undecidable.
265
+ */
266
+ export function cursorNativeToolDeclaration(
267
+ variant: CursorToolVariant,
268
+ description: string,
269
+ ): ToolDefinition {
270
+ return {
271
+ name: variant.name,
272
+ description,
273
+ jsonSchema: { type: "object", properties: {} },
274
+ };
275
+ }
@@ -422,6 +422,9 @@ class GithubAdapter extends OpenAICompatibleAdapter {
422
422
  const selectedModelId = autoDecision.modelId;
423
423
  let route = await githubModelRoute(selectedModelId, credential);
424
424
  if (route === undefined) {
425
+ // dynamic-import: discovery module is only loaded when the first
426
+ // request routes to a model id not in the bundled roster; off the hot
427
+ // path for most deployments.
425
428
  const { discoverGithubModels } = await import("./github-discovery");
426
429
  const outboundFetch = context.outbound_fetch;
427
430
  const fetcher = outboundFetch === undefined
@@ -655,7 +658,6 @@ class GithubAdapter extends OpenAICompatibleAdapter {
655
658
  : GITHUB_ENDPOINT_PATH;
656
659
  const url = `${this.#baseUrl(context).replace(/\/+$/, "")}${endpointPath}`;
657
660
  const outboundFetch = context.outbound_fetch ?? this.#fetch ?? globalThis.fetch;
658
- const { postUpstreamJson } = await import("../../../protocol/upstream/post-json");
659
661
  const upstream = await postUpstreamJson(url, headers, payload as Record<string, unknown>, context, outboundFetch);
660
662
  upstream.release();
661
663
  return upstream.res;