cartethyia 2.5.9 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/.env.example +15 -42
  2. package/README.md +11 -10
  3. package/dist/dashboard/assets/{BannedPage-Brvuj_Eb.js → BannedPage-l6XMnfr9.js} +1 -1
  4. package/dist/dashboard/assets/BannedPage-l6XMnfr9.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-CqfXtI3y.js → CliToolDetailPage-DwOzAW45.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-DwOzAW45.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-GQeS91bg.js → CliToolsPage-BT3Up3QA.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-BT3Up3QA.js.gz +0 -0
  9. package/dist/dashboard/assets/{CombosPage-BDRsTXBB.js → CombosPage-6kYIUpzR.js} +1 -1
  10. package/dist/dashboard/assets/CombosPage-6kYIUpzR.js.gz +0 -0
  11. package/dist/dashboard/assets/{ConsoleLogPage-zP8AFHX0.js → ConsoleLogPage-zRnj1mlR.js} +1 -1
  12. package/dist/dashboard/assets/ConsoleLogPage-zRnj1mlR.js.gz +0 -0
  13. package/dist/dashboard/assets/{CustomizationPage-BmfrNZ14.js → CustomizationPage-C7m-H1Rz.js} +1 -1
  14. package/dist/dashboard/assets/CustomizationPage-C7m-H1Rz.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-C8MR_BdB.js.gz +0 -0
  17. package/dist/dashboard/assets/{LoginPage-DoreIgm8.js → LoginPage-CbphLvjg.js} +1 -1
  18. package/dist/dashboard/assets/LoginPage-CbphLvjg.js.gz +0 -0
  19. package/dist/dashboard/assets/{ModelPicker-C7pDb41R.js → ModelPicker-DVny4S5_.js} +1 -1
  20. package/dist/dashboard/assets/ModelPicker-DVny4S5_.js.gz +0 -0
  21. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js +1 -0
  22. package/dist/dashboard/assets/OverviewPage-DABu2Wgt.js.gz +0 -0
  23. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js +3 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-C15x9q13.js.gz +0 -0
  25. package/dist/dashboard/assets/{ProvidersPage-BnoPgA7w.js → ProvidersPage-Dfb2896L.js} +1 -1
  26. package/dist/dashboard/assets/ProvidersPage-Dfb2896L.js.gz +0 -0
  27. package/dist/dashboard/assets/{ProxyPage-Bq_TGgdb.js → ProxyPage-BaCIdAUt.js} +1 -1
  28. package/dist/dashboard/assets/ProxyPage-BaCIdAUt.js.gz +0 -0
  29. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js +1 -0
  30. package/dist/dashboard/assets/QuotaPage-BsdoCIw1.js.gz +0 -0
  31. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js +1 -0
  32. package/dist/dashboard/assets/SettingsPage-KVJFh3Ip.js.gz +0 -0
  33. package/dist/dashboard/assets/{SetupPage-Day3mCOn.js → SetupPage-D4g6vOGc.js} +1 -1
  34. package/dist/dashboard/assets/SetupPage-D4g6vOGc.js.gz +0 -0
  35. package/dist/dashboard/assets/{SortableList-DQxllnB5.js → SortableList-C93i14BD.js} +1 -1
  36. package/dist/dashboard/assets/SortableList-C93i14BD.js.gz +0 -0
  37. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js → StudioPage-SgQpymjm.js} +1 -1
  38. package/dist/dashboard/assets/{StudioPage-uMExoWu1.js.gz → StudioPage-SgQpymjm.js.gz} +0 -0
  39. package/dist/dashboard/assets/{UsagePage-DXa1oR-4.js → UsagePage-BFME-eba.js} +2 -2
  40. package/dist/dashboard/assets/UsagePage-BFME-eba.js.gz +0 -0
  41. package/dist/dashboard/assets/{api-keys-DQYLQxpW.js → api-keys-C23S9sgp.js} +1 -1
  42. package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
  43. package/dist/dashboard/assets/{app-BIt446yE.js → app-2KhtHCv9.js} +1 -1
  44. package/dist/dashboard/assets/{app-BIt446yE.js.gz → app-2KhtHCv9.js.gz} +0 -0
  45. package/dist/dashboard/assets/app-CEeaMHOy.css +2 -0
  46. package/dist/dashboard/assets/app-CEeaMHOy.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-C9FD_JwJ.js → assert-DU6qrMA_.js} +1 -1
  48. package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-CR72dasT.js → badge-CKsF123d.js} +1 -1
  50. package/dist/dashboard/assets/badge-CKsF123d.js.gz +0 -0
  51. package/dist/dashboard/assets/{banner-CI9_eSfO.js → banner-8j7uChA9.js} +1 -1
  52. package/dist/dashboard/assets/banner-8j7uChA9.js.gz +0 -0
  53. package/dist/dashboard/assets/{card-DS7CQEsO.js → card-CdsSlWA3.js} +1 -1
  54. package/dist/dashboard/assets/card-CdsSlWA3.js.gz +0 -0
  55. package/dist/dashboard/assets/{cli-tools-CNqzrfdb.js → cli-tools-BaFUuFFF.js} +1 -1
  56. package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
  57. package/dist/dashboard/assets/{clipboard-button-611pSsaX.js → clipboard-button-uL5aYLfW.js} +1 -1
  58. package/dist/dashboard/assets/clipboard-button-uL5aYLfW.js.gz +0 -0
  59. package/dist/dashboard/assets/{dialog-k37exjNt.js → dialog-C07hr5_G.js} +1 -1
  60. package/dist/dashboard/assets/dialog-C07hr5_G.js.gz +0 -0
  61. package/dist/dashboard/assets/{drawer-CX7N8ucR.js → drawer-BPO1TcKH.js} +1 -1
  62. package/dist/dashboard/assets/drawer-BPO1TcKH.js.gz +0 -0
  63. package/dist/dashboard/assets/{entry-CTP8AyiS.js → entry-Bz_CtDfC.js} +1 -1
  64. package/dist/dashboard/assets/entry-Bz_CtDfC.js.gz +0 -0
  65. package/dist/dashboard/assets/entry-CwPRKk0d.js +4 -0
  66. package/dist/dashboard/assets/entry-CwPRKk0d.js.gz +0 -0
  67. package/dist/dashboard/assets/entry-GJRbmrpA.js +1 -0
  68. package/dist/dashboard/assets/entry-GJRbmrpA.js.gz +0 -0
  69. package/dist/dashboard/assets/{github-badge-sltk1qUi.js → github-badge-DmQreSDd.js} +1 -1
  70. package/dist/dashboard/assets/github-badge-DmQreSDd.js.gz +0 -0
  71. package/dist/dashboard/assets/{index-z3zDOSMM.js → index-Bblu6erR.js} +2 -2
  72. package/dist/dashboard/assets/index-Bblu6erR.js.gz +0 -0
  73. package/dist/dashboard/assets/{inline-BhY2sSnO.js → inline-C9dCYaBZ.js} +1 -1
  74. package/dist/dashboard/assets/inline-C9dCYaBZ.js.gz +0 -0
  75. package/dist/dashboard/assets/{input-V1umFiBk.js → input-CjCnXweJ.js} +1 -1
  76. package/dist/dashboard/assets/input-CjCnXweJ.js.gz +0 -0
  77. package/dist/dashboard/assets/{layout-BBOYycyS.js → layout-V6y8DAkl.js} +1 -1
  78. package/dist/dashboard/assets/layout-V6y8DAkl.js.gz +0 -0
  79. package/dist/dashboard/assets/{list-row-1zzZYM0B.js → list-row-CM1AaG_y.js} +1 -1
  80. package/dist/dashboard/assets/list-row-CM1AaG_y.js.gz +0 -0
  81. package/dist/dashboard/assets/{live-BivGfuUs.js → live-ta6GMb-8.js} +1 -1
  82. package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
  83. package/dist/dashboard/assets/{model-bans-CmffjLuG.js → model-bans-BmYTmbAk.js} +1 -1
  84. package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
  85. package/dist/dashboard/assets/{mutation-46P0oWMe.js → mutation-g_fduiNw.js} +1 -1
  86. package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
  87. package/dist/dashboard/assets/{numbers-DkfMR5Qs.js → numbers-BOevJzdz.js} +1 -1
  88. package/dist/dashboard/assets/numbers-BOevJzdz.js.gz +0 -0
  89. package/dist/dashboard/assets/{query-keys-BFhGpwR1.js → query-keys-UETqfytp.js} +1 -1
  90. package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
  91. package/dist/dashboard/assets/{routing-CAb4F37R.js → routing-BPUo-W8d.js} +1 -1
  92. package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
  93. package/dist/dashboard/assets/{select-C6MMiaio.js → select-C980c4cz.js} +1 -1
  94. package/dist/dashboard/assets/select-C980c4cz.js.gz +0 -0
  95. package/dist/dashboard/assets/{settings-DNX9sydi.js → settings--3hxSyry.js} +1 -1
  96. package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
  97. package/dist/dashboard/assets/{stack-BHTfXdz_.js → stack-_gfTdLVB.js} +1 -1
  98. package/dist/dashboard/assets/stack-_gfTdLVB.js.gz +0 -0
  99. package/dist/dashboard/assets/{state-mPDRlQkl.js → state-2c5V4zo7.js} +1 -1
  100. package/dist/dashboard/assets/state-2c5V4zo7.js.gz +0 -0
  101. package/dist/dashboard/assets/{switch-DOmJxg7H.js → switch-Dkke7Naf.js} +1 -1
  102. package/dist/dashboard/assets/switch-Dkke7Naf.js.gz +0 -0
  103. package/dist/dashboard/assets/{useMutation-Dem0lXQj.js → useMutation-EDFRkn1i.js} +1 -1
  104. package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
  105. package/dist/dashboard/index.html +1 -1
  106. package/dist/dashboard/index.html.gz +0 -0
  107. package/dist/dashboard/precompressed-assets.json +51 -51
  108. package/migrations/README.md +52 -52
  109. package/migrations/full-postgres/0020_add_telemetry_event_analytics.sql +77 -0
  110. package/migrations/full-postgres/0021_add_api_key_concurrency_tolerance.sql +13 -0
  111. package/migrations/full-postgres/0022_add_inferhub_config_key.sql +17 -0
  112. package/migrations/full-postgres/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  113. package/migrations/lite-sqlite3/0020_add_telemetry_event_analytics.sql +69 -0
  114. package/migrations/lite-sqlite3/0021_add_api_key_concurrency_tolerance.sql +13 -0
  115. package/migrations/lite-sqlite3/0022_add_inferhub_config_key.sql +17 -0
  116. package/migrations/lite-sqlite3/0023_drop_api_key_concurrency_tolerance.sql +13 -0
  117. package/package.json +96 -97
  118. package/scripts/cli/admin.ts +126 -125
  119. package/scripts/cli/autostart.ts +237 -237
  120. package/scripts/cli/background.ts +120 -110
  121. package/scripts/cli/bin/carte.cjs +8 -8
  122. package/scripts/cli/bin/cartethyia.cjs +167 -167
  123. package/scripts/cli/console-menu.ts +308 -275
  124. package/scripts/cli/controller.ts +145 -0
  125. package/scripts/cli/doctor.ts +1 -1
  126. package/scripts/cli/env.ts +99 -99
  127. package/scripts/cli/gateway.ts +264 -261
  128. package/scripts/{health.ts → cli/health.ts} +4 -4
  129. package/scripts/cli/instance.ts +234 -224
  130. package/scripts/cli/main.ts +188 -164
  131. package/scripts/cli/platform.ts +64 -64
  132. package/scripts/cli/prompt.ts +275 -107
  133. package/scripts/cli/services.ts +88 -88
  134. package/scripts/cli/setup.ts +445 -445
  135. package/scripts/cli/start.ts +85 -82
  136. package/scripts/cli/startup-signal.ts +23 -23
  137. package/scripts/cli/telemetry.ts +70 -0
  138. package/scripts/cli/tray/index.ts +263 -263
  139. package/scripts/cli/tray/windows.ps1 +107 -107
  140. package/scripts/cli/tray.ts +192 -208
  141. package/scripts/cli/update.ts +39 -39
  142. package/scripts/cli/version.ts +67 -67
  143. package/scripts/cli/wordmark.ts +58 -58
  144. package/src/boot/app.ts +16 -1
  145. package/src/boot/dependencies.ts +128 -25
  146. package/src/config/package-paths.ts +24 -0
  147. package/src/config/resources.ts +137 -0
  148. package/src/config/runtime.ts +133 -76
  149. package/src/config/spec.ts +30 -29
  150. package/src/config/telemetry.ts +0 -25
  151. package/src/console/api-keys/bucket-spend.ts +14 -17
  152. package/src/console/api-keys/contracts.ts +410 -410
  153. package/src/console/api-keys/routes.ts +12 -0
  154. package/src/console/audit/store.ts +2 -3
  155. package/src/console/auth/setup-service.ts +8 -1
  156. package/src/console/backup/routes.ts +7 -0
  157. package/src/console/backup/service.ts +463 -463
  158. package/src/console/backup/store.ts +16 -11
  159. package/src/console/backup/validate.ts +1 -4
  160. package/src/console/cli-tools/fs-ops.ts +18 -2
  161. package/src/console/data-management/contracts.ts +1 -8
  162. package/src/console/data-management/operations.ts +61 -48
  163. package/src/console/data-management/routes.ts +4 -2
  164. package/src/console/domain-registration.ts +25 -3
  165. package/src/console/inferhub/client.ts +139 -0
  166. package/src/console/inferhub/key-store.ts +129 -0
  167. package/src/console/inferhub/normalize.ts +347 -0
  168. package/src/console/inferhub/routes.ts +411 -0
  169. package/src/console/inferhub/store.ts +109 -0
  170. package/src/console/inferhub/types.ts +183 -0
  171. package/src/console/observability/contracts.ts +2 -41
  172. package/src/console/observability/store.ts +176 -371
  173. package/src/console/providers/catalog/public-model-store.ts +0 -0
  174. package/src/console/providers/catalog/store.ts +23 -36
  175. package/src/console/quota/account-quota-shared.ts +52 -52
  176. package/src/console/quota/account-quota-tenant.ts +16 -24
  177. package/src/console/quota/refresh.ts +441 -441
  178. package/src/console/remote-support/service.ts +270 -114
  179. package/src/console/routing/pools/import-parse.ts +206 -206
  180. package/src/console/routing/pools/operations.ts +543 -543
  181. package/src/console/routing/pools/probe-verdict.ts +132 -132
  182. package/src/console/routing/pools/routes.ts +181 -181
  183. package/src/console/routing/pools/store.ts +1 -1
  184. package/src/console/settings/contracts.ts +42 -40
  185. package/src/console/settings/store.ts +25 -25
  186. package/src/console/share/share-stats.ts +22 -4
  187. package/src/console/share/share-usage.ts +30 -4
  188. package/src/console/shared/cursor.ts +15 -0
  189. package/src/console/updates/repository-updates.ts +40 -39
  190. package/src/console/updates/routes.ts +12 -0
  191. package/src/main.ts +13 -5
  192. package/src/network/pool/resolver.ts +1104 -1104
  193. package/src/observability/client-name.ts +22 -0
  194. package/src/observability/event-log.ts +5 -29
  195. package/src/observability/event-query.ts +690 -0
  196. package/src/observability/log-ring.ts +26 -2
  197. package/src/observability/log-sanitize.ts +118 -0
  198. package/src/observability/logger.ts +17 -13
  199. package/src/observability/metrics.ts +35 -0
  200. package/src/observability/payload-capture.ts +114 -41
  201. package/src/observability/payload-store.ts +249 -24
  202. package/src/observability/raw-event-writer.ts +118 -0
  203. package/src/observability/runtime-metrics.ts +71 -1
  204. package/src/observability/telemetry-buffer.ts +100 -17
  205. package/src/observability/telemetry-reconciliation.ts +417 -0
  206. package/src/persistence/boot.ts +20 -9
  207. package/src/persistence/db-pg.ts +13 -0
  208. package/src/persistence/db-sqlite.ts +569 -497
  209. package/src/persistence/dialect.ts +3 -2
  210. package/src/persistence/migrate.ts +181 -181
  211. package/src/persistence/schema.ts +1496 -1406
  212. package/src/persistence/shared-cache.ts +5 -1
  213. package/src/persistence/stores/api-key-store.ts +581 -581
  214. package/src/persistence/stores/telemetry-store.ts +124 -63
  215. package/src/protocol/reasoning-text.ts +30 -0
  216. package/src/protocol/registry.ts +2 -0
  217. package/src/protocol/response/chat.ts +33 -7
  218. package/src/protocol/response/codex.ts +14 -2
  219. package/src/protocol/response/messages.ts +5 -2
  220. package/src/providers/authentication/oauth-flow-store.ts +3 -10
  221. package/src/providers/bundled-discovery-providers.ts +122 -122
  222. package/src/providers/default-registry.ts +14 -0
  223. package/src/providers/discovery/catalog/catalog-blob.ts +18 -18
  224. package/src/providers/discovery/models-dev-catalog.ts +354 -354
  225. package/src/providers/discovery/probe-phases.ts +43 -7
  226. package/src/providers/discovery/probing-service.ts +70 -32
  227. package/src/providers/integrations/antigravity/antigravity.ts +9 -2
  228. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +85 -17
  229. package/src/providers/integrations/buddy/buddy-chat-shared.ts +934 -934
  230. package/src/providers/integrations/buddy/buddy-checkin.ts +5 -9
  231. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +3 -7
  232. package/src/providers/integrations/buddy/buddy-quota-shared.ts +3 -1
  233. package/src/providers/integrations/buddy/capabilities.ts +4 -0
  234. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +57 -49
  235. package/src/providers/integrations/buddy/codebuddy/provider.ts +180 -180
  236. package/src/providers/integrations/buddy/workbuddy/provider.ts +206 -206
  237. package/src/providers/integrations/buddy/workbuddy/quota.ts +161 -161
  238. package/src/providers/integrations/claude/claude-quota.ts +2 -2
  239. package/src/providers/integrations/claude/claude-user-profiles.ts +3 -2
  240. package/src/providers/integrations/claude/claude.ts +3 -4
  241. package/src/providers/integrations/cline/cline.ts +94 -8
  242. package/src/providers/integrations/codex/codex.ts +61 -37
  243. package/src/providers/integrations/cursor/cursor-catalog.ts +368 -368
  244. package/src/providers/integrations/cursor/cursor-http2.ts +300 -300
  245. package/src/providers/integrations/cursor/cursor-identity.ts +2 -4
  246. package/src/providers/integrations/cursor/cursor-request.ts +11 -0
  247. package/src/providers/integrations/cursor/cursor.ts +29 -17
  248. package/src/providers/integrations/cursor/protocol/framing.ts +129 -129
  249. package/src/providers/integrations/cursor/protocol/messages.ts +2380 -2380
  250. package/src/providers/integrations/cursor/protocol/struct.ts +305 -305
  251. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +275 -0
  252. package/src/providers/integrations/github/github.ts +3 -1
  253. package/src/providers/integrations/grok/grok-quota.ts +279 -279
  254. package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -73
  255. package/src/providers/integrations/grok/grok-ratelimit.ts +218 -218
  256. package/src/providers/integrations/hermes.ts +7 -1
  257. package/src/providers/integrations/inferhub.ts +201 -73
  258. package/src/providers/integrations/kilo/kilo.ts +152 -152
  259. package/src/providers/integrations/kiro/kiro-machine-id.ts +2 -4
  260. package/src/providers/integrations/opencode/provider.ts +2 -0
  261. package/src/providers/integrations/openrouter/provider.ts +129 -129
  262. package/src/providers/integrations/qoder/qoder-quota.ts +193 -192
  263. package/src/providers/integrations/qoder/qoder-realm.ts +106 -106
  264. package/src/providers/integrations/trae/trae-headers.ts +17 -48
  265. package/src/providers/integrations/trae/trae-oauth.ts +4 -26
  266. package/src/providers/integrations/trae/trae-quota.ts +389 -384
  267. package/src/providers/integrations/trae/trae-realm.ts +15 -2
  268. package/src/providers/integrations/trae/trae.ts +22 -24
  269. package/src/providers/integrations/xiaomi-mimo/think-stream.ts +100 -24
  270. package/src/providers/integrations/zcode/oauth.ts +1 -1
  271. package/src/providers/operations/account-health-service.ts +605 -279
  272. package/src/providers/provider-metadata.ts +12 -1
  273. package/src/providers/provider-model-definition.ts +373 -373
  274. package/src/providers/provider-probe.ts +3 -0
  275. package/src/providers/quota/quota-contracts.ts +3 -7
  276. package/src/providers/search/search-provider.ts +2 -6
  277. package/src/security/admission/contracts.ts +10 -0
  278. package/src/security/admission/in-memory-store.ts +89 -14
  279. package/src/security/admission/lua.ts +191 -182
  280. package/src/security/admission/redis-store.ts +30 -0
  281. package/src/security/admission/service.ts +18 -0
  282. package/src/security/api-key-auth-cache.ts +96 -0
  283. package/src/security/api-key-auth.ts +11 -100
  284. package/src/security/client-router-fingerprint.ts +3 -7
  285. package/src/security/ip-boundary.ts +7 -3
  286. package/src/shared/coerce.ts +67 -0
  287. package/src/shared/hash.ts +6 -0
  288. package/src/shared/time.ts +7 -0
  289. package/src/transport/dispatch/attempt-finalize.ts +26 -138
  290. package/src/transport/dispatch/attempt-loop.ts +103 -81
  291. package/src/transport/dispatch/capture-policy.ts +78 -0
  292. package/src/transport/dispatch/proxy-request.ts +4 -2
  293. package/src/transport/dispatch/streaming/encoder.ts +111 -5
  294. package/src/transport/dispatch/streaming/stream.ts +19 -2
  295. package/src/transport/dispatch/streaming/thinking-loop.ts +300 -0
  296. package/src/transport/failure-policy.ts +27 -0
  297. package/src/transport/guards/abuse-guard.ts +2 -2
  298. package/src/transport/guards/auth-guard.ts +17 -0
  299. package/src/transport/guards/body-policy.ts +3 -2
  300. package/src/transport/guards/concurrency-guard.ts +89 -13
  301. package/src/transport/guards/early-rejection-capture.ts +43 -3
  302. package/src/transport/guards/error-lifecycle.ts +10 -2
  303. package/src/transport/guards/guard-errors.ts +23 -0
  304. package/src/transport/guards/headroom-guard.ts +41 -7
  305. package/src/transport/guards/pipeline.ts +24 -0
  306. package/src/transport/guards/request-context.ts +2 -1
  307. package/src/transport/routing/admission.ts +51 -9
  308. package/src/transport/routing/bounded-lru.ts +49 -0
  309. package/src/transport/routing/candidate-index.ts +88 -0
  310. package/src/transport/routing/reservations.ts +121 -7
  311. package/src/transport/routing/round-robin.ts +10 -22
  312. package/src/transport/routing/route-catalog.ts +26 -13
  313. package/src/transport/routing/route-model.ts +22 -2
  314. package/src/transport/routing/router.ts +53 -31
  315. package/src/transport/surface/chat/encode.ts +2 -3
  316. package/src/transport/surface/chat/parse.ts +2 -1
  317. package/src/transport/surface/dialects.ts +11 -3
  318. package/src/transport/surface/messages/encode.ts +2 -1
  319. package/src/transport/surface/messages/parse.ts +3 -1
  320. package/src/transport/surface/messages/stream.ts +2 -6
  321. package/src/workers/maintenance-lease.ts +200 -0
  322. package/src/workers/scheduler.ts +101 -1
  323. package/dist/dashboard/assets/BannedPage-Brvuj_Eb.js.gz +0 -0
  324. package/dist/dashboard/assets/CliToolDetailPage-CqfXtI3y.js.gz +0 -0
  325. package/dist/dashboard/assets/CliToolsPage-GQeS91bg.js.gz +0 -0
  326. package/dist/dashboard/assets/CombosPage-BDRsTXBB.js.gz +0 -0
  327. package/dist/dashboard/assets/ConsoleLogPage-zP8AFHX0.js.gz +0 -0
  328. package/dist/dashboard/assets/CustomizationPage-BmfrNZ14.js.gz +0 -0
  329. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js +0 -1
  330. package/dist/dashboard/assets/HealthEventsModal-Dn3M6WZc.js.gz +0 -0
  331. package/dist/dashboard/assets/LoginPage-DoreIgm8.js.gz +0 -0
  332. package/dist/dashboard/assets/ModelPicker-C7pDb41R.js.gz +0 -0
  333. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js +0 -1
  334. package/dist/dashboard/assets/OverviewPage-CvvD1Ugk.js.gz +0 -0
  335. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js +0 -3
  336. package/dist/dashboard/assets/ProviderDetailPage-Clbn1gsW.js.gz +0 -0
  337. package/dist/dashboard/assets/ProvidersPage-BnoPgA7w.js.gz +0 -0
  338. package/dist/dashboard/assets/ProxyPage-Bq_TGgdb.js.gz +0 -0
  339. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js +0 -1
  340. package/dist/dashboard/assets/QuotaPage-D9DHXvom.js.gz +0 -0
  341. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js +0 -1
  342. package/dist/dashboard/assets/SettingsPage-7xV8WkWL.js.gz +0 -0
  343. package/dist/dashboard/assets/SetupPage-Day3mCOn.js.gz +0 -0
  344. package/dist/dashboard/assets/SortableList-DQxllnB5.js.gz +0 -0
  345. package/dist/dashboard/assets/UsagePage-DXa1oR-4.js.gz +0 -0
  346. package/dist/dashboard/assets/api-keys-DQYLQxpW.js.gz +0 -0
  347. package/dist/dashboard/assets/app-CX_Z8cMs.css +0 -2
  348. package/dist/dashboard/assets/app-CX_Z8cMs.css.gz +0 -0
  349. package/dist/dashboard/assets/assert-C9FD_JwJ.js.gz +0 -0
  350. package/dist/dashboard/assets/badge-CR72dasT.js.gz +0 -0
  351. package/dist/dashboard/assets/banner-CI9_eSfO.js.gz +0 -0
  352. package/dist/dashboard/assets/card-DS7CQEsO.js.gz +0 -0
  353. package/dist/dashboard/assets/cli-tools-CNqzrfdb.js.gz +0 -0
  354. package/dist/dashboard/assets/clipboard-button-611pSsaX.js.gz +0 -0
  355. package/dist/dashboard/assets/dialog-k37exjNt.js.gz +0 -0
  356. package/dist/dashboard/assets/drawer-CX7N8ucR.js.gz +0 -0
  357. package/dist/dashboard/assets/entry-B9Xvtnfj.js +0 -1
  358. package/dist/dashboard/assets/entry-B9Xvtnfj.js.gz +0 -0
  359. package/dist/dashboard/assets/entry-ByMGkR3C.js +0 -4
  360. package/dist/dashboard/assets/entry-ByMGkR3C.js.gz +0 -0
  361. package/dist/dashboard/assets/entry-CTP8AyiS.js.gz +0 -0
  362. package/dist/dashboard/assets/github-badge-sltk1qUi.js.gz +0 -0
  363. package/dist/dashboard/assets/index-z3zDOSMM.js.gz +0 -0
  364. package/dist/dashboard/assets/inline-BhY2sSnO.js.gz +0 -0
  365. package/dist/dashboard/assets/input-V1umFiBk.js.gz +0 -0
  366. package/dist/dashboard/assets/layout-BBOYycyS.js.gz +0 -0
  367. package/dist/dashboard/assets/list-row-1zzZYM0B.js.gz +0 -0
  368. package/dist/dashboard/assets/live-BivGfuUs.js.gz +0 -0
  369. package/dist/dashboard/assets/model-bans-CmffjLuG.js.gz +0 -0
  370. package/dist/dashboard/assets/mutation-46P0oWMe.js.gz +0 -0
  371. package/dist/dashboard/assets/numbers-DkfMR5Qs.js.gz +0 -0
  372. package/dist/dashboard/assets/query-keys-BFhGpwR1.js.gz +0 -0
  373. package/dist/dashboard/assets/routing-CAb4F37R.js.gz +0 -0
  374. package/dist/dashboard/assets/select-C6MMiaio.js.gz +0 -0
  375. package/dist/dashboard/assets/settings-DNX9sydi.js.gz +0 -0
  376. package/dist/dashboard/assets/stack-BHTfXdz_.js.gz +0 -0
  377. package/dist/dashboard/assets/state-mPDRlQkl.js.gz +0 -0
  378. package/dist/dashboard/assets/switch-DOmJxg7H.js.gz +0 -0
  379. package/dist/dashboard/assets/useMutation-Dem0lXQj.js.gz +0 -0
  380. package/scripts/build/aot.ts +0 -143
  381. package/scripts/build/build.ts +0 -24
  382. package/scripts/build/compile.ts +0 -88
  383. package/scripts/build/restart.ts +0 -120
  384. package/scripts/build/start.ts +0 -25
  385. package/src/observability/event-compaction.ts +0 -317
  386. package/src/observability/event-day-index.ts +0 -440
@@ -1,3 +1,5 @@
1
+ import { asCoercedNumber as sharedAsNumber, asRecord as sharedAsRecord } from "../../../shared/coerce";
2
+
1
3
  // Buddy-family daily check-in (daily login credit claim), shared by all three
2
4
  // variants (`cb`, `cbcn`, `workbuddy`): same Tencent billing facade, same
3
5
  // status/claim contract — only the endpoint base and identity headers differ
@@ -370,20 +372,14 @@ function isRetryableClaim(error: unknown, status: number | null): boolean {
370
372
  }
371
373
 
372
374
  function asRecord(value: unknown): Record<string, unknown> | null {
373
- return value !== null && typeof value === "object" && !Array.isArray(value)
374
- ? (value as Record<string, unknown>)
375
- : null;
375
+ return sharedAsRecord(value) ?? null;
376
376
  }
377
377
 
378
378
  function asNumber(value: unknown): number | null {
379
- if (typeof value === "number") return Number.isFinite(value) ? value : null;
380
- if (typeof value === "string" && value.trim()) {
381
- const parsed = Number(value);
382
- return Number.isFinite(parsed) ? parsed : null;
383
- }
384
- return null;
379
+ return sharedAsNumber(value) ?? null;
385
380
  }
386
381
 
382
+
387
383
  /** Reads the envelope's business code; `0` means success. */
388
384
  function envelopeCode(payload: unknown): number | null {
389
385
  const envelope = asRecord(payload);
@@ -1,3 +1,5 @@
1
+ import { asNumber as sharedAsNumber, asRecord } from "../../../shared/coerce";
2
+
1
3
  /**
2
4
  * Model discovery for the buddy family (CodeBuddy intl / CN, WorkBuddy).
3
5
  *
@@ -77,14 +79,8 @@ function siteOrigin(baseUrl: string): string {
77
79
  return baseUrl.replace(/\/+$/, "").replace(/\/v\d+$/, "");
78
80
  }
79
81
 
80
- function asRecord(value: unknown): Record<string, unknown> | undefined {
81
- return typeof value === "object" && value !== null && !Array.isArray(value)
82
- ? (value as Record<string, unknown>)
83
- : undefined;
84
- }
85
-
86
82
  function asNumber(value: unknown): number | null {
87
- return typeof value === "number" && Number.isFinite(value) ? value : null;
83
+ return sharedAsNumber(value) ?? null;
88
84
  }
89
85
 
90
86
  /**
@@ -1,3 +1,5 @@
1
+ import { asNumber as sharedAsNumber } from "../../../shared/coerce";
2
+
1
3
  /**
2
4
  * Shared Tencent billing-meter parsing for the CodeBuddy family
3
5
  * (`cb`, `cbcn`, `workbuddy`).
@@ -348,7 +350,7 @@ function enterpriseUsageUrl(resourceUrl: string): string {
348
350
  }
349
351
 
350
352
  function finiteNumber(value: unknown): number | undefined {
351
- return typeof value === "number" && Number.isFinite(value) ? value : undefined;
353
+ return sharedAsNumber(value);
352
354
  }
353
355
 
354
356
  /**
@@ -1,3 +1,7 @@
1
+ // dynamic-import-ok: lazy per-realm capability map. Each buddy regional
2
+ // product (cb/cbcn/workbuddy/workbuddycn) imports its adapter + oauth +
3
+ // discovery on first use so a deployment that only serves one realm never
4
+ // drags the others into memory.
1
5
  import type { ProviderModuleCapabilities } from "../../provider-capabilities";
2
6
  import { oauthCapability, quotaCapability } from "../../provider-capabilities";
3
7
 
@@ -6,7 +6,7 @@
6
6
  // Headers: per-provider CodeBuddy headers (CLI identity for CN)
7
7
  // Payload: neutralize CN agent prompts, reasoning_summary auto only when reasoning_effort
8
8
 
9
- import { OpenAICompatibleAdapter } from "../../../adapters/compatible-adapter";
9
+ import { BuddyMediaAdapter } from "../buddy-media";
10
10
  import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderAdapter } from "../../../provider-contracts";
11
11
  import type { ModelDefinition } from "../../../provider-model-definition";
12
12
  import type { DiscoveryInput } from "../../../discovery/discovery-types";
@@ -16,7 +16,13 @@ import { providerBaseUrl } from "../../../provider-metadata";
16
16
  import {
17
17
  codebuddyAdapterConfig,
18
18
  } from "./shared";
19
- import { makeBuddyModel, type BuddyRawEntry } from "../buddy-catalog-shared";
19
+ import { CODEBUDDY_SYSTEM_PROMPT } from "./provider";
20
+ import {
21
+ BUDDY_CN_IMAGE_MODEL_ID_SET,
22
+ makeBuddyCnImageModels,
23
+ makeBuddyModel,
24
+ type BuddyRawEntry,
25
+ } from "../buddy-catalog-shared";
20
26
  import { BUDDY_CN_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
21
27
  import {
22
28
  buddyPrePayloadCommon,
@@ -100,59 +106,47 @@ export function codeBuddyCnPrePayload(
100
106
  // Exported because `buddyModelOutputLimit` searches every buddy raw table, and
101
107
  // a CN-only id would otherwise never get an output limit.
102
108
  export const CODEBUDDY_CN_RAW: readonly BuddyRawEntry[] = [
103
- ["glm-5.1", "GLM 5.1", true, true, 200_000, 131_072],
104
- ["glm-5.2", "GLM 5.2", true, true, 1_000_000, 131_072],
105
- ["glm-5.3", "GLM 5.3", true, true, 1_000_000, 131_072],
109
+ ["glm-5.1", "GLM 5.1", true, true, 200_000, 48_000],
110
+ ["glm-5.2", "GLM 5.2", true, true, 1_000_000, 64_000],
111
+ ["glm-5.3", "GLM 5.3", true, true, 1_000_000, 64_000],
106
112
  ["glm-5.3-flash", "GLM 5.3 Flash", true, true, 1_000_000, 131_072],
107
- ["glm-5v-turbo", "GLM 5v Turbo", true, true, 200_000, 131_072],
108
- ["minimax-m3", "MiniMax M3", true, true, 512_000, 512_000],
113
+ ["glm-5v-turbo", "GLM 5v Turbo", true, true, 200_000, 64_000],
114
+ ["minimax-m3", "MiniMax M3", true, true, 512_000, 64_000],
109
115
  // 1M context, reasoning always on (upstream states both); vision inherited
110
116
  // from the M3 row, which is the same family.
111
- ["minimax-m3.1-flash", "MiniMax M3.1 Flash", true, true, 1_000_000, 512_000],
112
- ["mimo-v2.6-pro", "MiMo V2.6 Pro", true, true, 1_000_000, 512_000],
113
- ["kimi-k2.8-preview", "Kimi K2.8 Preview", true, true, 1_048_576, 65_536],
114
- ["kimi-k2.7", "Kimi K2.7", true, true, 256_000, 65_536],
115
- ["kimi-k2.6", "Kimi K2.6", true, true, 256_000, 262_144],
116
- ["kimi-k2.5", "Kimi K2.5", true, true, 164_000, 262_144],
117
- ["kimi-k3.1-pro", "Kimi K3.1 Pro", true, true, 1_000_000, 64_000],
118
- ["kimi-k3.1-pro-highspeed", "Kimi K3.1 Pro Highspeed", true, true, 1_000_000, 64_000],
117
+ ["minimax-m3.1-flash", "MiniMax M3.1 Flash", true, true, 1_000_000, 128_000],
118
+ ["mimo-v2.6-pro", "MiMo V2.6 Pro", true, true, 1_000_000, 128_000],
119
+ ["kimi-k2.8-preview", "Kimi K2.8 Preview", true, true, 1_000_000, 64_000],
120
+ ["kimi-k3.1-pro", "Kimi K3.1 Pro", true, true, 1_000_000, 32_000],
119
121
  ["hy3", "Hy3", true, true, 192_000, 64_000],
120
- ["hy4-preview", "Hy4 Preview", true, true, 1_000_000, 64_000],
121
- ["uto", "UTO", true, true, 256_000, 32_000],
122
+ ["hy4-preview", "Hy4 Preview", true, true, 960_000, 64_000],
122
123
  ["space-bunny", "Space Bunny", true, true, 1_000_000, 128_000],
123
124
  ["step-5-preview", "Step 5 Preview", true, true, 1_000_000, 64_000],
124
- ["deepseek-v4-flash", "DeepSeek V4 Flash", true, true, 1_000_000, 384_000],
125
- ["deepseek-v4-pro", "DeepSeek V4 Pro", true, true, 1_000_000, 384_000],
126
- ["deepseek-v4.1-flash", "DeepSeek V4.1 Flash", true, true, 1_000_000, 384_000],
127
- // ---- Legacy CN fallback ids (reference `DEFAULT_MODELS`) ------------------
128
- // The reference's CN fallback table carries these and we did not. They are
129
- // *fallback* rows: the reference has no static international roster at all, so
130
- // an id appearing there means "there is a fallback value", not "the upstream
131
- // serves it today". Limits below are the closest sibling's where the
132
- // reference states none — unverified — confirm against a live account before
133
- // trusting the numbers.
134
- // unverified — confirm first: limits inherited from the sibling generation.
135
- // `hy4-preview-x` is deliberately absent: the reference's fallback list has
136
- // it, but a live CN CLI directory read does not publish it
137
- // (`test/providers/buddy-model-catalog.test.ts`), and live discovery beats a
138
- // fallback table.
139
- ["hy3-x", "Hy3 X", true, true, 192_000, 64_000],
140
- ["deepseek-v3-2-volc", "DeepSeek V3.2 Volc", true, true, 1_000_000, 384_000],
141
- ["glm-5.0", "GLM 5.0", true, true, 200_000, 131_072],
142
- ["glm-5.0-turbo", "GLM 5.0 Turbo", true, true, 200_000, 131_072],
143
- ["glm-4.7", "GLM 4.7", true, true, 200_000, 131_072],
144
- ["glm-4.6", "GLM 4.6", true, true, 200_000, 131_072],
145
- ["glm-4.6v", "GLM 4.6V", true, true, 200_000, 131_072],
146
- ["minimax-m2.7", "MiniMax M2.7", true, true, 512_000, 512_000],
147
- ["minimax-m2.5", "MiniMax M2.5", true, true, 512_000, 512_000],
148
- ["kimi-k2-thinking", "Kimi K2 Thinking", true, true, 256_000, 65_536],
149
- ["hunyuan-chat", "Hunyuan Chat", true, true, 256_000, 32_000],
150
- // `default` is the CN backend-selected id, the CN counterpart of the intl
151
- // `default-model`. Limits are the conservative floor of the roster.
152
- // unverified — confirm first.
153
- ["default", "Default", true, true, 200_000, 32_000],
125
+ ["deepseek-v4-pro", "DeepSeek V4 Pro", true, true, 1_000_000, 128_000],
126
+ ["deepseek-v4.1-flash", "DeepSeek V4.1 Flash", true, true, 1_000_000, 128_000],
127
+ // Live on the CN roster but absent here, so a request for it resolved to
128
+ // nothing. Limits as published by /v3/config.
129
+ ["kimi-k3-1", "Kimi K3-1", true, true, 1_000_000, 32_000],
130
+ ["minimax-m2.7", "MiniMax M2.7", true, true, 200_000, 48_000],
131
+ ];
132
+ /**
133
+ * CN's image-generation rows (`hunyuan-image-alpha`).
134
+ *
135
+ * Reached through `/images/generations` like the international rows. The image
136
+ * ids are filtered out of the chat pass so one id never appears under two
137
+ * service kinds, matching how the intl catalog does it.
138
+ */
139
+ export const CODEBUDDY_CN_IMAGE_MODELS: readonly ModelDefinition[] = makeBuddyCnImageModels(
140
+ CODEBUDDY_CN_PROVIDER_ID,
141
+ "/images/generations",
142
+ );
143
+
144
+ export const CODEBUDDY_CN_MODELS: readonly ModelDefinition[] = [
145
+ ...CODEBUDDY_CN_RAW.filter((entry) => !BUDDY_CN_IMAGE_MODEL_ID_SET.has(entry[0])).map((entry) =>
146
+ makeBuddyModel(entry, CODEBUDDY_CN_PROVIDER_ID, undefined, "cn"),
147
+ ),
148
+ ...CODEBUDDY_CN_IMAGE_MODELS,
154
149
  ];
155
- export const CODEBUDDY_CN_MODELS: readonly ModelDefinition[] = CODEBUDDY_CN_RAW.map((entry) => makeBuddyModel(entry, "cbcn", undefined, "cn"));
156
150
 
157
151
  /** Reads the CodeBuddy CN console directory (same envelope as the intl site). */
158
152
  export async function discoverCodeBuddyCnModels(
@@ -172,7 +166,10 @@ export async function discoverCodeBuddyCnModels(
172
166
  // Public factory
173
167
 
174
168
  export function createCodeBuddyCnAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
175
- return new OpenAICompatibleAdapter(
169
+ // BuddyMediaAdapter, not OpenAICompatibleAdapter: the CN realm publishes an
170
+ // image-generation row, and the plain compatible adapter has no image path,
171
+ // so `hunyuan-image-alpha` would route to /chat/completions and fail.
172
+ return new BuddyMediaAdapter(
176
173
  codebuddyAdapterConfig({
177
174
  providerId: CODEBUDDY_CN_PROVIDER_ID,
178
175
  baseUrl: CODEBUDDY_CN_BASE_URL,
@@ -180,5 +177,16 @@ export function createCodeBuddyCnAdapter(fetchImpl?: typeof fetch): ProviderAdap
180
177
  prePayload: codeBuddyCnPrePayload,
181
178
  ...(fetchImpl ? { fetchImpl } : {}),
182
179
  }),
180
+ {
181
+ variant: "CLI",
182
+ // The CN realm has no separate system prompt of its own; the neutral CN
183
+ // prompt is applied by `codeBuddyCnPrePayload`, so the media config
184
+ // reuses the intl one purely to satisfy the required field. Image
185
+ // generation sends a prompt, not a conversation, so this turn is
186
+ // discarded by the image path in every case.
187
+ systemPrompt: CODEBUDDY_SYSTEM_PROMPT,
188
+ baseUrl: CODEBUDDY_CN_BASE_URL,
189
+ imageGenerationPath: "/images/generations",
190
+ },
183
191
  );
184
192
  }
@@ -1,180 +1,180 @@
1
- // CodeBuddy International adapter — exact provider contract.
2
- // Canonical provider ID: cb
3
- // Base (manifest-owned CODEBUDDY_BASE_URL) → Chat: base + /chat/completions
4
- // Auth: Authorization Bearer for both api_key and oauth
5
- // Stream: force stream=true upstream, factory reaggregates for non-stream callers
6
- // Headers: per-provider CodeBuddy headers with fresh correlation IDs per dispatch
7
- // Payload: leading CodeBuddy system prompt + typed user content, reasoning_summary auto only when reasoning_effort
8
-
9
- import { BuddyMediaAdapter } from "../buddy-media";
10
- import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderAdapter } from "../../../provider-contracts";
11
- import type { ModelDefinition } from "../../../provider-model-definition";
12
- import type { DiscoveryInput } from "../../../discovery/discovery-types";
13
- import { GatewayError } from "../../../../protocol/gateway-error";
14
- import type { CanonicalRequest } from "../../../../protocol/canonical-model";
15
- import { providerBaseUrl } from "../../../provider-metadata";
16
- import {
17
- codebuddyAdapterConfig,
18
- codebuddyHeaders,
19
- } from "./shared";
20
- import {
21
- BUDDY_SHARED_RAW,
22
- BUDDY_IMAGE_MODEL_ID_SET,
23
- BUDDY_VIDEO_MODEL_ID_SET,
24
- makeBuddyModel,
25
- makeBuddyImageModels,
26
- makeBuddyVideoModels,
27
- type BuddyRawEntry,
28
- } from "../buddy-catalog-shared";
29
- import { BUDDY_INTL_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
30
- import {
31
- applyBuddySystemPrompt,
32
- buddyPrePayloadCommon,
33
- normalizeBuddyToolNames,
34
- } from "../buddy-chat-shared";
35
-
36
-
37
- // Constants — public contract
38
- export const CODEBUDDY_PROVIDER_ID = "cb" as const;
39
- export const CODEBUDDY_BASE_URL = providerBaseUrl("cb");
40
- // Upstream model translation — preserve provider mapping
41
-
42
- // Payload hook — provider intl semantics
43
- // - force stream=true
44
- // - reasoning_summary auto only when reasoning_effort requested
45
- // - upstreamId translation
46
- // - leading CodeBuddy system prompt + typed user content normalization
47
-
48
- /**
49
- * Leading system turn for this variant.
50
- *
51
- * The upstream validates that the wire *opens* with a `system` turn (code
52
- * `11128`) but does not check its text — the CN variant installs a plain
53
- * engineering-assistant sentence in the same slot and the gateway accepts it.
54
- * So this text is a product choice rather than a wire contract, and the
55
- * previous vendor-branded line ("You are CodeBuddy Code.") made every request
56
- * claim an identity the caller never chose, while also discarding whatever
57
- * system prompt the caller actually sent.
58
- *
59
- * The prompt is therefore a neutral assistant identity with an explicit
60
- * persona: pragmatic, direct, and honest — no sycophancy, no hedging, no
61
- * invented certainty.
62
- */
63
- export const CODEBUDDY_SYSTEM_PROMPT =
64
- "You are a pragmatic and direct software engineering assistant. " +
65
- "Be honest and truthful: state what you know, say plainly when you are unsure " +
66
- "or do not know, and never claim to have done something you have not done. " +
67
- "Prefer concrete answers over filler, and say so when a request is ambiguous " +
68
- "instead of guessing silently.";
69
-
70
- function codeBuddyIntlPrePayload(
71
- payload: Record<string, unknown>,
72
- request: CanonicalRequest,
73
- candidate: ProviderDispatchTarget,
74
- context?: ProviderDispatchContext,
75
- ): void {
76
- // International ladder: DeepSeek Flash and friends serve only `high`.
77
- buddyPrePayloadCommon(payload, request, "intl", context);
78
- const rawModel = payload["model"];
79
- const source =
80
- typeof rawModel === "string" && rawModel.length > 0
81
- ? rawModel
82
- : candidate.model_id;
83
- if (!source) throw new GatewayError("invalid_request", 400, "CodeBuddy model is required");
84
- const messages = payload["messages"];
85
- if (Array.isArray(messages)) {
86
- applyBuddySystemPrompt(messages as Array<Record<string, unknown>>, CODEBUDDY_SYSTEM_PROMPT);
87
- }
88
- normalizeBuddyToolNames(payload);
89
- void request;
90
- }
91
-
92
- // Model catalog — shared CodeBuddy / WorkBuddy international roster
93
-
94
- const CODEBUDDY_INTL_RAW: readonly BuddyRawEntry[] = BUDDY_SHARED_RAW;
95
-
96
- /**
97
- * CodeBuddy's image generation rows.
98
- *
99
- * These ids also sit on the shared chat roster as ordinary `llm` rows, which is
100
- * why they were unreachable as image models: nothing downstream could tell a
101
- * chat model from one that returns an image, so `mediaGeneration` was false for
102
- * every catalog row. The roster and the declared capabilities come from
103
- * {@link makeBuddyImageModels} so cb and WorkBuddy cannot drift.
104
- */
105
- export const CODEBUDDY_IMAGE_MODELS: readonly ModelDefinition[] = makeBuddyImageModels(
106
- "cb",
107
- "/images/generations",
108
- );
109
-
110
- /**
111
- * CodeBuddy's video-generation rows (`seedance-2.5`).
112
- *
113
- * Reached through `/videos/generations` on the `/v2` base, so the endpoint is
114
- * the upstream video path rather than a chat-completions path.
115
- */
116
- export const CODEBUDDY_VIDEO_MODELS: readonly ModelDefinition[] = makeBuddyVideoModels(
117
- "cb",
118
- "/videos/generations",
119
- );
120
-
121
- /**
122
- * The full cb catalog the registry loads: chat roster plus image and video rows.
123
- *
124
- * The image and video ids are filtered out of the chat pass so one id never
125
- * appears under two service kinds. Exported as a single list so
126
- * `default-registry.ts` keeps one import for this provider.
127
- */
128
- export const CODEBUDDY_MODELS: readonly ModelDefinition[] = [
129
- ...CODEBUDDY_INTL_RAW.filter(
130
- (entry) => !BUDDY_IMAGE_MODEL_ID_SET.has(entry[0]) && !BUDDY_VIDEO_MODEL_ID_SET.has(entry[0]),
131
- ).map((entry) => makeBuddyModel(entry, "cb")),
132
- ...CODEBUDDY_IMAGE_MODELS,
133
- ...CODEBUDDY_VIDEO_MODELS,
134
- ];
135
-
136
- /**
137
- * Reads the CodeBuddy intl console directory.
138
- *
139
- * The static `CODEBUDDY_MODELS` above stays the fallback — this console is
140
- * documented to answer 500 intermittently — while discovery carries the
141
- * upstream's own limits and capability flags.
142
- */
143
- export async function discoverCodeBuddyModels(
144
- input: DiscoveryInput,
145
- ): Promise<readonly ModelDefinition[] | null> {
146
- return fetchBuddyDirectoryModels({
147
- siteUrl: CODEBUDDY_BASE_URL,
148
- providerId: CODEBUDDY_PROVIDER_ID,
149
- credential: input.credential,
150
- modelsPath: BUDDY_INTL_MODELS_PATH,
151
- endpoint: undefined,
152
- ...(input.signal ? { signal: input.signal } : {}),
153
- ...(input.fetcher ? { fetcher: input.fetcher } : {}),
154
- });
155
- }
156
-
157
- // Public factory — uses OpenAI-compatible factory but forces provider semantics
158
- // Supports both api_key and oauth via Authorization Bearer (factory handles both)
159
-
160
- export function createCodeBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
161
- return new BuddyMediaAdapter(
162
- codebuddyAdapterConfig({
163
- providerId: CODEBUDDY_PROVIDER_ID,
164
- baseUrl: CODEBUDDY_BASE_URL,
165
- variant: "IDE",
166
- cliIdentity: true,
167
- prePayload: codeBuddyIntlPrePayload,
168
- ...(fetchImpl ? { fetchImpl } : {}),
169
- }),
170
- {
171
- variant: "IDE",
172
- // BuddyMediaConfig has no `cliIdentity`; the CLI identity is selected by
173
- // supplying the builder that takes it.
174
- buildHeaders: (context, request) => codebuddyHeaders("IDE", context, request, true),
175
- systemPrompt: CODEBUDDY_SYSTEM_PROMPT,
176
- baseUrl: CODEBUDDY_BASE_URL,
177
- imageGenerationPath: "/images/generations",
178
- },
179
- );
180
- }
1
+ // CodeBuddy International adapter — exact provider contract.
2
+ // Canonical provider ID: cb
3
+ // Base (manifest-owned CODEBUDDY_BASE_URL) → Chat: base + /chat/completions
4
+ // Auth: Authorization Bearer for both api_key and oauth
5
+ // Stream: force stream=true upstream, factory reaggregates for non-stream callers
6
+ // Headers: per-provider CodeBuddy headers with fresh correlation IDs per dispatch
7
+ // Payload: leading CodeBuddy system prompt + typed user content, reasoning_summary auto only when reasoning_effort
8
+
9
+ import { BuddyMediaAdapter } from "../buddy-media";
10
+ import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderAdapter } from "../../../provider-contracts";
11
+ import type { ModelDefinition } from "../../../provider-model-definition";
12
+ import type { DiscoveryInput } from "../../../discovery/discovery-types";
13
+ import { GatewayError } from "../../../../protocol/gateway-error";
14
+ import type { CanonicalRequest } from "../../../../protocol/canonical-model";
15
+ import { providerBaseUrl } from "../../../provider-metadata";
16
+ import {
17
+ codebuddyAdapterConfig,
18
+ codebuddyHeaders,
19
+ } from "./shared";
20
+ import {
21
+ BUDDY_SHARED_RAW,
22
+ BUDDY_IMAGE_MODEL_ID_SET,
23
+ BUDDY_VIDEO_MODEL_ID_SET,
24
+ makeBuddyModel,
25
+ makeBuddyImageModels,
26
+ makeBuddyVideoModels,
27
+ type BuddyRawEntry,
28
+ } from "../buddy-catalog-shared";
29
+ import { BUDDY_INTL_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
30
+ import {
31
+ applyBuddySystemPrompt,
32
+ buddyPrePayloadCommon,
33
+ normalizeBuddyToolNames,
34
+ } from "../buddy-chat-shared";
35
+
36
+
37
+ // Constants — public contract
38
+ export const CODEBUDDY_PROVIDER_ID = "cb" as const;
39
+ export const CODEBUDDY_BASE_URL = providerBaseUrl("cb");
40
+ // Upstream model translation — preserve provider mapping
41
+
42
+ // Payload hook — provider intl semantics
43
+ // - force stream=true
44
+ // - reasoning_summary auto only when reasoning_effort requested
45
+ // - upstreamId translation
46
+ // - leading CodeBuddy system prompt + typed user content normalization
47
+
48
+ /**
49
+ * Leading system turn for this variant.
50
+ *
51
+ * The upstream validates that the wire *opens* with a `system` turn (code
52
+ * `11128`) but does not check its text — the CN variant installs a plain
53
+ * engineering-assistant sentence in the same slot and the gateway accepts it.
54
+ * So this text is a product choice rather than a wire contract, and the
55
+ * previous vendor-branded line ("You are CodeBuddy Code.") made every request
56
+ * claim an identity the caller never chose, while also discarding whatever
57
+ * system prompt the caller actually sent.
58
+ *
59
+ * The prompt is therefore a neutral assistant identity with an explicit
60
+ * persona: pragmatic, direct, and honest — no sycophancy, no hedging, no
61
+ * invented certainty.
62
+ */
63
+ export const CODEBUDDY_SYSTEM_PROMPT =
64
+ "You are a pragmatic and direct software engineering assistant. " +
65
+ "Be honest and truthful: state what you know, say plainly when you are unsure " +
66
+ "or do not know, and never claim to have done something you have not done. " +
67
+ "Prefer concrete answers over filler, and say so when a request is ambiguous " +
68
+ "instead of guessing silently.";
69
+
70
+ function codeBuddyIntlPrePayload(
71
+ payload: Record<string, unknown>,
72
+ request: CanonicalRequest,
73
+ candidate: ProviderDispatchTarget,
74
+ context?: ProviderDispatchContext,
75
+ ): void {
76
+ // International ladder: DeepSeek Flash and friends serve only `high`.
77
+ buddyPrePayloadCommon(payload, request, "intl", context);
78
+ const rawModel = payload["model"];
79
+ const source =
80
+ typeof rawModel === "string" && rawModel.length > 0
81
+ ? rawModel
82
+ : candidate.model_id;
83
+ if (!source) throw new GatewayError("invalid_request", 400, "CodeBuddy model is required");
84
+ const messages = payload["messages"];
85
+ if (Array.isArray(messages)) {
86
+ applyBuddySystemPrompt(messages as Array<Record<string, unknown>>, CODEBUDDY_SYSTEM_PROMPT);
87
+ }
88
+ normalizeBuddyToolNames(payload);
89
+ void request;
90
+ }
91
+
92
+ // Model catalog — shared CodeBuddy / WorkBuddy international roster
93
+
94
+ const CODEBUDDY_INTL_RAW: readonly BuddyRawEntry[] = BUDDY_SHARED_RAW;
95
+
96
+ /**
97
+ * CodeBuddy's image generation rows.
98
+ *
99
+ * These ids also sit on the shared chat roster as ordinary `llm` rows, which is
100
+ * why they were unreachable as image models: nothing downstream could tell a
101
+ * chat model from one that returns an image, so `mediaGeneration` was false for
102
+ * every catalog row. The roster and the declared capabilities come from
103
+ * {@link makeBuddyImageModels} so cb and WorkBuddy cannot drift.
104
+ */
105
+ export const CODEBUDDY_IMAGE_MODELS: readonly ModelDefinition[] = makeBuddyImageModels(
106
+ "cb",
107
+ "/images/generations",
108
+ );
109
+
110
+ /**
111
+ * CodeBuddy's video-generation rows (`seedance-2.5`).
112
+ *
113
+ * Reached through `/videos/generations` on the `/v2` base, so the endpoint is
114
+ * the upstream video path rather than a chat-completions path.
115
+ */
116
+ export const CODEBUDDY_VIDEO_MODELS: readonly ModelDefinition[] = makeBuddyVideoModels(
117
+ "cb",
118
+ "/videos/generations",
119
+ );
120
+
121
+ /**
122
+ * The full cb catalog the registry loads: chat roster plus image and video rows.
123
+ *
124
+ * The image and video ids are filtered out of the chat pass so one id never
125
+ * appears under two service kinds. Exported as a single list so
126
+ * `default-registry.ts` keeps one import for this provider.
127
+ */
128
+ export const CODEBUDDY_MODELS: readonly ModelDefinition[] = [
129
+ ...CODEBUDDY_INTL_RAW.filter(
130
+ (entry) => !BUDDY_IMAGE_MODEL_ID_SET.has(entry[0]) && !BUDDY_VIDEO_MODEL_ID_SET.has(entry[0]),
131
+ ).map((entry) => makeBuddyModel(entry, "cb")),
132
+ ...CODEBUDDY_IMAGE_MODELS,
133
+ ...CODEBUDDY_VIDEO_MODELS,
134
+ ];
135
+
136
+ /**
137
+ * Reads the CodeBuddy intl console directory.
138
+ *
139
+ * The static `CODEBUDDY_MODELS` above stays the fallback — this console is
140
+ * documented to answer 500 intermittently — while discovery carries the
141
+ * upstream's own limits and capability flags.
142
+ */
143
+ export async function discoverCodeBuddyModels(
144
+ input: DiscoveryInput,
145
+ ): Promise<readonly ModelDefinition[] | null> {
146
+ return fetchBuddyDirectoryModels({
147
+ siteUrl: CODEBUDDY_BASE_URL,
148
+ providerId: CODEBUDDY_PROVIDER_ID,
149
+ credential: input.credential,
150
+ modelsPath: BUDDY_INTL_MODELS_PATH,
151
+ endpoint: undefined,
152
+ ...(input.signal ? { signal: input.signal } : {}),
153
+ ...(input.fetcher ? { fetcher: input.fetcher } : {}),
154
+ });
155
+ }
156
+
157
+ // Public factory — uses OpenAI-compatible factory but forces provider semantics
158
+ // Supports both api_key and oauth via Authorization Bearer (factory handles both)
159
+
160
+ export function createCodeBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
161
+ return new BuddyMediaAdapter(
162
+ codebuddyAdapterConfig({
163
+ providerId: CODEBUDDY_PROVIDER_ID,
164
+ baseUrl: CODEBUDDY_BASE_URL,
165
+ variant: "IDE",
166
+ cliIdentity: true,
167
+ prePayload: codeBuddyIntlPrePayload,
168
+ ...(fetchImpl ? { fetchImpl } : {}),
169
+ }),
170
+ {
171
+ variant: "IDE",
172
+ // BuddyMediaConfig has no `cliIdentity`; the CLI identity is selected by
173
+ // supplying the builder that takes it.
174
+ buildHeaders: (context, request) => codebuddyHeaders("IDE", context, request, true),
175
+ systemPrompt: CODEBUDDY_SYSTEM_PROMPT,
176
+ baseUrl: CODEBUDDY_BASE_URL,
177
+ imageGenerationPath: "/images/generations",
178
+ },
179
+ );
180
+ }