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,206 +1,206 @@
1
- // WorkBuddy international adapter — exact provider contract.
2
- // Canonical provider ID: workbuddy
3
- // Base (manifest-owned) → Chat: base + /v2/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: official desktop-client identity (WorkBuddy AI brand) with fresh
7
- // correlation IDs + account-stable device headers per dispatch
8
- // Payload: leading WorkBuddy system prompt + typed user content, reasoning_summary
9
- // auto only when reasoning_effort requested
10
-
11
- import { BuddyMediaAdapter } from "../buddy-media";
12
- import { providerBaseUrl } from "../../../provider-metadata";
13
- import { GatewayError } from "../../../../protocol/gateway-error";
14
- import type { CanonicalRequest } from "../../../../protocol/canonical-model";
15
- import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../../provider-contracts";
16
- import type { ModelDefinition } from "../../../provider-model-definition";
17
- import type { DiscoveryInput } from "../../../discovery/discovery-types";
18
- import {
19
- WORKBUDDY_CHAT_PATH,
20
- WORKBUDDY_DOMAIN,
21
- workbuddyAdapterConfig,
22
- workbuddyHeaders,
23
- } from "./shared";
24
- import {
25
- BUDDY_SHARED_RAW,
26
- BUDDY_IMAGE_MODEL_ID_SET,
27
- BUDDY_VIDEO_MODEL_ID_SET,
28
- makeBuddyModel,
29
- makeBuddyImageModels,
30
- makeBuddyVideoModels,
31
- type BuddyRawEntry,
32
- } from "../buddy-catalog-shared";
33
- import { BUDDY_INTL_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
34
- import {
35
- applyBuddySystemPrompt,
36
- buddyPrePayloadCommon,
37
- normalizeBuddyToolNames,
38
- } from "../buddy-chat-shared";
39
-
40
- // Constants — public contract
41
- export const WORKBUDDY_PROVIDER_ID = "workbuddy" as const;
42
- export const WORKBUDDY_BASE_URL = providerBaseUrl("workbuddy");
43
-
44
- // Payload hook — provider semantics
45
- // - force stream=true
46
- // - reasoning_summary auto only when reasoning_effort requested
47
- // - leading WorkBuddy system prompt + typed user content normalization
48
-
49
- /**
50
- * Leading system turn for this variant.
51
- *
52
- * The upstream does validate the leading system turn's *text*, not just that
53
- * the wire opens with one: sending caller text in its place answers
54
- * `400 · 11128 "Illegal API invocation from an unapproved channel"` on
55
- * CodeBuddy, which treats that prompt as the calling channel's identity. So
56
- * this prompt is a wire contract, not merely a product choice — see the
57
- * sibling in `codebuddy.ts`. The previous line named the vendor product, which
58
- * made every request claim an identity the caller never chose.
59
- */
60
- export const WORKBUDDY_SYSTEM_PROMPT =
61
- "You are a pragmatic and direct software engineering assistant. " +
62
- "Be honest and truthful: state what you know, say plainly when you are unsure " +
63
- "or do not know, and never claim to have done something you have not done. " +
64
- "Prefer concrete answers over filler, and say so when a request is ambiguous " +
65
- "instead of guessing silently.";
66
-
67
- /**
68
- * Reconstructs generic function declarations when a later tool-history turn
69
- * arrives without the client's current `tools` array. WorkBuddy validates the
70
- * Chat Completions envelope against every historical tool call, so forwarding
71
- * `tool_calls`/`tool` messages without declarations yields model_param_invalid.
72
- */
73
- function restoreHistoricalToolDefinitions(
74
- payload: Record<string, unknown>,
75
- messages: readonly Record<string, unknown>[],
76
- ): void {
77
- const historicalNames = new Set<string>();
78
- for (const message of messages) {
79
- if (message["role"] !== "assistant" || !Array.isArray(message["tool_calls"])) continue;
80
- for (const rawCall of message["tool_calls"]) {
81
- if (!rawCall || typeof rawCall !== "object") continue;
82
- const call = rawCall as Record<string, unknown>;
83
- const functionValue =
84
- call["function"] && typeof call["function"] === "object"
85
- ? (call["function"] as Record<string, unknown>)
86
- : undefined;
87
- const name = functionValue?.["name"];
88
- if (typeof name === "string" && name.trim().length > 0) historicalNames.add(name);
89
- }
90
- }
91
- if (historicalNames.size === 0) return;
92
-
93
- const existing = Array.isArray(payload["tools"])
94
- ? (payload["tools"] as Array<Record<string, unknown>>)
95
- : [];
96
- const definedNames = new Set<string>();
97
- for (const rawTool of existing) {
98
- if (!rawTool || typeof rawTool !== "object") continue;
99
- const tool = rawTool as Record<string, unknown>;
100
- const functionValue =
101
- tool["function"] && typeof tool["function"] === "object"
102
- ? (tool["function"] as Record<string, unknown>)
103
- : tool;
104
- if (typeof functionValue["name"] === "string") definedNames.add(functionValue["name"]);
105
- }
106
- const recovered = [...historicalNames]
107
- .filter((name) => !definedNames.has(name))
108
- .map((name) => ({
109
- type: "function",
110
- function: {
111
- name,
112
- description: "Recovered from historical tool calls.",
113
- parameters: { type: "object", additionalProperties: true },
114
- },
115
- }));
116
- if (recovered.length > 0) payload["tools"] = [...existing, ...recovered];
117
- }
118
-
119
-
120
- export function workbuddyPrePayload(
121
- payload: Record<string, unknown>,
122
- request: CanonicalRequest,
123
- candidate: ProviderDispatchTarget,
124
- context?: ProviderDispatchContext,
125
- ): void {
126
- // International ladder. This hook is shared by `workbuddy` and `workbuddycn`
127
- // (see workbuddy/cn-provider.ts): the CN effort ladders in the reference
128
- // gateways are a CodeBuddy-CN concern, so `workbuddycn` deliberately stays on
129
- // the intl table. Switch to `"cn"` only if a live CN WorkBuddy account proves
130
- // it serves levels the intl table clamps.
131
- buddyPrePayloadCommon(payload, request, "intl", context);
132
- const rawModel = payload["model"];
133
- const source =
134
- typeof rawModel === "string" && rawModel.length > 0 ? rawModel : candidate.model_id;
135
- if (!source) throw new GatewayError("invalid_request", 400, "WorkBuddy model is required");
136
- const messages = payload["messages"];
137
- if (Array.isArray(messages)) {
138
- const normalizedMessages = messages as Array<Record<string, unknown>>;
139
- applyBuddySystemPrompt(normalizedMessages, WORKBUDDY_SYSTEM_PROMPT);
140
- restoreHistoricalToolDefinitions(payload, normalizedMessages);
141
- }
142
- normalizeBuddyToolNames(payload);
143
- void request;
144
- }
145
-
146
- // Model catalog — WorkBuddy international catalog.
147
- // Static seed derived from the reference gateway's model.json (context/output
148
- // limits) plus its global effort table; `reasoning` marks models with a
149
- // declared reasoning-effort scale.
150
- const WORKBUDDY_RAW: readonly BuddyRawEntry[] = BUDDY_SHARED_RAW;
151
-
152
- export function makeWorkBuddyModels(providerId: "workbuddy" | "workbuddycn"): readonly ModelDefinition[] {
153
- return [
154
- ...WORKBUDDY_RAW.filter(
155
- (entry) => !BUDDY_IMAGE_MODEL_ID_SET.has(entry[0]) && !BUDDY_VIDEO_MODEL_ID_SET.has(entry[0]),
156
- ).map((entry) => makeBuddyModel(entry, providerId, WORKBUDDY_CHAT_PATH)),
157
- // WorkBuddy's base URL carries no version segment, so the image rows need the
158
- // same explicit path the chat rows use — the generic default would produce a
159
- // URL this upstream answers with a 405.
160
- ...makeBuddyImageModels(providerId, WORKBUDDY_CHAT_PATH),
161
- ...makeBuddyVideoModels(providerId, "/v2/videos/generations"),
162
- ];
163
- }
164
-
165
- export const WORKBUDDY_MODELS: readonly ModelDefinition[] = makeWorkBuddyModels("workbuddy");
166
-
167
- /**
168
- * Reads WorkBuddy's live console directory.
169
- *
170
- * The static `WORKBUDDY_MODELS` above is the fallback: this is what the "Fetch
171
- * models" action persists, and it carries the upstream's own limits and
172
- * capability flags rather than the seed's snapshot of them.
173
- */
174
- export async function discoverWorkBuddyModels(
175
- input: DiscoveryInput,
176
- ): Promise<readonly ModelDefinition[] | null> {
177
- return fetchBuddyDirectoryModels({
178
- siteUrl: WORKBUDDY_BASE_URL,
179
- providerId: WORKBUDDY_PROVIDER_ID,
180
- credential: input.credential,
181
- modelsPath: BUDDY_INTL_MODELS_PATH,
182
- endpoint: WORKBUDDY_CHAT_PATH,
183
- ...(input.signal ? { signal: input.signal } : {}),
184
- ...(input.fetcher ? { fetcher: input.fetcher } : {}),
185
- });
186
- }
187
-
188
- // Public factory — uses the OpenAI-compatible factory but forces provider semantics.
189
- // Supports both api_key and oauth via Authorization Bearer (factory handles both).
190
- export function createWorkBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
191
- return new BuddyMediaAdapter(
192
- workbuddyAdapterConfig({
193
- providerId: WORKBUDDY_PROVIDER_ID,
194
- baseUrl: WORKBUDDY_BASE_URL,
195
- prePayload: workbuddyPrePayload,
196
- ...(fetchImpl ? { fetchImpl } : {}),
197
- }),
198
- {
199
- variant: "IDE",
200
- systemPrompt: WORKBUDDY_SYSTEM_PROMPT,
201
- baseUrl: WORKBUDDY_BASE_URL,
202
- buildHeaders: (context, request) =>
203
- workbuddyHeaders(context, request, WORKBUDDY_DOMAIN, undefined, true),
204
- },
205
- );
206
- }
1
+ // WorkBuddy international adapter — exact provider contract.
2
+ // Canonical provider ID: workbuddy
3
+ // Base (manifest-owned) → Chat: base + /v2/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: official desktop-client identity (WorkBuddy AI brand) with fresh
7
+ // correlation IDs + account-stable device headers per dispatch
8
+ // Payload: leading WorkBuddy system prompt + typed user content, reasoning_summary
9
+ // auto only when reasoning_effort requested
10
+
11
+ import { BuddyMediaAdapter } from "../buddy-media";
12
+ import { providerBaseUrl } from "../../../provider-metadata";
13
+ import { GatewayError } from "../../../../protocol/gateway-error";
14
+ import type { CanonicalRequest } from "../../../../protocol/canonical-model";
15
+ import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../../provider-contracts";
16
+ import type { ModelDefinition } from "../../../provider-model-definition";
17
+ import type { DiscoveryInput } from "../../../discovery/discovery-types";
18
+ import {
19
+ WORKBUDDY_CHAT_PATH,
20
+ WORKBUDDY_DOMAIN,
21
+ workbuddyAdapterConfig,
22
+ workbuddyHeaders,
23
+ } from "./shared";
24
+ import {
25
+ BUDDY_SHARED_RAW,
26
+ BUDDY_IMAGE_MODEL_ID_SET,
27
+ BUDDY_VIDEO_MODEL_ID_SET,
28
+ makeBuddyModel,
29
+ makeBuddyImageModels,
30
+ makeBuddyVideoModels,
31
+ type BuddyRawEntry,
32
+ } from "../buddy-catalog-shared";
33
+ import { BUDDY_INTL_MODELS_PATH, fetchBuddyDirectoryModels } from "../buddy-discovery-shared";
34
+ import {
35
+ applyBuddySystemPrompt,
36
+ buddyPrePayloadCommon,
37
+ normalizeBuddyToolNames,
38
+ } from "../buddy-chat-shared";
39
+
40
+ // Constants — public contract
41
+ export const WORKBUDDY_PROVIDER_ID = "workbuddy" as const;
42
+ export const WORKBUDDY_BASE_URL = providerBaseUrl("workbuddy");
43
+
44
+ // Payload hook — provider semantics
45
+ // - force stream=true
46
+ // - reasoning_summary auto only when reasoning_effort requested
47
+ // - leading WorkBuddy system prompt + typed user content normalization
48
+
49
+ /**
50
+ * Leading system turn for this variant.
51
+ *
52
+ * The upstream does validate the leading system turn's *text*, not just that
53
+ * the wire opens with one: sending caller text in its place answers
54
+ * `400 · 11128 "Illegal API invocation from an unapproved channel"` on
55
+ * CodeBuddy, which treats that prompt as the calling channel's identity. So
56
+ * this prompt is a wire contract, not merely a product choice — see the
57
+ * sibling in `codebuddy.ts`. The previous line named the vendor product, which
58
+ * made every request claim an identity the caller never chose.
59
+ */
60
+ export const WORKBUDDY_SYSTEM_PROMPT =
61
+ "You are a pragmatic and direct software engineering assistant. " +
62
+ "Be honest and truthful: state what you know, say plainly when you are unsure " +
63
+ "or do not know, and never claim to have done something you have not done. " +
64
+ "Prefer concrete answers over filler, and say so when a request is ambiguous " +
65
+ "instead of guessing silently.";
66
+
67
+ /**
68
+ * Reconstructs generic function declarations when a later tool-history turn
69
+ * arrives without the client's current `tools` array. WorkBuddy validates the
70
+ * Chat Completions envelope against every historical tool call, so forwarding
71
+ * `tool_calls`/`tool` messages without declarations yields model_param_invalid.
72
+ */
73
+ function restoreHistoricalToolDefinitions(
74
+ payload: Record<string, unknown>,
75
+ messages: readonly Record<string, unknown>[],
76
+ ): void {
77
+ const historicalNames = new Set<string>();
78
+ for (const message of messages) {
79
+ if (message["role"] !== "assistant" || !Array.isArray(message["tool_calls"])) continue;
80
+ for (const rawCall of message["tool_calls"]) {
81
+ if (!rawCall || typeof rawCall !== "object") continue;
82
+ const call = rawCall as Record<string, unknown>;
83
+ const functionValue =
84
+ call["function"] && typeof call["function"] === "object"
85
+ ? (call["function"] as Record<string, unknown>)
86
+ : undefined;
87
+ const name = functionValue?.["name"];
88
+ if (typeof name === "string" && name.trim().length > 0) historicalNames.add(name);
89
+ }
90
+ }
91
+ if (historicalNames.size === 0) return;
92
+
93
+ const existing = Array.isArray(payload["tools"])
94
+ ? (payload["tools"] as Array<Record<string, unknown>>)
95
+ : [];
96
+ const definedNames = new Set<string>();
97
+ for (const rawTool of existing) {
98
+ if (!rawTool || typeof rawTool !== "object") continue;
99
+ const tool = rawTool as Record<string, unknown>;
100
+ const functionValue =
101
+ tool["function"] && typeof tool["function"] === "object"
102
+ ? (tool["function"] as Record<string, unknown>)
103
+ : tool;
104
+ if (typeof functionValue["name"] === "string") definedNames.add(functionValue["name"]);
105
+ }
106
+ const recovered = [...historicalNames]
107
+ .filter((name) => !definedNames.has(name))
108
+ .map((name) => ({
109
+ type: "function",
110
+ function: {
111
+ name,
112
+ description: "Recovered from historical tool calls.",
113
+ parameters: { type: "object", additionalProperties: true },
114
+ },
115
+ }));
116
+ if (recovered.length > 0) payload["tools"] = [...existing, ...recovered];
117
+ }
118
+
119
+
120
+ export function workbuddyPrePayload(
121
+ payload: Record<string, unknown>,
122
+ request: CanonicalRequest,
123
+ candidate: ProviderDispatchTarget,
124
+ context?: ProviderDispatchContext,
125
+ ): void {
126
+ // International ladder. This hook is shared by `workbuddy` and `workbuddycn`
127
+ // (see workbuddy/cn-provider.ts): the CN effort ladders in the reference
128
+ // gateways are a CodeBuddy-CN concern, so `workbuddycn` deliberately stays on
129
+ // the intl table. Switch to `"cn"` only if a live CN WorkBuddy account proves
130
+ // it serves levels the intl table clamps.
131
+ buddyPrePayloadCommon(payload, request, "intl", context);
132
+ const rawModel = payload["model"];
133
+ const source =
134
+ typeof rawModel === "string" && rawModel.length > 0 ? rawModel : candidate.model_id;
135
+ if (!source) throw new GatewayError("invalid_request", 400, "WorkBuddy model is required");
136
+ const messages = payload["messages"];
137
+ if (Array.isArray(messages)) {
138
+ const normalizedMessages = messages as Array<Record<string, unknown>>;
139
+ applyBuddySystemPrompt(normalizedMessages, WORKBUDDY_SYSTEM_PROMPT);
140
+ restoreHistoricalToolDefinitions(payload, normalizedMessages);
141
+ }
142
+ normalizeBuddyToolNames(payload);
143
+ void request;
144
+ }
145
+
146
+ // Model catalog — WorkBuddy international catalog.
147
+ // Static seed derived from the reference gateway's model.json (context/output
148
+ // limits) plus its global effort table; `reasoning` marks models with a
149
+ // declared reasoning-effort scale.
150
+ const WORKBUDDY_RAW: readonly BuddyRawEntry[] = BUDDY_SHARED_RAW;
151
+
152
+ export function makeWorkBuddyModels(providerId: "workbuddy" | "workbuddycn"): readonly ModelDefinition[] {
153
+ return [
154
+ ...WORKBUDDY_RAW.filter(
155
+ (entry) => !BUDDY_IMAGE_MODEL_ID_SET.has(entry[0]) && !BUDDY_VIDEO_MODEL_ID_SET.has(entry[0]),
156
+ ).map((entry) => makeBuddyModel(entry, providerId, WORKBUDDY_CHAT_PATH)),
157
+ // WorkBuddy's base URL carries no version segment, so the image rows need the
158
+ // same explicit path the chat rows use — the generic default would produce a
159
+ // URL this upstream answers with a 405.
160
+ ...makeBuddyImageModels(providerId, WORKBUDDY_CHAT_PATH),
161
+ ...makeBuddyVideoModels(providerId, "/v2/videos/generations"),
162
+ ];
163
+ }
164
+
165
+ export const WORKBUDDY_MODELS: readonly ModelDefinition[] = makeWorkBuddyModels("workbuddy");
166
+
167
+ /**
168
+ * Reads WorkBuddy's live console directory.
169
+ *
170
+ * The static `WORKBUDDY_MODELS` above is the fallback: this is what the "Fetch
171
+ * models" action persists, and it carries the upstream's own limits and
172
+ * capability flags rather than the seed's snapshot of them.
173
+ */
174
+ export async function discoverWorkBuddyModels(
175
+ input: DiscoveryInput,
176
+ ): Promise<readonly ModelDefinition[] | null> {
177
+ return fetchBuddyDirectoryModels({
178
+ siteUrl: WORKBUDDY_BASE_URL,
179
+ providerId: WORKBUDDY_PROVIDER_ID,
180
+ credential: input.credential,
181
+ modelsPath: BUDDY_INTL_MODELS_PATH,
182
+ endpoint: WORKBUDDY_CHAT_PATH,
183
+ ...(input.signal ? { signal: input.signal } : {}),
184
+ ...(input.fetcher ? { fetcher: input.fetcher } : {}),
185
+ });
186
+ }
187
+
188
+ // Public factory — uses the OpenAI-compatible factory but forces provider semantics.
189
+ // Supports both api_key and oauth via Authorization Bearer (factory handles both).
190
+ export function createWorkBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
191
+ return new BuddyMediaAdapter(
192
+ workbuddyAdapterConfig({
193
+ providerId: WORKBUDDY_PROVIDER_ID,
194
+ baseUrl: WORKBUDDY_BASE_URL,
195
+ prePayload: workbuddyPrePayload,
196
+ ...(fetchImpl ? { fetchImpl } : {}),
197
+ }),
198
+ {
199
+ variant: "IDE",
200
+ systemPrompt: WORKBUDDY_SYSTEM_PROMPT,
201
+ baseUrl: WORKBUDDY_BASE_URL,
202
+ buildHeaders: (context, request) =>
203
+ workbuddyHeaders(context, request, WORKBUDDY_DOMAIN, undefined, true),
204
+ },
205
+ );
206
+ }