cartethyia 2.5.4 → 2.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (395) hide show
  1. package/.env.example +13 -4
  2. package/README.md +2 -2
  3. package/dist/dashboard/assets/{BannedPage-C2orBsI2.js → BannedPage-CADDq4IU.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-CADDq4IU.js.gz +0 -0
  5. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js +1 -0
  6. package/dist/dashboard/assets/CliToolDetailPage-_z1hID7E.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BV6pxVQo.js → CliToolsPage-DuO1Z7dq.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-DuO1Z7dq.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-DNEPi3xU.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-CW-wPmJ6.js → ConsoleLogPage-BVdpfiz1.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-BVdpfiz1.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-0p8uX7vB.js → CustomizationPage-BR5HHvbi.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-BR5HHvbi.js.gz +0 -0
  15. package/dist/dashboard/assets/{HealthEventsModal-BjqSMfko.js → HealthEventsModal-mUfcknqm.js} +1 -1
  16. package/dist/dashboard/assets/HealthEventsModal-mUfcknqm.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-BvzCx8Kr.js → LoginPage-V5faV9V2.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-V5faV9V2.js.gz +0 -0
  19. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js +1 -0
  20. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-BDu20Jdx.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-Dllr_aFO.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-Js9jUPSb.js → ProvidersPage-uPiGVTTK.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-uPiGVTTK.js.gz +0 -0
  27. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js +7 -0
  28. package/dist/dashboard/assets/ProxyPage-BaUkO-4O.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-o0IFAsFb.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-CYWqbXjp.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-DDbMQsoo.js → SetupPage-UB690SE2.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-UB690SE2.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-CB3Z7VTf.js → SortableList-BLujdX7N.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-BLujdX7N.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-D95UCPHI.js → StudioPage-D5C2raAc.js} +3 -3
  38. package/dist/dashboard/assets/StudioPage-D5C2raAc.js.gz +0 -0
  39. package/dist/dashboard/assets/UsagePage-8uIcxa1W.js +56 -0
  40. package/dist/dashboard/assets/UsagePage-8uIcxa1W.js.gz +0 -0
  41. package/dist/dashboard/assets/api-keys-DQYLQxpW.js +1 -0
  42. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  43. package/dist/dashboard/assets/app-CX_Z8cMs.css +2 -0
  44. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  45. package/dist/dashboard/assets/{assert-Chi7pCnt.js → assert-C9FD_JwJ.js} +1 -1
  46. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  47. package/dist/dashboard/assets/{badge-D4pQapKj.js → badge-CR72dasT.js} +1 -1
  48. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  49. package/dist/dashboard/assets/{banner-DH6cg-_B.js → banner-CI9_eSfO.js} +1 -1
  50. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  51. package/dist/dashboard/assets/{card-BKqlUOe4.js → card-DS7CQEsO.js} +1 -1
  52. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  53. package/dist/dashboard/assets/{cli-tools-fTgljTGA.js → cli-tools-CNqzrfdb.js} +1 -1
  54. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  55. package/dist/dashboard/assets/{clipboard-button-D5Ys_sM0.js → clipboard-button-611pSsaX.js} +1 -1
  56. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  57. package/dist/dashboard/assets/{fingerprint-pattern-BWuHtbW4.js → concurrency-BDF0ok7y.js} +1 -1
  58. package/dist/dashboard/assets/concurrency-BDF0ok7y.js.gz +0 -0
  59. package/dist/dashboard/assets/dialog-k37exjNt.js +1 -0
  60. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  61. package/dist/dashboard/assets/drawer-CX7N8ucR.js +1 -0
  62. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CQBr6U9c.js → entry-B9Xvtnfj.js} +1 -1
  64. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CTP8AyiS.js +1 -0
  66. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-DxBHnauy.js +4 -0
  68. package/dist/dashboard/assets/entry-DxBHnauy.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-BlptL8Uf.js → github-badge-sltk1qUi.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-js6TJvdr.js → index-CmxZr14F.js} +2 -2
  72. package/dist/dashboard/assets/index-CmxZr14F.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-DUWDSmDV.js → inline-BhY2sSnO.js} +1 -1
  74. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-LVjgZq4f.js → input-V1umFiBk.js} +1 -1
  76. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  77. package/dist/dashboard/assets/layout-BBOYycyS.js +1 -0
  78. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-DupvLfDx.js → list-row-1zzZYM0B.js} +1 -1
  80. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-C4pEJUqI.js → live-BivGfuUs.js} +1 -1
  82. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-BRiuufkB.js → model-bans-CmffjLuG.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-B4ROwk8L.js → mutation-46P0oWMe.js} +1 -1
  86. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  87. package/dist/dashboard/assets/numbers-DkfMR5Qs.js +2 -0
  88. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-gmjzC3RS.js → query-keys-BFhGpwR1.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-C7tBT5o-.js → routing-CAb4F37R.js} +1 -1
  92. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-WUCXorXw.js → select-BYR_5K2c.js} +1 -1
  94. package/dist/dashboard/assets/select-BYR_5K2c.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-C_zKl1GS.js → settings-DNX9sydi.js} +1 -1
  96. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-_3O0F8Xn.js → stack-BHTfXdz_.js} +1 -1
  98. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-BgTxHcJS.js → state-mPDRlQkl.js} +1 -1
  100. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DEjTtOWf.js → switch-DOmJxg7H.js} +1 -1
  102. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  103. package/dist/dashboard/assets/tokens-COzario9.js +1 -0
  104. package/dist/dashboard/assets/tokens-COzario9.js.gz +0 -0
  105. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js +1 -0
  106. package/dist/dashboard/assets/use-modal-focus-By7oJoGd.js.gz +0 -0
  107. package/dist/dashboard/assets/{useMutation-BWSC0UAS.js → useMutation-Dem0lXQj.js} +1 -1
  108. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  109. package/dist/dashboard/index.html +1 -1
  110. package/dist/dashboard/index.html.gz +0 -0
  111. package/dist/dashboard/precompressed-assets.json +54 -54
  112. package/migrations/README.md +52 -52
  113. package/migrations/lite-sqlite3/0000_baseline.sql +2 -2
  114. package/package.json +96 -95
  115. package/scripts/cli/admin.ts +125 -0
  116. package/scripts/cli/{ui/background.ts → background.ts} +1 -1
  117. package/scripts/cli/{command/console-menu.ts → console-menu.ts} +275 -244
  118. package/scripts/cli/doctor.ts +37 -0
  119. package/scripts/cli/{support/env.ts → env.ts} +99 -99
  120. package/scripts/cli/{gateway/spawn.ts → gateway.ts} +112 -24
  121. package/scripts/cli/instance.ts +224 -0
  122. package/scripts/cli/main.ts +61 -18
  123. package/scripts/cli/{support/platform.ts → platform.ts} +64 -64
  124. package/scripts/cli/port.ts +100 -0
  125. package/scripts/cli/{support/services.ts → services.ts} +88 -88
  126. package/scripts/cli/{command/setup.ts → setup.ts} +35 -34
  127. package/scripts/cli/{command/start.ts → start.ts} +10 -5
  128. package/scripts/cli/{support/startup-signal.ts → startup-signal.ts} +23 -23
  129. package/scripts/cli/tray/index.ts +62 -12
  130. package/scripts/cli/{command/tray.ts → tray.ts} +208 -208
  131. package/scripts/cli/{command/update.ts → update.ts} +39 -39
  132. package/scripts/cli/version.ts +67 -0
  133. package/scripts/cli/{ui/wordmark.ts → wordmark.ts} +58 -58
  134. package/src/boot/app.ts +697 -693
  135. package/src/boot/dependencies.ts +647 -646
  136. package/src/boot/timeout.ts +2 -13
  137. package/src/config/cooldowns.ts +186 -138
  138. package/src/config/network.ts +8 -14
  139. package/src/config/providers.ts +7 -10
  140. package/src/config/runtime.ts +76 -76
  141. package/src/config/security.ts +15 -0
  142. package/src/config/spec.ts +20 -30
  143. package/src/config/telemetry.ts +0 -20
  144. package/src/config/timeouts.ts +0 -6
  145. package/src/console/admin/model-abuse/contracts.ts +28 -6
  146. package/src/console/admin/model-abuse/routes.ts +56 -3
  147. package/src/console/api-keys/contracts.ts +410 -414
  148. package/src/console/api-keys/routes.ts +881 -880
  149. package/src/console/auth/credentials.ts +3 -3
  150. package/src/console/auth/setup-service.ts +2 -2
  151. package/src/console/backup/export-endpoint.ts +6 -2
  152. package/src/console/backup/nine-router.ts +2 -5
  153. package/src/console/backup/service.ts +4 -0
  154. package/src/console/backup/store.ts +192 -29
  155. package/src/console/backup/validate.ts +3 -45
  156. package/src/console/cli-tools/fs-ops.ts +487 -487
  157. package/src/console/console-router-guards.ts +1 -1
  158. package/src/console/data-management/contracts.ts +13 -6
  159. package/src/console/data-management/operations.ts +23 -18
  160. package/src/console/data-management/routes.ts +0 -1
  161. package/src/console/domain-registration.ts +10 -5
  162. package/src/console/observability/live.ts +22 -0
  163. package/src/console/observability/store.ts +39 -16
  164. package/src/console/observability/usage-dimensions.ts +4 -4
  165. package/src/console/providers/catalog/catalog-projections.ts +6 -7
  166. package/src/console/providers/catalog/model-operations.ts +5 -2
  167. package/src/console/providers/catalog/provider-operations.ts +4 -4
  168. package/src/console/providers/catalog/public-model-store.ts +8 -11
  169. package/src/console/providers/catalog/store.ts +1553 -1553
  170. package/src/console/providers/oauth/routes.ts +8 -12
  171. package/src/console/quota/account-quota-tenant.ts +6 -6
  172. package/src/console/quota/quota-view.ts +1 -1
  173. package/src/console/remote-support/contracts.ts +61 -0
  174. package/src/console/remote-support/routes.ts +65 -0
  175. package/src/console/remote-support/service.ts +207 -0
  176. package/src/console/response-compression.ts +0 -3
  177. package/src/console/routing/pools/probe-result.ts +3 -2
  178. package/src/console/routing/pools/probe-verdict.ts +132 -132
  179. package/src/console/routing/pools/store.ts +8 -8
  180. package/src/console/settings/contracts.ts +58 -2
  181. package/src/console/settings/store.ts +30 -3
  182. package/src/console/shared/cursor.ts +8 -8
  183. package/src/console/shared/errors.ts +1 -3
  184. package/src/network/http2-bidi.ts +2 -4
  185. package/src/network/pool/agent.ts +478 -478
  186. package/src/network/pool/selector.ts +5 -4
  187. package/src/network/retry.ts +1 -2
  188. package/src/network/ssrf.ts +5 -4
  189. package/src/observability/event-compaction.ts +80 -78
  190. package/src/observability/event-day-index.ts +13 -15
  191. package/src/observability/event-log.ts +4 -4
  192. package/src/observability/logger.ts +6 -6
  193. package/src/observability/payload-capture.ts +151 -33
  194. package/src/observability/payload-store.ts +397 -440
  195. package/src/observability/redaction.ts +5 -6
  196. package/src/observability/request-notify.ts +43 -0
  197. package/src/observability/telemetry-status.ts +8 -9
  198. package/src/observability/token-speed.ts +5 -4
  199. package/src/persistence/db-mode.ts +7 -7
  200. package/src/persistence/readiness.ts +1 -1
  201. package/src/persistence/schema.ts +1406 -1402
  202. package/src/persistence/shared-cache.ts +1 -2
  203. package/src/persistence/stores/api-key-store.ts +18 -6
  204. package/src/persistence/stores/share-store.ts +4 -3
  205. package/src/persistence/stores/telemetry-store.ts +236 -237
  206. package/src/protocol/canonical-model.ts +11 -3
  207. package/src/protocol/codecs.ts +138 -4
  208. package/src/protocol/gateway-error.ts +6 -4
  209. package/src/protocol/request/chat.ts +21 -1
  210. package/src/protocol/request/codex.ts +10 -1
  211. package/src/protocol/request/messages.ts +4 -5
  212. package/src/protocol/request/responses.ts +9 -1
  213. package/src/protocol/response/chat.ts +34 -4
  214. package/src/protocol/response/codex.ts +7 -4
  215. package/src/protocol/response/dsml.ts +140 -28
  216. package/src/protocol/response/responses.ts +11 -5
  217. package/src/protocol/stream-error-frames.ts +4 -5
  218. package/src/providers/authentication/jwt-validator.ts +9 -10
  219. package/src/providers/authentication/oauth-refresh-service.ts +9 -11
  220. package/src/providers/configured-openai-providers.ts +134 -136
  221. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  222. package/src/providers/discovery/catalog/catalog-format.ts +3 -6
  223. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  224. package/src/providers/discovery/probe-phases.ts +4 -4
  225. package/src/providers/discovery/probe-wire.ts +6 -13
  226. package/src/providers/discovery/probing-service.ts +1117 -1045
  227. package/src/providers/integrations/alibabacp/alibabacp.ts +1 -1
  228. package/src/providers/integrations/antigravity/antigravity-quota.ts +5 -7
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +23 -2
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +1 -4
  231. package/src/providers/integrations/buddy/buddy-cli-headers.ts +23 -6
  232. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -1
  233. package/src/providers/integrations/buddy/buddy-identity.ts +52 -0
  234. package/src/providers/integrations/buddy/buddy-media.ts +2 -2
  235. package/src/providers/integrations/buddy/buddy-usage-store.ts +3 -4
  236. package/src/providers/integrations/buddy/codebuddy/quota.ts +2 -13
  237. package/src/providers/integrations/buddy/codebuddy/shared.ts +118 -115
  238. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -11
  239. package/src/providers/integrations/buddy/workbuddy/shared.ts +5 -2
  240. package/src/providers/integrations/claude/claude.ts +608 -608
  241. package/src/providers/integrations/cline/cline-quota.ts +132 -132
  242. package/src/providers/integrations/cline/cline.ts +537 -539
  243. package/src/providers/integrations/codex/codex-oauth.ts +1 -1
  244. package/src/providers/integrations/commandcode/commandcode.ts +674 -675
  245. package/src/providers/integrations/commandcode/discovery.ts +117 -116
  246. package/src/providers/integrations/cursor/cursor-auth.ts +418 -418
  247. package/src/providers/integrations/cursor/cursor-quota.ts +309 -310
  248. package/src/providers/integrations/cursor/cursor.ts +11 -163
  249. package/src/providers/integrations/factory/factory-models.ts +3 -5
  250. package/src/providers/integrations/grok/grok-install-id.ts +2 -3
  251. package/src/providers/integrations/grok/grok.ts +6 -7
  252. package/src/providers/integrations/hermes.ts +14 -18
  253. package/src/providers/integrations/kiro/kiro-discovery.ts +1 -1
  254. package/src/providers/integrations/kiro/kiro.ts +1 -1
  255. package/src/providers/integrations/mistral.ts +6 -6
  256. package/src/providers/integrations/opencode/fingerprint.ts +3 -3
  257. package/src/providers/integrations/opencode/provider.ts +8 -8
  258. package/src/providers/integrations/qoder/qoder-catalog.ts +450 -450
  259. package/src/providers/integrations/qoder/qoder-oauth.ts +388 -310
  260. package/src/providers/integrations/qoder/qoder.ts +884 -865
  261. package/src/providers/integrations/shared/connect.ts +6 -6
  262. package/src/providers/integrations/trae/trae-catalog.ts +1 -2
  263. package/src/providers/integrations/trae/trae.ts +2 -2
  264. package/src/providers/integrations/zcode/oauth.ts +6 -1
  265. package/src/providers/operations/account-health-service.ts +1528 -1523
  266. package/src/providers/operations/account-reset-service.ts +1 -1
  267. package/src/providers/operations/client-versions.ts +6 -6
  268. package/src/providers/operations/custom-cli-headers.ts +3 -4
  269. package/src/providers/operations/provider-catalog-seeder.ts +95 -95
  270. package/src/providers/operations/provider-catalog-service.ts +3 -4
  271. package/src/providers/provider-metadata.ts +4 -8
  272. package/src/providers/provider-registry.ts +6 -7
  273. package/src/providers/provider-usage.ts +1 -1
  274. package/src/security/abuse.ts +15 -10
  275. package/src/security/access-control.ts +144 -146
  276. package/src/security/admission/contracts.ts +11 -0
  277. package/src/security/admission/in-memory-store.ts +4 -3
  278. package/src/security/admission/lease-sweep.ts +6 -6
  279. package/src/security/admission/reasons.ts +5 -1
  280. package/src/security/admission/redis-store.ts +211 -210
  281. package/src/security/admission/service.ts +4 -0
  282. package/src/security/api-key-auth.ts +504 -504
  283. package/src/security/ip-boundary.ts +155 -15
  284. package/src/security/model-abuse.ts +366 -94
  285. package/src/security/outbound-headers.ts +3 -4
  286. package/src/shared/sleep.ts +4 -0
  287. package/src/transport/dispatch/attempt-finalize.ts +47 -5
  288. package/src/transport/dispatch/attempt-loop.ts +531 -530
  289. package/src/transport/dispatch/stream-bridge.ts +1 -3
  290. package/src/transport/dispatch/streaming/finalize.ts +1 -1
  291. package/src/transport/dispatch/streaming/stream.ts +5 -6
  292. package/src/transport/failure-policy.ts +162 -8
  293. package/src/transport/guards/auth-guard.ts +7 -4
  294. package/src/transport/guards/concurrency-guard.ts +0 -5
  295. package/src/transport/guards/error-lifecycle.ts +13 -6
  296. package/src/transport/guards/pipeline.ts +15 -3
  297. package/src/transport/guards/request-context.ts +8 -2
  298. package/src/transport/request/inflight.ts +5 -6
  299. package/src/transport/request/preparer.ts +2 -2
  300. package/src/transport/request/state.ts +12 -8
  301. package/src/transport/routing/admission.ts +4 -0
  302. package/src/transport/routing/route-catalog.ts +8 -1
  303. package/src/transport/routing/route-model.ts +46 -14
  304. package/src/transport/routing/router.ts +21 -14
  305. package/src/transport/surface/completion.ts +2 -3
  306. package/src/transport/surface/dialects.ts +5 -6
  307. package/src/transport/surface/responses/encode.ts +38 -0
  308. package/src/transport/surface/responses/parse.ts +4 -0
  309. package/src/transport/translation/capabilities.ts +2 -3
  310. package/src/transport/translation/quirks.ts +3 -3
  311. package/src/workers/buddy-growth-tasks.ts +5 -10
  312. package/src/workers/daily-checkin.ts +17 -23
  313. package/src/workers/quota-refresh-sweep.ts +26 -26
  314. package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
  315. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +0 -1
  316. package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
  317. package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
  318. package/dist/dashboard/assets/CombosPage-Bsan4679.js +0 -1
  319. package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
  320. package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
  321. package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
  322. package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
  323. package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
  324. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js +0 -1
  325. package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
  326. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +0 -1
  327. package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
  328. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +0 -3
  329. package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
  330. package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
  331. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +0 -7
  332. package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
  333. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +0 -1
  334. package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
  335. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +0 -1
  336. package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
  337. package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
  338. package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
  339. package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
  340. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js +0 -56
  341. package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
  342. package/dist/dashboard/assets/api-keys-VY68Mhd1.js +0 -1
  343. package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
  344. package/dist/dashboard/assets/app-COlK95oi.css +0 -2
  345. package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
  346. package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
  347. package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
  348. package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
  349. package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
  350. package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
  351. package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
  352. package/dist/dashboard/assets/dialog-BYj-8WuK.js +0 -1
  353. package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
  354. package/dist/dashboard/assets/drawer-CmXIZ6H1.js +0 -1
  355. package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
  356. package/dist/dashboard/assets/entry-CBg5zeu8.js +0 -1
  357. package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
  358. package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-CgdSAzEV.js +0 -4
  360. package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
  361. package/dist/dashboard/assets/fingerprint-pattern-BWuHtbW4.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
  363. package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
  365. package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-CPfxpsfy.js +0 -1
  367. package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
  368. package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
  369. package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
  370. package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
  371. package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
  372. package/dist/dashboard/assets/numbers-YNcHvRY7.js +0 -2
  373. package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
  374. package/dist/dashboard/assets/query-keys-gmjzC3RS.js.gz +0 -0
  375. package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
  376. package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
  377. package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
  378. package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
  379. package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
  380. package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
  381. package/dist/dashboard/assets/tokens-DDxMbSRL.js +0 -1
  382. package/dist/dashboard/assets/tokens-DDxMbSRL.js.gz +0 -0
  383. package/dist/dashboard/assets/use-presence-BSZEBx7U.js +0 -1
  384. package/dist/dashboard/assets/use-presence-BSZEBx7U.js.gz +0 -0
  385. package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
  386. package/scripts/cli/command/admin.ts +0 -65
  387. package/scripts/cli/command/doctor.ts +0 -257
  388. package/scripts/cli/gateway/drain-token.ts +0 -78
  389. package/scripts/cli/gateway/instance-lock.ts +0 -105
  390. package/scripts/cli/gateway/stop.ts +0 -51
  391. package/scripts/cli/support/bun.ts +0 -27
  392. package/scripts/cli/support/version.ts +0 -37
  393. /package/dist/dashboard/assets/{app-DCQZRmHY.js → app-BIt446yE.js} +0 -0
  394. /package/dist/dashboard/assets/{app-DCQZRmHY.js.gz → app-BIt446yE.js.gz} +0 -0
  395. /package/scripts/cli/{ui/prompt.ts → prompt.ts} +0 -0
@@ -6,7 +6,7 @@
6
6
  * plans are served by different hosts and their keys are not interchangeable,
7
7
  * and which plan a key belongs to is per-account state stored with it. A spec
8
8
  * declares one `base_url` at construction, so the host is resolved from the
9
- * credential at dispatch time and a stored region that no longer resolves is a
9
+ * credential at dispatch time and a stored region that does not resolve is a
10
10
  * dispatch-time error rather than a silent fallback to the default host.
11
11
  */
12
12
  import { createApiKeyAdapter } from "../../configured-provider";
@@ -33,10 +33,9 @@ interface AntigravityQuotaFamily {
33
33
  * resulting id, so a quota row exists for exactly the models the operator can
34
34
  * select.
35
35
  *
36
- * This replaced a hand-kept list plus a permissive id pattern, which let a
37
- * deployment the catalog no longer serves (`gemini-2.5-pro`) report a quota row
38
- * for a model that cannot be chosen. Deriving the set means removing a catalog
39
- * model removes its quota row in the same change.
36
+ * Deriving the set means removing a catalog model removes its quota row in the
37
+ * same change — a hand-kept list would let a deployment the catalog does not
38
+ * serve report a quota row for a model that cannot be chosen.
40
39
  */
41
40
  const CATALOG_MODEL_IDS: ReadonlySet<string> = new Set(
42
41
  ANTIGRAVITY_MODELS.filter((model) => model.serviceKind !== "websearch").map((model) => model.modelId),
@@ -83,9 +82,8 @@ const SUMMARY_WINDOW_LABELS: Readonly<Record<SummaryWindowKind, string>> = Objec
83
82
  *
84
83
  * The upstream names the window in `window` (`5h`, `daily`, `weekly`) and
85
84
  * repeats it in the display name. Daily must be tested before the 5-hour
86
- * session: an older spelling put `daily` on the session bucket, but a bucket
87
- * whose own text says "daily" is the daily allowance, and treating it as the
88
- * session is what dropped the daily row.
85
+ * session: a bucket whose own text says "daily" is the daily allowance, and
86
+ * treating it as the session is what drops the daily row.
89
87
  */
90
88
  function summaryWindowKind(bucket: Record<string, unknown>): SummaryWindowKind | undefined {
91
89
  const source = `${text(bucket.window) ?? ""} ${text(bucket.bucketId) ?? ""} ${text(bucket.displayName) ?? ""}`.toLowerCase();
@@ -822,9 +822,30 @@ export function dropEmptyBuddyMessages(messages: Array<Record<string, unknown>>)
822
822
  if (Array.isArray(message["tool_calls"]) && message["tool_calls"].length > 0) return true;
823
823
  if (typeof message["tool_call_id"] === "string" && message["tool_call_id"].trim().length > 0)
824
824
  return true;
825
- if (typeof message["reasoning_content"] === "string") return true;
826
825
  const content = message["content"];
827
- if (typeof content === "string") return content.trim().length > 0;
826
+ if (typeof content === "string") {
827
+ if (content.trim().length > 0) return true;
828
+ // `content === ""` on a bare assistant turn (no tool_calls, no
829
+ // tool_call_id) is unverifiable by the receiving model regardless of
830
+ // what `reasoning_content` carries. The upstream rejects it with
831
+ // code `11151 "history not found"` for both shapes observed in the
832
+ // wild:
833
+ // (a) `reasoning_content: ""` — the Chat encoder's output for a
834
+ // canonical `reasoning` part with no `.summary` and a non-string
835
+ // `.payload` (signature-less thinking block already stripped on
836
+ // an earlier hop), and
837
+ // (b) `reasoning_content: "reasoning unavailable"` — the OMP client's
838
+ // sentinel in a Responses `reasoning` input item of shape
839
+ // `{summary: [], content: [{type: "reasoning_text",
840
+ // text: "reasoning unavailable"}]}`, emitted when the client
841
+ // strips the previous turn's trace on a model switch.
842
+ // Both are unverifiable: the receiving model never issued that
843
+ // signature, so nothing is round-trippable. Verifiable signatures
844
+ // round-trip on `tool_calls` turns (kept by the guard above) via the
845
+ // `reasoning_content` side channel; a signature on a bare turn with
846
+ // no tool_calls is not a shape any upstream in this family accepts.
847
+ return false;
848
+ }
828
849
  if (Array.isArray(content)) return content.length > 0;
829
850
  // Null content with no tool/reasoning load is a bare turn the upstream
830
851
  // rejects — drop it rather than dispatch a known-invalid payload.
@@ -19,6 +19,7 @@
19
19
  // claim short-circuits the day, so a restart cannot double-post.
20
20
 
21
21
  import { providerBaseUrl } from "../../provider-metadata";
22
+ import { sleep } from "../../../shared/sleep";
22
23
  import { WORKBUDDY_DOMAIN } from "./workbuddy/shared";
23
24
  import { BUDDY_PROVIDER_IDS } from "../../provider-metadata";
24
25
  import {
@@ -368,10 +369,6 @@ function isRetryableClaim(error: unknown, status: number | null): boolean {
368
369
  return !(error instanceof DOMException && error.name === "AbortError");
369
370
  }
370
371
 
371
- function sleep(ms: number): Promise<void> {
372
- return new Promise((resolve) => setTimeout(resolve, ms));
373
- }
374
-
375
372
  function asRecord(value: unknown): Record<string, unknown> | null {
376
373
  return value !== null && typeof value === "object" && !Array.isArray(value)
377
374
  ? (value as Record<string, unknown>)
@@ -69,7 +69,14 @@ export function buddyCliTraceHeaders(
69
69
  * conversation family, because those vary by provider and realm: only the
70
70
  * headers that are the same for every CLI dispatch are built here.
71
71
  */
72
- export function buddyCliHeaders(args: { readonly userId: string }): Record<string, string> {
72
+ export function buddyCliHeaders(args: {
73
+ readonly userId: string;
74
+ readonly enterpriseId?: string | undefined;
75
+ }): Record<string, string> {
76
+ const enterpriseId =
77
+ args.enterpriseId !== undefined && args.enterpriseId.trim().length > 0
78
+ ? args.enterpriseId.trim()
79
+ : undefined;
73
80
  return {
74
81
  "X-Agent-Intent": "craft",
75
82
  "X-Agent-Type": "main",
@@ -78,11 +85,21 @@ export function buddyCliHeaders(args: { readonly userId: string }): Record<strin
78
85
  // of the three, so "other" is the honest value rather than a guess.
79
86
  "X-Agent-Runtime": "other",
80
87
  "X-User-Id": args.userId,
81
- // Personal accounts are not an enterprise and the reference sends the flag
82
- // either way (`true` only for an enterprise id), so the non-enterprise
83
- // default goes out here. Step 3 replaces this with the account's real
84
- // enterprise id once discovery carries one.
85
- "X-Private-Data": "false",
88
+ // The reference sends the flag either way, `true` only for an enterprise
89
+ // id. A personal account stays `false`; an enterprise account flips to
90
+ // `true` and names the enterprise, because the two travel together — a
91
+ // `true` with no id, or an id under `false`, is a combination no real
92
+ // client produces.
93
+ "X-Private-Data": enterpriseId === undefined ? "false" : "true",
94
+ ...(enterpriseId === undefined
95
+ ? {}
96
+ : {
97
+ "X-Enterprise-Id": enterpriseId,
98
+ // The tenant falls back to the enterprise: the two are the same value
99
+ // for an account that belongs to one enterprise, and the upstream
100
+ // reads both.
101
+ "X-Tenant-Id": enterpriseId,
102
+ }),
86
103
  ...buddyStainlessHeaders(),
87
104
  };
88
105
  }
@@ -91,7 +91,6 @@ export function buddyConversationHeaders(
91
91
  };
92
92
  // Always sent, invented when the caller gave none.
93
93
  //
94
- // This used to be omitted unless the client supplied one. That was wrong:
95
94
  // `x-conversation-id` is mandatory, and a chat request without it is refused
96
95
  // with `400 · 11-128 "request illegal"` — an error that names neither the
97
96
  // header nor the channel, and which reads like a block rather than a missing
@@ -1,4 +1,5 @@
1
1
  import type { ProviderDispatchContext } from "../../provider-contracts";
2
+ import { decodeJwtPayload } from "../../authentication/oauth-flow-store";
2
3
 
3
4
  /**
4
5
  * Which upstream client a buddy provider presents itself as.
@@ -44,3 +45,54 @@ export function buddyUserId(context?: ProviderDispatchContext): string {
44
45
  const accountId = context?.credential.account_id;
45
46
  return accountId !== undefined && accountId.length > 0 ? accountId : "anonymous";
46
47
  }
48
+
49
+ /**
50
+ * Claim names a buddy access token may carry the enterprise id under.
51
+ *
52
+ * A list of candidates rather than one name because the upstream's token shape
53
+ * is not pinned anywhere this codebase can verify, and guessing one name would
54
+ * silently report "personal" for every account whose token spells it another
55
+ * way. Every candidate is a plausible spelling of the same fact; the first that
56
+ * holds a non-empty string wins, and a token carrying none yields no enterprise.
57
+ */
58
+ const ENTERPRISE_CLAIMS: readonly string[] = [
59
+ "enterprise_id",
60
+ "enterpriseId",
61
+ "enterprise",
62
+ "tenant_id",
63
+ "tenantId",
64
+ "org_id",
65
+ "organization_id",
66
+ ];
67
+
68
+ /**
69
+ * The enterprise this buddy account belongs to, or `undefined` for a personal
70
+ * one.
71
+ *
72
+ * Two sources, in this order:
73
+ *
74
+ * 1. **`auth_state.enterpriseId`** — written when the account was authorized, or
75
+ * set by an operator for an account whose token does not carry the fact.
76
+ * Wins because it is the one a human can correct.
77
+ * 2. **A claim on the access token** — for accounts authorized before this
78
+ * existed, whose `auth_state` was never populated.
79
+ *
80
+ * Deliberately conservative: no enterprise id means *personal*, and personal is
81
+ * what the gateway already sends. An unknown account is therefore unchanged
82
+ * rather than being given an enterprise it may not have — claiming one the
83
+ * upstream does not recognise is the kind of mismatch that draws a channel
84
+ * check.
85
+ */
86
+ export function buddyEnterprise(context?: ProviderDispatchContext): string | undefined {
87
+ const stored = context?.credential.auth_state?.["enterpriseId"];
88
+ if (typeof stored === "string" && stored.trim().length > 0) return stored.trim();
89
+ const token = context?.credential.secret;
90
+ if (token === undefined || token.length === 0) return undefined;
91
+ const claims = decodeJwtPayload(new TextDecoder().decode(token).trim());
92
+ if (claims === undefined) return undefined;
93
+ for (const claim of ENTERPRISE_CLAIMS) {
94
+ const value = claims[claim];
95
+ if (typeof value === "string" && value.trim().length > 0) return value.trim();
96
+ }
97
+ return undefined;
98
+ }
@@ -15,7 +15,7 @@
15
15
  *
16
16
  * ⚠️ The provider's actual polling route has not been verified. The sibling
17
17
  * URL is an implementation inference, not an observed contract. See
18
- * `documentation/features/buddy-media-generation.md` before changing it.
18
+ * `documentation/features/07-buddy-media-generation.md` before changing it.
19
19
  */
20
20
  import { OpenAICompatibleAdapter, authHeaders, type OpenAICompatibleAdapterConfig } from "../../adapters/compatible-adapter";
21
21
  import { GatewayError } from "../../../protocol/gateway-error";
@@ -305,7 +305,7 @@ export function buddyErrorOf(payload: unknown): string | undefined {
305
305
  * inferred sibling task URL until it reports a finished clip.
306
306
  *
307
307
  * ⚠️ The status path is not provider-verified; see the module header and
308
- * `documentation/features/buddy-media-generation.md`.
308
+ * `documentation/features/07-buddy-media-generation.md`.
309
309
  */
310
310
  export async function buddyGenerateVideo(
311
311
  config: BuddyMediaConfig,
@@ -92,10 +92,9 @@ const DEFAULT_LIMIT_PER_ACCOUNT = 30;
92
92
  /**
93
93
  * Reads each account's stored usage, newest day first.
94
94
  *
95
- * Bounded on both axes, because it used to be bounded on neither: with no day
96
- * filter and no `LIMIT`, an account fetched every bucket it had ever stored
97
- * (~1500 rows for a 30-day window) to render 30 of them, on the route the
98
- * dashboard polls.
95
+ * Bounded on both axes: with no day filter and no `LIMIT`, an account would
96
+ * fetch every bucket it had ever stored (~1500 rows for a 30-day window) to
97
+ * render 30 of them, on the route the dashboard polls.
99
98
  *
100
99
  * - The day window is semantic, not a truncation: {@link pruneBuddyUsageSnapshots}
101
100
  * already drops everything older, so no row it excludes could have been
@@ -24,9 +24,9 @@ export const CODEBUDDY_CN_USAGE_URL =
24
24
  `${providerBaseUrl("cbcn")}/billing/meter/get-user-resource`;
25
25
  export const CODEBUDDY_INTL_USAGE_URL =
26
26
  `${providerBaseUrl("cb")}/billing/meter/get-user-resource`;
27
- export const CODEBUDDY_CN_REQUEST_USAGE_URL =
27
+ const CODEBUDDY_CN_REQUEST_USAGE_URL =
28
28
  `${providerBaseUrl("cbcn")}/billing/meter/get-user-request-usage`;
29
- export const CODEBUDDY_INTL_REQUEST_USAGE_URL =
29
+ const CODEBUDDY_INTL_REQUEST_USAGE_URL =
30
30
  `${providerBaseUrl("cb")}/billing/meter/get-user-request-usage`;
31
31
 
32
32
  type CodeBuddyProviderId = "cb" | "cbcn";
@@ -152,14 +152,3 @@ export async function fetchCodeBuddyRequestUsage(
152
152
  });
153
153
  }
154
154
 
155
- export const fetchCodeBuddyCnRequestUsage = (
156
- credential: string,
157
- fetcher: FetchLike,
158
- days: number = 30,
159
- ): Promise<BuddyUsageResult> => fetchCodeBuddyRequestUsage(credential, fetcher, "cbcn", days);
160
-
161
- export const fetchCodeBuddyIntlRequestUsage = (
162
- credential: string,
163
- fetcher: FetchLike,
164
- days: number = 30,
165
- ): Promise<BuddyUsageResult> => fetchCodeBuddyRequestUsage(credential, fetcher, "cb", days);
@@ -1,115 +1,118 @@
1
- import { withBearerAuthentication, type OpenAICompatibleAdapterConfig } from "../../../adapters/compatible-adapter";
2
- import type { CanonicalRequest } from "../../../../protocol/canonical-model";
3
- import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
4
- import { resolveInboundSessionId } from "../../../operations/session-resolution";
5
- import { buddyConversationHeaders } from "../buddy-conversation-headers";
6
- import { buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
7
- import { buildCodeBuddyUserAgent, getCodeBuddyCnVersion, getCodeBuddyVersion } from "../../../operations/client-versions";
8
- import { readBuddyDeviceToken } from "../workbuddy/shared";
9
- import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
10
-
11
- /** Client identity variant behind the per-request CodeBuddy headers. */
12
- export type CodeBuddyVariant = "IDE" | "CLI";
13
-
14
- export function codebuddyDomain(variant: CodeBuddyVariant): string {
15
- return variant === "IDE" ? "www.codebuddy.ai" : "copilot.tencent.com";
16
- }
17
-
18
-
19
- /**
20
- * Per-request CodeBuddy headers — exact provider contract shared by the
21
- * international (IDE identity) and CN (CLI identity). The stable conversation
22
- * header is preserved from the client when available; request IDs rotate.
23
- *
24
- * `cliIdentity` selects the real CLI contract rather than today's hybrid: the
25
- * reference CLI is issued by the OpenAI Node SDK, so it carries no browser
26
- * headers and no device token, and it adds the agent envelope. Left unset it
27
- * keeps the current behaviour for every provider.
28
- */
29
- export async function codebuddyHeaders(
30
- variant: CodeBuddyVariant,
31
- context?: ProviderDispatchContext,
32
- request?: CanonicalRequest,
33
- cliIdentity?: boolean,
34
- ): Promise<Record<string, string>> {
35
- const identity = variant === "IDE" ? "IDE" : "CLI";
36
- const ua = buildCodeBuddyUserAgent(identity);
37
- const deviceToken = readBuddyDeviceToken(context);
38
- const conversationId = resolveInboundSessionId(context, request);
39
- const conversation = buddyConversationHeaders({
40
- ...(conversationId === undefined ? {} : { conversationId }),
41
- });
42
- if (resolveBuddyIdentity(context, cliIdentity) === "cli") {
43
- return {
44
- // The CLI sends `Accept: application/json` and no device token. The
45
- // browser-shaped pair (`X-Requested-With`, `x-codebuddy-request`) stays
46
- // off this branch: a request carrying both halves is a hybrid no real
47
- // client produces, and that is a fidelity choice, not a requirement —
48
- // the live API answers either way.
49
- accept: "application/json",
50
- "User-Agent": `CLI/${getCodeBuddyVersion()} CodeBuddy/${getCodeBuddyVersion()}`,
51
- "X-Product": "SaaS",
52
- "X-IDE-Type": "CLI",
53
- "X-IDE-Name": "CLI",
54
- "X-IDE-Version": getCodeBuddyVersion(),
55
- "X-Domain": codebuddyDomain(variant),
56
- // The conversation purpose the reference client states. Not required —
57
- // verified against the live API that a request succeeds without it — but
58
- // it is part of the client's real request, and matching the client is the
59
- // defence against a channel check tightening later.
60
- "X-Agent-Purpose": "conversation",
61
- ...conversation,
62
- ...buddyCliTraceHeaders(conversation),
63
- ...buddyCliHeaders({ userId: buddyUserId(context) }),
64
- };
65
- }
66
- return {
67
- accept: "text/event-stream",
68
- "User-Agent": ua,
69
- "X-Product": "SaaS",
70
- "X-IDE-Type": identity,
71
- "X-IDE-Name": identity,
72
- // Every reference branch sends this, in both the desktop and the CLI
73
- // product; its absence here is what made a CodeBuddy dispatch the only
74
- // buddy caller with no client version on the wire.
75
- "X-IDE-Version": identity === "CLI" ? getCodeBuddyCnVersion() : getCodeBuddyVersion(),
76
- "X-Domain": codebuddyDomain(variant),
77
- "x-requested-with": "XMLHttpRequest",
78
- "x-codebuddy-request": "1",
79
- // Same value the CLI branch sends, for the same reason: part of the
80
- // client's real request, harmless when the channel check does not read it.
81
- "X-Agent-Purpose": "conversation",
82
- // Same family WorkBuddy sends: the upstream's channel check reads the
83
- // turn-level aggregation key, and a chat request without it is refused for a
84
- // missing conversation id.
85
- ...conversation,
86
- ...(deviceToken === undefined ? {} : { "X-Device-Token": deviceToken }),
87
- };
88
- }
89
-
90
- /**
91
- * Shared OpenAI-compatible chat-adapter config for both CodeBuddy variants:
92
- * bearer auth, chat-only wire contract, per-request identity headers, and the
93
- * variant's payload hook.
94
- */
95
- export function codebuddyAdapterConfig(args: {
96
- providerId: ProviderId;
97
- baseUrl: string;
98
- variant: CodeBuddyVariant;
99
- prePayload: (
100
- payload: Record<string, unknown>,
101
- request: CanonicalRequest,
102
- candidate: ProviderDispatchTarget,
103
- ) => void;
104
- fetchImpl?: typeof fetch;
105
- cliIdentity?: boolean;
106
- }): OpenAICompatibleAdapterConfig {
107
- return withBearerAuthentication({
108
- provider_id: args.providerId,
109
- base_url: args.baseUrl,
110
- buildExtraHeaders: (context, request) =>
111
- codebuddyHeaders(args.variant, context, request, args.cliIdentity),
112
- prePayload: args.prePayload,
113
- ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
114
- });
115
- }
1
+ import { withBearerAuthentication, type OpenAICompatibleAdapterConfig } from "../../../adapters/compatible-adapter";
2
+ import type { CanonicalRequest } from "../../../../protocol/canonical-model";
3
+ import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
4
+ import { resolveInboundSessionId } from "../../../operations/session-resolution";
5
+ import { buddyConversationHeaders } from "../buddy-conversation-headers";
6
+ import { buddyEnterprise, buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
7
+ import { buildCodeBuddyUserAgent, getCodeBuddyCnVersion, getCodeBuddyVersion } from "../../../operations/client-versions";
8
+ import { readBuddyDeviceToken } from "../workbuddy/shared";
9
+ import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
10
+
11
+ /** Client identity variant behind the per-request CodeBuddy headers. */
12
+ export type CodeBuddyVariant = "IDE" | "CLI";
13
+
14
+ export function codebuddyDomain(variant: CodeBuddyVariant): string {
15
+ return variant === "IDE" ? "www.codebuddy.ai" : "copilot.tencent.com";
16
+ }
17
+
18
+
19
+ /**
20
+ * Per-request CodeBuddy headers — exact provider contract shared by the
21
+ * international (IDE identity) and CN (CLI identity). The stable conversation
22
+ * header is preserved from the client when available; request IDs rotate.
23
+ *
24
+ * `cliIdentity` selects the real CLI contract rather than today's hybrid: the
25
+ * reference CLI is issued by the OpenAI Node SDK, so it carries no browser
26
+ * headers and no device token, and it adds the agent envelope. Left unset it
27
+ * keeps the current behaviour for every provider.
28
+ */
29
+ export async function codebuddyHeaders(
30
+ variant: CodeBuddyVariant,
31
+ context?: ProviderDispatchContext,
32
+ request?: CanonicalRequest,
33
+ cliIdentity?: boolean,
34
+ ): Promise<Record<string, string>> {
35
+ const identity = variant === "IDE" ? "IDE" : "CLI";
36
+ const ua = buildCodeBuddyUserAgent(identity);
37
+ const deviceToken = readBuddyDeviceToken(context);
38
+ const conversationId = resolveInboundSessionId(context, request);
39
+ const conversation = buddyConversationHeaders({
40
+ ...(conversationId === undefined ? {} : { conversationId }),
41
+ });
42
+ if (resolveBuddyIdentity(context, cliIdentity) === "cli") {
43
+ return {
44
+ // The CLI sends `Accept: application/json` and no device token. The
45
+ // browser-shaped pair (`X-Requested-With`, `x-codebuddy-request`) stays
46
+ // off this branch: a request carrying both halves is a hybrid no real
47
+ // client produces, and that is a fidelity choice, not a requirement —
48
+ // the live API answers either way.
49
+ accept: "application/json",
50
+ "User-Agent": `CLI/${getCodeBuddyVersion()} CodeBuddy/${getCodeBuddyVersion()}`,
51
+ "X-Product": "SaaS",
52
+ "X-IDE-Type": "CLI",
53
+ "X-IDE-Name": "CLI",
54
+ "X-IDE-Version": getCodeBuddyVersion(),
55
+ "X-Domain": codebuddyDomain(variant),
56
+ // The conversation purpose the reference client states. Not required —
57
+ // verified against the live API that a request succeeds without it — but
58
+ // it is part of the client's real request, and matching the client is the
59
+ // defence against a channel check tightening later.
60
+ "X-Agent-Purpose": "conversation",
61
+ ...conversation,
62
+ ...buddyCliTraceHeaders(conversation),
63
+ ...buddyCliHeaders({
64
+ userId: buddyUserId(context),
65
+ enterpriseId: buddyEnterprise(context),
66
+ }),
67
+ };
68
+ }
69
+ return {
70
+ accept: "text/event-stream",
71
+ "User-Agent": ua,
72
+ "X-Product": "SaaS",
73
+ "X-IDE-Type": identity,
74
+ "X-IDE-Name": identity,
75
+ // Every reference branch sends this, in both the desktop and the CLI
76
+ // product; its absence here is what made a CodeBuddy dispatch the only
77
+ // buddy caller with no client version on the wire.
78
+ "X-IDE-Version": identity === "CLI" ? getCodeBuddyCnVersion() : getCodeBuddyVersion(),
79
+ "X-Domain": codebuddyDomain(variant),
80
+ "x-requested-with": "XMLHttpRequest",
81
+ "x-codebuddy-request": "1",
82
+ // Same value the CLI branch sends, for the same reason: part of the
83
+ // client's real request, harmless when the channel check does not read it.
84
+ "X-Agent-Purpose": "conversation",
85
+ // Same family WorkBuddy sends: the upstream's channel check reads the
86
+ // turn-level aggregation key, and a chat request without it is refused for a
87
+ // missing conversation id.
88
+ ...conversation,
89
+ ...(deviceToken === undefined ? {} : { "X-Device-Token": deviceToken }),
90
+ };
91
+ }
92
+
93
+ /**
94
+ * Shared OpenAI-compatible chat-adapter config for both CodeBuddy variants:
95
+ * bearer auth, chat-only wire contract, per-request identity headers, and the
96
+ * variant's payload hook.
97
+ */
98
+ export function codebuddyAdapterConfig(args: {
99
+ providerId: ProviderId;
100
+ baseUrl: string;
101
+ variant: CodeBuddyVariant;
102
+ prePayload: (
103
+ payload: Record<string, unknown>,
104
+ request: CanonicalRequest,
105
+ candidate: ProviderDispatchTarget,
106
+ ) => void;
107
+ fetchImpl?: typeof fetch;
108
+ cliIdentity?: boolean;
109
+ }): OpenAICompatibleAdapterConfig {
110
+ return withBearerAuthentication({
111
+ provider_id: args.providerId,
112
+ base_url: args.baseUrl,
113
+ buildExtraHeaders: (context, request) =>
114
+ codebuddyHeaders(args.variant, context, request, args.cliIdentity),
115
+ prePayload: args.prePayload,
116
+ ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
117
+ });
118
+ }
@@ -38,11 +38,6 @@ const WORKBUDDY_CN_BILLING_BASE_URL = "https://www.codebuddy.cn";
38
38
  export const WORKBUDDY_USAGE_URL =
39
39
  `${providerBaseUrl("workbuddy")}/v2/billing/meter/get-user-resource`;
40
40
 
41
- export const WORKBUDDY_REQUEST_USAGE_URL =
42
- `${providerBaseUrl("workbuddy")}/billing/meter/get-user-request-usage`;
43
- export const WORKBUDDY_CN_REQUEST_USAGE_URL =
44
- `${providerBaseUrl("workbuddycn")}/billing/meter/get-user-request-usage`;
45
-
46
41
  async function billingHeaders(
47
42
  domain: string,
48
43
  clientVersion: string,
@@ -164,9 +159,3 @@ export async function fetchWorkBuddyRequestUsage(
164
159
  });
165
160
  }
166
161
 
167
- export const fetchWorkBuddyCnRequestUsage = (
168
- credential: string,
169
- fetcher: FetchLike,
170
- days: number = 30,
171
- ): Promise<BuddyUsageResult> =>
172
- fetchWorkBuddyRequestUsage(credential, fetcher, { providerId: "workbuddycn", days });
@@ -8,7 +8,7 @@ import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from
8
8
  import { resolveInboundSessionId } from "../../../operations/session-resolution";
9
9
  import { buddyConversationHeaders } from "../buddy-conversation-headers";
10
10
  import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
11
- import { buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
11
+ import { buddyEnterprise, buddyUserId, resolveBuddyIdentity } from "../buddy-identity";
12
12
  import {
13
13
  buildWorkBuddyUserAgent,
14
14
  getWorkBuddyClientVersion,
@@ -91,7 +91,10 @@ export async function workbuddyHeaders(
91
91
  "x-no-enterprise-id": "1",
92
92
  ...conversation,
93
93
  ...buddyCliTraceHeaders(conversation),
94
- ...buddyCliHeaders({ userId: buddyUserId(context) }),
94
+ ...buddyCliHeaders({
95
+ userId: buddyUserId(context),
96
+ enterpriseId: buddyEnterprise(context),
97
+ }),
95
98
  };
96
99
  }
97
100
  const headers: Record<string, string> = {