cartethyia 2.7.4 → 2.7.5

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 (553) hide show
  1. package/.env.example +2 -0
  2. package/README.md +17 -5
  3. package/dist/dashboard/assets/{BannedPage-ChG5svFb.js → BannedPage-Cj15GsMp.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-Cj15GsMp.js.gz +0 -0
  5. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js +1 -0
  6. package/dist/dashboard/assets/ClaimGiftsButton-D83pBJ6J.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolDetailPage-BIcWQun7.js → CliToolDetailPage-DZKmVuJN.js} +1 -1
  8. package/dist/dashboard/assets/CliToolDetailPage-DZKmVuJN.js.gz +0 -0
  9. package/dist/dashboard/assets/{CliToolsPage-Bf2VelDe.js → CliToolsPage-BIccZmeL.js} +1 -1
  10. package/dist/dashboard/assets/CliToolsPage-BIccZmeL.js.gz +0 -0
  11. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js +1 -0
  12. package/dist/dashboard/assets/CombosPage-DEEKkYD-.js.gz +0 -0
  13. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js +1 -0
  14. package/dist/dashboard/assets/ConsoleLogPage-D5rol2j2.js.gz +0 -0
  15. package/dist/dashboard/assets/{CustomizationPage-ggeMSjte.js → CustomizationPage-BKj_r0rp.js} +1 -1
  16. package/dist/dashboard/assets/CustomizationPage-BKj_r0rp.js.gz +0 -0
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js +656 -0
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-B5nZvmf0.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-U6AKaJcF.js → LoginPage-DkXb6dx-.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-DkXb6dx-.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-BMS2t8BA.js → ModelPicker-DnQPSIA8.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-DnQPSIA8.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-Ci2wQKUz.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js +5 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-odlgYrOg.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-EfeloBn4.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CqFBQEB8.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-lsrx7NYg.js → ProxyPage-5SnUSy3j.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-5SnUSy3j.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-CmnMDzhP.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-BJtRZ4qD.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-f0DE1h0-.js → SetupPage-WTa0sktC.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-WTa0sktC.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-Cq5tW7hW.js → StudioPage-BfAb5-o_.js} +3 -3
  40. package/dist/dashboard/assets/StudioPage-BfAb5-o_.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-BNzeZ2Vk.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-l29JROPv.js +1 -0
  44. package/dist/dashboard/assets/api-keys-l29JROPv.js.gz +0 -0
  45. package/dist/dashboard/assets/app--PJWq8_C.css +2 -0
  46. package/dist/dashboard/assets/app--PJWq8_C.css.gz +0 -0
  47. package/dist/dashboard/assets/assert-C0K-c4eo.js +1 -0
  48. package/dist/dashboard/assets/assert-C0K-c4eo.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-D9CS6dZk.js → badge-DfbhQU4k.js} +1 -1
  50. package/dist/dashboard/assets/badge-DfbhQU4k.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-DympBNq4.js → banner-BllT4LcF.js} +1 -1
  52. package/dist/dashboard/assets/banner-BllT4LcF.js.gz +0 -0
  53. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  54. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  55. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  56. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  57. package/dist/dashboard/assets/{card-ibRWU_uT.js → card-CtkX66Wd.js} +1 -1
  58. package/dist/dashboard/assets/card-CtkX66Wd.js.gz +0 -0
  59. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js +1 -0
  60. package/dist/dashboard/assets/chevron-left-Bf6CaTSJ.js.gz +0 -0
  61. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js +1 -0
  62. package/dist/dashboard/assets/cli-tools-CQXVMn4P.js.gz +0 -0
  63. package/dist/dashboard/assets/{clipboard-button-DJm-9pz7.js → clipboard-button-BQqBQd2n.js} +1 -1
  64. package/dist/dashboard/assets/clipboard-button-BQqBQd2n.js.gz +0 -0
  65. package/dist/dashboard/assets/{dialog-8fiE6tec.js → dialog-BEK7KP0H.js} +1 -1
  66. package/dist/dashboard/assets/dialog-BEK7KP0H.js.gz +0 -0
  67. package/dist/dashboard/assets/{drawer-CqGYeOrd.js → drawer-BrTEZ8zu.js} +1 -1
  68. package/dist/dashboard/assets/drawer-BrTEZ8zu.js.gz +0 -0
  69. package/dist/dashboard/assets/entry-CHWxbS56.js +1 -0
  70. package/dist/dashboard/assets/entry-CHWxbS56.js.gz +0 -0
  71. package/dist/dashboard/assets/{entry-BSAsYsmV.js → entry-EBHJ3DrE.js} +1 -1
  72. package/dist/dashboard/assets/entry-EBHJ3DrE.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-LCS85hiq.js +4 -0
  74. package/dist/dashboard/assets/entry-LCS85hiq.js.gz +0 -0
  75. package/dist/dashboard/assets/{formatters-D-MTJxMr.js → formatters-BAACA727.js} +1 -1
  76. package/dist/dashboard/assets/formatters-BAACA727.js.gz +0 -0
  77. package/dist/dashboard/assets/{github-badge-CPK47xQx.js → github-badge-YSCE4UC2.js} +1 -1
  78. package/dist/dashboard/assets/github-badge-YSCE4UC2.js.gz +0 -0
  79. package/dist/dashboard/assets/{index-DBNPOfhV.js → index-FQlj0HUT.js} +2 -2
  80. package/dist/dashboard/assets/index-FQlj0HUT.js.gz +0 -0
  81. package/dist/dashboard/assets/{inline-BT0zntEr.js → inline-C4gU5iOL.js} +1 -1
  82. package/dist/dashboard/assets/inline-C4gU5iOL.js.gz +0 -0
  83. package/dist/dashboard/assets/{input-Da2ZViWg.js → input-BHHX_Tmm.js} +1 -1
  84. package/dist/dashboard/assets/input-BHHX_Tmm.js.gz +0 -0
  85. package/dist/dashboard/assets/{layout-BXNeLw6M.js → layout-CajrYUnD.js} +1 -1
  86. package/dist/dashboard/assets/layout-CajrYUnD.js.gz +0 -0
  87. package/dist/dashboard/assets/{list-row-BycOrrIV.js → list-row-Bx2I7XUe.js} +1 -1
  88. package/dist/dashboard/assets/list-row-Bx2I7XUe.js.gz +0 -0
  89. package/dist/dashboard/assets/live-DNNqRbj2.js +1 -0
  90. package/dist/dashboard/assets/live-DNNqRbj2.js.gz +0 -0
  91. package/dist/dashboard/assets/network-C5UBACrJ.js +1 -0
  92. package/dist/dashboard/assets/network-C5UBACrJ.js.gz +0 -0
  93. package/dist/dashboard/assets/numbers-CUWAZK4J.js +2 -0
  94. package/dist/dashboard/assets/numbers-CUWAZK4J.js.gz +0 -0
  95. package/dist/dashboard/assets/pagination-Xsi9Qx04.js +1 -0
  96. package/dist/dashboard/assets/pagination-Xsi9Qx04.js.gz +0 -0
  97. package/dist/dashboard/assets/quota-DvQbD_sr.js +1 -0
  98. package/dist/dashboard/assets/quota-DvQbD_sr.js.gz +0 -0
  99. package/dist/dashboard/assets/routing-in0f_IfK.js +1 -0
  100. package/dist/dashboard/assets/routing-in0f_IfK.js.gz +0 -0
  101. package/dist/dashboard/assets/{select-BIYIBkMU.js → select-BLULNqTp.js} +1 -1
  102. package/dist/dashboard/assets/select-BLULNqTp.js.gz +0 -0
  103. package/dist/dashboard/assets/settings-CcGczj6I.js +1 -0
  104. package/dist/dashboard/assets/settings-CcGczj6I.js.gz +0 -0
  105. package/dist/dashboard/assets/shield-BMQNxORh.js +1 -0
  106. package/dist/dashboard/assets/shield-BMQNxORh.js.gz +0 -0
  107. package/dist/dashboard/assets/{stack-DfgnFDWY.js → stack-D2lIR0tg.js} +1 -1
  108. package/dist/dashboard/assets/stack-D2lIR0tg.js.gz +0 -0
  109. package/dist/dashboard/assets/{state-CkfdYWel.js → state-DTARjfiW.js} +1 -1
  110. package/dist/dashboard/assets/state-DTARjfiW.js.gz +0 -0
  111. package/dist/dashboard/assets/{switch-SYm237HG.js → switch-c0oPSnqW.js} +1 -1
  112. package/dist/dashboard/assets/switch-c0oPSnqW.js.gz +0 -0
  113. package/dist/dashboard/assets/{useMutation-BQqCRNIi.js → useMutation-m8WGNPrz.js} +1 -1
  114. package/dist/dashboard/assets/useMutation-m8WGNPrz.js.gz +0 -0
  115. package/dist/dashboard/console-backgrounds.jpg +0 -0
  116. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  117. package/dist/dashboard/index.html +2 -2
  118. package/dist/dashboard/index.html.gz +0 -0
  119. package/dist/dashboard/precompressed-assets.json +56 -55
  120. package/migrations/full-postgres/0036_system_prompt_presets_refs.sql +10 -0
  121. package/migrations/full-postgres/0037_share_concurrency_scope.sql +3 -0
  122. package/migrations/full-postgres/0038_add_accounts_quota_snapshot.sql +7 -0
  123. package/migrations/full-postgres/0039_add_telemetry_provider_model_indexes.sql +13 -0
  124. package/migrations/full-postgres/0040_add_models_dialect.sql +3 -0
  125. package/migrations/full-postgres/0041_add_daily_checkin_ledger_account_fk.sql +7 -0
  126. package/migrations/lite-sqlite3/0036_system_prompt_presets_refs.sql +14 -0
  127. package/migrations/lite-sqlite3/0037_share_concurrency_scope.sql +3 -0
  128. package/migrations/lite-sqlite3/0038_add_accounts_quota_snapshot.sql +4 -0
  129. package/migrations/lite-sqlite3/0039_add_telemetry_provider_model_indexes.sql +6 -0
  130. package/migrations/lite-sqlite3/0040_add_models_dialect.sql +3 -0
  131. package/migrations/lite-sqlite3/0041_add_daily_checkin_ledger_account_fk.sql +26 -0
  132. package/package.json +4 -6
  133. package/scripts/cli/update.ts +15 -41
  134. package/src/boot/app.ts +58 -2
  135. package/src/boot/dependencies.ts +786 -732
  136. package/src/boot/lifecycle.ts +11 -12
  137. package/src/config/cooldowns.ts +34 -55
  138. package/src/config/network.ts +1 -1
  139. package/src/config/package-paths.ts +1 -1
  140. package/src/config/providers.ts +13 -14
  141. package/src/config/resources.ts +0 -5
  142. package/src/config/runtime.ts +2 -5
  143. package/src/config/spec.ts +26 -6
  144. package/src/console/api-keys/ban-constants.ts +38 -0
  145. package/src/console/api-keys/contracts.ts +71 -62
  146. package/src/console/api-keys/routes.ts +48 -12
  147. package/src/console/auth/access.ts +4 -4
  148. package/src/console/auth/account-reset.ts +1 -1
  149. package/src/console/auth/audit-recorder.ts +1 -1
  150. package/src/console/auth/lockout.ts +7 -3
  151. package/src/console/auth/row-coercion.ts +57 -12
  152. package/src/console/auth/session-resolver.ts +1 -1
  153. package/src/console/auth/session-service.ts +8 -2
  154. package/src/console/auth/session.ts +37 -31
  155. package/src/console/auth/setup-service.ts +4 -3
  156. package/src/console/auth/user-store.ts +1 -1
  157. package/src/console/backup/9router-map.ts +0 -3
  158. package/src/console/backup/contracts.ts +9 -9
  159. package/src/console/backup/export-endpoint.ts +5 -6
  160. package/src/console/backup/nine-router.ts +1 -7
  161. package/src/console/backup/routes.ts +29 -33
  162. package/src/console/backup/service.ts +468 -468
  163. package/src/console/backup/store.ts +47 -29
  164. package/src/console/backup/validate.ts +11 -1
  165. package/src/console/cli-tools/contracts.ts +7 -7
  166. package/src/console/cli-tools/injectors/cline.ts +110 -110
  167. package/src/console/cli-tools/injectors/codex.ts +181 -181
  168. package/src/console/cli-tools/injectors/copilot.ts +108 -108
  169. package/src/console/cli-tools/injectors/driver.ts +247 -247
  170. package/src/console/cli-tools/injectors/jcode.ts +115 -115
  171. package/src/console/cli-tools/injectors/openclaw.ts +161 -161
  172. package/src/console/cli-tools/injectors/opencode.ts +153 -153
  173. package/src/console/cli-tools/routes.ts +1 -1
  174. package/src/console/cli-tools/service.ts +1 -1
  175. package/src/console/cli-tools/store.ts +2 -2
  176. package/src/console/console-router.ts +32 -0
  177. package/src/console/dashboard-assets.ts +9 -9
  178. package/src/console/domain-registration.ts +16 -2
  179. package/src/console/inferhub/client.ts +0 -7
  180. package/src/console/inferhub/key-store.ts +1 -1
  181. package/src/console/inferhub/normalize.ts +2 -2
  182. package/src/console/inferhub/routes.ts +1 -1
  183. package/src/console/inferhub/types.ts +1 -1
  184. package/src/console/observability/contracts.ts +1 -1
  185. package/src/console/observability/live.ts +31 -18
  186. package/src/console/observability/logs.ts +1 -1
  187. package/src/console/observability/sse.ts +62 -8
  188. package/src/console/observability/store.ts +20 -4
  189. package/src/console/providers/catalog/catalog-projections.ts +1 -1
  190. package/src/console/providers/catalog/contracts.ts +39 -0
  191. package/src/console/providers/catalog/model-operations.ts +1 -1
  192. package/src/console/providers/catalog/provider-operations.ts +95 -17
  193. package/src/console/providers/catalog/public-model-store.ts +0 -0
  194. package/src/console/providers/catalog/routes.ts +27 -3
  195. package/src/console/providers/catalog/store.ts +147 -8
  196. package/src/console/providers/detail/routes.ts +1 -1
  197. package/src/console/providers/oauth/callback-listener.ts +100 -18
  198. package/src/console/providers/oauth/routes.ts +92 -13
  199. package/src/console/quota/account-quota-global.ts +41 -3
  200. package/src/console/quota/account-quota-shared.ts +10 -3
  201. package/src/console/quota/account-quota-tenant.ts +259 -66
  202. package/src/console/quota/daily-growth-job.ts +308 -0
  203. package/src/console/quota/native-identity.ts +2 -2
  204. package/src/console/quota/quota-view.ts +1 -1
  205. package/src/console/remote-support/routes.ts +1 -1
  206. package/src/console/remote-support/service.ts +2 -2
  207. package/src/console/routing/model/contracts.ts +1 -1
  208. package/src/console/routing/pools/contracts.ts +2 -2
  209. package/src/console/routing/pools/import-parse.ts +3 -3
  210. package/src/console/routing/pools/relay-deploy.ts +3 -3
  211. package/src/console/settings/contracts.ts +29 -2
  212. package/src/console/settings/store.ts +20 -0
  213. package/src/console/share/share-router.ts +100 -32
  214. package/src/console/share/share-stats.ts +4 -4
  215. package/src/console/share/share-usage.ts +1 -1
  216. package/src/console/shared/errors.ts +2 -2
  217. package/src/console/shared/object.ts +18 -0
  218. package/src/console/shared/read-through-cache.ts +4 -4
  219. package/src/console/shared/transaction.ts +14 -0
  220. package/src/console/system-prompt/contracts.ts +89 -12
  221. package/src/console/system-prompt/routes.ts +98 -45
  222. package/src/console/updates/apply-update.ts +244 -0
  223. package/src/console/updates/routes.ts +252 -97
  224. package/src/main.ts +11 -5
  225. package/src/network/http2-bidi.ts +1 -1
  226. package/src/network/ip-utils.ts +298 -0
  227. package/src/network/outbound-fetch.ts +1 -1
  228. package/src/network/pool/agent.ts +7 -6
  229. package/src/network/pool/byte-accounting.ts +1 -1
  230. package/src/network/pool/resolver.ts +16 -12
  231. package/src/network/pool/selector.ts +150 -136
  232. package/src/network/pool-health-machine.ts +1 -1
  233. package/src/network/rate-limit-verdict.ts +1 -1
  234. package/src/network/retry.ts +1 -1
  235. package/src/network/ssrf.ts +20 -71
  236. package/src/observability/event-log.ts +2 -2
  237. package/src/observability/event-query.ts +59 -291
  238. package/src/observability/log-sanitize.ts +1 -1
  239. package/src/observability/metrics.ts +4 -4
  240. package/src/observability/payload-capture.ts +6 -5
  241. package/src/observability/payload-store.ts +1 -1
  242. package/src/observability/runtime-metrics.ts +1 -1
  243. package/src/observability/telemetry-buffer.ts +12 -3
  244. package/src/observability/telemetry-reconciliation.ts +3 -3
  245. package/src/observability/token-speed.ts +1 -1
  246. package/src/persistence/connection-url.ts +1 -1
  247. package/src/persistence/db-handle.ts +1 -1
  248. package/src/persistence/db-pg.ts +2 -2
  249. package/src/persistence/db-sqlite.ts +3 -3
  250. package/src/persistence/dialect.ts +5 -1
  251. package/src/persistence/readiness.ts +1 -1
  252. package/src/persistence/redis.ts +1 -1
  253. package/src/persistence/schema.ts +113 -40
  254. package/src/persistence/shared-cache.ts +2 -2
  255. package/src/persistence/sort-order.ts +1 -1
  256. package/src/persistence/stores/api-key-store.ts +10 -1
  257. package/src/persistence/stores/share-store.ts +20 -8
  258. package/src/persistence/system-prompt-store.ts +63 -18
  259. package/src/persistence/tenant-preferences.ts +1 -1
  260. package/src/persistence/ttl-cache.ts +3 -3
  261. package/src/persistence/usage-flush.ts +7 -2
  262. package/src/protocol/canonical-model.ts +1 -1
  263. package/src/protocol/codecs.ts +6 -10
  264. package/src/protocol/dsml.ts +3 -49
  265. package/src/protocol/image-clamp.ts +2 -2
  266. package/src/protocol/reasoning-text.ts +1 -1
  267. package/src/protocol/reasoning.ts +7 -52
  268. package/src/protocol/registry.ts +50 -15
  269. package/src/protocol/request/chat.ts +46 -19
  270. package/src/protocol/request/codex.ts +1 -1
  271. package/src/protocol/request/messages.ts +46 -14
  272. package/src/protocol/request/responses.ts +19 -10
  273. package/src/protocol/response/chat.ts +25 -10
  274. package/src/protocol/response/codex.ts +1 -1
  275. package/src/protocol/response/messages.ts +1 -1
  276. package/src/protocol/response/omp-tool-call-markup.ts +1 -1
  277. package/src/protocol/response/responses.ts +1 -1
  278. package/src/protocol/sse-decoder.ts +50 -1
  279. package/src/protocol/stop-reason.ts +2 -2
  280. package/src/protocol/think-split.ts +347 -0
  281. package/src/protocol/translation/attachment-integrity.ts +3 -3
  282. package/src/protocol/translation/cache-controls.ts +8 -20
  283. package/src/protocol/translation/capabilities.ts +6 -6
  284. package/src/protocol/translation/dialect/deepseek.ts +10 -0
  285. package/src/protocol/translation/dialect/inband.ts +39 -0
  286. package/src/protocol/translation/dialect/model-thinking.ts +89 -0
  287. package/src/protocol/translation/dialect/qwen.ts +114 -0
  288. package/src/protocol/translation/dialect/resolver.ts +83 -0
  289. package/src/protocol/translation/dialect/rules.ts +93 -0
  290. package/src/protocol/translation/dialect/thinking-ladder.ts +245 -0
  291. package/src/protocol/translation/dialect/types.ts +58 -0
  292. package/src/protocol/translation/quirks.ts +18 -4
  293. package/src/protocol/translation/thinking.ts +12 -252
  294. package/src/protocol/translation/tool-id.ts +3 -3
  295. package/src/protocol/translation/tool-repair.ts +1 -1
  296. package/src/protocol/upstream/post-json.ts +6 -1
  297. package/src/providers/adapters/compatible-adapter.ts +42 -3
  298. package/src/providers/authentication/jwt-validator.ts +0 -5
  299. package/src/providers/authentication/oauth-client.ts +254 -253
  300. package/src/providers/authentication/oauth-flow-store.ts +42 -7
  301. package/src/providers/bundled-discovery-providers.ts +6 -30
  302. package/src/providers/configured-openai-providers.ts +82 -97
  303. package/src/providers/default-registry.ts +23 -35
  304. package/src/providers/discovery/catalog/catalog-format.ts +13 -2
  305. package/src/providers/discovery/discovery-types.ts +0 -1
  306. package/src/providers/discovery/openai-model-discovery.ts +2 -2
  307. package/src/providers/discovery/probe-phases.ts +48 -13
  308. package/src/providers/discovery/probing-service.ts +6 -8
  309. package/src/providers/integrations/agentrouter/agentrouter.ts +12 -2
  310. package/src/providers/integrations/antigravity/antigravity-oauth.ts +0 -1
  311. package/src/providers/integrations/antigravity/antigravity-protocol.ts +0 -14
  312. package/src/providers/integrations/antigravity/antigravity.ts +2 -2
  313. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +1 -1
  314. package/src/providers/integrations/buddy/buddy-chat-shared.ts +20 -4
  315. package/src/providers/integrations/buddy/buddy-cli-headers.ts +19 -52
  316. package/src/providers/integrations/buddy/buddy-identity.ts +86 -0
  317. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +1 -1
  318. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +1 -2
  319. package/src/providers/integrations/buddy/codebuddy/provider.ts +4 -15
  320. package/src/providers/integrations/buddy/codebuddy/shared.ts +30 -9
  321. package/src/providers/integrations/buddy/workbuddy/provider.ts +5 -9
  322. package/src/providers/integrations/buddy/workbuddy/shared.ts +21 -3
  323. package/src/providers/integrations/claude/claude-cch.ts +148 -148
  324. package/src/providers/integrations/claude/fallback-credit.ts +3 -7
  325. package/src/providers/integrations/cline/cline.ts +1 -1
  326. package/src/providers/integrations/codex/codex-device-code.ts +101 -101
  327. package/src/providers/integrations/codex/codex-oauth.ts +0 -1
  328. package/src/providers/integrations/commandcode/commandcode.ts +75 -115
  329. package/src/providers/integrations/commandcode/quota.ts +131 -51
  330. package/src/providers/integrations/cursor/cursor-http2.ts +0 -3
  331. package/src/providers/integrations/cursor/cursor-quota.ts +2 -6
  332. package/src/providers/integrations/cursor/cursor-request.ts +0 -87
  333. package/src/providers/integrations/cursor/cursor-shared.ts +0 -4
  334. package/src/providers/integrations/cursor/cursor.ts +38 -5
  335. package/src/providers/integrations/cursor/protocol/framing.ts +0 -56
  336. package/src/providers/integrations/cursor/protocol/messages.ts +0 -96
  337. package/src/providers/integrations/factory/factory.ts +9 -9
  338. package/src/providers/integrations/github/github-discovery.ts +55 -10
  339. package/src/providers/integrations/github/github-oauth.ts +6 -5
  340. package/src/providers/integrations/github/github.ts +41 -14
  341. package/src/providers/integrations/grok/grok-oauth.ts +261 -261
  342. package/src/providers/integrations/grok/grok-quota-frame.ts +1 -1
  343. package/src/providers/integrations/grok/grok-quota.ts +16 -7
  344. package/src/providers/integrations/grok/grok-ratelimit-store.ts +0 -5
  345. package/src/providers/integrations/grok/grok-ratelimit.ts +3 -0
  346. package/src/providers/integrations/grok/grok.ts +86 -36
  347. package/src/providers/integrations/kilo/kilo-oauth.ts +1 -1
  348. package/src/providers/integrations/kiro/kiro-cache.ts +31 -0
  349. package/src/providers/integrations/kiro/kiro-catalog.ts +31 -5
  350. package/src/providers/integrations/kiro/kiro-discovery.ts +47 -43
  351. package/src/providers/integrations/kiro/kiro-machine-id.ts +6 -3
  352. package/src/providers/integrations/kiro/kiro-oauth.ts +523 -255
  353. package/src/providers/integrations/kiro/kiro-quota.ts +35 -47
  354. package/src/providers/integrations/kiro/kiro-request.ts +8 -11
  355. package/src/providers/integrations/kiro/kiro-stream.ts +13 -0
  356. package/src/providers/integrations/kiro/kiro.ts +81 -68
  357. package/src/providers/integrations/muse/muse-oauth.ts +0 -1
  358. package/src/providers/integrations/muse/muse-quota.ts +0 -4
  359. package/src/providers/integrations/opencode/fingerprint.ts +7 -5
  360. package/src/providers/integrations/opencode/provider.ts +17 -24
  361. package/src/providers/integrations/qoder/qoder-catalog.ts +85 -8
  362. package/src/providers/integrations/qoder/qoder-oauth.ts +165 -25
  363. package/src/providers/integrations/qoder/qoder-quota.ts +48 -6
  364. package/src/providers/integrations/qoder/qoder-realm.ts +10 -31
  365. package/src/providers/integrations/qoder/qoder-sse.ts +159 -0
  366. package/src/providers/integrations/qoder/qoder-umid.ts +21 -25
  367. package/src/providers/integrations/qoder/qoder-virtual.ts +12 -0
  368. package/src/providers/integrations/qoder/qoder.ts +354 -62
  369. package/src/providers/integrations/shared/connect.ts +0 -54
  370. package/src/providers/integrations/shared/hash.ts +15 -0
  371. package/src/providers/integrations/shared/session-cache.ts +136 -0
  372. package/src/providers/integrations/trae/trae-cache.ts +7 -87
  373. package/src/providers/integrations/trae/trae-catalog.ts +1 -6
  374. package/src/providers/integrations/trae/trae-protocol.ts +17 -8
  375. package/src/providers/integrations/trae/trae-realm.ts +0 -7
  376. package/src/providers/integrations/trae/trae.ts +53 -10
  377. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  378. package/src/providers/integrations/zcode-start-plan/gifts.ts +265 -0
  379. package/src/providers/integrations/zcode-start-plan/oauth.ts +154 -0
  380. package/src/providers/integrations/zcode-start-plan/provider.ts +131 -0
  381. package/src/providers/integrations/zcode-start-plan/quota.ts +152 -0
  382. package/src/providers/integrations/zcode-start-plan/zcode_prompt.json +10 -0
  383. package/src/providers/operations/account-error-classification.ts +131 -116
  384. package/src/providers/operations/account-health-service.ts +31 -39
  385. package/src/providers/operations/account-reset-service.ts +58 -1
  386. package/src/providers/operations/cli-platform.ts +31 -5
  387. package/src/providers/operations/client-version-resolver.ts +4 -6
  388. package/src/providers/operations/client-versions.ts +10 -7
  389. package/src/providers/operations/provider-catalog-seeder.ts +2 -0
  390. package/src/providers/operations/provider-catalog-service.ts +18 -2
  391. package/src/providers/operations/provider-credential-service.ts +19 -2
  392. package/src/providers/provider-contracts.ts +18 -7
  393. package/src/providers/provider-metadata.ts +17 -2
  394. package/src/providers/provider-model-definition.ts +22 -1
  395. package/src/providers/provider-probe.ts +4 -2
  396. package/src/providers/provider-usage.ts +81 -16
  397. package/src/providers/quota/cache.ts +29 -0
  398. package/src/providers/quota/quota-contracts.ts +4 -0
  399. package/src/providers/quota/refresh.ts +27 -4
  400. package/src/providers/quota/snapshot.ts +94 -0
  401. package/src/providers/search/search-provider.ts +1 -3
  402. package/src/providers/search/search-providers.ts +2 -1
  403. package/src/security/abuse.ts +4 -4
  404. package/src/security/admission/service.ts +2 -2
  405. package/src/security/admission/ttl.ts +61 -61
  406. package/src/security/api-key-auth.ts +16 -4
  407. package/src/security/client-router-fingerprint.ts +4 -4
  408. package/src/security/credential-codec.ts +3 -3
  409. package/src/security/csrf.ts +2 -2
  410. package/src/security/ip-boundary.ts +16 -189
  411. package/src/security/model-access-rule.ts +1 -1
  412. package/src/security/outbound-headers.ts +18 -0
  413. package/src/shared/invoke-guard.ts +47 -0
  414. package/src/transport/contracts.ts +13 -4
  415. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  416. package/src/transport/dispatch/capture-policy.ts +34 -37
  417. package/src/transport/dispatch/empty-stream.ts +23 -20
  418. package/src/transport/dispatch/generation.ts +25 -45
  419. package/src/transport/dispatch/native-shared.ts +127 -0
  420. package/src/transport/dispatch/proxy-request.ts +3 -1
  421. package/src/transport/dispatch/responses-compact.ts +25 -46
  422. package/src/transport/dispatch/streaming/encoder.ts +18 -72
  423. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  424. package/src/transport/dispatch/streaming/stream.ts +7 -3
  425. package/src/transport/dispatch/streaming/thinking-loop.ts +1 -1
  426. package/src/transport/dispatch/systemone.ts +20 -48
  427. package/src/transport/dispatch/token-count.ts +41 -38
  428. package/src/transport/dispatch/websearch.ts +19 -45
  429. package/src/transport/drain-endpoint.ts +1 -1
  430. package/src/transport/failure-policy.ts +6 -0
  431. package/src/transport/guards/auth-guard.ts +0 -6
  432. package/src/transport/guards/body-policy.ts +3 -3
  433. package/src/transport/guards/headroom-guard.ts +1 -1
  434. package/src/transport/guards/pipeline.ts +1 -1
  435. package/src/transport/guards/request-context.ts +12 -17
  436. package/src/transport/request/preparer.ts +286 -7
  437. package/src/transport/request/rtk/compress-request.ts +3 -3
  438. package/src/transport/request/rtk/rtk-constants.ts +2 -2
  439. package/src/transport/request/rtk/rtk-filters.ts +8 -8
  440. package/src/transport/request/state.ts +1 -13
  441. package/src/transport/request/system-prompt-injection.ts +74 -11
  442. package/src/transport/request/tenant-preferences.ts +22 -0
  443. package/src/transport/routing/candidate-index.ts +2 -2
  444. package/src/transport/routing/round-robin.ts +1 -1
  445. package/src/transport/routing/route-catalog.ts +17 -18
  446. package/src/transport/routing/route-model.ts +126 -33
  447. package/src/transport/routing/router.ts +152 -37
  448. package/src/transport/shutdown-notice.ts +2 -2
  449. package/src/transport/surface/adapters.ts +3 -3
  450. package/src/transport/surface/chat/encode.ts +7 -7
  451. package/src/transport/surface/chat/parse.ts +7 -7
  452. package/src/transport/surface/completion.ts +2 -2
  453. package/src/transport/surface/content-parts.ts +1 -1
  454. package/src/transport/surface/dialects.ts +2 -2
  455. package/src/transport/surface/messages/parse.ts +3 -3
  456. package/src/transport/surface/responses/adapter.ts +1 -1
  457. package/src/transport/surface/responses/errors.ts +0 -9
  458. package/src/transport/vision-handoff-cache.ts +58 -0
  459. package/src/transport/vision-handoff.ts +376 -0
  460. package/src/workers/account-identity-sweep.ts +2 -2
  461. package/src/workers/buddy-growth-tasks.ts +392 -346
  462. package/src/workers/daily-checkin.ts +102 -49
  463. package/src/workers/maintenance-lease.ts +2 -35
  464. package/src/workers/oauth-refresh-sweep.ts +8 -1
  465. package/src/workers/quota-refresh-sweep.ts +120 -82
  466. package/src/workers/scheduler.ts +67 -4
  467. package/src/workers/sweep-runner.ts +24 -5
  468. package/src/workers/zcode-gift-claim.ts +108 -0
  469. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js +0 -1
  470. package/dist/dashboard/assets/AccountCooldown-Bjo92Qat.js.gz +0 -0
  471. package/dist/dashboard/assets/BannedPage-ChG5svFb.js.gz +0 -0
  472. package/dist/dashboard/assets/CliToolDetailPage-BIcWQun7.js.gz +0 -0
  473. package/dist/dashboard/assets/CliToolsPage-Bf2VelDe.js.gz +0 -0
  474. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js +0 -1
  475. package/dist/dashboard/assets/CombosPage-DCgm5g6g.js.gz +0 -0
  476. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js +0 -1
  477. package/dist/dashboard/assets/ConsoleLogPage-a8mD0QF1.js.gz +0 -0
  478. package/dist/dashboard/assets/CustomizationPage-ggeMSjte.js.gz +0 -0
  479. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js +0 -1
  480. package/dist/dashboard/assets/HealthEventsModal-DzSWzE_j.js.gz +0 -0
  481. package/dist/dashboard/assets/LoginPage-U6AKaJcF.js.gz +0 -0
  482. package/dist/dashboard/assets/ModelPicker-BMS2t8BA.js.gz +0 -0
  483. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js +0 -1
  484. package/dist/dashboard/assets/OverviewPage-D2D4IiHl.js.gz +0 -0
  485. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js +0 -5
  486. package/dist/dashboard/assets/ProviderDetailPage-CrNf7j_X.js.gz +0 -0
  487. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js +0 -1
  488. package/dist/dashboard/assets/ProviderIcon-FB6yS4v1.js.gz +0 -0
  489. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js +0 -1
  490. package/dist/dashboard/assets/ProvidersPage-BSDbquc1.js.gz +0 -0
  491. package/dist/dashboard/assets/ProxyPage-lsrx7NYg.js.gz +0 -0
  492. package/dist/dashboard/assets/QuotaPage-L0skzML8.js +0 -1
  493. package/dist/dashboard/assets/QuotaPage-L0skzML8.js.gz +0 -0
  494. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js +0 -1
  495. package/dist/dashboard/assets/SettingsPage-CmAbjRHW.js.gz +0 -0
  496. package/dist/dashboard/assets/SetupPage-f0DE1h0-.js.gz +0 -0
  497. package/dist/dashboard/assets/SortableList-ClzpwyET.js +0 -1
  498. package/dist/dashboard/assets/SortableList-ClzpwyET.js.gz +0 -0
  499. package/dist/dashboard/assets/StudioPage-Cq5tW7hW.js.gz +0 -0
  500. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js +0 -56
  501. package/dist/dashboard/assets/UsagePage-Dfc9rWQn.js.gz +0 -0
  502. package/dist/dashboard/assets/api-keys-C38iXoO4.js +0 -1
  503. package/dist/dashboard/assets/api-keys-C38iXoO4.js.gz +0 -0
  504. package/dist/dashboard/assets/app-a159k0ub.css +0 -2
  505. package/dist/dashboard/assets/app-a159k0ub.css.gz +0 -0
  506. package/dist/dashboard/assets/assert-DbRA8EG2.js +0 -15
  507. package/dist/dashboard/assets/assert-DbRA8EG2.js.gz +0 -0
  508. package/dist/dashboard/assets/badge-D9CS6dZk.js.gz +0 -0
  509. package/dist/dashboard/assets/banner-DympBNq4.js.gz +0 -0
  510. package/dist/dashboard/assets/card-ibRWU_uT.js.gz +0 -0
  511. package/dist/dashboard/assets/cli-tools-63qBGaRw.js +0 -1
  512. package/dist/dashboard/assets/cli-tools-63qBGaRw.js.gz +0 -0
  513. package/dist/dashboard/assets/clipboard-button-DJm-9pz7.js.gz +0 -0
  514. package/dist/dashboard/assets/dialog-8fiE6tec.js.gz +0 -0
  515. package/dist/dashboard/assets/drawer-CqGYeOrd.js.gz +0 -0
  516. package/dist/dashboard/assets/entry-BSAsYsmV.js.gz +0 -0
  517. package/dist/dashboard/assets/entry-CiIQULZD.js +0 -4
  518. package/dist/dashboard/assets/entry-CiIQULZD.js.gz +0 -0
  519. package/dist/dashboard/assets/entry-Daz0lJ-W.js +0 -1
  520. package/dist/dashboard/assets/entry-Daz0lJ-W.js.gz +0 -0
  521. package/dist/dashboard/assets/formatters-D-MTJxMr.js.gz +0 -0
  522. package/dist/dashboard/assets/github-badge-CPK47xQx.js.gz +0 -0
  523. package/dist/dashboard/assets/index-DBNPOfhV.js.gz +0 -0
  524. package/dist/dashboard/assets/inline-BT0zntEr.js.gz +0 -0
  525. package/dist/dashboard/assets/input-Da2ZViWg.js.gz +0 -0
  526. package/dist/dashboard/assets/layout-BXNeLw6M.js.gz +0 -0
  527. package/dist/dashboard/assets/list-row-BycOrrIV.js.gz +0 -0
  528. package/dist/dashboard/assets/live-DCQNZpF7.js +0 -1
  529. package/dist/dashboard/assets/live-DCQNZpF7.js.gz +0 -0
  530. package/dist/dashboard/assets/network-9Yj2ZyLo.js +0 -1
  531. package/dist/dashboard/assets/network-9Yj2ZyLo.js.gz +0 -0
  532. package/dist/dashboard/assets/numbers-CEagj6ZZ.js +0 -2
  533. package/dist/dashboard/assets/numbers-CEagj6ZZ.js.gz +0 -0
  534. package/dist/dashboard/assets/quota-Caw7wqci.js +0 -1
  535. package/dist/dashboard/assets/quota-Caw7wqci.js.gz +0 -0
  536. package/dist/dashboard/assets/routing-CO9zCUus.js +0 -1
  537. package/dist/dashboard/assets/routing-CO9zCUus.js.gz +0 -0
  538. package/dist/dashboard/assets/select-BIYIBkMU.js.gz +0 -0
  539. package/dist/dashboard/assets/settings-jS3-PNSA.js +0 -1
  540. package/dist/dashboard/assets/settings-jS3-PNSA.js.gz +0 -0
  541. package/dist/dashboard/assets/stack-DfgnFDWY.js.gz +0 -0
  542. package/dist/dashboard/assets/state-CkfdYWel.js.gz +0 -0
  543. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js +0 -1
  544. package/dist/dashboard/assets/stream-retry-5QnVuSSo.js.gz +0 -0
  545. package/dist/dashboard/assets/switch-SYm237HG.js.gz +0 -0
  546. package/dist/dashboard/assets/useMutation-BQqCRNIi.js.gz +0 -0
  547. package/src/network/response-headers.ts +0 -39
  548. package/src/protocol/response/dsml.ts +0 -38
  549. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +0 -229
  550. /package/dist/dashboard/assets/{app-BayTTy01.js → app-Bgd3zANQ.js} +0 -0
  551. /package/dist/dashboard/assets/{app-BayTTy01.js.gz → app-Bgd3zANQ.js.gz} +0 -0
  552. /package/dist/dashboard/assets/brand/{og_bansos.webp → og_bansos_initial.webp} +0 -0
  553. /package/dist/dashboard/assets/brand/{og_image.webp → og_image_initial.webp} +0 -0
@@ -303,17 +303,6 @@ export function buildHeartbeat(): Uint8Array {
303
303
  return encodeMessage("AgentClientMessage", { client_heartbeat: {} });
304
304
  }
305
305
 
306
- /**
307
- * `ACM#5 exec_client_control_message.heartbeat{id}`: Cursor CLI sends one every
308
- * few seconds for each exec it is still running. A zero id is left out, as
309
- * proto3 does for a default scalar.
310
- */
311
- export function buildExecHeartbeat(execId: number): Uint8Array {
312
- return encodeMessage("AgentClientMessage", {
313
- exec_client_control_message: { heartbeat: execId === 0 ? {} : { id: execId } },
314
- });
315
- }
316
-
317
306
  /** `ACM#5 exec_client_control_message.stream_close{id}` after an exec result. */
318
307
  export function buildExecStreamClose(execId: number, execIdString?: string): Uint8Array {
319
308
  return encodeMessage("AgentClientMessage", {
@@ -424,82 +413,6 @@ export function buildMcpResult(input: {
424
413
  });
425
414
  }
426
415
 
427
- /**
428
- * `ACM#2 exec_client_message{shell_result|write_result|read_result}` for a host
429
- * exec the canonical client executed locally.
430
- *
431
- * Cursor's executor replies to its own host requests with the variant's typed
432
- * result frame (the generic `mcp_result` leaves the server unmatched on a frame
433
- * it did rank), and after every exec result it sends `stream_close` — without
434
- * it the cloud waits forever on shell execs. `is_error` keeps the failure as
435
- * the variant's error/failure case rather than a crafted success.
436
- */
437
- export type CursorHostExecResultVariant = "shell" | "write" | "read";
438
-
439
- export function buildHostExecResult(input: {
440
- readonly execId: number;
441
- readonly execIdString?: string;
442
- readonly variant: CursorHostExecResultVariant;
443
- readonly text: string;
444
- readonly isError: boolean;
445
- readonly host: {
446
- readonly command?: string;
447
- readonly workingDirectory?: string;
448
- readonly path?: string;
449
- readonly lines?: number;
450
- readonly fileSize?: number;
451
- };
452
- }): Uint8Array[] {
453
- const id = { id: input.execId, exec_id: input.execIdString ?? "" };
454
- const variant = input.variant;
455
- const text = input.text;
456
- let result: Record<string, unknown>;
457
- if (variant === "shell") {
458
- result = {
459
- shell_result: input.isError
460
- ? { failure: { command: input.host.command ?? "", exit_code: 1, stderr: text } }
461
- : {
462
- success: {
463
- command: input.host.command ?? "",
464
- exit_code: 0,
465
- stdout: text,
466
- ...(input.host.workingDirectory === undefined ? {} : { working_directory: input.host.workingDirectory }),
467
- },
468
- },
469
- };
470
- } else if (variant === "write") {
471
- result = {
472
- write_result: input.isError
473
- ? { error: { path: input.host.path ?? "", error: text } }
474
- : {
475
- success: {
476
- path: input.host.path ?? "",
477
- lines_created: input.host.lines ?? 0,
478
- file_size: input.host.fileSize ?? 0,
479
- },
480
- },
481
- };
482
- } else {
483
- result = {
484
- read_result: input.isError
485
- ? { error: { path: input.host.path ?? "", error: text } }
486
- : {
487
- success: {
488
- path: input.host.path ?? "",
489
- content: text,
490
- total_lines: text.length > 0 ? text.split("\n").length : 0,
491
- },
492
- },
493
- };
494
- }
495
- return [
496
- encodeMessage("AgentClientMessage", { exec_client_message: { ...id, ...result } }),
497
- // The real CLI pairs every typed exec result with stream_close — the cloud
498
- // waits on it for shell execs specifically.
499
- buildExecStreamClose(input.execId, input.execIdString),
500
- ];
501
- }
502
-
503
416
  /**
504
417
  * `ACM#2 exec_client_message{mcp_result}` rejecting a tool the client never
505
418
  * declared.
@@ -5,7 +5,6 @@
5
5
  // protocol was verified against: they are declared once so the auth flow, the
6
6
  // unary catalog calls, and the Run stream cannot drift apart on host, path, or
7
7
  // client id.
8
- import type { WireFamily } from "../../../protocol/canonical-model";
9
8
 
10
9
  /** Canonical bundled provider id. */
11
10
  export const CURSOR_PROVIDER_ID = "cursor";
@@ -72,9 +71,6 @@ export const SESSION_REFRESH_TIMEOUT_MS = 20_000;
72
71
  */
73
72
  export const RUN_IDLE_TTL_MS = 10 * 60_000;
74
73
 
75
- /** Chat wire is the declared default; the adapter owns the native protocol. */
76
- export const CURSOR_WIRE_FAMILY: WireFamily = "chat";
77
-
78
74
  /**
79
75
  * Any HTTPS subdomain of `cursor.sh` is an acceptable Run host: the region
80
76
  * Cursor routes an account to varies (`agentn.*`, `agent.*`, `api5`, …).
@@ -27,6 +27,7 @@ import type {
27
27
  } from "../../../protocol/canonical-model";
28
28
  import { resolveImageSource, splitDataUrl } from "../../../protocol/codecs";
29
29
  import { IMAGE_CLAMP_MAX_BYTES } from "../../../protocol/image-clamp";
30
+ import { applyCacheMode } from "../../provider-usage";
30
31
  import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
31
32
  import { readCredentialSecret } from "../../provider-contracts";
32
33
  import type { Http2BidiEndReason, ValidatedHttp2BidiStream } from "../../../network/http2-bidi";
@@ -62,6 +63,7 @@ import { defaultParameterValues, fetchCursorModels } from "./cursor-catalog";
62
63
  import type { CursorModelInfo } from "./cursor-catalog";
63
64
  import { decodeValueToJson, decodeStructEntriesToJson } from "./protocol/struct";
64
65
  import { cursorVariantForExecArgs } from "./protocol/tool-canonical";
66
+ import { fnv1a32 } from "../shared/hash";
65
67
 
66
68
  /**
67
69
  * Client-heartbeat cadence for every Cursor Run.
@@ -81,8 +83,38 @@ const CURSOR_HEARTBEAT_INTERVAL_MS = 5_000;
81
83
  * every dispatch.
82
84
  */
83
85
  const CURSOR_ROSTER_TTL_MS = 300_000;
84
- /** credential → { roster, fetchedAt } for the parameter lookup. */
86
+ /**
87
+ * credential → { roster, fetchedAt } for the parameter lookup.
88
+ *
89
+ * Keyed by an FNV-1a digest of the credential rather than the raw token so a
90
+ * long-lived map does not hold live credentials as keys. Bounded by
91
+ * `ROSTER_CACHE_MAX` with oldest-first eviction: the TTL is only checked on
92
+ * read, so without a cap rotated tokens would grow the map without bound.
93
+ */
94
+ const ROSTER_CACHE_MAX = 1024;
85
95
  const rosterCache = new Map<string, { roster: readonly CursorModelInfo[]; fetchedAt: number }>();
96
+
97
+ function rosterCacheSet(credential: string, roster: readonly CursorModelInfo[]): void {
98
+ const key = String(fnv1a32(credential));
99
+ rosterCache.delete(key); // re-set moves the entry to newest position
100
+ rosterCache.set(key, { roster, fetchedAt: Date.now() });
101
+ while (rosterCache.size > ROSTER_CACHE_MAX) {
102
+ const oldest = rosterCache.keys().next().value;
103
+ if (oldest === undefined) break;
104
+ rosterCache.delete(oldest);
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Test-only access to the roster cache (cap/eviction/TTL behavior is covered
110
+ * by `test/providers/cursor-roster-cache.test.ts` without a full dispatch).
111
+ */
112
+ export const rosterCacheForTests = {
113
+ size: (): number => rosterCache.size,
114
+ set: rosterCacheSet,
115
+ get: (credential: string): { roster: readonly CursorModelInfo[]; fetchedAt: number } | undefined =>
116
+ rosterCache.get(String(fnv1a32(credential))),
117
+ };
86
118
  /** Client-heartbeat cadence the Cursor edge expects (donor `heartbeatMs`). */
87
119
  const CURSOR_HEARTBEAT_INTERVAL_OVERRIDE = (() => {
88
120
  const raw = process.env.CARTETHYIA_CURSOR_HEARTBEAT_MS?.trim();
@@ -249,7 +281,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
249
281
  const input = count(turnEnded["input_tokens"]);
250
282
  const output = count(turnEnded["output_tokens"]);
251
283
  const cacheRead = count(turnEnded["cache_read"]);
252
- return {
284
+ return applyCacheMode({
253
285
  input_tokens: input,
254
286
  cached_input_tokens: cacheRead,
255
287
  cache_write_tokens: count(turnEnded["cache_write"]),
@@ -258,7 +290,7 @@ function usageFromTurnEnded(turnEnded: Record<string, unknown>): UsageRecord {
258
290
  reasoning_tokens: count(turnEnded["reasoning_tokens"]),
259
291
  estimated_cost: null,
260
292
  total_tokens: input + output,
261
- };
293
+ });
262
294
  }
263
295
 
264
296
  function nonEmptyStringOf(value: unknown): string | undefined {
@@ -846,7 +878,8 @@ class CursorAdapter implements ProviderAdapter {
846
878
  credential: string,
847
879
  context: ProviderDispatchContext,
848
880
  ): Promise<readonly CursorModelInfo[]> {
849
- const cached = rosterCache.get(credential);
881
+ const key = String(fnv1a32(credential));
882
+ const cached = rosterCache.get(key);
850
883
  if (cached !== undefined && Date.now() - cached.fetchedAt < CURSOR_ROSTER_TTL_MS) {
851
884
  return cached.roster;
852
885
  }
@@ -858,7 +891,7 @@ class CursorAdapter implements ProviderAdapter {
858
891
  : { fetcher: context.outbound_fetch as unknown as typeof fetch }),
859
892
  signal: context.abort_signal,
860
893
  });
861
- rosterCache.set(credential, { roster, fetchedAt: Date.now() });
894
+ rosterCacheSet(credential, roster);
862
895
  return roster;
863
896
  } catch {
864
897
  return cached?.roster ?? [];
@@ -71,59 +71,3 @@ export function* streamFrames(buffer: Uint8Array): Generator<Frame, void, void>
71
71
  offset = start + len
72
72
  }
73
73
  }
74
-
75
- export async function* asyncStreamFrames(
76
- stream: ReadableStream<Uint8Array>,
77
- ): AsyncGenerator<Frame, void, void> {
78
- const reader = stream.getReader()
79
- const chunks: Uint8Array[] = []
80
- let pendingLength = 0
81
-
82
- try {
83
- while (true) {
84
- const { done, value } = await reader.read()
85
- if (done && chunks.length === 0) return
86
- if (value) {
87
- chunks.push(value)
88
- pendingLength += value.length
89
- }
90
-
91
- // Try to parse frames from accumulated data
92
- const merged = mergeChunks(chunks)
93
- const frames = Array.from(streamFrames(merged))
94
- const consumed = frames.reduce((sum, f) => sum + 5 + f.payload.length, 0)
95
-
96
- if (frames.length > 0) {
97
- for (const frame of frames) {
98
- yield frame
99
- }
100
- // Keep any trailing bytes for next iteration
101
- const remaining = merged.subarray(consumed)
102
- chunks.length = 0
103
- if (remaining.length > 0) {
104
- chunks.push(remaining)
105
- pendingLength = remaining.length
106
- } else {
107
- pendingLength = 0
108
- }
109
- }
110
-
111
- if (done) return
112
- }
113
- } finally {
114
- reader.releaseLock()
115
- }
116
- }
117
-
118
- function mergeChunks(chunks: Uint8Array[]): Uint8Array {
119
- const first = chunks[0]
120
- if (chunks.length === 1 && first !== undefined) return first
121
- const total = chunks.reduce((s, c) => s + c.length, 0)
122
- const merged = new Uint8Array(total)
123
- let offset = 0
124
- for (const c of chunks) {
125
- merged.set(c, offset)
126
- offset += c.length
127
- }
128
- return merged
129
- }
@@ -2282,99 +2282,3 @@ export function decodeMessage<T = Record<string, unknown>>(
2282
2282
  const decoded = type.decode(data)
2283
2283
  return type.toObject(decoded, { defaults: true, json: true, longs: Number }) as T
2284
2284
  }
2285
-
2286
- /** Decode without inventing absent proto defaults (used for byte-stable snapshots). */
2287
- export function decodeMessageSparse<T = Record<string, unknown>>(
2288
- typeName: string,
2289
- data: Uint8Array,
2290
- ): T {
2291
- const root = getMessageTypes()
2292
- const type = root.lookupType(typeName)
2293
- const decoded = type.decode(data)
2294
- return type.toObject(decoded, { json: true, longs: Number }) as T
2295
- }
2296
-
2297
- type RawField = {
2298
- field: number
2299
- wireType: number
2300
- varint?: string
2301
- fixed?: number | string
2302
- bytes?: Uint8Array
2303
- }
2304
-
2305
- /** Schema-free walk of one message's top-level wire fields (no nested descent). */
2306
- function readRawFields(buf: Uint8Array): RawField[] {
2307
- const reader = protobuf.Reader.create(buf)
2308
- const fields: RawField[] = []
2309
- while (reader.pos < reader.len) {
2310
- const tag = reader.uint32()
2311
- const field = tag >>> 3
2312
- const wireType = tag & 7
2313
- switch (wireType) {
2314
- case 0:
2315
- fields.push({ field, wireType, varint: reader.uint64().toString() })
2316
- break
2317
- case 1:
2318
- fields.push({ field, wireType, fixed: reader.fixed64().toString() })
2319
- break
2320
- case 2:
2321
- fields.push({ field, wireType, bytes: reader.bytes() })
2322
- break
2323
- case 5:
2324
- fields.push({ field, wireType, fixed: reader.fixed32() })
2325
- break
2326
- default:
2327
- // Groups (3/4) aren't used on this wire; bail rather than desync the reader.
2328
- return fields
2329
- }
2330
- }
2331
- return fields
2332
- }
2333
-
2334
- /**
2335
- * Diagnostic-only: walk AgentServerMessage.interaction_update(1).turn_ended(14)
2336
- * without going through our hand-written TurnEnded schema, so a `cache_write`/
2337
- * `reasoning_tokens` question can be checked against the raw wire instead of
2338
- * guessed. Confirmed field ids 1-5 (input/output/cache_read/cache_write/
2339
- * reasoning) decode correctly. Live captures routinely include `f4` explicitly
2340
- * as `0` while `f3` (cache_read) and `f5` (reasoning) are non-zero — Cursor's
2341
- * agent TurnEnded populates the field but does not report write counts here.
2342
- */
2343
- export function debugWalkTurnEnded(payload: Uint8Array): string {
2344
- try {
2345
- const top = readRawFields(payload)
2346
- const iuField = top.find((f) => f.field === 1 && f.wireType === 2)
2347
- if (!iuField?.bytes) return "(no interaction_update field)"
2348
- const iu = readRawFields(iuField.bytes)
2349
- const teField = iu.find((f) => f.field === 14 && f.wireType === 2)
2350
- if (!teField?.bytes) return "(no turn_ended field in interaction_update)"
2351
- const te = readRawFields(teField.bytes)
2352
- return te
2353
- .map(
2354
- (f) =>
2355
- `f${f.field}:wt${f.wireType}=${f.varint ?? f.fixed ?? (f.bytes ? `bytes[${f.bytes.length}]` : "?")}`,
2356
- )
2357
- .join(" ")
2358
- } catch (e) {
2359
- return `(walk failed: ${(e as Error).message})`
2360
- }
2361
- }
2362
-
2363
- /**
2364
- * Decode a protobuf sub-message from a frame payload that wraps it in
2365
- * a top-level field key + length varint. Skips the outer wrapper and
2366
- * decodes the inner body as `typeName`.
2367
- */
2368
- export function decodeWrappedMessage<T = Record<string, unknown>>(
2369
- typeName: string,
2370
- data: Uint8Array,
2371
- ): T {
2372
- let offset = 1 // skip field key
2373
- // skip varint length
2374
- while (offset < data.length) {
2375
- const b = data[offset] ?? 0
2376
- offset++
2377
- if (!(b & 0x80)) break
2378
- }
2379
- return decodeMessage<T>(typeName, data.subarray(offset))
2380
- }
@@ -106,7 +106,7 @@ function factoryClientHeaders(orgId: string): Record<string, string> {
106
106
  * (`packages/ai/src/providers/factory-droid.ts:271` — `"x-api-provider":
107
107
  * input.upstream`), so a value outside it has no meaning on this wire.
108
108
  */
109
- export const FACTORY_DROID_UPSTREAMS = [
109
+ const FACTORY_DROID_UPSTREAMS = [
110
110
  "fireworks",
111
111
  "baseten",
112
112
  "mistral",
@@ -123,7 +123,7 @@ export const FACTORY_DROID_UPSTREAMS = [
123
123
  "databricks",
124
124
  ] as const;
125
125
 
126
- export type FactoryDroidUpstream = (typeof FACTORY_DROID_UPSTREAMS)[number];
126
+ type FactoryDroidUpstream = (typeof FACTORY_DROID_UPSTREAMS)[number];
127
127
 
128
128
  const FACTORY_DROID_UPSTREAM_SET: ReadonlySet<string> = new Set(FACTORY_DROID_UPSTREAMS);
129
129
 
@@ -154,7 +154,7 @@ function logDroppedUpstream(reason: string, value: string): void {
154
154
  * unmapped failure. Omitting falls back to Factory's default routing, which is
155
155
  * the behavior a request that names no upstream already gets.
156
156
  */
157
- export function factoryApiProviderHeader(
157
+ function factoryApiProviderHeader(
158
158
  options: Readonly<Record<string, unknown>> | undefined,
159
159
  ): Record<string, string> {
160
160
  const value = options?.["factory_api_provider"];
@@ -179,7 +179,7 @@ export function factoryApiProviderHeader(
179
179
  * `/api/cli/whoami` reported. An account with no recorded residency is the
180
180
  * global host, which is Factory's default.
181
181
  */
182
- export function factoryBaseUrl(context: ProviderDispatchContext): string {
182
+ function factoryBaseUrl(context: ProviderDispatchContext): string {
183
183
  const region = context.credential.auth_state?.["region"];
184
184
  return region === "eu" ? FACTORY_DROID_EU_BASE_URL : FACTORY_DROID_BASE_URL;
185
185
  }
@@ -200,7 +200,7 @@ export function factoryBaseUrl(context: ProviderDispatchContext): string {
200
200
  * operator wrote into `auth_state`. The two-axis read is kept because the donor
201
201
  * needs it, not because we currently populate the second axis.
202
202
  */
203
- export function factoryInferenceRegion(
203
+ function factoryInferenceRegion(
204
204
  context: ProviderDispatchContext,
205
205
  ): "global" | "us" | "eu" {
206
206
  const state = context.credential.auth_state;
@@ -266,7 +266,7 @@ const REGION_UPSTREAMS: Readonly<Record<"global" | "us" | "eu", readonly Factory
266
266
  * is, which is a property of the route rather than of the request. The donor's
267
267
  * own message text is preserved as the `reason` so the mapping is traceable.
268
268
  */
269
- export function factoryRegionUnavailable(modelId: string, region: string): GatewayError {
269
+ function factoryRegionUnavailable(modelId: string, region: string): GatewayError {
270
270
  return new GatewayError(
271
271
  "capability_unsupported",
272
272
  400,
@@ -294,7 +294,7 @@ export function factoryRegionUnavailable(modelId: string, region: string): Gatew
294
294
  * Sending `configured_order` without that discovery would claim a rotation we
295
295
  * never resolved.
296
296
  */
297
- export function factoryRoutingSourceHeader(request: CanonicalRequest): Record<string, string> {
297
+ function factoryRoutingSourceHeader(request: CanonicalRequest): Record<string, string> {
298
298
  const continuing = request.messages.some((message) => message.role === "assistant");
299
299
  return { "x-provider-routing-source": continuing ? "session_lock" : "registry_default" };
300
300
  }
@@ -313,7 +313,7 @@ export function factoryRoutingSourceHeader(request: CanonicalRequest): Record<st
313
313
  * donor's own region-unavailable error rather than an upstream 4xx this layer
314
314
  * cannot explain.
315
315
  */
316
- export function factoryRegionCheckedApiProviderHeader(
316
+ function factoryRegionCheckedApiProviderHeader(
317
317
  request: CanonicalRequest,
318
318
  context: ProviderDispatchContext,
319
319
  ): Record<string, string> {
@@ -330,7 +330,7 @@ export function factoryRegionCheckedApiProviderHeader(
330
330
  }
331
331
 
332
332
  /** The two routing headers together, as every Factory wire sends them. */
333
- export function factoryRoutingHeaders(
333
+ function factoryRoutingHeaders(
334
334
  request: CanonicalRequest,
335
335
  context: ProviderDispatchContext,
336
336
  ): Record<string, string> {
@@ -29,6 +29,7 @@ import {
29
29
  GITHUB_PROVIDER_ID,
30
30
  GITHUB_ENDPOINT_PATH,
31
31
  GITHUB_RESPONSES_ENDPOINT_PATH,
32
+ GITHUB_MESSAGES_ENDPOINT_PATH,
32
33
  GITHUB_AUTO_MODELS,
33
34
  recordGithubModelRoutes,
34
35
  } from "./github";
@@ -47,12 +48,11 @@ function positiveLimit(value: unknown): number | undefined {
47
48
  * The surfaces a row answers on, normalized to the canonical paths this
48
49
  * gateway registers.
49
50
  *
50
- * A row that supports neither chat nor responses is skipped rather than
51
- * defaulted: Copilot also serves a native Anthropic `/v1/messages` surface for
52
- * some SKUs, and this adapter speaks only the OpenAI wire. Registering such a
53
- * row as chat would publish a route that fails on first dispatch.
51
+ * Copilot serves three OpenAI/Anthropic surfaces: `/chat/completions`,
52
+ * `/responses`, and `/v1/messages`. A row that supports none of them is
53
+ * skipped rather than defaulted.
54
54
  */
55
- function wireFamilyFor(entry: Record<string, unknown>): "chat" | "responses" | undefined {
55
+ function wireFamilyFor(entry: Record<string, unknown>): "chat" | "responses" | "messages" | undefined {
56
56
  const declared = boundedUpstreamArray(entry.supported_endpoints);
57
57
  if (!declared) return "chat";
58
58
  const endpoints = new Set<string>();
@@ -60,11 +60,12 @@ function wireFamilyFor(entry: Record<string, unknown>): "chat" | "responses" | u
60
60
  const label = sanitizeUpstreamLabel(value);
61
61
  if (label !== undefined) endpoints.add(label.replace(/^\/v1(?=\/)/, ""));
62
62
  }
63
- // Chat is preferred when a row supports both: it is the surface every
64
- // OpenAI-compatible client already speaks, and the upstream answers it for
65
- // the same SKU. Responses is used only when chat is absent.
63
+ // Chat is preferred when a row supports it: it is the surface every
64
+ // OpenAI-compatible client already speaks. Responses and Messages are used
65
+ // only when chat is absent, in that order.
66
66
  if (endpoints.has("/chat/completions")) return "chat";
67
67
  if (endpoints.has("/responses")) return "responses";
68
+ if (endpoints.has("/messages")) return "messages";
68
69
  return undefined;
69
70
  }
70
71
 
@@ -75,6 +76,34 @@ function supports(entry: Record<string, unknown>, key: string): boolean {
75
76
  return declared?.[key] === true;
76
77
  }
77
78
 
79
+ /**
80
+ * Price deltas from the account's `/models` row when it publishes `token_prices`
81
+ * (dollars per 1M tokens). This is the real per-account price Copilot serves,
82
+ * which the shared models.dev catalog cannot know; when absent the base-catalog
83
+ * estimate is used instead.
84
+ */
85
+ function copilotCost(entry: Record<string, unknown>): ModelDefinition["cost"] {
86
+ const billing = isRecord(entry.billing) ? entry.billing : undefined;
87
+ const prices = isRecord(billing?.token_prices) ? billing.token_prices : undefined;
88
+ const defaultTier = isRecord(prices?.default) ? prices.default : undefined;
89
+ const input = positiveLimit(defaultTier?.input_price);
90
+ const output = positiveLimit(defaultTier?.output_price);
91
+ if (input === undefined && output === undefined) {
92
+ return modelsDevCatalog.costFor(GITHUB_PROVIDER_ID, String(entry.id ?? ""));
93
+ }
94
+ return {
95
+ input: input ?? null,
96
+ output: output ?? null,
97
+ ...(typeof (defaultTier as Record<string, unknown> | undefined)?.cache_read_price === "number"
98
+ ? { cache_read: (defaultTier as { cache_read_price?: number }).cache_read_price }
99
+ : {}),
100
+ ...(typeof (defaultTier as Record<string, unknown> | undefined)?.cache_write_price === "number"
101
+ ? { cache_write: (defaultTier as { cache_write_price?: number }).cache_write_price }
102
+ : {}),
103
+ pricing_model: "pay-per-use",
104
+ };
105
+ }
106
+
78
107
  function toModelDefinition(entry: Record<string, unknown>): ModelDefinition | undefined {
79
108
  const modelId = sanitizeUpstreamLabel(entry.id);
80
109
  if (modelId === undefined) return undefined;
@@ -89,16 +118,32 @@ function toModelDefinition(entry: Record<string, unknown>): ModelDefinition | un
89
118
  // clamped the same way every other catalog row is.
90
119
  const outputLimit = Math.min(declaredOutput, contextLimit);
91
120
  const vision = supports(entry, "vision");
121
+ // `reasoning_effort` is a list (e.g. ["low","medium","high","xhigh","max"])
122
+ // when the model supports effort levels; absence means the model does not
123
+ // expose an effort knob. Carrying it lets routing clamp to the model's real
124
+ // ladder instead of the provider-wide `max→high` cap.
125
+ const supportsObj = isRecord(capabilities?.supports) ? capabilities.supports : undefined;
126
+ const reasoningEfforts = Array.isArray(supportsObj?.reasoning_effort)
127
+ ? (supportsObj.reasoning_effort as unknown[])
128
+ .filter((level): level is string => typeof level === "string" && level.length > 0)
129
+ : undefined;
130
+ const cost = copilotCost(entry);
92
131
  return {
93
132
  modelId,
94
133
  wireFamily,
95
- endpointPath: wireFamily === "responses" ? GITHUB_RESPONSES_ENDPOINT_PATH : GITHUB_ENDPOINT_PATH,
134
+ endpointPath:
135
+ wireFamily === "responses"
136
+ ? GITHUB_RESPONSES_ENDPOINT_PATH
137
+ : wireFamily === "messages"
138
+ ? GITHUB_MESSAGES_ENDPOINT_PATH
139
+ : GITHUB_ENDPOINT_PATH,
96
140
  contextLimit,
97
141
  outputLimit,
98
142
  modalities: { input: vision ? ["text", "image"] : ["text"], output: ["text"] },
99
143
  reasoning: true,
144
+ ...(reasoningEfforts === undefined ? {} : { reasoningEfforts }),
100
145
  toolCall: true,
101
- cost: modelsDevCatalog.costFor(GITHUB_PROVIDER_ID, modelId),
146
+ cost,
102
147
  };
103
148
  }
104
149
 
@@ -43,13 +43,14 @@ export const GITHUB_DEFAULT_API_HOST = "api.individual.githubcopilot.com" as con
43
43
  * The API rejects a request that does not identify a Copilot client, so these
44
44
  * are a protocol requirement rather than cosmetic fingerprinting — unlike the
45
45
  * Codex/Claude CLI identities elsewhere in this repository, which exist to look
46
- * like a first-party client. The version pair is the Copilot Chat extension's,
47
- * which is what the upstream expects for this client id.
46
+ * like a first-party client. The version pair is the Copilot Chat extension's
47
+ * (0.72.0 on VS Code 1.144), which is what the upstream expects for this
48
+ * client id.
48
49
  */
49
50
  export const GITHUB_REQUEST_HEADERS: Readonly<Record<string, string>> = Object.freeze({
50
- "user-agent": "GitHubCopilotChat/0.70.0",
51
- "editor-version": "vscode/1.142.0",
52
- "editor-plugin-version": "copilot-chat/0.70.0",
51
+ "user-agent": "GitHubCopilotChat/0.72.0",
52
+ "editor-version": "vscode/1.144.0",
53
+ "editor-plugin-version": "copilot-chat/0.72.0",
53
54
  "copilot-integration-id": "vscode-chat",
54
55
  "x-github-api-version": "2026-08-01",
55
56
  });