cartethyia 2.8.0 → 2.8.1

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 (348) hide show
  1. package/.env.example +3 -3
  2. package/dist/dashboard/assets/{BannedPage-Cc0vKpMG.js → BannedPage-Dq530awD.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-Bqj2aa1T.js → CliToolDetailPage-DZzaS-7S.js} +1 -1
  5. package/dist/dashboard/assets/CliToolDetailPage-DZzaS-7S.js.gz +0 -0
  6. package/dist/dashboard/assets/{CliToolsPage-CXsaOAO2.js → CliToolsPage-DaZZ3cqP.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-BeLpJ4ma.js → CombosPage-BlC_xdkX.js} +1 -1
  9. package/dist/dashboard/assets/CombosPage-BlC_xdkX.js.gz +0 -0
  10. package/dist/dashboard/assets/{ConsoleLogPage-DnV0uZ3m.js → ConsoleLogPage-D-rqeVtG.js} +1 -1
  11. package/dist/dashboard/assets/ConsoleLogPage-D-rqeVtG.js.gz +0 -0
  12. package/dist/dashboard/assets/{CustomizationPage-CBxAjo63.js → CustomizationPage-7xT5yg2E.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
  14. package/dist/dashboard/assets/{HealthEventsModal-B5yEE0k6.js → HealthEventsModal-Clq8E9cW.js} +1 -1
  15. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
  16. package/dist/dashboard/assets/{InjectSystemPromptPanel-BWFLECmz.js → InjectSystemPromptPanel-6Teoq9Se.js} +1 -1
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-CgoPc5B9.js → LoginPage-CZuI0MAR.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
  20. package/dist/dashboard/assets/{ModelPicker-D9bFQern.js → ModelPicker-C1hNTlkr.js} +1 -1
  21. package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
  22. package/dist/dashboard/assets/{OverviewPage-B_p4tL8k.js → OverviewPage-0yfhSI1C.js} +1 -1
  23. package/dist/dashboard/assets/OverviewPage-0yfhSI1C.js.gz +0 -0
  24. package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js +8 -0
  25. package/dist/dashboard/assets/ProviderDetailPage-xqTxdQ4c.js.gz +0 -0
  26. package/dist/dashboard/assets/{ProviderIcon-D_0PiZtg.js → ProviderIcon-Ddhm1InL.js} +1 -1
  27. package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
  28. package/dist/dashboard/assets/{ProvidersPage-CLI2bJTK.js → ProvidersPage-C3fYuu6i.js} +1 -1
  29. package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js.gz +0 -0
  30. package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js +9 -0
  31. package/dist/dashboard/assets/ProxyPage-CHtJtZ3u.js.gz +0 -0
  32. package/dist/dashboard/assets/{QuotaPage-DA-a1iSN.js → QuotaPage-D1RV_2BX.js} +1 -1
  33. package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-CctTga2C.js → SettingsPage-BzZAvYSX.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
  36. package/dist/dashboard/assets/{SetupPage-febLU4r1.js → SetupPage--s-EfEIL.js} +1 -1
  37. package/dist/dashboard/assets/SetupPage--s-EfEIL.js.gz +0 -0
  38. package/dist/dashboard/assets/{StudioPage-M6fvR5Wz.js → StudioPage-BjXFGSK4.js} +1 -1
  39. package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
  40. package/dist/dashboard/assets/{UsagePage-nyeuRqz9.js → UsagePage-CP8F8BN7.js} +1 -1
  41. package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BFOlvrJC.js → api-keys-2hc12Uz2.js} +1 -1
  43. package/dist/dashboard/assets/api-keys-2hc12Uz2.js.gz +0 -0
  44. package/dist/dashboard/assets/app-DGXbNfAR.css +2 -0
  45. package/dist/dashboard/assets/app-DGXbNfAR.css.gz +0 -0
  46. package/dist/dashboard/assets/{assert-CqTLw5e7.js → assert-BMcj1xZE.js} +1 -1
  47. package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-C83EqLB0.js → badge-DkRUuVfz.js} +1 -1
  49. package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-D1xn7pIe.js → banner-CDjW841Q.js} +1 -1
  51. package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-DU3Lq5Lm.js → card-Bto5UlL9.js} +1 -1
  53. package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-Dw1U_drK.js → cli-tools-DaH6g9hL.js} +1 -1
  55. package/dist/dashboard/assets/cli-tools-DaH6g9hL.js.gz +0 -0
  56. package/dist/dashboard/assets/{clipboard-button-CEL5Sg_J.js → clipboard-button-BYKBCzjk.js} +1 -1
  57. package/dist/dashboard/assets/clipboard-button-BYKBCzjk.js.gz +0 -0
  58. package/dist/dashboard/assets/{dialog-BjFR5UHy.js → dialog-DL0Zftwv.js} +1 -1
  59. package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-HvBW0AjI.js → drawer-Dpx_UXaS.js} +1 -1
  61. package/dist/dashboard/assets/drawer-Dpx_UXaS.js.gz +0 -0
  62. package/dist/dashboard/assets/{entry-CECVELyy.js → entry-BV7-1NoM.js} +1 -1
  63. package/dist/dashboard/assets/entry-BV7-1NoM.js.gz +0 -0
  64. package/dist/dashboard/assets/{entry-DYYofQ7W.js → entry-CGvdNU6r.js} +1 -1
  65. package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
  66. package/dist/dashboard/assets/{entry-BSu3gFlt.js → entry-DScKYvZj.js} +3 -3
  67. package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
  68. package/dist/dashboard/assets/{formatters-DLW4i8zK.js → formatters-BS3DZlZj.js} +1 -1
  69. package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-1-fCqe64.js → index-SQnvvTWX.js} +2 -2
  71. package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-DGvU2oLK.js → inline-Dl-cuLK0.js} +1 -1
  73. package/dist/dashboard/assets/inline-Dl-cuLK0.js.gz +0 -0
  74. package/dist/dashboard/assets/{input-iNnO1X2K.js → input-Bfx0EzRc.js} +1 -1
  75. package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-0q8UGypb.js → layout-BxhbQ_JS.js} +1 -1
  77. package/dist/dashboard/assets/layout-BxhbQ_JS.js.gz +0 -0
  78. package/dist/dashboard/assets/{list-row-C0w2bQjJ.js → list-row-D49Y4ptn.js} +1 -1
  79. package/dist/dashboard/assets/list-row-D49Y4ptn.js.gz +0 -0
  80. package/dist/dashboard/assets/{live-M5aJ_xCa.js → live-CbVTdX9V.js} +1 -1
  81. package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
  82. package/dist/dashboard/assets/{network-BKeQGT3K.js → network-JGvDveof.js} +1 -1
  83. package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
  84. package/dist/dashboard/assets/{numbers-CivAk3da.js → numbers-Dw6kiew-.js} +1 -1
  85. package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
  86. package/dist/dashboard/assets/{pagination-CpzvI5ep.js → pagination-iUoI8GeE.js} +1 -1
  87. package/dist/dashboard/assets/pagination-iUoI8GeE.js.gz +0 -0
  88. package/dist/dashboard/assets/providers/sensenova-intl.png +0 -0
  89. package/dist/dashboard/assets/providers/sensenova.png +0 -0
  90. package/dist/dashboard/assets/{routing-BFQX2VBc.js → routing-8jZr-3WE.js} +1 -1
  91. package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
  92. package/dist/dashboard/assets/{select-CXbck0jG.js → select-oO1FxMVb.js} +1 -1
  93. package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
  94. package/dist/dashboard/assets/{settings-C_XvMHh9.js → settings-CLr3kdIx.js} +1 -1
  95. package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
  96. package/dist/dashboard/assets/{stack-DggRiCxE.js → stack-Y3pDteZr.js} +1 -1
  97. package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
  98. package/dist/dashboard/assets/{state-ClFzfbYp.js → state-CArX_Iak.js} +1 -1
  99. package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
  100. package/dist/dashboard/assets/{switch-CTIFxKqS.js → switch-DwlwmDO-.js} +1 -1
  101. package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
  102. package/dist/dashboard/assets/{useMutation-BClG3yWj.js → useMutation-DJ9GYEgf.js} +1 -1
  103. package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
  104. package/dist/dashboard/index.html +2 -2
  105. package/dist/dashboard/index.html.gz +0 -0
  106. package/dist/dashboard/precompressed-assets.json +51 -51
  107. package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
  108. package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
  109. package/package.json +1 -1
  110. package/src/boot/app.ts +1 -1
  111. package/src/boot/dependencies.ts +4 -6
  112. package/src/config/providers.ts +6 -5
  113. package/src/config/spec.ts +8 -8
  114. package/src/console/backup/nine-router.ts +71 -10
  115. package/src/console/backup/service.ts +8 -1
  116. package/src/console/console-router.ts +1 -1
  117. package/src/console/domain-registration.ts +7 -2
  118. package/src/console/inferhub/client.ts +1 -1
  119. package/src/console/observability/live.ts +2 -2
  120. package/src/console/providers/catalog/contracts.ts +9 -3
  121. package/src/console/providers/catalog/model-operations.ts +2 -3
  122. package/src/console/providers/catalog/provider-operations.ts +1 -1
  123. package/src/console/providers/catalog/routes.ts +2 -2
  124. package/src/console/providers/catalog/store.ts +1914 -1907
  125. package/src/console/providers/detail/routes.ts +1 -0
  126. package/src/console/providers/detail/store.ts +4 -0
  127. package/src/console/providers/oauth/callback-listener.ts +30 -11
  128. package/src/console/providers/oauth/device-egress.ts +123 -0
  129. package/src/console/providers/oauth/routes.ts +123 -16
  130. package/src/console/quota/account-quota-tenant.ts +5 -5
  131. package/src/console/quota/account-test-egress.ts +2 -2
  132. package/src/console/quota/daily-growth-job.ts +1 -1
  133. package/src/console/routing/pools/contracts.ts +1 -1
  134. package/src/console/routing/pools/operations.ts +1 -1
  135. package/src/console/routing/pools/probe-verdict.ts +2 -2
  136. package/src/console/routing/pools/relay-deploy.ts +1 -1
  137. package/src/console/routing/pools/store.ts +4 -4
  138. package/src/network/client.ts +67 -0
  139. package/src/network/egress/bidi-session.ts +322 -0
  140. package/src/network/egress/dial.ts +201 -0
  141. package/src/network/egress/factory.ts +191 -0
  142. package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
  143. package/src/network/egress/tls-profile.ts +123 -0
  144. package/src/network/egress/ws.ts +175 -0
  145. package/src/network/{types.ts → pool/agent-config.ts} +1 -1
  146. package/src/network/pool/agent.ts +2 -2
  147. package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +7 -7
  148. package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
  149. package/src/network/pool/resolver.ts +10 -849
  150. package/src/network/pool/selector.ts +2 -2
  151. package/src/network/ssrf.ts +1 -1
  152. package/src/network/{retry.ts → util/retry.ts} +1 -1
  153. package/src/observability/telemetry-buffer.ts +1 -1
  154. package/src/persistence/schema.ts +9 -0
  155. package/src/persistence/ttl-cache.ts +1 -1
  156. package/src/protocol/codecs.ts +58 -1
  157. package/src/protocol/request/messages.ts +31 -18
  158. package/src/protocol/response/messages.ts +34 -7
  159. package/src/protocol/translation/quirks.ts +15 -0
  160. package/src/protocol/upstream/send-claude-messages.ts +2 -2
  161. package/src/providers/adapters/compatible-adapter.ts +5 -0
  162. package/src/providers/authentication/oauth-client.ts +40 -6
  163. package/src/providers/authentication/oauth-device-flow.ts +7 -3
  164. package/src/providers/authentication/oauth-flow-store.ts +82 -1
  165. package/src/providers/authentication/oauth-refresh-service.ts +766 -739
  166. package/src/providers/default-registry.ts +76 -0
  167. package/src/providers/discovery/discovery-types.ts +7 -0
  168. package/src/providers/discovery/probe-phases.ts +6 -2
  169. package/src/providers/discovery/probing-service.ts +7 -0
  170. package/src/providers/integrations/antigravity/antigravity-protocol.ts +11 -0
  171. package/src/providers/integrations/buddy/account.ts +969 -0
  172. package/src/providers/integrations/buddy/capabilities.ts +10 -10
  173. package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
  174. package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +5 -5
  175. package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
  176. package/src/providers/integrations/buddy/codebuddy/shared.ts +4 -4
  177. package/src/providers/integrations/buddy/{buddy-identity.ts → headers.ts} +138 -140
  178. package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
  179. package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
  180. package/src/providers/integrations/cline/cline-oauth.ts +10 -5
  181. package/src/providers/integrations/cline/cline.ts +3 -4
  182. package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
  183. package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
  184. package/src/providers/integrations/clixad/provider.ts +145 -0
  185. package/src/providers/integrations/codex/codex-oauth.ts +8 -5
  186. package/src/providers/integrations/cursor/cursor-auth.ts +1 -1
  187. package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
  188. package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
  189. package/src/providers/integrations/cursor/cursor-shared.ts +1 -1
  190. package/src/providers/integrations/cursor/cursor.ts +485 -70
  191. package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
  192. package/src/providers/integrations/deepai/deepai-common.ts +145 -0
  193. package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
  194. package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
  195. package/src/providers/integrations/deepai/provider.ts +42 -0
  196. package/src/providers/integrations/devin/devin-auth.ts +7 -0
  197. package/src/providers/integrations/factory/factory-oauth.ts +16 -7
  198. package/src/providers/integrations/freebuff/freebuff.ts +2 -2
  199. package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
  200. package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
  201. package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
  202. package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
  203. package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
  204. package/src/providers/integrations/freepi/freepi-session.ts +158 -0
  205. package/src/providers/integrations/freepi/freepi.ts +80 -54
  206. package/src/providers/integrations/github/github-discovery.ts +30 -13
  207. package/src/providers/integrations/github/github-oauth.ts +217 -44
  208. package/src/providers/integrations/github/github-quota.ts +22 -5
  209. package/src/providers/integrations/github/github.ts +40 -32
  210. package/src/providers/integrations/grok/grok-oauth.ts +4 -4
  211. package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
  212. package/src/providers/integrations/hermes/hermes.ts +34 -5
  213. package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
  214. package/src/providers/integrations/kilo/kilo.ts +1 -1
  215. package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
  216. package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
  217. package/src/providers/integrations/muse/muse-oauth.ts +5 -5
  218. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  219. package/src/providers/integrations/openrouter/provider.ts +1 -1
  220. package/src/providers/integrations/perch/perch-protocol.ts +0 -3
  221. package/src/providers/integrations/perch/perch.ts +3 -3
  222. package/src/providers/integrations/qoder/claim-qoder-credits.ts +1 -1
  223. package/src/providers/integrations/qoder/qoder-adapter.ts +19 -113
  224. package/src/providers/integrations/qoder/qoder-auth.ts +8 -1
  225. package/src/providers/integrations/qoder/qoder-catalog.ts +1 -1
  226. package/src/providers/integrations/qoder/qoder-chat.ts +25 -8
  227. package/src/providers/integrations/qoder/qoder-checkin.ts +1 -1
  228. package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
  229. package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
  230. package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
  231. package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
  232. package/src/providers/integrations/qoder/qoder-types.ts +9 -0
  233. package/src/providers/integrations/qoder/qoder.ts +3 -25
  234. package/src/providers/integrations/sensenova/provider.ts +144 -0
  235. package/src/providers/integrations/trae/trae-quota.ts +15 -1
  236. package/src/providers/integrations/vercel/provider.ts +117 -0
  237. package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
  238. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  239. package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
  240. package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
  241. package/src/providers/integrations/zro/zro.ts +2 -1
  242. package/src/providers/operations/account-refresh-status.ts +14 -0
  243. package/src/providers/operations/client-versions.ts +95 -30
  244. package/src/providers/operations/oauth-refresh-lead.ts +46 -22
  245. package/src/providers/operations/provider-caches.ts +1 -1
  246. package/src/providers/operations/provider-credential-service.ts +22 -25
  247. package/src/providers/operations/session-resolution.ts +17 -1
  248. package/src/providers/provider-contracts.ts +2 -2
  249. package/src/providers/provider-metadata.ts +30 -0
  250. package/src/providers/quota/quota-contracts.ts +2 -0
  251. package/src/providers/quota/refresh.ts +25 -3
  252. package/src/security/ip-boundary.ts +1 -1
  253. package/src/transport/dispatch/attempt-finalize.ts +1 -1
  254. package/src/transport/dispatch/attempt-loop.ts +3 -3
  255. package/src/transport/dispatch/handler-deps.ts +1 -1
  256. package/src/transport/dispatch/leases.ts +1 -1
  257. package/src/transport/dispatch/retry-policy.ts +1 -1
  258. package/src/transport/dispatch/streaming/finalize.ts +2 -2
  259. package/src/transport/dispatch/streaming/stream.ts +1 -1
  260. package/src/transport/dispatch/upstream.ts +1 -1
  261. package/src/transport/shutdown-notice.ts +1 -1
  262. package/src/workers/buddy-growth-tasks.ts +8 -8
  263. package/src/workers/daily-checkin.ts +4 -4
  264. package/src/workers/quota-refresh-sweep.ts +1 -1
  265. package/src/workers/zcode-gift-claim.ts +1 -1
  266. package/dist/dashboard/assets/BannedPage-Cc0vKpMG.js.gz +0 -0
  267. package/dist/dashboard/assets/CliToolDetailPage-Bqj2aa1T.js.gz +0 -0
  268. package/dist/dashboard/assets/CliToolsPage-CXsaOAO2.js.gz +0 -0
  269. package/dist/dashboard/assets/CombosPage-BeLpJ4ma.js.gz +0 -0
  270. package/dist/dashboard/assets/ConsoleLogPage-DnV0uZ3m.js.gz +0 -0
  271. package/dist/dashboard/assets/CustomizationPage-CBxAjo63.js.gz +0 -0
  272. package/dist/dashboard/assets/HealthEventsModal-B5yEE0k6.js.gz +0 -0
  273. package/dist/dashboard/assets/InjectSystemPromptPanel-BWFLECmz.js.gz +0 -0
  274. package/dist/dashboard/assets/LoginPage-CgoPc5B9.js.gz +0 -0
  275. package/dist/dashboard/assets/ModelPicker-D9bFQern.js.gz +0 -0
  276. package/dist/dashboard/assets/OverviewPage-B_p4tL8k.js.gz +0 -0
  277. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js +0 -8
  278. package/dist/dashboard/assets/ProviderDetailPage-rs5E2rxv.js.gz +0 -0
  279. package/dist/dashboard/assets/ProviderIcon-D_0PiZtg.js.gz +0 -0
  280. package/dist/dashboard/assets/ProvidersPage-CLI2bJTK.js.gz +0 -0
  281. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js +0 -9
  282. package/dist/dashboard/assets/ProxyPage-BwNC_-Cx.js.gz +0 -0
  283. package/dist/dashboard/assets/QuotaPage-DA-a1iSN.js.gz +0 -0
  284. package/dist/dashboard/assets/SettingsPage-CctTga2C.js.gz +0 -0
  285. package/dist/dashboard/assets/SetupPage-febLU4r1.js.gz +0 -0
  286. package/dist/dashboard/assets/StudioPage-M6fvR5Wz.js.gz +0 -0
  287. package/dist/dashboard/assets/UsagePage-nyeuRqz9.js.gz +0 -0
  288. package/dist/dashboard/assets/api-keys-BFOlvrJC.js.gz +0 -0
  289. package/dist/dashboard/assets/app-Dx2QgsNj.css +0 -2
  290. package/dist/dashboard/assets/app-Dx2QgsNj.css.gz +0 -0
  291. package/dist/dashboard/assets/assert-CqTLw5e7.js.gz +0 -0
  292. package/dist/dashboard/assets/badge-C83EqLB0.js.gz +0 -0
  293. package/dist/dashboard/assets/banner-D1xn7pIe.js.gz +0 -0
  294. package/dist/dashboard/assets/card-DU3Lq5Lm.js.gz +0 -0
  295. package/dist/dashboard/assets/cli-tools-Dw1U_drK.js.gz +0 -0
  296. package/dist/dashboard/assets/clipboard-button-CEL5Sg_J.js.gz +0 -0
  297. package/dist/dashboard/assets/dialog-BjFR5UHy.js.gz +0 -0
  298. package/dist/dashboard/assets/drawer-HvBW0AjI.js.gz +0 -0
  299. package/dist/dashboard/assets/entry-BSu3gFlt.js.gz +0 -0
  300. package/dist/dashboard/assets/entry-CECVELyy.js.gz +0 -0
  301. package/dist/dashboard/assets/entry-DYYofQ7W.js.gz +0 -0
  302. package/dist/dashboard/assets/formatters-DLW4i8zK.js.gz +0 -0
  303. package/dist/dashboard/assets/index-1-fCqe64.js.gz +0 -0
  304. package/dist/dashboard/assets/inline-DGvU2oLK.js.gz +0 -0
  305. package/dist/dashboard/assets/input-iNnO1X2K.js.gz +0 -0
  306. package/dist/dashboard/assets/layout-0q8UGypb.js.gz +0 -0
  307. package/dist/dashboard/assets/list-row-C0w2bQjJ.js.gz +0 -0
  308. package/dist/dashboard/assets/live-M5aJ_xCa.js.gz +0 -0
  309. package/dist/dashboard/assets/network-BKeQGT3K.js.gz +0 -0
  310. package/dist/dashboard/assets/numbers-CivAk3da.js.gz +0 -0
  311. package/dist/dashboard/assets/pagination-CpzvI5ep.js.gz +0 -0
  312. package/dist/dashboard/assets/routing-BFQX2VBc.js.gz +0 -0
  313. package/dist/dashboard/assets/select-CXbck0jG.js.gz +0 -0
  314. package/dist/dashboard/assets/settings-C_XvMHh9.js.gz +0 -0
  315. package/dist/dashboard/assets/stack-DggRiCxE.js.gz +0 -0
  316. package/dist/dashboard/assets/state-ClFzfbYp.js.gz +0 -0
  317. package/dist/dashboard/assets/switch-CTIFxKqS.js.gz +0 -0
  318. package/dist/dashboard/assets/useMutation-BClG3yWj.js.gz +0 -0
  319. package/src/console/providers/catalog/discover-constants.ts +0 -6
  320. package/src/network/pool-health.ts +0 -198
  321. package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
  322. package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
  323. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
  324. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
  325. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
  326. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
  327. package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
  328. package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
  329. package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
  330. package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
  331. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
  332. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -188
  333. package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
  334. package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -179
  335. package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
  336. package/src/providers/integrations/qoder/chat-proto.ts +0 -328
  337. package/src/providers/integrations/qoder/qoder-grpc.ts +0 -870
  338. package/src/providers/integrations/qoder/qoder-ide.ts +0 -481
  339. /package/dist/dashboard/assets/{app-DIXLjojg.js → app-C0gTXEoN.js} +0 -0
  340. /package/dist/dashboard/assets/{app-DIXLjojg.js.gz → app-C0gTXEoN.js.gz} +0 -0
  341. /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
  342. /package/src/network/pool/{byte-accounting.ts → accounting.ts} +0 -0
  343. /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
  344. /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
  345. /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
  346. /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
  347. /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
  348. /package/src/network/{rate-limit-verdict.ts → verdict.ts} +0 -0
@@ -22,7 +22,7 @@ import {
22
22
  proxyCooldownProvidersKey,
23
23
  proxyInflightKey,
24
24
  proxyProviderInflightKey,
25
- } from "./pool-scripts";
25
+ } from "./scripts";
26
26
  import {
27
27
  advanceRotation,
28
28
  createPoolLocalState,
@@ -34,7 +34,7 @@ import {
34
34
  type PoolRotation,
35
35
  type PoolUsageSnapshot,
36
36
  type ProxyCooldownEntry,
37
- } from "./pool-state";
37
+ } from "./state";
38
38
 
39
39
  export type { PoolRotation, ProxyCooldownEntry };
40
40
 
@@ -9,7 +9,7 @@ import {
9
9
  ipv4ToNumberStrict,
10
10
  ipv6GroupsToBytes,
11
11
  normalizeIpv6Groups,
12
- } from "./ip-utils";
12
+ } from "./util/ip";
13
13
 
14
14
  const DNS_CACHE_TTL_MS = 60_000;
15
15
  const DNS_CACHE_MAX = 64;
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { exponentialBackoff, type BackoffOptions } from "./backoff";
10
- import { sleep as defaultSleep } from "../shared/sleep";
10
+ import { sleep as defaultSleep } from "../../shared/sleep";
11
11
 
12
12
  interface RetryOptions {
13
13
  readonly maxRetries?: number;
@@ -174,7 +174,7 @@ const DRAIN_MAX_ATTEMPTS = 5;
174
174
  const DRAIN_RETRY_BASE_MS = 25;
175
175
  const DRAIN_RETRY_MAX_MS = 1_000;
176
176
 
177
- import { exponentialBackoff, type BackoffOptions } from "../network/backoff";
177
+ import { exponentialBackoff, type BackoffOptions } from "../network/util/backoff";
178
178
 
179
179
  /** Exponential retry delay for the `attempt`-th retry, clamped to the ceiling. */
180
180
  function drainRetryDelayMs(attempt: number, baseDelayMs = DRAIN_RETRY_BASE_MS): number {
@@ -816,6 +816,12 @@ export const providerRoutingSettings = pgTable(
816
816
  // dispatch automatically selects among every active network pool the
817
817
  // tenant owns (least-loaded/non-cooldown) — never an admin-pinned pool.
818
818
  skipProxy: boolean("skip_proxy").notNull().default(false),
819
+ // How device-code OAuth flows (start + poll) choose their egress:
820
+ // 'random' (default) routes them through a randomly selected active
821
+ // network pool so the upstream sees a rotating IP (avoids "multiple codes
822
+ // from one IP" detection for Cursor/Grok/device-code providers); 'direct'
823
+ // always dials direct egress.
824
+ deviceFlowProxy: text("device_flow_proxy").$type<DeviceFlowProxyMode>().notNull().default("random"),
819
825
  },
820
826
  (table) => ({
821
827
  tenantProviderUnique: uniqueIndex("provider_routing_settings_tenant_provider_idx").on(
@@ -835,6 +841,9 @@ export const poolRoutingStrategy = pgEnum("pool_routing_strategy", [
835
841
  ]);
836
842
  export type PoolRoutingStrategy = (typeof poolRoutingStrategy.enumValues)[number];
837
843
 
844
+ /** Egress mode for device-code OAuth flows: random active pool, or direct. */
845
+ export type DeviceFlowProxyMode = "random" | "direct";
846
+
838
847
  /**
839
848
  * Per-tenant selection strategy across the tenant's active network pools —
840
849
  * the pool-group counterpart to `provider_routing_settings`. `least_loaded`
@@ -1,4 +1,4 @@
1
- import { dedupeRequest } from "../network/deduplication";
1
+ import { dedupeRequest } from "../network/util/dedupe";
2
2
  /**
3
3
  * Bounded TTL cache with automatic eviction.
4
4
  *
@@ -91,6 +91,63 @@ export function hash32(input: string): number {
91
91
 
92
92
  const CLAUDE_TOOL_PREFIX = "_";
93
93
 
94
+ /**
95
+ * Per-request tool-name rename map, mirroring the two-way alias pattern the
96
+ * OpenCode free-tier fingerprint uses: a caller tool whose name collides with
97
+ * an upstream-reserved name (or with the built-in prefix) travels under an
98
+ * alias, and the response side restores the caller's original name.
99
+ *
100
+ * The map is a bag of `{ sent, original }` pairs so a provider can rename at
101
+ * build time and restore at decode time without guessing from a fixed prefix
102
+ * (a fixed prefix collides when a caller already uses it — `_bash` from a
103
+ * caller named `bash` vs a caller already named `_bash`).
104
+ */
105
+ export interface ToolNameAlias {
106
+ /** Name sent to the upstream wire. */
107
+ readonly sent: string;
108
+ /** Caller's original name; restore to this on the way back. */
109
+ readonly original: string;
110
+ }
111
+
112
+ /** Restore a sent name to the caller's original, when it was renamed. */
113
+ export function restoreAliasedToolName(
114
+ sent: string,
115
+ aliases: ReadonlyArray<ToolNameAlias>,
116
+ ): string {
117
+ for (const alias of aliases) {
118
+ if (alias.sent === sent) return alias.original;
119
+ }
120
+ return sent;
121
+ }
122
+
123
+ /**
124
+ * Registry of per-request tool renames, keyed by the canonical request object
125
+ * (the same object the builder saw and the decoder receives). This is the
126
+ * transport-agnostic way to pair `encodeWireRequest` with `decodeWireResponse`
127
+ * without threading a new parameter through every adapter: a request records
128
+ * its aliases at build time, and any decoder that still has the request can
129
+ * restore the caller's original tool names exactly.
130
+ *
131
+ * The WeakMap keeps no lifetime: entries die with the request object.
132
+ */
133
+ const toolAliasesByRequest = new WeakMap<object, readonly ToolNameAlias[]>();
134
+
135
+ /** Record the rename map a request produced. Idempotent per request. */
136
+ export function recordToolAliases(request: object, aliases: readonly ToolNameAlias[]): void {
137
+ if (aliases.length === 0) return;
138
+ toolAliasesByRequest.set(request, aliases);
139
+ }
140
+
141
+ /** Read the rename map a request recorded, if any. */
142
+ export function toolAliasesFor(request: object): readonly ToolNameAlias[] {
143
+ return toolAliasesByRequest.get(request) ?? [];
144
+ }
145
+
146
+ /** Restore a tool name exactly from the request's recorded renames. */
147
+ export function restoreToolNameFor(request: object, sent: string): string {
148
+ return restoreAliasedToolName(sent, toolAliasesFor(request));
149
+ }
150
+
94
151
  export type ClaudeWireObject = Record<string, unknown>;
95
152
 
96
153
  /**
@@ -366,7 +423,7 @@ function sanitizeSchemaWalk(value: unknown, walk: RewriteWalk): unknown {
366
423
 
367
424
  // OAuth tool-name prefixing
368
425
 
369
- const ANTHROPIC_BUILTIN_TOOL_NAMES = new Set([
426
+ export const ANTHROPIC_BUILTIN_TOOL_NAMES = new Set([
370
427
  "web_search",
371
428
  "web_fetch",
372
429
  "code_execution",
@@ -17,11 +17,13 @@ import {
17
17
  normalizeAnthropicToolCallId,
18
18
  parseArguments,
19
19
  prefixClaudeToolName,
20
+ recordToolAliases,
20
21
  sanitizeSchemaForAnthropic,
21
22
  stringValue,
22
23
  toWellFormedDeep,
23
24
  toWellFormedString,
24
25
  type ClaudeWireObject,
26
+ type ToolNameAlias,
25
27
  isRecord,
26
28
  resolveImageSource,
27
29
  splitDataUrl,
@@ -287,6 +289,7 @@ function partToClaudeBlock(
287
289
  idMap: Map<string, string>;
288
290
  isOAuth: boolean;
289
291
  imageCount: number;
292
+ toolAliases: ToolNameAlias[];
290
293
  maxBytesOverride?: number;
291
294
  },
292
295
  ): ClaudeWireObject | undefined {
@@ -336,10 +339,12 @@ function partToClaudeBlock(
336
339
  // stamp every call with its array position, so copying it here leaked a
337
340
  // stream-only field into a request. The position is not lost: the block
338
341
  // order in `content[]` already expresses it.
342
+ const sentName = prefixClaudeToolName(part.name, ctx?.isOAuth ?? false);
343
+ if (sentName !== part.name) ctx?.toolAliases.push({ sent: sentName, original: part.name });
339
344
  return {
340
345
  type: "tool_use",
341
346
  id: normalized,
342
- name: prefixClaudeToolName(part.name, ctx?.isOAuth ?? false),
347
+ name: sentName,
343
348
  input: toWellFormedDeep(parseArguments(part.arguments)),
344
349
  ...(part.namespace === undefined ? {} : { namespace: part.namespace }),
345
350
  };
@@ -577,6 +582,7 @@ export function canonicalToClaudeMessagesPayload(
577
582
  idMap,
578
583
  isOAuth: options.isOAuth ?? false,
579
584
  imageCount,
585
+ toolAliases: [] as ToolNameAlias[],
580
586
  ...(options.maxBytesOverride === undefined
581
587
  ? {}
582
588
  : { maxBytesOverride: options.maxBytesOverride }),
@@ -755,27 +761,34 @@ export function canonicalToClaudeMessagesPayload(
755
761
  });
756
762
  }
757
763
  if (request.tools?.length) {
758
- payload.tools = request.tools.map((tool) => ({
759
- name: prefixClaudeToolName(tool.name, isOAuth),
760
- ...(tool.description === undefined
761
- ? {}
762
- : { description: toWellFormedDeep(tool.description) }),
763
- input_schema: sanitizeSchemaForAnthropic(tool.jsonSchema),
764
- ...(tool.strict === true ? { strict: true } : {}),
765
- ...(tool.eager_input_streaming === undefined
766
- ? {}
767
- : { eager_input_streaming: tool.eager_input_streaming }),
768
- ...(tool.defer_loading === undefined
769
- ? {}
770
- : { defer_loading: tool.defer_loading }),
771
- ...(tool.input_examples === undefined ? {} : { input_examples: tool.input_examples }),
772
- ...(tool.allowed_callers === undefined ? {} : { allowed_callers: tool.allowed_callers }),
773
- }));
764
+ payload.tools = request.tools.map((tool) => {
765
+ const sentName = prefixClaudeToolName(tool.name, isOAuth);
766
+ if (sentName !== tool.name) ctx.toolAliases.push({ sent: sentName, original: tool.name });
767
+ return {
768
+ name: sentName,
769
+ ...(tool.description === undefined
770
+ ? {}
771
+ : { description: toWellFormedDeep(tool.description) }),
772
+ input_schema: sanitizeSchemaForAnthropic(tool.jsonSchema),
773
+ ...(tool.strict === true ? { strict: true } : {}),
774
+ ...(tool.eager_input_streaming === undefined
775
+ ? {}
776
+ : { eager_input_streaming: tool.eager_input_streaming }),
777
+ ...(tool.defer_loading === undefined
778
+ ? {}
779
+ : { defer_loading: tool.defer_loading }),
780
+ ...(tool.input_examples === undefined ? {} : { input_examples: tool.input_examples }),
781
+ ...(tool.allowed_callers === undefined ? {} : { allowed_callers: tool.allowed_callers }),
782
+ };
783
+ });
774
784
  }
775
785
  const rawToolChoice = canonicalToolChoice(request.tool_choice);
776
786
  if (isRecord(rawToolChoice) && rawToolChoice.type === "tool" && stringValue(rawToolChoice.name)) {
777
- rawToolChoice.name = prefixClaudeToolName(rawToolChoice.name, isOAuth);
787
+ const sentName = prefixClaudeToolName(rawToolChoice.name, isOAuth);
788
+ if (sentName !== rawToolChoice.name) ctx.toolAliases.push({ sent: sentName, original: rawToolChoice.name });
789
+ rawToolChoice.name = sentName;
778
790
  }
791
+ recordToolAliases(request, ctx.toolAliases);
779
792
  const parallelToolCallsDisabled =
780
793
  request.generation_controls.parallel_tool_calls === false;
781
794
  const supportsToolChoice = options.dialectPolicy?.supportsToolChoice ?? true;
@@ -12,12 +12,33 @@ import { usageFromProvider } from '../../providers/provider-usage';
12
12
  import { mapClaudeStreamError } from '../messages-errors';
13
13
  import {
14
14
  finiteNumber,
15
+ restoreAliasedToolName,
15
16
  stringValue,
17
+ toolAliasesFor,
16
18
  unprefixClaudeToolName,
17
19
  type ClaudeWireObject,
20
+ type ToolNameAlias,
18
21
  isRecord,
19
22
  } from '../codecs';
20
23
 
24
+ /**
25
+ * Restore a tool name from the wire to the caller's original, exactly.
26
+ *
27
+ * A name the builder renamed (recorded in `aliases`) is restored verbatim; any
28
+ * other name falls back to the OAuth underscore-unprefixing rule. This is the
29
+ * single restoration point for the Claude wire, so the two rules can never
30
+ * disagree between the stream and non-stream decoders.
31
+ */
32
+ function restoreClaudeToolName(
33
+ sent: string,
34
+ isOAuth: boolean,
35
+ aliases: ReadonlyArray<ToolNameAlias>,
36
+ ): string {
37
+ const restored = restoreAliasedToolName(sent, aliases);
38
+ if (restored !== sent) return restored;
39
+ return unprefixClaudeToolName(sent, isOAuth);
40
+ }
41
+
21
42
  export function mapClaudeStopReason(raw: string): CanonicalStopReason {
22
43
  switch (raw) {
23
44
  case "end_turn":
@@ -38,7 +59,7 @@ export function mapClaudeStopReason(raw: string): CanonicalStopReason {
38
59
  }
39
60
  }
40
61
 
41
- export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart {
62
+ export function parseClaudeContent(value: unknown, isOAuth = false, aliases: ReadonlyArray<ToolNameAlias> = []): ContentPart {
42
63
  if (stringValue(value)) return { kind: "text", text: value };
43
64
  if (!isRecord(value))
44
65
  return { kind: "extension", name: "messages:unknown", payload: value };
@@ -59,7 +80,7 @@ export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart
59
80
  return {
60
81
  kind: "toolCall",
61
82
  call_id: value.id,
62
- name: unprefixClaudeToolName(value.name, isOAuth),
83
+ name: restoreClaudeToolName(value.name, isOAuth, aliases),
63
84
  arguments: value.input ?? {},
64
85
  ...(finiteNumber(value.index) ? { index: value.index } : {}),
65
86
  };
@@ -77,7 +98,7 @@ export function parseClaudeContent(value: unknown, isOAuth = false): ContentPart
77
98
  const content = stringValue(value.content)
78
99
  ? value.content
79
100
  : Array.isArray(value.content)
80
- ? value.content.map((content) => parseClaudeContent(content, isOAuth))
101
+ ? value.content.map((content) => parseClaudeContent(content, isOAuth, aliases))
81
102
  : value.content == null
82
103
  ? ""
83
104
  : [{ kind: "text" as const, text: String(value.content) }];
@@ -239,8 +260,9 @@ export function claudeResponseToEvents(
239
260
  model,
240
261
  },
241
262
  ];
263
+ const aliases = toolAliasesFor(request);
242
264
  const blocks = Array.isArray(json.content)
243
- ? json.content.map((content) => parseClaudeContent(content, isOAuth))
265
+ ? json.content.map((content) => parseClaudeContent(content, isOAuth, aliases))
244
266
  : [];
245
267
  let sequence = 2;
246
268
  for (const block of blocks) {
@@ -292,6 +314,8 @@ interface ClaudeStreamState {
292
314
  rawUsage: Record<string, unknown> | undefined;
293
315
  sawMessageStop: boolean;
294
316
  isOAuth: boolean;
317
+ /** Tool renames recorded for this request, for exact restore. */
318
+ aliases: ReadonlyArray<ToolNameAlias>;
295
319
  }
296
320
 
297
321
  function streamEventToCanonical(
@@ -321,7 +345,7 @@ function streamEventToCanonical(
321
345
  state.calls.set(index, {
322
346
  call_id: block.id,
323
347
  ...(stringValue(block.name)
324
- ? { name: unprefixClaudeToolName(block.name, state.isOAuth) }
348
+ ? { name: restoreClaudeToolName(block.name, state.isOAuth, state.aliases) }
325
349
  : {}),
326
350
  });
327
351
  // Anthropic sends `input: {}` as a *placeholder* on content_block_start,
@@ -332,13 +356,14 @@ function streamEventToCanonical(
332
356
  // send complete arguments here still gets them through.
333
357
  if (
334
358
  isRecord(block.input) &&
335
- Object.keys(block.input).length > 0
359
+ Object.keys(block.input).length > 0 &&
360
+ stringValue(block.name)
336
361
  ) {
337
362
  events.push({
338
363
  type: "tool_call_delta",
339
364
  sequence_number: next++,
340
365
  call_id: block.id,
341
- ...(stringValue(block.name) ? { name: unprefixClaudeToolName(block.name, state.isOAuth) } : {}),
366
+ name: restoreClaudeToolName(block.name, state.isOAuth, state.aliases),
342
367
  arguments_delta: JSON.stringify(block.input),
343
368
  });
344
369
  }
@@ -446,6 +471,7 @@ export async function* parseClaudeSseStream(
446
471
  body: ReadableStream<Uint8Array>,
447
472
  signal?: AbortSignal,
448
473
  isOAuth = false,
474
+ aliases: ReadonlyArray<ToolNameAlias> = [],
449
475
  ): AsyncIterable<CanonicalEvent> {
450
476
  const state: ClaudeStreamState = {
451
477
  calls: new Map(),
@@ -455,6 +481,7 @@ export async function* parseClaudeSseStream(
455
481
  rawUsage: undefined,
456
482
  sawMessageStop: false,
457
483
  isOAuth,
484
+ aliases,
458
485
  };
459
486
  let sequence = 1;
460
487
  for await (const sse of decodeSseEvents(body, { signal })) {
@@ -158,6 +158,21 @@ const PARAM_QUIRKS: readonly ParamQuirk[] = [
158
158
  // confirms that the selected-model request must not carry temperature.
159
159
  stripControls: ["temperature"],
160
160
  },
161
+ {
162
+ provider: "nvidia",
163
+ // NVIDIA NIM rejects a set of cross-wire fields with 400 even though the
164
+ // OpenAI-compatible chat wire permits them. Stripping them here keeps the
165
+ // dispatch on the same wire shape the upstream accepts.
166
+ stripControls: [
167
+ "extension:client_metadata",
168
+ "extension:prompt_cache_key",
169
+ "service_tier",
170
+ "extension:anthropic_beta",
171
+ "extension:thinking_budget",
172
+ "extension:metadata_user_id",
173
+ "extension:custom_field",
174
+ ],
175
+ },
161
176
  {
162
177
  provider: "anthropic",
163
178
  matchModel: rejectsSamplingParams,
@@ -9,7 +9,7 @@ import { GatewayError } from '../gateway-error';
9
9
  import { applyRouteUserAgent, type ProviderDispatchContext } from "../../providers/provider-contracts";
10
10
  import { abortGatewayError, createUpstreamDeadlineLifecycle } from '../../providers/operations/upstream-deadline';
11
11
  import { mapClaudeHttpError } from '../messages-errors';
12
- import { isRecord } from '../codecs';
12
+ import { isRecord, toolAliasesFor } from '../codecs';
13
13
  import { upstreamMessageAsIs, MAX_UPSTREAM_ERROR_BYTES } from '../../transport/failure-policy';
14
14
  import { parseClaudeSseStream, claudeResponseToEvents } from '../response/messages';
15
15
 
@@ -60,7 +60,7 @@ export async function* sendClaudeMessagesRequest(
60
60
  {},
61
61
  "upstream",
62
62
  );
63
- yield* parseClaudeSseStream(response.body, context.abort_signal, isOAuth);
63
+ yield* parseClaudeSseStream(response.body, context.abort_signal, isOAuth, toolAliasesFor(request));
64
64
  return;
65
65
  }
66
66
  const body = await response.text().catch(() => "");
@@ -310,6 +310,11 @@ export class OpenAICompatibleAdapter extends BaseProviderAdapter {
310
310
  // plus `message_delta.usage` — so nothing is lost by omitting it.
311
311
  const existing = payload["stream_options"] as Record<string, unknown> | undefined;
312
312
  payload["stream_options"] = { ...(existing ?? {}), include_usage: true };
313
+ } else if (!effectiveRequest.stream && payload["stream_options"] !== undefined) {
314
+ // A non-streaming request must not carry `stream_options`: several
315
+ // OpenAI-compatible upstreams (NVIDIA NIM, DeepSeek) reject the body
316
+ // with 400 "Stream options can only be defined when stream=True".
317
+ delete payload["stream_options"];
313
318
  }
314
319
  // Apply structured_output configuration
315
320
  if (this.config.structured_output?.enabled) {
@@ -12,18 +12,20 @@ import {
12
12
  record,
13
13
  } from "./oauth-flow-store";
14
14
  import type {
15
+ OAuthAccountIdentity,
15
16
  OAuthAuthorizeRequest,
16
17
  OAuthCodeExchangeContext,
17
18
  OAuthExchangeResult,
18
19
  OAuthLoginClient,
19
20
  } from "./oauth-flow-store";
21
+ import { oauthAccountIdentity } from "./oauth-flow-store";
20
22
  import type { OAuthTokenRefreshResult, OAuthTokenRefresher } from "./oauth-refresh-service";
21
23
 
22
24
  /** Minimal fetch surface accepted by the generic OAuth client. */
23
25
  export type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
24
26
 
25
27
  /** Normalized token shape returned by provider token endpoints. */
26
- export interface NormalizedTokenResponse {
28
+ export interface NormalizedTokenResponse extends OAuthAccountIdentity {
27
29
  readonly access: string;
28
30
  readonly refresh: string;
29
31
  readonly expiresAt: Date;
@@ -83,12 +85,32 @@ export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresh
83
85
  */
84
86
  readonly browserRedirectUri?: string;
85
87
 
88
+ /**
89
+ * Custom state generator; `undefined` keeps the shared base64url state.
90
+ * A provider whose authorization server validates the format (e.g. DeepAI
91
+ * requires 32 hex chars) overrides this.
92
+ */
93
+ generateState(): string | undefined {
94
+ return undefined;
95
+ }
96
+
86
97
  protected readonly fetchFn: FetchLike;
87
98
 
88
99
  constructor(fetchFn: FetchLike = globalThis.fetch) {
89
100
  this.fetchFn = fetchFn;
90
101
  }
91
102
 
103
+ /**
104
+ * Resolves the transport a flow should use. When the console injects a
105
+ * `fetchFn` in the flow context (device-code OAuth routed through a network
106
+ * pool, see `device_flow_proxy`), that override wins; otherwise the
107
+ * client's own fetch is used. Every start/poll/exchange request that talks
108
+ * to the provider MUST route through this so the override is honored.
109
+ */
110
+ protected fetchFor(context?: { readonly fetchFn?: FetchLike | undefined }): FetchLike {
111
+ return context?.fetchFn ?? this.fetchFn;
112
+ }
113
+
92
114
  // ---------------------------------------------------------------------------
93
115
  // Public OAuthLoginClient surface
94
116
  // ---------------------------------------------------------------------------
@@ -135,8 +157,9 @@ export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresh
135
157
  }
136
158
 
137
159
  /** Extracts an account label from a token exchange/refresh response. */
138
- protected extractAccountLabel(_data: unknown): string | undefined {
139
- return undefined;
160
+ protected extractAccountLabel(data: unknown): string | undefined {
161
+ const identity = oauthAccountIdentity(data);
162
+ return identity.accountEmail ?? identity.accountName;
140
163
  }
141
164
 
142
165
  /** Calculates an expiry Date from an `expires_in` value. */
@@ -172,7 +195,14 @@ export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresh
172
195
  const refresh = nonEmptyString(body.refresh_token) ?? fallbackRefresh ?? "";
173
196
  const expiresAt = this.calculateExpiry(body.expires_in);
174
197
  const accountLabel = this.extractAccountLabel(data);
175
- return { access, refresh, expiresAt, ...(accountLabel ? { accountLabel } : {}) };
198
+ const identity = oauthAccountIdentity(data);
199
+ return {
200
+ access,
201
+ refresh,
202
+ expiresAt,
203
+ ...identity,
204
+ ...(accountLabel ? { accountLabel } : {}),
205
+ };
176
206
  }
177
207
 
178
208
  /** Builds a PKCE authorization URL using the shared helper. */
@@ -231,22 +261,26 @@ export abstract class OAuthClient implements OAuthLoginClient, OAuthTokenRefresh
231
261
  // ---------------------------------------------------------------------------
232
262
 
233
263
  protected toExchangeResult(normalized: NormalizedTokenResponse): OAuthExchangeResult {
234
- const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
264
+ const { access, refresh, expiresAt, accountLabel, accountEmail, accountName, auth_state } = normalized;
235
265
  return {
236
266
  access,
237
267
  refresh,
238
268
  expiresAt,
269
+ ...(accountEmail === undefined ? {} : { accountEmail }),
270
+ ...(accountName === undefined ? {} : { accountName }),
239
271
  ...(accountLabel ? { accountLabel } : {}),
240
272
  ...(auth_state === undefined ? {} : { auth_state }),
241
273
  };
242
274
  }
243
275
 
244
276
  protected toRefreshResult(normalized: NormalizedTokenResponse): OAuthTokenRefreshResult {
245
- const { access, refresh, expiresAt, accountLabel, auth_state } = normalized;
277
+ const { access, refresh, expiresAt, accountLabel, accountEmail, accountName, auth_state } = normalized;
246
278
  return {
247
279
  access,
248
280
  ...(refresh ? { refresh } : {}),
249
281
  expiresAt,
282
+ ...(accountEmail === undefined ? {} : { accountEmail }),
283
+ ...(accountName === undefined ? {} : { accountName }),
250
284
  ...(accountLabel ? { accountLabel } : {}),
251
285
  ...(auth_state === undefined ? {} : { auth_state }),
252
286
  };
@@ -37,9 +37,12 @@ export abstract class OAuthDeviceFlow extends OAuthClient {
37
37
  }
38
38
 
39
39
  /** Standard device-authorization start. Override the body builder for custom providers. */
40
- protected async startGenericDeviceAuth(config: DeviceFlowConfig): Promise<OAuthDeviceStartResult> {
40
+ protected async startGenericDeviceAuth(
41
+ config: DeviceFlowConfig,
42
+ context?: OAuthDeviceFlowContext,
43
+ ): Promise<OAuthDeviceStartResult> {
41
44
  const body = this.buildDeviceStartBody(config);
42
- const response = await this.fetchFn(config.deviceAuthUrl, {
45
+ const response = await this.fetchFor(context)(config.deviceAuthUrl, {
43
46
  method: "POST",
44
47
  ...(config.formHeaders === undefined ? {} : { headers: config.formHeaders }),
45
48
  body,
@@ -124,8 +127,9 @@ export abstract class OAuthDeviceFlow extends OAuthClient {
124
127
  protected async pollGenericDeviceAuth(
125
128
  deviceAuthId: string,
126
129
  config: DeviceFlowConfig,
130
+ context?: OAuthDeviceFlowContext,
127
131
  ): Promise<OAuthDevicePollResult> {
128
- const response = await this.fetchFn(config.tokenUrl, {
132
+ const response = await this.fetchFor(context)(config.tokenUrl, {
129
133
  method: "POST",
130
134
  ...(config.formHeaders === undefined ? {} : { headers: config.formHeaders }),
131
135
  body: new URLSearchParams({