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
@@ -159,8 +159,21 @@ export const TRAE_REALMS: Readonly<Record<TraeRealm, TraeRealmConfig>> = {
159
159
  modelListSupported: true,
160
160
  },
161
161
  intl: {
162
- core: "https://core-normal.traeapi.us",
163
- coreFallbacks: ["https://core-normal.trae.ai", "https://coresg-normal.trae.ai"],
162
+ // SG is the primary, not a fallback. Region-routing is a property of the
163
+ // account, not the deployment: an account provisioned into `sg` only
164
+ // authenticates against the SG host, and sending it to the US core answers
165
+ // `1001 "we are not able to authenticate you"`. Accounts with a captured
166
+ // region still resolve to their own host through `TRAE_REGION_CORE_HOSTS`,
167
+ // so moving the default only changes the answer for accounts whose region
168
+ // was never recorded — and SG serves the wider international roster, which
169
+ // makes it the better bet for those than US.
170
+ // Inlined rather than read from `TRAE_REGION_CORE_HOSTS` below: that map is
171
+ // declared after this one, and a `const` forward reference throws at module
172
+ // init. The value must stay identical to `TRAE_REGION_CORE_HOSTS.sg`.
173
+ core: "https://coresg-normal.trae.ai",
174
+ // US stays reachable as a fallback: an account that really is US-provisioned
175
+ // but has no stored region still has to have somewhere to land.
176
+ coreFallbacks: ["https://core-normal.traeapi.us", "https://core-normal.trae.ai"],
164
177
  account: "https://grow-normal.trae.ai",
165
178
  accountFallbacks: ["https://grow-normal.traeapi.us"],
166
179
  pay: "https://grow-normal.traeapi.us",
@@ -1,9 +1,8 @@
1
1
  // Trae adapter.
2
2
  //
3
3
  // Realm-aware: `trae` (intl) and `traecn` (CN) share this code but nothing of
4
- // the address, the authorization scheme, or the roster. The intl deployment
5
- // additionally gates on the *current* client version, which is why the version
6
- // here comes from `getTraeVersion()` (a live resolver) rather than a constant.
4
+ // the address or the roster. Both realms authenticate with
5
+ // `Authorization: Cloud-IDE-JWT <token>` per the Trae 1.107.1 bundle.
7
6
 
8
7
  import { GatewayError } from "../../../protocol/gateway-error";
9
8
  import type { CanonicalEvent, CanonicalRequest, CanonicalStopReason } from "../../../protocol/canonical-model";
@@ -16,7 +15,6 @@ import {
16
15
  type ProviderId,
17
16
  } from "../../provider-contracts";
18
17
  import { mapUpstreamHttpError } from "../../../transport/failure-policy";
19
- import { getTraeVersion } from "../../operations/client-versions";
20
18
  import { abortGatewayError, createUpstreamDeadlineLifecycle } from "../../operations/upstream-deadline";
21
19
  import { TRAE_CN_MODELS, TRAE_INTL_MODELS, traeMaxContextWindow } from "./trae-catalog";
22
20
  import { buildTraeHeaders } from "./trae-headers";
@@ -92,14 +90,6 @@ class TraeAdapter implements ProviderAdapter {
92
90
  readonly provider_id: ProviderId;
93
91
  private readonly realm: TraeRealm;
94
92
  private readonly fetchFn: typeof fetch;
95
- /**
96
- * Maps a frame's `index` to the call id seen for it.
97
- *
98
- * Argument fragments arrive without the id, so the association has to be
99
- * remembered between frames rather than read from the fragment itself.
100
- */
101
- readonly #toolCallIds = new Map<string, string>();
102
-
103
93
  constructor(options: TraeAdapterOptions = {}) {
104
94
  this.provider_id = (options.providerId ?? TRAE_PROVIDER_ID) as ProviderId;
105
95
  this.realm = options.realm ?? "intl";
@@ -124,9 +114,6 @@ class TraeAdapter implements ProviderAdapter {
124
114
  const outboundFetch =
125
115
  (context.outbound_fetch as unknown as typeof fetch | undefined) ?? this.fetchFn;
126
116
 
127
- // intl refuses a stale client version with 4015, so the resolved version is
128
- // part of every request rather than a startup detail.
129
- const version = getTraeVersion();
130
117
  const auth = traeAuth(secret, context.credential.account_id);
131
118
  const body = buildTraeChatBody(modelId, request, this.realm);
132
119
  /**
@@ -144,7 +131,6 @@ class TraeAdapter implements ProviderAdapter {
144
131
  realm: this.realm,
145
132
  token: auth.token,
146
133
  uid: auth.uid,
147
- clientVersion: version,
148
134
  stream: true,
149
135
  });
150
136
 
@@ -192,6 +178,9 @@ class TraeAdapter implements ProviderAdapter {
192
178
  yield { type: "response_start", sequence_number: seq++, model: requestModel } as CanonicalEvent;
193
179
  let stopReason: CanonicalStopReason = "stop";
194
180
  let usage: Record<string, unknown> | undefined;
181
+ // Tool ids are scoped to one stream. Argument-only frames from a later
182
+ // request must never inherit an earlier request's id at the same index.
183
+ const toolCallIds = new Map<string, string>();
195
184
  /**
196
185
  * Tool calls arrive fragmented across frames and the id is not repeated.
197
186
  *
@@ -212,8 +201,12 @@ class TraeAdapter implements ProviderAdapter {
212
201
  continue;
213
202
  }
214
203
  if (frame.event === "error") {
215
- const data = frame.data as { message?: unknown };
216
- const message = typeof data.message === "string" ? data.message : "Trae stream error";
204
+ const data = frame.data as { message?: unknown; code?: unknown };
205
+ const message = typeof data.message === "string" && data.message.length > 0
206
+ ? data.message
207
+ : typeof data.code === "number" || typeof data.code === "string"
208
+ ? `Trae stream error (upstream code ${data.code})`
209
+ : "Trae stream error";
217
210
  throw new GatewayError("platform_unavailable", 502, message, {}, "upstream");
218
211
  }
219
212
  if (typeof frame.data !== "object" || frame.data === null) continue;
@@ -245,7 +238,7 @@ class TraeAdapter implements ProviderAdapter {
245
238
  content: { kind: "reasoning", payload: null, summary: flatReasoning },
246
239
  } as CanonicalEvent;
247
240
  }
248
- yield* this.#toolCallDeltas(record["tool_calls"], announced, () => seq++);
241
+ yield* this.#toolCallDeltas(record["tool_calls"], announced, toolCallIds, () => seq++);
249
242
  if (typeof record["finish_reason"] === "string") {
250
243
  stopReason = STOP_REASONS[record["finish_reason"] as string] ?? "stop";
251
244
  }
@@ -277,8 +270,9 @@ class TraeAdapter implements ProviderAdapter {
277
270
  } as CanonicalEvent;
278
271
  }
279
272
  if (typeof payload["finish_reason"] === "string") {
280
- stopReason = STOP_REASONS[payload["finish_reason"]] ?? "stop";
273
+ stopReason = STOP_REASONS[payload["finish_reason"] as string] ?? "stop";
281
274
  }
275
+ yield* this.#toolCallDeltas(payload["tool_calls"], announced, toolCallIds, () => seq++);
282
276
  if (typeof payload["usage"] === "object" && payload["usage"] !== null) {
283
277
  usage = payload["usage"] as Record<string, unknown>;
284
278
  }
@@ -311,6 +305,7 @@ class TraeAdapter implements ProviderAdapter {
311
305
  async *#toolCallDeltas(
312
306
  raw: unknown,
313
307
  announced: Set<string>,
308
+ toolCallIds: Map<string, string>,
314
309
  nextSeq: () => number,
315
310
  ): AsyncIterable<CanonicalEvent> {
316
311
  if (!Array.isArray(raw)) return;
@@ -326,7 +321,7 @@ class TraeAdapter implements ProviderAdapter {
326
321
  const slot = `idx:${index}`;
327
322
 
328
323
  if (declaredId.length > 0) {
329
- this.#toolCallIds.set(slot, declaredId);
324
+ toolCallIds.set(slot, declaredId);
330
325
  // The closing frame repeats a known id with no payload; emitting it
331
326
  // again would append a duplicate empty call.
332
327
  if (announced.has(declaredId)) continue;
@@ -338,11 +333,11 @@ class TraeAdapter implements ProviderAdapter {
338
333
  name: name ?? "",
339
334
  arguments_delta: "",
340
335
  } as CanonicalEvent;
341
- continue;
336
+ if (args.length === 0) continue;
342
337
  }
343
338
 
344
339
  if (args.length === 0) continue;
345
- const id = this.#toolCallIds.get(slot);
340
+ const id = toolCallIds.get(slot);
346
341
  if (id === undefined) continue;
347
342
  yield {
348
343
  type: "tool_call_delta",
@@ -400,7 +395,10 @@ export async function discoverTraeModels(input: {
400
395
  readonly providerId?: string;
401
396
  /** Account region, so the listing is asked of the host that serves it. */
402
397
  readonly region?: string;
403
- }): Promise<readonly { id: string; ctx: number | undefined }[]> {
398
+ }): Promise<readonly {
399
+ id: string;
400
+ ctx: number | undefined;
401
+ }[]> {
404
402
  const headers = buildTraeHeaders({
405
403
  realm: input.realm,
406
404
  token: input.token,
@@ -39,15 +39,40 @@ const CLOSE_TAGS = ["</thinking>", "</think>"] as const;
39
39
  * Both case variants pass through: `<Think>` and `<THINK>` survived everyone's
40
40
  * normalizer long enough for them not to be the leak this closes.
41
41
  */
42
+ /**
43
+ * Removes visible thinking tags, leaving any that sit inside a code span or
44
+ * fence alone.
45
+ *
46
+ * A tag inside backticks is the *subject* of the answer — documentation or a
47
+ * code sample showing the tag — not markup the upstream leaked, so stripping it
48
+ * would silently rewrite the answer.
49
+ */
42
50
  export function stripThinkingTags(value: string): string {
43
51
  if (!value.includes("<")) return value;
44
- // Both the open-close pair and a stray marker on its own: an upstream that
45
- // dropped the opening tag before `reasoning_content` was committed still
46
- // leaves the closing one behind, and the lone tag reads just as badly to the
47
- // client as a paired one.
48
- return value
49
- .replace(/<think(?:ing)?\b[^>]*>/g, "")
50
- .replace(/<\/think(?:ing)?\s*>/g, "");
52
+ const pattern = /<think(?:ing)?\b[^>]*>|<\/think(?:ing)?\s*>|`+/g;
53
+ let out = "";
54
+ let last = 0;
55
+ let ticks = 0;
56
+ for (const match of value.matchAll(pattern)) {
57
+ const text = match[0];
58
+ const index = match.index ?? 0;
59
+ if (text.startsWith("`")) {
60
+ // A fence and an inline span are both just "inside code" here: the
61
+ // distinguishing case (a newline closing an unterminated span) cannot
62
+ // affect a tag already indexed in a settled string.
63
+ if (ticks === 0) {
64
+ ticks = text.length;
65
+ } else if (text.length === ticks) {
66
+ ticks = 0;
67
+ }
68
+ continue;
69
+ }
70
+ // Inside code: keep the tag verbatim.
71
+ if (ticks > 0) continue;
72
+ out += value.slice(last, index);
73
+ last = index + text.length;
74
+ }
75
+ return out + value.slice(last);
51
76
  }
52
77
 
53
78
  /** The longest suffix of `text` that is a proper prefix of any tag. */
@@ -74,6 +99,14 @@ export interface ThinkSplit {
74
99
  readonly reasoning: string;
75
100
  }
76
101
 
102
+ /** A tag match plus the code state at the match, so the caller commits it. */
103
+ interface TagMatch {
104
+ readonly index: number;
105
+ readonly length: number;
106
+ readonly codeTicks: number;
107
+ readonly codeFenced: boolean;
108
+ }
109
+
77
110
  /**
78
111
  * Splits one upstream text chunk into answer text and reasoning text.
79
112
  *
@@ -83,6 +116,14 @@ export interface ThinkSplit {
83
116
  export class MimoThinkSplitter {
84
117
  #buffer = "";
85
118
  #inReasoning = false;
119
+ /** Backtick run that opened the code span/fence we are inside; 0 when not in
120
+ * code. A tag inside a code span is the *subject* of the answer — a doc or a
121
+ * code sample mentioning `<think>` — not a delimiter, so it must survive
122
+ * verbatim instead of splitting the stream. */
123
+ #codeTicks = 0;
124
+ /** Whether `#codeTicks` opened a fenced block (closes on its own line) rather
125
+ * than an inline span. */
126
+ #codeFenced = false;
86
127
 
87
128
  /** Feeds a chunk; returns the text/reasoning split for everything settled. */
88
129
  push(chunk: string): ThinkSplit {
@@ -94,14 +135,14 @@ export class MimoThinkSplitter {
94
135
  if (!this.#inReasoning) {
95
136
  const opened = this.#findOpen();
96
137
  if (opened === undefined) break;
97
- text += this.#buffer.slice(0, opened.index);
138
+ text += this.#consumeUpTo(opened);
98
139
  this.#buffer = this.#buffer.slice(opened.index + opened.length);
99
140
  this.#inReasoning = true;
100
141
  continue;
101
142
  }
102
143
  const closed = this.#findClose();
103
144
  if (closed === undefined) break;
104
- reasoning += this.#buffer.slice(0, closed.index);
145
+ reasoning += this.#consumeUpTo(closed);
105
146
  this.#buffer = this.#buffer.slice(closed.index + closed.length);
106
147
  this.#inReasoning = false;
107
148
  }
@@ -125,29 +166,64 @@ export class MimoThinkSplitter {
125
166
  flush(): ThinkSplit {
126
167
  const rest = this.#buffer;
127
168
  this.#buffer = "";
169
+ this.#codeTicks = 0;
170
+ this.#codeFenced = false;
128
171
  return this.#inReasoning
129
172
  ? { text: "", reasoning: rest }
130
173
  : { text: stripThinkingTags(rest), reasoning: "" };
131
174
  }
132
175
 
133
- #findOpen(): { index: number; length: number } | undefined {
134
- let best: { index: number; length: number } | undefined;
135
- for (const tag of OPEN_TAGS) {
136
- const index = this.#buffer.indexOf(tag);
137
- if (index === -1) continue;
138
- if (best === undefined || index < best.index) best = { index, length: tag.length };
139
- }
140
- return best;
176
+ /** Returns the text before a tag and commits the code state at it. */
177
+ #consumeUpTo(match: TagMatch): string {
178
+ this.#codeTicks = match.codeTicks;
179
+ this.#codeFenced = match.codeFenced;
180
+ return this.#buffer.slice(0, match.index);
181
+ }
182
+
183
+ #findOpen(): TagMatch | undefined {
184
+ return this.#findTag(OPEN_TAGS);
185
+ }
186
+
187
+ #findClose(): TagMatch | undefined {
188
+ return this.#findTag(CLOSE_TAGS);
141
189
  }
142
190
 
143
- #findClose(): { index: number; length: number } | undefined {
144
- let best: { index: number; length: number } | undefined;
145
- for (const tag of CLOSE_TAGS) {
146
- const index = this.#buffer.indexOf(tag);
147
- if (index === -1) continue;
148
- if (best === undefined || index < best.index) best = { index, length: tag.length };
191
+ /**
192
+ * The earliest occurrence of any of `tags` that is *not* inside a code span
193
+ * or fence, scanning left to right so code state is tracked exactly once per
194
+ * position. Returns the match and the code state at it, so `push` can commit
195
+ * that state when it consumes the tag.
196
+ */
197
+ #findTag(tags: readonly string[]): TagMatch | undefined {
198
+ const buffer = this.#buffer;
199
+ let ticks = this.#codeTicks;
200
+ let fenced = this.#codeFenced;
201
+ for (let i = 0; i < buffer.length; i++) {
202
+ const char = buffer[i];
203
+ if (char === "`") {
204
+ let run = 1;
205
+ while (buffer[i + run] === "`") run++;
206
+ if (ticks === 0) {
207
+ ticks = run;
208
+ // Three or more backticks open a fence rather than an inline span.
209
+ fenced = run >= 3;
210
+ } else if (run === ticks) {
211
+ ticks = 0;
212
+ fenced = false;
213
+ }
214
+ i += run - 1;
215
+ continue;
216
+ }
217
+ // A newline closes an inline span that never closed on its own line; a
218
+ // fence runs to a closing line instead.
219
+ if (char === "\n" && ticks > 0 && !fenced) ticks = 0;
220
+ if (char !== "<" || ticks > 0) continue;
221
+ for (const tag of tags) {
222
+ if (!buffer.startsWith(tag, i)) continue;
223
+ return { index: i, length: tag.length, codeTicks: ticks, codeFenced: fenced };
224
+ }
149
225
  }
150
- return best;
226
+ return undefined;
151
227
  }
152
228
  }
153
229
 
@@ -25,8 +25,8 @@
25
25
  import {
26
26
  nonEmptyTrimmedString,
27
27
  readJsonResponse,
28
- record,
29
28
  } from "../../authentication/oauth-flow-store";
29
+ import { asRecord as record } from "../../../shared/coerce";
30
30
  import type {
31
31
  OAuthAuthorizeRequest,
32
32
  OAuthExchangeResult,