cartethyia 2.7.8 → 2.8.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 (519) hide show
  1. package/.env.example +3 -3
  2. package/README.md +29 -59
  3. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js +1 -0
  4. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
  5. package/dist/dashboard/assets/{CliToolDetailPage-BRWKPQPf.js → CliToolDetailPage-Bqj2aa1T.js} +1 -1
  6. package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
  7. package/dist/dashboard/assets/{CliToolsPage-BP-Y5iHN.js → CliToolsPage-CXsaOAO2.js} +1 -1
  8. package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
  9. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js +1 -0
  10. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
  11. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js +1 -0
  12. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
  13. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js +1 -0
  14. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
  15. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js +1 -0
  16. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
  17. package/dist/dashboard/assets/{InjectSystemPromptPanel-Cv-2Ol_K.js → InjectSystemPromptPanel-BWFLECmz.js} +2 -2
  18. package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
  19. package/dist/dashboard/assets/{LoginPage-bKfz_b1K.js → LoginPage-CgoPc5B9.js} +1 -1
  20. package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
  21. package/dist/dashboard/assets/{ModelPicker-B-WQxx_H.js → ModelPicker-D9bFQern.js} +1 -1
  22. package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
  23. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js +1 -0
  24. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +8 -0
  26. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
  27. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js +1 -0
  28. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
  29. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js +1 -0
  30. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
  31. package/dist/dashboard/assets/{ProxyPage-emlTuxz6.js → ProxyPage-BwNC_-Cx.js} +1 -1
  32. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
  33. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js +1 -0
  34. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
  35. package/dist/dashboard/assets/SettingsPage-CctTga2C.js +1 -0
  36. package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
  37. package/dist/dashboard/assets/{SetupPage-CUZrKs9r.js → SetupPage-febLU4r1.js} +1 -1
  38. package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
  39. package/dist/dashboard/assets/{StudioPage-jWmUdDpy.js → StudioPage-M6fvR5Wz.js} +1 -1
  40. package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
  41. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js +56 -0
  42. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
  43. package/dist/dashboard/assets/api-keys-BFOlvrJC.js +1 -0
  44. package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
  45. package/dist/dashboard/assets/app-Dx2QgsNj.css +2 -0
  46. package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
  47. package/dist/dashboard/assets/{assert-CidQVoNo.js → assert-CqTLw5e7.js} +1 -1
  48. package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
  49. package/dist/dashboard/assets/{badge-DyI_mJfi.js → badge-C83EqLB0.js} +1 -1
  50. package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
  51. package/dist/dashboard/assets/ban-durations-B58FyRxC.js +1 -0
  52. package/dist/dashboard/assets/ban-durations-B58FyRxC.js.gz +0 -0
  53. package/dist/dashboard/assets/{banner-B-yXtCqb.js → banner-D1xn7pIe.js} +1 -1
  54. package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
  55. package/dist/dashboard/assets/brand/bansos_page.webp +0 -0
  56. package/dist/dashboard/assets/brand/denia_bansos.webp +0 -0
  57. package/dist/dashboard/assets/brand/favicon.webp +0 -0
  58. package/dist/dashboard/assets/brand/login_register.webp +0 -0
  59. package/dist/dashboard/assets/brand/login_register_initial.webp +0 -0
  60. package/dist/dashboard/assets/brand/og_bansos.webp +0 -0
  61. package/dist/dashboard/assets/brand/og_image.webp +0 -0
  62. package/dist/dashboard/assets/brand/sidebar_ico.webp +0 -0
  63. package/dist/dashboard/assets/{card-_HwAEqFF.js → card-DU3Lq5Lm.js} +1 -1
  64. package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
  65. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js +1 -0
  66. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
  67. package/dist/dashboard/assets/{clipboard-button-ByjCk0o9.js → clipboard-button-CEL5Sg_J.js} +1 -1
  68. package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
  69. package/dist/dashboard/assets/{dialog-BZhOlfz-.js → dialog-BjFR5UHy.js} +1 -1
  70. package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
  71. package/dist/dashboard/assets/{drawer-BADqIRYP.js → drawer-HvBW0AjI.js} +1 -1
  72. package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
  73. package/dist/dashboard/assets/entry-BSu3gFlt.js +4 -0
  74. package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
  75. package/dist/dashboard/assets/{entry-COaC-irN.js → entry-CECVELyy.js} +1 -1
  76. package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
  77. package/dist/dashboard/assets/entry-DYYofQ7W.js +1 -0
  78. package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
  79. package/dist/dashboard/assets/{formatters-DcHJyRiu.js → formatters-DLW4i8zK.js} +1 -1
  80. package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
  81. package/dist/dashboard/assets/{index-CgKmFngv.js → index-1-fCqe64.js} +2 -2
  82. package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
  83. package/dist/dashboard/assets/{inline-B2BirKry.js → inline-DGvU2oLK.js} +1 -1
  84. package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
  85. package/dist/dashboard/assets/{input-D-qV9dKY.js → input-iNnO1X2K.js} +1 -1
  86. package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
  87. package/dist/dashboard/assets/{layout-B7tVWhtV.js → layout-0q8UGypb.js} +1 -1
  88. package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
  89. package/dist/dashboard/assets/{list-row-CtkGE3bF.js → list-row-C0w2bQjJ.js} +1 -1
  90. package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
  91. package/dist/dashboard/assets/{live-DGizF06-.js → live-M5aJ_xCa.js} +1 -1
  92. package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
  93. package/dist/dashboard/assets/{mutation-GU7XdEjz.js → mutation-BQ0ccH_A.js} +1 -1
  94. package/dist/dashboard/assets/mutation-BQ0ccH_A.js.gz +0 -0
  95. package/dist/dashboard/assets/{network-C9UE-bOr.js → network-BKeQGT3K.js} +1 -1
  96. package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
  97. package/dist/dashboard/assets/{numbers-BnAd22a_.js → numbers-CivAk3da.js} +1 -1
  98. package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
  99. package/dist/dashboard/assets/{pagination-BAywyMzS.js → pagination-CpzvI5ep.js} +1 -1
  100. package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
  101. package/dist/dashboard/assets/providers/devin.svg +9 -0
  102. package/dist/dashboard/assets/providers/devin.svg.gz +0 -0
  103. package/dist/dashboard/assets/providers/windsurf.svg +10 -0
  104. package/dist/dashboard/assets/providers/windsurf.svg.gz +0 -0
  105. package/dist/dashboard/assets/providers/zro.svg +3 -0
  106. package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
  107. package/dist/dashboard/assets/{query-keys-YSoQOUh6.js → query-keys-IKLh0YFd.js} +1 -1
  108. package/dist/dashboard/assets/query-keys-IKLh0YFd.js.gz +0 -0
  109. package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
  110. package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
  111. package/dist/dashboard/assets/routing-BFQX2VBc.js +1 -0
  112. package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
  113. package/dist/dashboard/assets/{select-BCOcv8WK.js → select-CXbck0jG.js} +2 -2
  114. package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
  115. package/dist/dashboard/assets/settings-C_XvMHh9.js +1 -0
  116. package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
  117. package/dist/dashboard/assets/{stack-ByKt3Q1g.js → stack-DggRiCxE.js} +1 -1
  118. package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
  119. package/dist/dashboard/assets/{state-DXbGTx7N.js → state-ClFzfbYp.js} +1 -1
  120. package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
  121. package/dist/dashboard/assets/story/25817331.webp +0 -0
  122. package/dist/dashboard/assets/story/Shorekeeper.webp +0 -0
  123. package/dist/dashboard/assets/story/cartethyia-god.webp +0 -0
  124. package/dist/dashboard/assets/story/fleurdelys_plus.webp +0 -0
  125. package/dist/dashboard/assets/story/jinhsi-blossom.webp +0 -0
  126. package/dist/dashboard/assets/story/phrolova-a.webp +0 -0
  127. package/dist/dashboard/assets/story/requestdeniawokkjpg.webp +0 -0
  128. package/dist/dashboard/assets/story/wuthering-waves-hiyuki-aemeath-hiyuki-rover.webp +0 -0
  129. package/dist/dashboard/assets/{switch-ZeTsW623.js → switch-CTIFxKqS.js} +1 -1
  130. package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
  131. package/dist/dashboard/assets/{useMutation-CbCP4w1o.js → useMutation-BClG3yWj.js} +1 -1
  132. package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
  133. package/dist/dashboard/console-backgrounds.webp +0 -0
  134. package/dist/dashboard/console-backgrounds_initial.webp +0 -0
  135. package/dist/dashboard/donation/qris-risun-marke.webp +0 -0
  136. package/dist/dashboard/index.html +3 -3
  137. package/dist/dashboard/index.html.gz +0 -0
  138. package/dist/dashboard/precompressed-assets.json +59 -56
  139. package/migrations/full-postgres/0044_add_models_warning_metadata.sql +10 -0
  140. package/migrations/full-postgres/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  141. package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
  142. package/migrations/lite-sqlite3/0044_add_models_warning_metadata.sql +11 -0
  143. package/migrations/lite-sqlite3/0045_migrate_workbuddy_to_codebuddy.sql +156 -0
  144. package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
  145. package/package.json +1 -1
  146. package/src/boot/app.ts +10 -13
  147. package/src/boot/dependencies.ts +12 -4
  148. package/src/boot/flush.ts +20 -0
  149. package/src/boot/lifecycle.ts +7 -5
  150. package/src/config/cooldowns.ts +1 -1
  151. package/src/config/routing.ts +26 -0
  152. package/src/config/spec-metadata.ts +72 -0
  153. package/src/config/spec.ts +20 -6
  154. package/src/console/api-keys/contracts.ts +12 -1
  155. package/src/console/api-keys/routes.ts +50 -31
  156. package/src/console/auth/account-reset.ts +7 -9
  157. package/src/console/backup/contracts.ts +4 -0
  158. package/src/console/backup/export-endpoint.ts +7 -5
  159. package/src/console/cli-tools/service.ts +6 -12
  160. package/src/console/console-router-guards.ts +23 -16
  161. package/src/console/console-router.ts +7 -0
  162. package/src/console/dashboard-assets.ts +5 -5
  163. package/src/console/domain-registration.ts +27 -2
  164. package/src/console/inferhub/normalize.ts +24 -28
  165. package/src/console/inferhub/types.ts +3 -0
  166. package/src/console/ip-bans/routes.ts +93 -0
  167. package/src/console/observability/store.ts +0 -53
  168. package/src/console/providers/catalog/catalog-projections.ts +5 -2
  169. package/src/console/providers/catalog/contracts.ts +123 -0
  170. package/src/console/providers/catalog/discover-constants.ts +6 -0
  171. package/src/console/providers/catalog/model-operations.ts +122 -10
  172. package/src/console/providers/catalog/provider-operations.ts +116 -8
  173. package/src/console/providers/catalog/public-model-store.ts +0 -0
  174. package/src/console/providers/catalog/routes.ts +65 -4
  175. package/src/console/providers/catalog/store-helpers.ts +30 -1
  176. package/src/console/providers/catalog/store.ts +249 -4
  177. package/src/console/quota/account-quota-global.ts +97 -19
  178. package/src/console/quota/account-quota-shared.ts +49 -0
  179. package/src/console/quota/account-quota-tenant.ts +6 -18
  180. package/src/console/quota/native-identity.ts +2 -0
  181. package/src/console/quota/quota-view.ts +19 -3
  182. package/src/console/routing/pools/operations.ts +31 -46
  183. package/src/console/settings/contracts.ts +18 -0
  184. package/src/console/settings/store.ts +32 -0
  185. package/src/console/shared/errors.ts +33 -6
  186. package/src/console/system-prompt/contracts.ts +0 -1
  187. package/src/main.ts +3 -3
  188. package/src/network/pool/byte-accounting.ts +3 -2
  189. package/src/network/pool/selector.ts +182 -39
  190. package/src/network/pool-cooldown-store.ts +89 -14
  191. package/src/network/pool-health.ts +49 -61
  192. package/src/network/rate-limit-verdict.ts +1 -1
  193. package/src/network/ssrf.ts +6 -6
  194. package/src/observability/event-log.ts +7 -361
  195. package/src/observability/event-query.ts +18 -4
  196. package/src/observability/performance-metrics.ts +9 -0
  197. package/src/observability/runtime-metrics.ts +14 -9
  198. package/src/observability/telemetry-buffer.ts +15 -25
  199. package/src/observability/telemetry-reconciliation.ts +9 -37
  200. package/src/observability/telemetry-row.ts +125 -0
  201. package/src/persistence/db-mode.ts +4 -1
  202. package/src/persistence/dialect.ts +30 -0
  203. package/src/persistence/migrate.ts +6 -3
  204. package/src/persistence/schema.ts +28 -2
  205. package/src/persistence/ttl-cache.ts +20 -2
  206. package/src/protocol/codecs.ts +1 -1
  207. package/src/protocol/dsml.ts +35 -87
  208. package/src/protocol/gateway-error.ts +1 -0
  209. package/src/protocol/markup-stream-parser.ts +195 -0
  210. package/src/protocol/reasoning-text.ts +19 -0
  211. package/src/protocol/reasoning.ts +1 -1
  212. package/src/protocol/request/chat.ts +14 -14
  213. package/src/protocol/request/gemini.ts +8 -2
  214. package/src/protocol/request/messages.ts +4 -5
  215. package/src/protocol/response/chat.ts +12 -20
  216. package/src/protocol/response/gemini.ts +6 -1
  217. package/src/protocol/response/omp-tool-call-markup.ts +43 -86
  218. package/src/protocol/response/responses.ts +18 -2
  219. package/src/protocol/sse-decoder.ts +25 -8
  220. package/src/protocol/stop-reason.ts +23 -1
  221. package/src/protocol/stream-error-frames.ts +13 -3
  222. package/src/protocol/think-split.ts +112 -0
  223. package/src/protocol/translation/dialect/qwen.ts +26 -58
  224. package/src/protocol/translation/quirks.ts +1 -1
  225. package/src/protocol/translation/tool-repair.ts +2 -2
  226. package/src/protocol/upstream/send-claude-messages.ts +15 -4
  227. package/src/protocol/upstream-parsing.ts +1 -1
  228. package/src/providers/adapters/compatible-adapter.ts +78 -17
  229. package/src/providers/authentication/oauth-client.ts +1 -1
  230. package/src/providers/authentication/oauth-device-flow.ts +98 -8
  231. package/src/providers/authentication/oauth-refresh-service.ts +153 -59
  232. package/src/providers/configured-provider.ts +148 -0
  233. package/src/providers/default-registry.ts +117 -27
  234. package/src/providers/discovery/discovery-types.ts +12 -0
  235. package/src/providers/discovery/probe-phases.ts +74 -33
  236. package/src/providers/discovery/probing-service.ts +293 -165
  237. package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
  238. package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
  239. package/src/providers/integrations/antigravity/antigravity-protocol.ts +121 -2
  240. package/src/providers/integrations/antigravity/antigravity.ts +13 -2
  241. package/src/providers/integrations/buddy/buddy-catalog-shared.ts +72 -34
  242. package/src/providers/integrations/buddy/buddy-chat-shared.ts +191 -35
  243. package/src/providers/integrations/buddy/buddy-checkin.ts +17 -39
  244. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +2 -2
  245. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +5 -5
  246. package/src/providers/integrations/buddy/buddy-identity.ts +89 -6
  247. package/src/providers/integrations/buddy/buddy-media.ts +4 -5
  248. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +2 -2
  249. package/src/providers/integrations/buddy/buddy-quota-shared.ts +1 -1
  250. package/src/providers/integrations/buddy/buddy-usage-shared.ts +1 -3
  251. package/src/providers/integrations/buddy/capabilities.ts +6 -43
  252. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +2 -1
  253. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +23 -1
  254. package/src/providers/integrations/buddy/codebuddy/provider.ts +6 -2
  255. package/src/providers/integrations/buddy/codebuddy/shared.ts +38 -27
  256. package/src/providers/integrations/claude/claude-quota.ts +14 -17
  257. package/src/providers/integrations/cline/cline.ts +2 -2
  258. package/src/providers/integrations/commandcode/quota.ts +22 -28
  259. package/src/providers/integrations/cursor/cursor-auth.ts +0 -8
  260. package/src/providers/integrations/cursor/cursor-catalog.ts +2 -0
  261. package/src/providers/integrations/cursor/cursor-exec.ts +745 -0
  262. package/src/providers/integrations/cursor/cursor-http2.ts +2 -0
  263. package/src/providers/integrations/cursor/cursor-request.ts +35 -20
  264. package/src/providers/integrations/cursor/cursor-shared.ts +26 -5
  265. package/src/providers/integrations/cursor/cursor.ts +139 -70
  266. package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
  267. package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
  268. package/src/providers/integrations/cursor/protocol/tool-canonical.ts +26 -100
  269. package/src/providers/integrations/devin/devin-auth.ts +353 -0
  270. package/src/providers/integrations/devin/devin-catalog.ts +207 -0
  271. package/src/providers/integrations/devin/devin-http.ts +91 -0
  272. package/src/providers/integrations/devin/devin-quota.ts +214 -0
  273. package/src/providers/integrations/devin/devin-shared.ts +111 -0
  274. package/src/providers/integrations/devin/devin.ts +539 -0
  275. package/src/providers/integrations/devin/protocol/devin-proto.ts +558 -0
  276. package/src/providers/integrations/devin/protocol/framing.ts +124 -0
  277. package/src/providers/integrations/factory/factory-oauth.ts +17 -44
  278. package/src/providers/integrations/factory/factory.ts +2 -2
  279. package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
  280. package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
  281. package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
  282. package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
  283. package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
  284. package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
  285. package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
  286. package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
  287. package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
  288. package/src/providers/integrations/freebuff/freebuff.ts +682 -0
  289. package/src/providers/integrations/freepi/freepi-catalog.ts +60 -0
  290. package/src/providers/integrations/freepi/freepi-discovery.ts +82 -0
  291. package/src/providers/integrations/freepi/freepi-headers.ts +21 -0
  292. package/src/providers/integrations/freepi/freepi-oauth.ts +142 -0
  293. package/src/providers/integrations/freepi/freepi-protocol.ts +242 -0
  294. package/src/providers/integrations/freepi/freepi-quota.ts +126 -0
  295. package/src/providers/integrations/freepi/freepi-realm.ts +35 -0
  296. package/src/providers/integrations/freepi/freepi.ts +292 -0
  297. package/src/providers/integrations/gemini.ts +2 -2
  298. package/src/providers/integrations/grok/grok-oauth.ts +48 -45
  299. package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
  300. package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
  301. package/src/providers/integrations/hermes/hermes-oauth.ts +94 -0
  302. package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +13 -21
  303. package/src/providers/integrations/hermes/index.ts +2 -0
  304. package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
  305. package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
  306. package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
  307. package/src/providers/integrations/kiro/kiro.ts +15 -19
  308. package/src/providers/integrations/ollamacloud/index.ts +2 -0
  309. package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
  310. package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
  311. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  312. package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
  313. package/src/providers/integrations/perch/perch-catalog.ts +105 -0
  314. package/src/providers/integrations/perch/perch-credential.ts +25 -0
  315. package/src/providers/integrations/perch/perch-oauth.ts +170 -0
  316. package/src/providers/integrations/perch/perch-protocol.ts +208 -0
  317. package/src/providers/integrations/perch/perch-quota.ts +123 -0
  318. package/src/providers/integrations/perch/perch-realm.ts +82 -0
  319. package/src/providers/integrations/perch/perch-system-prompt.ts +13 -0
  320. package/src/providers/integrations/perch/perch.ts +305 -0
  321. package/src/providers/integrations/perch/saffron-system-prompt.txt +8 -0
  322. package/src/providers/integrations/qoder/chat-proto.ts +328 -328
  323. package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
  324. package/src/providers/integrations/qoder/qoder-adapter.ts +90 -40
  325. package/src/providers/integrations/qoder/qoder-auth.ts +101 -29
  326. package/src/providers/integrations/qoder/qoder-cache.ts +32 -0
  327. package/src/providers/integrations/qoder/qoder-catalog.ts +26 -6
  328. package/src/providers/integrations/qoder/qoder-chat.ts +7 -21
  329. package/src/providers/integrations/qoder/qoder-checkin.ts +6 -6
  330. package/src/providers/integrations/qoder/qoder-grpc.ts +210 -7
  331. package/src/providers/integrations/qoder/qoder-ide.ts +5 -108
  332. package/src/providers/integrations/qoder/qoder-identity-cache.ts +184 -0
  333. package/src/providers/integrations/qoder/qoder-native-identity-store.ts +83 -18
  334. package/src/providers/integrations/qoder/qoder-realm.ts +9 -6
  335. package/src/providers/integrations/qoder/qoder-umid.ts +109 -342
  336. package/src/providers/integrations/qoder/qoder-virtual.ts +33 -1
  337. package/src/providers/integrations/qoder/qoder.ts +3 -7
  338. package/src/providers/integrations/trae/trae-catalog.ts +9 -14
  339. package/src/providers/integrations/trae/trae-headers.ts +36 -11
  340. package/src/providers/integrations/trae/trae-oauth.ts +14 -17
  341. package/src/providers/integrations/trae/trae-protocol.ts +12 -11
  342. package/src/providers/integrations/trae/trae-quota.ts +96 -36
  343. package/src/providers/integrations/trae/trae-realm.ts +74 -15
  344. package/src/providers/integrations/trae/trae.ts +99 -26
  345. package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
  346. package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
  347. package/src/providers/integrations/zro/zro.ts +204 -0
  348. package/src/providers/operations/account-error-classification.ts +235 -278
  349. package/src/providers/operations/account-health-service.ts +273 -26
  350. package/src/providers/operations/account-refresh-status.ts +269 -0
  351. package/src/providers/operations/account-tier.ts +66 -0
  352. package/src/providers/operations/client-version-resolver.ts +1 -1
  353. package/src/providers/operations/client-versions.ts +42 -150
  354. package/src/providers/operations/cooldown-rules.ts +56 -0
  355. package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
  356. package/src/providers/operations/provider-catalog-seeder.ts +4 -0
  357. package/src/providers/operations/provider-catalog-service.ts +1 -1
  358. package/src/providers/operations/provider-credential-service.ts +102 -32
  359. package/src/providers/operations/provider-rules/github.ts +48 -0
  360. package/src/providers/operations/provider-rules/grok.ts +33 -0
  361. package/src/providers/operations/provider-rules/inception.ts +49 -0
  362. package/src/providers/operations/provider-rules/index.ts +32 -0
  363. package/src/providers/operations/provider-rules/perch.ts +37 -0
  364. package/src/providers/operations/provider-rules/qoder.ts +70 -0
  365. package/src/providers/operations/provider-rules/trae.ts +81 -0
  366. package/src/providers/provider-contracts.ts +33 -2
  367. package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
  368. package/src/providers/provider-metadata.ts +99 -14
  369. package/src/providers/provider-model-definition.ts +36 -0
  370. package/src/providers/provider-probe.ts +15 -1
  371. package/src/providers/provider-registry.ts +42 -33
  372. package/src/providers/quota/quota-limit-windows.ts +16 -5
  373. package/src/providers/quota/quota-support.ts +1 -1
  374. package/src/providers/quota/quota-window-parser.ts +90 -18
  375. package/src/providers/quota/refresh.ts +96 -18
  376. package/src/security/abuse.ts +71 -0
  377. package/src/security/api-key-auth-cache.ts +1 -1
  378. package/src/security/api-key-auth.ts +6 -2
  379. package/src/transport/dispatch/attempt-finalize.ts +14 -13
  380. package/src/transport/dispatch/attempt-loop.ts +71 -17
  381. package/src/transport/dispatch/generation.ts +2 -8
  382. package/src/transport/dispatch/native-shared.ts +25 -0
  383. package/src/transport/dispatch/proxy-request.ts +9 -46
  384. package/src/transport/dispatch/responses-compact.ts +2 -8
  385. package/src/transport/dispatch/streaming/finalize.ts +9 -6
  386. package/src/transport/dispatch/streaming/stream.ts +9 -36
  387. package/src/transport/dispatch/systemone.ts +2 -8
  388. package/src/transport/dispatch/token-count.ts +2 -6
  389. package/src/transport/dispatch/upstream.ts +67 -1
  390. package/src/transport/drain-endpoint.ts +31 -4
  391. package/src/transport/failure-policy.ts +129 -37
  392. package/src/transport/guards/body-policy.ts +7 -1
  393. package/src/transport/guards/error-lifecycle.ts +13 -1
  394. package/src/transport/guards/request-context.ts +22 -14
  395. package/src/transport/request/preparer.ts +81 -71
  396. package/src/transport/routing/bounded-lru.ts +14 -0
  397. package/src/transport/routing/drain-reserve.ts +129 -0
  398. package/src/transport/routing/plan-gate.ts +7 -1
  399. package/src/transport/routing/round-robin.ts +60 -0
  400. package/src/transport/routing/route-catalog.ts +123 -111
  401. package/src/transport/routing/route-model.ts +51 -9
  402. package/src/transport/routing/router.ts +418 -33
  403. package/src/transport/surface/adapters.ts +11 -2
  404. package/src/transport/surface/chat/adapter.ts +2 -2
  405. package/src/transport/surface/chat/encode.ts +47 -4
  406. package/src/transport/surface/chat/parse.ts +2 -12
  407. package/src/transport/surface/completion.ts +44 -33
  408. package/src/transport/surface/content-parts.ts +21 -0
  409. package/src/transport/surface/messages/adapter.ts +9 -2
  410. package/src/transport/surface/messages/encode.ts +11 -3
  411. package/src/transport/surface/messages/parse.ts +2 -1
  412. package/src/transport/surface/messages/stream.ts +33 -17
  413. package/src/transport/surface/responses/encode.ts +34 -6
  414. package/src/transport/surface/responses/parse.ts +3 -11
  415. package/src/workers/daily-checkin.ts +1 -1
  416. package/src/workers/quota-refresh-sweep.ts +1 -1
  417. package/src/workers/scheduler.ts +22 -4
  418. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js +0 -1
  419. package/dist/dashboard/assets/BannedPage-DeIbIiBU.js.gz +0 -0
  420. package/dist/dashboard/assets/CliToolDetailPage-BRWKPQPf.js.gz +0 -0
  421. package/dist/dashboard/assets/CliToolsPage-BP-Y5iHN.js.gz +0 -0
  422. package/dist/dashboard/assets/CombosPage-B7JHozVa.js +0 -1
  423. package/dist/dashboard/assets/CombosPage-B7JHozVa.js.gz +0 -0
  424. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js +0 -1
  425. package/dist/dashboard/assets/ConsoleLogPage-GX7iGGcu.js.gz +0 -0
  426. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js +0 -1
  427. package/dist/dashboard/assets/CustomizationPage-HVonbGEa.js.gz +0 -0
  428. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js +0 -1
  429. package/dist/dashboard/assets/HealthEventsModal-xaut4OJ9.js.gz +0 -0
  430. package/dist/dashboard/assets/InjectSystemPromptPanel-Cv-2Ol_K.js.gz +0 -0
  431. package/dist/dashboard/assets/LoginPage-bKfz_b1K.js.gz +0 -0
  432. package/dist/dashboard/assets/ModelPicker-B-WQxx_H.js.gz +0 -0
  433. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js +0 -1
  434. package/dist/dashboard/assets/OverviewPage-Z9pJZFo8.js.gz +0 -0
  435. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js +0 -7
  436. package/dist/dashboard/assets/ProviderDetailPage-CMeDBxR1.js.gz +0 -0
  437. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js +0 -1
  438. package/dist/dashboard/assets/ProviderIcon-jjqXJDA3.js.gz +0 -0
  439. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js +0 -1
  440. package/dist/dashboard/assets/ProvidersPage-BXPdOpG4.js.gz +0 -0
  441. package/dist/dashboard/assets/ProxyPage-emlTuxz6.js.gz +0 -0
  442. package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js +0 -1
  443. package/dist/dashboard/assets/QuotaPage-CMJKNYWb.js.gz +0 -0
  444. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js +0 -1
  445. package/dist/dashboard/assets/SettingsPage-BSy7EwGo.js.gz +0 -0
  446. package/dist/dashboard/assets/SetupPage-CUZrKs9r.js.gz +0 -0
  447. package/dist/dashboard/assets/StudioPage-jWmUdDpy.js.gz +0 -0
  448. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js +0 -56
  449. package/dist/dashboard/assets/UsagePage-5F9tGVGG.js.gz +0 -0
  450. package/dist/dashboard/assets/api-keys-KvX83mRe.js +0 -1
  451. package/dist/dashboard/assets/api-keys-KvX83mRe.js.gz +0 -0
  452. package/dist/dashboard/assets/app-BEsU8hKs.css +0 -2
  453. package/dist/dashboard/assets/app-BEsU8hKs.css.gz +0 -0
  454. package/dist/dashboard/assets/assert-CidQVoNo.js.gz +0 -0
  455. package/dist/dashboard/assets/badge-DyI_mJfi.js.gz +0 -0
  456. package/dist/dashboard/assets/banner-B-yXtCqb.js.gz +0 -0
  457. package/dist/dashboard/assets/brand/bansos_page.png +0 -0
  458. package/dist/dashboard/assets/brand/denia_bansos.jpg +0 -0
  459. package/dist/dashboard/assets/brand/favicon.jpg +0 -0
  460. package/dist/dashboard/assets/brand/login_register.jpg +0 -0
  461. package/dist/dashboard/assets/brand/login_register_initial.jpg +0 -0
  462. package/dist/dashboard/assets/brand/og_bansos.jpg +0 -0
  463. package/dist/dashboard/assets/brand/og_image.jpg +0 -0
  464. package/dist/dashboard/assets/brand/sidebar_ico.jpg +0 -0
  465. package/dist/dashboard/assets/card-_HwAEqFF.js.gz +0 -0
  466. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js +0 -1
  467. package/dist/dashboard/assets/cli-tools-Bwv5-zGZ.js.gz +0 -0
  468. package/dist/dashboard/assets/clipboard-button-ByjCk0o9.js.gz +0 -0
  469. package/dist/dashboard/assets/dialog-BZhOlfz-.js.gz +0 -0
  470. package/dist/dashboard/assets/drawer-BADqIRYP.js.gz +0 -0
  471. package/dist/dashboard/assets/entry-COaC-irN.js.gz +0 -0
  472. package/dist/dashboard/assets/entry-Ca7LSCet.js +0 -4
  473. package/dist/dashboard/assets/entry-Ca7LSCet.js.gz +0 -0
  474. package/dist/dashboard/assets/entry-PDd27uCd.js +0 -1
  475. package/dist/dashboard/assets/entry-PDd27uCd.js.gz +0 -0
  476. package/dist/dashboard/assets/formatters-DcHJyRiu.js.gz +0 -0
  477. package/dist/dashboard/assets/index-CgKmFngv.js.gz +0 -0
  478. package/dist/dashboard/assets/inline-B2BirKry.js.gz +0 -0
  479. package/dist/dashboard/assets/input-D-qV9dKY.js.gz +0 -0
  480. package/dist/dashboard/assets/layout-B7tVWhtV.js.gz +0 -0
  481. package/dist/dashboard/assets/list-row-CtkGE3bF.js.gz +0 -0
  482. package/dist/dashboard/assets/live-DGizF06-.js.gz +0 -0
  483. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js +0 -1
  484. package/dist/dashboard/assets/minimize-2-BTmMTK4o.js.gz +0 -0
  485. package/dist/dashboard/assets/mutation-GU7XdEjz.js.gz +0 -0
  486. package/dist/dashboard/assets/network-C9UE-bOr.js.gz +0 -0
  487. package/dist/dashboard/assets/numbers-BnAd22a_.js.gz +0 -0
  488. package/dist/dashboard/assets/pagination-BAywyMzS.js.gz +0 -0
  489. package/dist/dashboard/assets/query-keys-YSoQOUh6.js.gz +0 -0
  490. package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
  491. package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
  492. package/dist/dashboard/assets/routing-fnCsxgNO.js +0 -1
  493. package/dist/dashboard/assets/routing-fnCsxgNO.js.gz +0 -0
  494. package/dist/dashboard/assets/select-BCOcv8WK.js.gz +0 -0
  495. package/dist/dashboard/assets/settings-BxslsErn.js +0 -1
  496. package/dist/dashboard/assets/settings-BxslsErn.js.gz +0 -0
  497. package/dist/dashboard/assets/stack-ByKt3Q1g.js.gz +0 -0
  498. package/dist/dashboard/assets/state-DXbGTx7N.js.gz +0 -0
  499. package/dist/dashboard/assets/switch-ZeTsW623.js.gz +0 -0
  500. package/dist/dashboard/assets/useMutation-CbCP4w1o.js.gz +0 -0
  501. package/dist/dashboard/console-backgrounds.jpg +0 -0
  502. package/dist/dashboard/console-backgrounds_initial.jpg +0 -0
  503. package/dist/dashboard/donation/qris-risun-marke.png +0 -0
  504. package/src/providers/bundled-discovery-providers.ts +0 -98
  505. package/src/providers/configured-openai-providers.ts +0 -120
  506. package/src/providers/integrations/buddy/turing-device-token.ts +0 -262
  507. package/src/providers/integrations/buddy/workbuddy/cn-oauth.ts +0 -30
  508. package/src/providers/integrations/buddy/workbuddy/cn-provider.ts +0 -58
  509. package/src/providers/integrations/buddy/workbuddy/oauth.ts +0 -31
  510. package/src/providers/integrations/buddy/workbuddy/provider.ts +0 -209
  511. package/src/providers/integrations/buddy/workbuddy/quota.ts +0 -161
  512. package/src/providers/integrations/buddy/workbuddy/shared.ts +0 -285
  513. package/src/providers/operations/model-discovery-cache.ts +0 -34
  514. package/src/providers/operations/probe-fetch.ts +0 -15
  515. package/src/providers/operations/provider-version-cache.ts +0 -30
  516. package/src/providers/provider-capabilities.ts +0 -33
  517. package/src/providers/provider-credential-envelope.ts +0 -43
  518. /package/dist/dashboard/assets/{app-CTxoqyYB.js → app-DIXLjojg.js} +0 -0
  519. /package/dist/dashboard/assets/{app-CTxoqyYB.js.gz → app-DIXLjojg.js.gz} +0 -0
@@ -1,209 +0,0 @@
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
- injectBuddyParallelToolCalls,
38
- normalizeBuddyToolNames,
39
- } from "../buddy-chat-shared";
40
-
41
- // Constants — public contract
42
- export const WORKBUDDY_PROVIDER_ID = "workbuddy" as const;
43
- export const WORKBUDDY_BASE_URL = providerBaseUrl("workbuddy");
44
-
45
- // Payload hook — provider semantics
46
- // - force stream=true
47
- // - reasoning_summary auto only when reasoning_effort requested
48
- // - leading WorkBuddy system prompt + typed user content normalization
49
-
50
- /**
51
- * Leading system turn for this variant.
52
- *
53
- * The upstream validates that the wire opens with a `system` turn and treats
54
- * that prompt as the calling channel's identity: forwarding caller text in its
55
- * place answers `400 · 11128 "Illegal API invocation from an unapproved
56
- * channel"`. So this prompt is a wire contract, not merely a product choice —
57
- * see the sibling in `codebuddy.ts`.
58
- *
59
- * The text is deliberately neutral: a simple helpful-assistant persona with no
60
- * client/CLI branding, kept minimal so it reads naturally to any model and
61
- * does not advertise a channel identity upstream.
62
- */
63
- export const WORKBUDDY_SYSTEM_PROMPT = "You are a helpful assistant.";
64
-
65
- /**
66
- * Reconstructs generic function declarations when a later tool-history turn
67
- * arrives without the client's current `tools` array. WorkBuddy validates the
68
- * Chat Completions envelope against every historical tool call, so forwarding
69
- * `tool_calls`/`tool` messages without declarations yields model_param_invalid.
70
- */
71
- function restoreHistoricalToolDefinitions(
72
- payload: Record<string, unknown>,
73
- messages: readonly Record<string, unknown>[],
74
- ): void {
75
- const historicalNames = new Set<string>();
76
- for (const message of messages) {
77
- if (message["role"] !== "assistant" || !Array.isArray(message["tool_calls"])) continue;
78
- for (const rawCall of message["tool_calls"]) {
79
- if (!rawCall || typeof rawCall !== "object") continue;
80
- const call = rawCall as Record<string, unknown>;
81
- const functionValue =
82
- call["function"] && typeof call["function"] === "object"
83
- ? (call["function"] as Record<string, unknown>)
84
- : undefined;
85
- const name = functionValue?.["name"];
86
- if (typeof name === "string" && name.trim().length > 0) historicalNames.add(name);
87
- }
88
- }
89
- if (historicalNames.size === 0) return;
90
-
91
- const existing = Array.isArray(payload["tools"])
92
- ? (payload["tools"] as Array<Record<string, unknown>>)
93
- : [];
94
- const definedNames = new Set<string>();
95
- for (const rawTool of existing) {
96
- if (!rawTool || typeof rawTool !== "object") continue;
97
- const tool = rawTool as Record<string, unknown>;
98
- const functionValue =
99
- tool["function"] && typeof tool["function"] === "object"
100
- ? (tool["function"] as Record<string, unknown>)
101
- : tool;
102
- if (typeof functionValue["name"] === "string") definedNames.add(functionValue["name"]);
103
- }
104
- const recovered = [...historicalNames]
105
- .filter((name) => !definedNames.has(name))
106
- .map((name) => ({
107
- type: "function",
108
- function: {
109
- name,
110
- description: "Recovered from historical tool calls.",
111
- parameters: { type: "object", additionalProperties: true },
112
- },
113
- }));
114
- if (recovered.length > 0) payload["tools"] = [...existing, ...recovered];
115
- }
116
-
117
-
118
- export function workbuddyPrePayload(
119
- payload: Record<string, unknown>,
120
- request: CanonicalRequest,
121
- candidate: ProviderDispatchTarget,
122
- context?: ProviderDispatchContext,
123
- ): void {
124
- // International ladder. This hook is shared by `workbuddy` and `workbuddycn`
125
- // (see workbuddy/cn-provider.ts): the CN effort ladders in the reference
126
- // gateways are a CodeBuddy-CN concern, so `workbuddycn` deliberately stays on
127
- // the intl table. Switch to `"cn"` only if a live CN WorkBuddy account proves
128
- // it serves levels the intl table clamps.
129
- buddyPrePayloadCommon(payload, request, "intl", context);
130
- const rawModel = payload["model"];
131
- const source =
132
- typeof rawModel === "string" && rawModel.length > 0 ? rawModel : candidate.model_id;
133
- if (!source) throw new GatewayError("invalid_request", 400, "WorkBuddy model is required (request {requestId}). Check the shape of what you sent — then resend 🪞");
134
- const messages = payload["messages"];
135
- if (Array.isArray(messages)) {
136
- const normalizedMessages = messages as Array<Record<string, unknown>>;
137
- applyBuddySystemPrompt(
138
- normalizedMessages,
139
- WORKBUDDY_SYSTEM_PROMPT,
140
- context?.tenant_system_prompt,
141
- );
142
- restoreHistoricalToolDefinitions(payload, normalizedMessages);
143
- }
144
- normalizeBuddyToolNames(payload);
145
- injectBuddyParallelToolCalls(payload, request);
146
- void request;
147
- }
148
-
149
- // Model catalog — WorkBuddy international catalog.
150
- // Static seed derived from the reference gateway's model.json (context/output
151
- // limits) plus its global effort table; `reasoning` marks models with a
152
- // declared reasoning-effort scale.
153
- const WORKBUDDY_RAW: readonly BuddyRawEntry[] = BUDDY_SHARED_RAW;
154
-
155
- function makeWorkBuddyModels(providerId: "workbuddy" | "workbuddycn"): readonly ModelDefinition[] {
156
- return [
157
- ...WORKBUDDY_RAW.filter(
158
- (entry) => !BUDDY_IMAGE_MODEL_ID_SET.has(entry[0]) && !BUDDY_VIDEO_MODEL_ID_SET.has(entry[0]),
159
- ).map((entry) => makeBuddyModel(entry, providerId, WORKBUDDY_CHAT_PATH)),
160
- // WorkBuddy's base URL carries no version segment, so the image rows need the
161
- // same explicit path the chat rows use — the generic default would produce a
162
- // URL this upstream answers with a 405.
163
- ...makeBuddyImageModels(providerId, WORKBUDDY_CHAT_PATH),
164
- ...makeBuddyVideoModels(providerId, "/v2/videos/generations"),
165
- ];
166
- }
167
-
168
- export const WORKBUDDY_MODELS: readonly ModelDefinition[] = makeWorkBuddyModels("workbuddy");
169
-
170
- /**
171
- * Reads WorkBuddy's live console directory.
172
- *
173
- * The static `WORKBUDDY_MODELS` above is the fallback: this is what the "Fetch
174
- * models" action persists, and it carries the upstream's own limits and
175
- * capability flags rather than the seed's snapshot of them.
176
- */
177
- export async function discoverWorkBuddyModels(
178
- input: DiscoveryInput,
179
- ): Promise<readonly ModelDefinition[] | null> {
180
- return fetchBuddyDirectoryModels({
181
- siteUrl: WORKBUDDY_BASE_URL,
182
- providerId: WORKBUDDY_PROVIDER_ID,
183
- credential: input.credential,
184
- modelsPath: BUDDY_INTL_MODELS_PATH,
185
- endpoint: WORKBUDDY_CHAT_PATH,
186
- ...(input.signal ? { signal: input.signal } : {}),
187
- ...(input.fetcher ? { fetcher: input.fetcher } : {}),
188
- });
189
- }
190
-
191
- // Public factory — uses the OpenAI-compatible factory but forces provider semantics.
192
- // Supports both api_key and oauth via Authorization Bearer (factory handles both).
193
- export function createWorkBuddyAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
194
- return new BuddyMediaAdapter(
195
- workbuddyAdapterConfig({
196
- providerId: WORKBUDDY_PROVIDER_ID,
197
- baseUrl: WORKBUDDY_BASE_URL,
198
- prePayload: workbuddyPrePayload,
199
- ...(fetchImpl ? { fetchImpl } : {}),
200
- }),
201
- {
202
- variant: "IDE",
203
- systemPrompt: WORKBUDDY_SYSTEM_PROMPT,
204
- baseUrl: WORKBUDDY_BASE_URL,
205
- buildHeaders: (context, request) =>
206
- workbuddyHeaders(context, request, WORKBUDDY_DOMAIN, undefined, true),
207
- },
208
- );
209
- }
@@ -1,161 +0,0 @@
1
- import type { FetchLike, ProviderQuotaResult } from "../../../quota/quota-contracts";
2
- import type { QuotaCollectionContext } from "../../../quota/quota-support";
3
- import { providerBaseUrl } from "../../../provider-metadata";
4
- import {
5
- buildWorkBuddyUserAgent,
6
- getWorkBuddyClientVersion,
7
- getWorkBuddyCnClientVersion,
8
- getWorkBuddyCliVersion,
9
- } from "../../../operations/client-versions";
10
- import { WORKBUDDY_DOMAIN } from "./shared";
11
- import { fetchTencentBillingQuota } from "../buddy-quota-shared";
12
- import { fetchBuddyRequestUsage, type BuddyUsageResult } from "../buddy-usage-shared";
13
- import { buddyAccountUid } from "../buddy-oauth-shared";
14
-
15
- /**
16
- * WorkBuddy international billing quota.
17
- *
18
- * Endpoint: POST https://www.workbuddy.ai/v2/billing/meter/get-user-resource
19
- * Request: Authorization: Bearer <accessToken||apiKey>, desktop-client headers,
20
- * X-User-Id for the account UID, and the reference filter envelope
21
- * (ProductCode p_tcaca, statuses [0, 3], 101-year package window).
22
- * Response: { code: 0, data: { Response: { Data: { Accounts: [...] } } } }
23
- *
24
- * Same Tencent billing envelope as CodeBuddy CN, so the parsing is the shared
25
- * one in `buddy-quota-shared.ts`; only the endpoint and identity headers are
26
- * WorkBuddy-specific.
27
- */
28
-
29
- /**
30
- * The CN billing realm's host.
31
- *
32
- * The reference bills the CN realm here rather than on the CN chat host
33
- * (`www.workbuddy.cn`): billing is a separate service, and the chat host does
34
- * not serve the meter path.
35
- */
36
- const WORKBUDDY_CN_BILLING_BASE_URL = "https://www.codebuddy.cn";
37
-
38
- export const WORKBUDDY_USAGE_URL =
39
- `${providerBaseUrl("workbuddy")}/v2/billing/meter/get-user-resource`;
40
-
41
- async function billingHeaders(
42
- domain: string,
43
- clientVersion: string,
44
- enterpriseId?: string,
45
- ): Promise<Record<string, string>> {
46
- return {
47
- "User-Agent": buildWorkBuddyUserAgent(clientVersion, getWorkBuddyCliVersion()),
48
- "X-Product": "SaaS",
49
- "X-Domain": domain,
50
- "X-Requested-With": "XMLHttpRequest",
51
- "X-CodeBuddy-Request": "1",
52
- "Accept-Language": "en-US",
53
- ...(enterpriseId === undefined || enterpriseId.length === 0
54
- ? {}
55
- : { "X-Tenant-Id": enterpriseId, "X-Enterprise-Id": enterpriseId }),
56
- };
57
- }
58
-
59
- /**
60
- * Fetches WorkBuddy quota via the Tencent billing endpoint.
61
- *
62
- * Auth: `Authorization: Bearer <credential>` (api_key and oauth both use
63
- * Bearer; the caller passes the resolved secret).
64
- */
65
- export async function fetchWorkBuddyQuota(
66
- credential: string,
67
- fetcher: FetchLike,
68
- context?: QuotaCollectionContext,
69
- ): Promise<ProviderQuotaResult> {
70
- return fetchWorkBuddyQuotaFor({
71
- providerId: "workbuddy",
72
- display: "WorkBuddy",
73
- domain: WORKBUDDY_DOMAIN,
74
- credential,
75
- fetcher,
76
- ...(context === undefined ? {} : { context }),
77
- });
78
- }
79
-
80
- export async function fetchWorkBuddyCnQuota(
81
- credential: string,
82
- fetcher: FetchLike,
83
- context?: QuotaCollectionContext,
84
- ): Promise<ProviderQuotaResult> {
85
- return fetchWorkBuddyQuotaFor({
86
- providerId: "workbuddycn",
87
- display: "WorkBuddy CN",
88
- domain: "www.workbuddy.cn",
89
- credential,
90
- fetcher,
91
- ...(context === undefined ? {} : { context }),
92
- });
93
- }
94
-
95
- async function fetchWorkBuddyQuotaFor(args: {
96
- readonly providerId: "workbuddy" | "workbuddycn";
97
- readonly display: string;
98
- readonly domain: string;
99
- readonly credential: string;
100
- readonly fetcher: FetchLike;
101
- readonly context?: QuotaCollectionContext;
102
- }): Promise<ProviderQuotaResult> {
103
- const { providerId, display, domain, credential, fetcher, context } = args;
104
- const authState = typeof context?.auth_state === "object" && context?.auth_state !== null
105
- ? (context.auth_state as Record<string, unknown>)
106
- : undefined;
107
- const enterpriseId = typeof authState?.enterpriseId === "string" ? authState.enterpriseId : undefined;
108
- const clientVersion = providerId === "workbuddycn"
109
- ? getWorkBuddyCnClientVersion()
110
- : getWorkBuddyClientVersion();
111
- // The reference bills the CN realm on `www.codebuddy.cn`, not the chat host:
112
- // the billing realm is a different service from the one that serves chat,
113
- // and the CN chat host answers the meter path with an HTML error page.
114
- const billingBase = providerId === "workbuddycn" ? WORKBUDDY_CN_BILLING_BASE_URL : providerBaseUrl(providerId);
115
- return fetchTencentBillingQuota({
116
- source: providerId,
117
- display,
118
- url: `${billingBase}/v2/billing/meter/get-user-resource`,
119
- headers: await billingHeaders(domain, clientVersion, enterpriseId),
120
- credential,
121
- fetcher,
122
- defaultPlan: display,
123
- uid: buddyAccountUid(credential),
124
- });
125
- }
126
-
127
- /**
128
- * Real credit deductions for one WorkBuddy account.
129
- *
130
- * Mirrors {@link fetchWorkBuddyQuotaFor} in every respect but the endpoint —
131
- * same billing host, same client-version identity headers, same account UID —
132
- * because the usage-detail surface is the billing meter's other read.
133
- */
134
- export async function fetchWorkBuddyRequestUsage(
135
- credential: string,
136
- fetcher: FetchLike,
137
- args: {
138
- readonly providerId?: "workbuddy" | "workbuddycn";
139
- readonly days?: number;
140
- readonly context?: QuotaCollectionContext;
141
- } = {},
142
- ): Promise<BuddyUsageResult> {
143
- const providerId = args.providerId ?? "workbuddy";
144
- const domain = providerId === "workbuddycn" ? "www.workbuddy.cn" : WORKBUDDY_DOMAIN;
145
- const authState = typeof args.context?.auth_state === "object" && args.context?.auth_state !== null
146
- ? (args.context.auth_state as Record<string, unknown>)
147
- : undefined;
148
- const enterpriseId = typeof authState?.enterpriseId === "string" ? authState.enterpriseId : undefined;
149
- const clientVersion = providerId === "workbuddycn"
150
- ? getWorkBuddyCnClientVersion()
151
- : getWorkBuddyClientVersion();
152
- return fetchBuddyRequestUsage({
153
- url: `${providerBaseUrl(providerId)}/billing/meter/get-user-request-usage`,
154
- headers: await billingHeaders(domain, clientVersion, enterpriseId),
155
- credential,
156
- fetcher,
157
- days: args.days ?? 30,
158
- uid: buddyAccountUid(credential),
159
- });
160
- }
161
-
@@ -1,285 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { readFileSync } from "node:fs";
3
-
4
- import type { OpenAICompatibleAdapterConfig } from "../../../adapters/compatible-adapter";
5
- import { withBearerAuthentication } from "../../../adapters/compatible-adapter";
6
- import type { CanonicalRequest } from "../../../../protocol/canonical-model";
7
- import type { ProviderDispatchContext, ProviderDispatchTarget, ProviderId } from "../../../provider-contracts";
8
- import { resolveInboundSessionId } from "../../../operations/session-resolution";
9
- import { buddyConversationHeaders } from "../buddy-conversation-headers";
10
- import { buddyCliHeaders, buddyCliTraceHeaders } from "../buddy-cli-headers";
11
- import {
12
- buddyAgentPurpose,
13
- buddyEnterprise,
14
- buddyOAuthIdentityHeaders,
15
- buddyPrivateData,
16
- buddyUserId,
17
- resolveBuddyDeviceBinding,
18
- resolveBuddyIdentity,
19
- } from "../buddy-identity";
20
- import {
21
- buildWorkBuddyUserAgent,
22
- getWorkBuddyClientVersion,
23
- getWorkBuddyCliVersion,
24
- } from "../../../operations/client-versions";
25
- import {
26
- getTuringDeviceTokenService,
27
- resolveTuringSdkRoot,
28
- type TuringSdkConfig,
29
- WORKBUDDY_TURING_CONFIG,
30
- } from "../turing-device-token";
31
-
32
- /**
33
- * WorkBuddy serves chat from a versioned path on a base URL that carries no
34
- * version segment (billing uses the unversioned `/billing/…` path), so both the
35
- * adapter config and the static catalog rows must state it. The generic
36
- * `/chat/completions` default would join into
37
- * `https://www.workbuddy.ai/chat/completions`, which that upstream answers with
38
- * a 405 HTML error page.
39
- */
40
- export const WORKBUDDY_CHAT_PATH = "/v2/chat/completions" as const;
41
-
42
- export {
43
- buildWorkBuddyUserAgent,
44
- getWorkBuddyClientVersion,
45
- getWorkBuddyCliVersion,
46
- };
47
-
48
- /** WorkBuddy international gateway domain (Origin/Referer/X-Domain). */
49
- export const WORKBUDDY_DOMAIN = "www.workbuddy.ai";
50
-
51
- /**
52
- * Stable per-account device identifiers.
53
- *
54
- * WorkBuddy's desktop client presents one fixed virtual device per account.
55
- * Deriving `X-Machine-ID` / `X-Session-ID` from the account id (sha256, 36 hex)
56
- * keeps them constant across restarts while staying distinct per account, so
57
- * multiple pooled accounts are not correlated by a missing or drifting device
58
- * fingerprint. Mirrors the reference gateway's `wb2a:<purpose>:<uid>` scheme.
59
- */
60
- function deriveAccountStableId(accountId: string, purpose: string): string {
61
- const sum = createHash("sha256").update(`wb2a:${purpose}:${accountId}`).digest("hex");
62
- return sum.slice(0, 36);
63
- }
64
-
65
- /**
66
- * Per-request WorkBuddy chat headers — the exact desktop-client contract.
67
- *
68
- * The international gateway gates chat on the desktop `User-Agent` (platform
69
- * brand `WorkBuddy AI`, carried on the wire as the token `workbuddy-ai`;
70
- * the wrong token trips 403 code 11140), plus the `X-CodeBuddy-Request` risk
71
- * gate and the account-scoped device headers.
72
- * The background client-version monitor keeps this value fresh; dispatch only
73
- * reads the cached value and never waits on a version endpoint.
74
- *
75
- * `cliIdentity` selects the reference CLI contract instead. The two are not
76
- * variations of one set: the CLI drops every browser header and the device
77
- * token, and adds the agent envelope. Left unset, nothing changes.
78
- */
79
- export async function workbuddyHeaders(
80
- context?: ProviderDispatchContext,
81
- request?: CanonicalRequest,
82
- domain = WORKBUDDY_DOMAIN,
83
- clientVersion = getWorkBuddyClientVersion(),
84
- cliIdentity?: boolean,
85
- ): Promise<Record<string, string>> {
86
- const identity = resolveBuddyIdentity(context, cliIdentity);
87
- const conversation = buddyConversationHeaders({
88
- ...(resolveInboundSessionId(context, request) === undefined
89
- ? {}
90
- : { conversationId: resolveInboundSessionId(context, request) }),
91
- // The reference emits dashed-UUID message/request ids on the WorkBuddy
92
- // desktop product and 32-hex on CLI traffic (build_attempt_headers converts
93
- // only the message/request ids, and only for the WorkBuddy profiles).
94
- messageIdStyle: identity === "desktop" ? "uuid" : "hex",
95
- });
96
- const accountId = context?.credential.account_id;
97
- const purpose = buddyAgentPurpose(context, request);
98
- if (identity === "cli") {
99
- const inbound = context?.request_headers;
100
- const rootRequestId = inbound?.["x-root-request-id"]?.trim();
101
- const parentConversationId = inbound?.["x-parent-conversation-id"]?.trim();
102
- // The reference CLI: issued by the OpenAI Node SDK, so no browser
103
- // *transport* header (origin/referer/accept-language) and no device token,
104
- // and the machine/session device pair does not exist — only `X-User-Id`,
105
- // which is `anonymous` without a uid. It keeps the request-shape markers
106
- // (`x-requested-with`, `x-codebuddy-request`) the reference sends on every
107
- // call regardless of transport.
108
- return {
109
- accept: "application/json",
110
- "user-agent": `CLI/${getWorkBuddyCliVersion()} CodeBuddy/${getWorkBuddyCliVersion()}`,
111
- "x-requested-with": "XMLHttpRequest",
112
- "x-codebuddy-request": "1",
113
- "x-domain": domain,
114
- ...(purpose === undefined ? {} : { "x-agent-purpose": purpose }),
115
- "x-ide-name": "CLI",
116
- "x-ide-type": "CLI",
117
- "x-ide-version": getWorkBuddyCliVersion(),
118
- "x-product": "SaaS",
119
- "x-no-enterprise-id": "1",
120
- ...conversation,
121
- ...(rootRequestId === undefined ? {} : { "x-root-request-id": rootRequestId }),
122
- ...(parentConversationId === undefined
123
- ? {}
124
- : { "x-parent-conversation-id": parentConversationId }),
125
- ...buddyCliTraceHeaders(conversation),
126
- ...buddyOAuthIdentityHeaders(context),
127
- ...buddyCliHeaders({
128
- userId: buddyUserId(context),
129
- enterpriseId: buddyEnterprise(context),
130
- privateData: buddyPrivateData(context),
131
- }),
132
- };
133
- }
134
- const headers: Record<string, string> = {
135
- accept: "application/json, text/event-stream",
136
- "user-agent": buildWorkBuddyUserAgent(clientVersion, getWorkBuddyCliVersion()),
137
- origin: `https://${domain}`,
138
- referer: `https://${domain}/`,
139
- "accept-language": "en-US",
140
- "x-requested-with": "XMLHttpRequest",
141
- "x-codebuddy-request": "1",
142
- "x-domain": domain,
143
- ...(purpose === undefined ? {} : { "x-agent-purpose": purpose }),
144
- "x-ide-name": "WorkBuddy",
145
- "x-ide-type": "WorkBuddy",
146
- "x-ide-version": clientVersion,
147
- // Both references send the literal `SaaS` here. `WorkBuddy` was a value
148
- // this repo invented; the desktop product name belongs in `x-ide-name`,
149
- // and the CN test below compares the two realms against each other rather
150
- // than to a hard-coded string.
151
- "x-product": "SaaS",
152
- // Personal international accounts carry no enterprise id: declare it
153
- // explicitly so upstream risk control does not treat the omission as
154
- // suspicious.
155
- "x-no-enterprise-id": "1",
156
- };
157
- // The conversation/tracing family the upstream's channel check looks for. A
158
- // live request carrying only `x-session-id` was refused for a missing
159
- // conversation id; the aggregation key below is the one the reference marks
160
- // mandatory.
161
- Object.assign(headers, conversation);
162
- if (accountId) {
163
- headers["x-user-id"] = accountId;
164
- headers["x-machine-id"] = deriveAccountStableId(accountId, "machine");
165
- headers["x-session-id"] = deriveAccountStableId(accountId, "session");
166
- }
167
- // Per-account device binding: distinct device identity per account (see
168
- // resolveBuddyDeviceBinding). Sent as the desktop's X-Device-Id-List.
169
- const binding = resolveBuddyDeviceBinding(context);
170
- if (binding !== undefined) {
171
- headers["x-device-id-list"] = JSON.stringify({ qimei36: binding });
172
- }
173
- Object.assign(headers, await buddyDeviceTokenHeaders({
174
- realm: domain.endsWith(".cn") ? "cn" : "intl",
175
- context,
176
- cliIdentity,
177
- }));
178
- return headers;
179
- }
180
-
181
- /**
182
- * Desktop risk token, sent only when the account actually has one.
183
- *
184
- * The account's own `auth_state` wins. When it carries none, a file the
185
- * desktop client writes (`CARTETHYIA_DEVICE_TOKEN_FILE`, default
186
- * `/app/data/device_token`) is read instead — cached for five minutes, and
187
- * ignored when it is larger than 1 KB, because a token file that size is not
188
- * a token. A missing file is the normal case and reads as "no token".
189
- */
190
- const DEVICE_TOKEN_FILE_MAX_BYTES = 1024;
191
- const DEVICE_TOKEN_FILE_TTL_MS = 5 * 60_000;
192
- let deviceTokenFileCache: { readonly value: string | undefined; readonly readAt: number } | undefined;
193
-
194
- export function readBuddyDeviceToken(context?: ProviderDispatchContext): string | undefined {
195
- const state = context?.credential.auth_state;
196
- const value = state?.["deviceToken"] ?? state?.["device_token"];
197
- if (typeof value === "string" && value.trim().length > 0) return value.trim();
198
- return readDeviceTokenFile();
199
- }
200
-
201
- /**
202
- * The reference `X-Device-Token` pair, per the official desktop app.
203
- *
204
- * The desktop client (WorkBuddyAI, channel 400111) always presents one of the
205
- * two on chat traffic — a real token from the TuringShield SDK, or an
206
- * `X-Device-Token-Error` when the SDK cannot produce one. It never omits both,
207
- * and it sends the header on every realm (Intl and CN alike). The SDK is a
208
- * proprietary native addon; when it is not configured we fall back to a
209
- * captured token (auth_state / `CARTETHYIA_DEVICE_TOKEN_FILE`) and only then
210
- * to the official failure state.
211
- *
212
- * - `CARTETHYIA_TURING_SDK_PATH` → real token via `TuringDeviceTokenService`.
213
- * - Legacy token (auth_state/file) → used when the SDK is unavailable.
214
- * - CLI identity never carries a device token (the CLI has no device).
215
- */
216
- export async function buddyDeviceTokenHeaders(args: {
217
- realm: "intl" | "cn";
218
- context: ProviderDispatchContext | undefined;
219
- cliIdentity: boolean | undefined;
220
- turingConfig?: TuringSdkConfig;
221
- }): Promise<Record<string, string>> {
222
- const { context, cliIdentity, turingConfig } = args;
223
- void args.realm; // the desktop client sends the token on both realms
224
- if (resolveBuddyIdentity(context, cliIdentity) === "cli") return {};
225
- // Native SDK first (real token), when configured.
226
- if (resolveTuringSdkRoot() !== null) {
227
- const sdkHeaders = await getTuringDeviceTokenService(turingConfig ?? WORKBUDDY_TURING_CONFIG).headersForRequest(false);
228
- if (sdkHeaders["x-device-token"] !== undefined) return sdkHeaders;
229
- // SDK configured but could not produce a token: mirror its failure state,
230
- // like the desktop client does — do not fall back to a stale file token.
231
- return sdkHeaders;
232
- }
233
- // No SDK on this deployment: a captured token is better than nothing.
234
- const token = readBuddyDeviceToken(context);
235
- if (token !== undefined) return { "x-device-token": token };
236
- return { "x-device-token-error": "sdk_not_initialized" };
237
- }
238
-
239
- function readDeviceTokenFile(): string | undefined {
240
- const now = Date.now();
241
- if (deviceTokenFileCache !== undefined && now - deviceTokenFileCache.readAt < DEVICE_TOKEN_FILE_TTL_MS) {
242
- return deviceTokenFileCache.value;
243
- }
244
- const path = process.env["CARTETHYIA_DEVICE_TOKEN_FILE"] ?? "/app/data/device_token";
245
- let value: string | undefined;
246
- try {
247
- const raw = readFileSync(path);
248
- if (raw.byteLength > 0 && raw.byteLength <= DEVICE_TOKEN_FILE_MAX_BYTES) {
249
- const text = raw.toString("utf8").trim();
250
- if (text.length > 0) value = text;
251
- }
252
- } catch {
253
- value = undefined;
254
- }
255
- deviceTokenFileCache = { value, readAt: now };
256
- return value;
257
- }
258
-
259
- /**
260
- * Shared OpenAI-compatible chat-adapter config for WorkBuddy: bearer auth
261
- * (api_key and oauth both use `Authorization: Bearer`), `/v2/chat/completions`
262
- * endpoint, per-request desktop-client headers, and the payload hook.
263
- */
264
- export function workbuddyAdapterConfig(args: {
265
- providerId: ProviderId;
266
- baseUrl: string;
267
- domain?: string;
268
- prePayload: (
269
- payload: Record<string, unknown>,
270
- request: CanonicalRequest,
271
- candidate: ProviderDispatchTarget,
272
- ) => void;
273
- fetchImpl?: typeof fetch;
274
- cliIdentity?: boolean;
275
- }): OpenAICompatibleAdapterConfig {
276
- return withBearerAuthentication({
277
- provider_id: args.providerId,
278
- base_url: args.baseUrl,
279
- endpoint_paths_by_wire_family: { chat: WORKBUDDY_CHAT_PATH },
280
- buildExtraHeaders: (context, request) =>
281
- workbuddyHeaders(context, request, args.domain ?? WORKBUDDY_DOMAIN, undefined, args.cliIdentity),
282
- prePayload: args.prePayload,
283
- ...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
284
- });
285
- }
@@ -1,34 +0,0 @@
1
- /**
2
- * TTL cache for credential-free model discovery.
3
- *
4
- * Only non-null, non-empty results are cached, so failed discovery stays
5
- * retryable. Concurrent misses for one key share one load through TtlCache.
6
- */
7
- import { TtlCacheFamily } from "../../persistence/ttl-cache";
8
- import type { ModelDefinition } from "../provider-model-definition";
9
-
10
- const MODEL_DISCOVERY_CACHE_TTL_MS = 10 * 60 * 1000;
11
- const discoveryCaches = new TtlCacheFamily<readonly ModelDefinition[]>({
12
- defaultTtlMs: MODEL_DISCOVERY_CACHE_TTL_MS,
13
- });
14
-
15
- export interface CachedModelDiscoveryOptions {
16
- readonly ttlMs?: number;
17
- }
18
-
19
- /** Returns cached models, retrying null/empty loads on the next call. */
20
- export async function getCachedModelDiscovery(
21
- key: string,
22
- loader: () => Promise<readonly ModelDefinition[] | null>,
23
- options: CachedModelDiscoveryOptions = {},
24
- ): Promise<readonly ModelDefinition[] | null> {
25
- return discoveryCaches.for(options.ttlMs).load(key, loader, {
26
- namespace: "model-discovery",
27
- shouldCache: (models) => models.length > 0,
28
- });
29
- }
30
-
31
- /** Drops all cached discoveries. Test-only. */
32
- export function resetModelDiscoveryCacheForTesting(): void {
33
- discoveryCaches.clear();
34
- }