cartethyia 2.7.9 → 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 (496) hide show
  1. package/.env.example +6 -5
  2. package/dist/dashboard/assets/{BannedPage-BxoG1MrL.js → BannedPage-Dq530awD.js} +1 -1
  3. package/dist/dashboard/assets/BannedPage-Dq530awD.js.gz +0 -0
  4. package/dist/dashboard/assets/{CliToolDetailPage-ixwgKk53.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-BmttNV3U.js → CliToolsPage-DaZZ3cqP.js} +1 -1
  7. package/dist/dashboard/assets/CliToolsPage-DaZZ3cqP.js.gz +0 -0
  8. package/dist/dashboard/assets/{CombosPage-BE3qwwfC.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-CRZdmMIX.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-Dv_FJ6Er.js → CustomizationPage-7xT5yg2E.js} +1 -1
  13. package/dist/dashboard/assets/CustomizationPage-7xT5yg2E.js.gz +0 -0
  14. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js +1 -0
  15. package/dist/dashboard/assets/HealthEventsModal-Clq8E9cW.js.gz +0 -0
  16. package/dist/dashboard/assets/{InjectSystemPromptPanel-BOoO8rpz.js → InjectSystemPromptPanel-6Teoq9Se.js} +2 -2
  17. package/dist/dashboard/assets/InjectSystemPromptPanel-6Teoq9Se.js.gz +0 -0
  18. package/dist/dashboard/assets/{LoginPage-ChJuNNVN.js → LoginPage-CZuI0MAR.js} +1 -1
  19. package/dist/dashboard/assets/LoginPage-CZuI0MAR.js.gz +0 -0
  20. package/dist/dashboard/assets/{ModelPicker-BZAJtPg1.js → ModelPicker-C1hNTlkr.js} +1 -1
  21. package/dist/dashboard/assets/ModelPicker-C1hNTlkr.js.gz +0 -0
  22. package/dist/dashboard/assets/{OverviewPage-BE40s3u5.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-CQ6bPUf_.js → ProviderIcon-Ddhm1InL.js} +1 -1
  27. package/dist/dashboard/assets/ProviderIcon-Ddhm1InL.js.gz +0 -0
  28. package/dist/dashboard/assets/ProvidersPage-C3fYuu6i.js +1 -0
  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-D1RV_2BX.js +1 -0
  33. package/dist/dashboard/assets/QuotaPage-D1RV_2BX.js.gz +0 -0
  34. package/dist/dashboard/assets/{SettingsPage-C5HPWqEv.js → SettingsPage-BzZAvYSX.js} +1 -1
  35. package/dist/dashboard/assets/SettingsPage-BzZAvYSX.js.gz +0 -0
  36. package/dist/dashboard/assets/{SetupPage-CFNcATJJ.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-YoD4tY5l.js → StudioPage-BjXFGSK4.js} +1 -1
  39. package/dist/dashboard/assets/StudioPage-BjXFGSK4.js.gz +0 -0
  40. package/dist/dashboard/assets/{UsagePage-DxjaAhb_.js → UsagePage-CP8F8BN7.js} +1 -1
  41. package/dist/dashboard/assets/UsagePage-CP8F8BN7.js.gz +0 -0
  42. package/dist/dashboard/assets/{api-keys-BTlkq_Uk.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-BMcj1xZE.js +1 -0
  47. package/dist/dashboard/assets/assert-BMcj1xZE.js.gz +0 -0
  48. package/dist/dashboard/assets/{badge-DdbT_7Am.js → badge-DkRUuVfz.js} +1 -1
  49. package/dist/dashboard/assets/badge-DkRUuVfz.js.gz +0 -0
  50. package/dist/dashboard/assets/{banner-CsGN-nbm.js → banner-CDjW841Q.js} +1 -1
  51. package/dist/dashboard/assets/banner-CDjW841Q.js.gz +0 -0
  52. package/dist/dashboard/assets/{card-mgZ_TLLZ.js → card-Bto5UlL9.js} +1 -1
  53. package/dist/dashboard/assets/card-Bto5UlL9.js.gz +0 -0
  54. package/dist/dashboard/assets/{cli-tools-A1-v8-03.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-CJ4Zty89.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-B5L2jPQ_.js → dialog-DL0Zftwv.js} +1 -1
  59. package/dist/dashboard/assets/dialog-DL0Zftwv.js.gz +0 -0
  60. package/dist/dashboard/assets/{drawer-DkjUouAj.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-B-LVLV6o.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-CAhdYl3B.js → entry-CGvdNU6r.js} +1 -1
  65. package/dist/dashboard/assets/entry-CGvdNU6r.js.gz +0 -0
  66. package/dist/dashboard/assets/entry-DScKYvZj.js +4 -0
  67. package/dist/dashboard/assets/entry-DScKYvZj.js.gz +0 -0
  68. package/dist/dashboard/assets/{formatters-CrsdLVsn.js → formatters-BS3DZlZj.js} +1 -1
  69. package/dist/dashboard/assets/formatters-BS3DZlZj.js.gz +0 -0
  70. package/dist/dashboard/assets/{index-BU64Lqvp.js → index-SQnvvTWX.js} +2 -2
  71. package/dist/dashboard/assets/index-SQnvvTWX.js.gz +0 -0
  72. package/dist/dashboard/assets/{inline-B2aDLyyg.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-BCVkdR9d.js → input-Bfx0EzRc.js} +1 -1
  75. package/dist/dashboard/assets/input-Bfx0EzRc.js.gz +0 -0
  76. package/dist/dashboard/assets/{layout-DNcAdMK-.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-DgrIH0hw.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-Cae01iu8.js → live-CbVTdX9V.js} +1 -1
  81. package/dist/dashboard/assets/live-CbVTdX9V.js.gz +0 -0
  82. package/dist/dashboard/assets/{network-CRib7H_2.js → network-JGvDveof.js} +1 -1
  83. package/dist/dashboard/assets/network-JGvDveof.js.gz +0 -0
  84. package/dist/dashboard/assets/{numbers-BKQE8Xpz.js → numbers-Dw6kiew-.js} +1 -1
  85. package/dist/dashboard/assets/numbers-Dw6kiew-.js.gz +0 -0
  86. package/dist/dashboard/assets/{pagination-ecPvG_8g.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/providers/zro.svg +3 -0
  91. package/dist/dashboard/assets/providers/zro.svg.gz +0 -0
  92. package/dist/dashboard/assets/quota-DiPD6UKH.js +1 -0
  93. package/dist/dashboard/assets/quota-DiPD6UKH.js.gz +0 -0
  94. package/dist/dashboard/assets/{routing-Ckm1UXuC.js → routing-8jZr-3WE.js} +1 -1
  95. package/dist/dashboard/assets/routing-8jZr-3WE.js.gz +0 -0
  96. package/dist/dashboard/assets/{select-ChoFWyKz.js → select-oO1FxMVb.js} +2 -2
  97. package/dist/dashboard/assets/select-oO1FxMVb.js.gz +0 -0
  98. package/dist/dashboard/assets/{settings-CKjFPlKW.js → settings-CLr3kdIx.js} +1 -1
  99. package/dist/dashboard/assets/settings-CLr3kdIx.js.gz +0 -0
  100. package/dist/dashboard/assets/{stack-DWCwU3fh.js → stack-Y3pDteZr.js} +1 -1
  101. package/dist/dashboard/assets/stack-Y3pDteZr.js.gz +0 -0
  102. package/dist/dashboard/assets/{state-Cg3VL5J_.js → state-CArX_Iak.js} +1 -1
  103. package/dist/dashboard/assets/state-CArX_Iak.js.gz +0 -0
  104. package/dist/dashboard/assets/{switch-Db70BMix.js → switch-DwlwmDO-.js} +1 -1
  105. package/dist/dashboard/assets/switch-DwlwmDO-.js.gz +0 -0
  106. package/dist/dashboard/assets/{useMutation-BqdE0LuM.js → useMutation-DJ9GYEgf.js} +1 -1
  107. package/dist/dashboard/assets/useMutation-DJ9GYEgf.js.gz +0 -0
  108. package/dist/dashboard/index.html +2 -2
  109. package/dist/dashboard/index.html.gz +0 -0
  110. package/dist/dashboard/precompressed-assets.json +54 -53
  111. package/migrations/full-postgres/0046_add_accounts_quota_plan_fetched_at.sql +7 -0
  112. package/migrations/full-postgres/0047_add_provider_device_flow_proxy.sql +17 -0
  113. package/migrations/lite-sqlite3/0046_add_accounts_quota_plan_fetched_at.sql +4 -0
  114. package/migrations/lite-sqlite3/0047_add_provider_device_flow_proxy.sql +19 -0
  115. package/package.json +1 -1
  116. package/src/boot/app.ts +11 -14
  117. package/src/boot/dependencies.ts +5 -7
  118. package/src/boot/flush.ts +20 -0
  119. package/src/boot/lifecycle.ts +7 -5
  120. package/src/config/providers.ts +6 -5
  121. package/src/config/routing.ts +26 -0
  122. package/src/config/spec-metadata.ts +72 -0
  123. package/src/config/spec.ts +28 -8
  124. package/src/console/api-keys/contracts.ts +12 -1
  125. package/src/console/api-keys/routes.ts +40 -28
  126. package/src/console/auth/account-reset.ts +7 -9
  127. package/src/console/backup/contracts.ts +4 -0
  128. package/src/console/backup/export-endpoint.ts +7 -5
  129. package/src/console/backup/nine-router.ts +71 -10
  130. package/src/console/backup/service.ts +8 -1
  131. package/src/console/cli-tools/service.ts +6 -12
  132. package/src/console/console-router-guards.ts +23 -16
  133. package/src/console/console-router.ts +1 -1
  134. package/src/console/domain-registration.ts +7 -4
  135. package/src/console/inferhub/client.ts +1 -1
  136. package/src/console/inferhub/normalize.ts +24 -28
  137. package/src/console/inferhub/types.ts +3 -0
  138. package/src/console/ip-bans/routes.ts +7 -13
  139. package/src/console/observability/live.ts +2 -2
  140. package/src/console/observability/store.ts +0 -53
  141. package/src/console/providers/catalog/contracts.ts +9 -3
  142. package/src/console/providers/catalog/model-operations.ts +2 -3
  143. package/src/console/providers/catalog/provider-operations.ts +1 -1
  144. package/src/console/providers/catalog/routes.ts +3 -2
  145. package/src/console/providers/catalog/store.ts +1914 -1902
  146. package/src/console/providers/detail/routes.ts +1 -0
  147. package/src/console/providers/detail/store.ts +4 -0
  148. package/src/console/providers/oauth/callback-listener.ts +30 -11
  149. package/src/console/providers/oauth/device-egress.ts +123 -0
  150. package/src/console/providers/oauth/routes.ts +123 -16
  151. package/src/console/quota/account-quota-global.ts +14 -24
  152. package/src/console/quota/account-quota-shared.ts +49 -0
  153. package/src/console/quota/account-quota-tenant.ts +11 -23
  154. package/src/console/quota/account-test-egress.ts +2 -2
  155. package/src/console/quota/daily-growth-job.ts +1 -1
  156. package/src/console/quota/quota-view.ts +19 -3
  157. package/src/console/routing/pools/contracts.ts +1 -1
  158. package/src/console/routing/pools/operations.ts +32 -47
  159. package/src/console/routing/pools/probe-verdict.ts +2 -2
  160. package/src/console/routing/pools/relay-deploy.ts +1 -1
  161. package/src/console/routing/pools/store.ts +4 -4
  162. package/src/console/shared/errors.ts +33 -6
  163. package/src/main.ts +2 -3
  164. package/src/network/client.ts +67 -0
  165. package/src/network/egress/bidi-session.ts +322 -0
  166. package/src/network/egress/dial.ts +201 -0
  167. package/src/network/egress/factory.ts +191 -0
  168. package/src/network/{outbound-fetch.ts → egress/fetch.ts} +195 -29
  169. package/src/network/egress/tls-profile.ts +123 -0
  170. package/src/network/egress/ws.ts +175 -0
  171. package/src/network/pool/{byte-accounting.ts → accounting.ts} +3 -2
  172. package/src/network/{types.ts → pool/agent-config.ts} +1 -1
  173. package/src/network/pool/agent.ts +2 -2
  174. package/src/network/{pool-cooldown-store.ts → pool/cooldown-store.ts} +95 -20
  175. package/src/network/{pool-health-machine.ts → pool/health.ts} +205 -6
  176. package/src/network/pool/resolver.ts +10 -849
  177. package/src/network/pool/selector.ts +184 -41
  178. package/src/network/ssrf.ts +7 -7
  179. package/src/network/{retry.ts → util/retry.ts} +1 -1
  180. package/src/network/{rate-limit-verdict.ts → verdict.ts} +1 -1
  181. package/src/observability/event-log.ts +7 -361
  182. package/src/observability/performance-metrics.ts +9 -0
  183. package/src/observability/runtime-metrics.ts +14 -9
  184. package/src/observability/telemetry-buffer.ts +16 -26
  185. package/src/observability/telemetry-reconciliation.ts +9 -37
  186. package/src/observability/telemetry-row.ts +125 -0
  187. package/src/persistence/db-mode.ts +4 -1
  188. package/src/persistence/dialect.ts +18 -0
  189. package/src/persistence/migrate.ts +6 -3
  190. package/src/persistence/schema.ts +17 -0
  191. package/src/persistence/ttl-cache.ts +21 -3
  192. package/src/protocol/codecs.ts +59 -2
  193. package/src/protocol/dsml.ts +34 -86
  194. package/src/protocol/markup-stream-parser.ts +195 -0
  195. package/src/protocol/reasoning-text.ts +19 -0
  196. package/src/protocol/request/chat.ts +10 -10
  197. package/src/protocol/request/gemini.ts +8 -2
  198. package/src/protocol/request/messages.ts +34 -22
  199. package/src/protocol/response/chat.ts +12 -20
  200. package/src/protocol/response/messages.ts +34 -7
  201. package/src/protocol/response/omp-tool-call-markup.ts +43 -86
  202. package/src/protocol/response/responses.ts +18 -2
  203. package/src/protocol/stop-reason.ts +23 -1
  204. package/src/protocol/think-split.ts +112 -0
  205. package/src/protocol/translation/dialect/qwen.ts +26 -58
  206. package/src/protocol/translation/quirks.ts +15 -0
  207. package/src/protocol/upstream/send-claude-messages.ts +2 -2
  208. package/src/providers/adapters/compatible-adapter.ts +76 -12
  209. package/src/providers/authentication/oauth-client.ts +40 -6
  210. package/src/providers/authentication/oauth-device-flow.ts +105 -11
  211. package/src/providers/authentication/oauth-flow-store.ts +82 -1
  212. package/src/providers/authentication/oauth-refresh-service.ts +766 -758
  213. package/src/providers/configured-provider.ts +148 -0
  214. package/src/providers/default-registry.ts +137 -36
  215. package/src/providers/discovery/discovery-types.ts +7 -0
  216. package/src/providers/discovery/probe-phases.ts +20 -6
  217. package/src/providers/discovery/probing-service.ts +22 -2
  218. package/src/providers/integrations/alibabacp/alibabacp-models.ts +1 -2
  219. package/src/providers/integrations/{dashscope-models.ts → alibabacp/dashscope-models.ts} +2 -2
  220. package/src/providers/integrations/antigravity/antigravity-protocol.ts +16 -1
  221. package/src/providers/integrations/buddy/account.ts +969 -0
  222. package/src/providers/integrations/buddy/capabilities.ts +12 -12
  223. package/src/providers/integrations/buddy/{buddy-catalog-shared.ts → catalog.ts} +198 -136
  224. package/src/providers/integrations/buddy/{buddy-chat-shared.ts → chat.ts} +176 -20
  225. package/src/providers/integrations/buddy/codebuddy/index.ts +429 -0
  226. package/src/providers/integrations/buddy/codebuddy/shared.ts +41 -26
  227. package/src/providers/integrations/buddy/headers.ts +311 -0
  228. package/src/providers/integrations/buddy/lifecycle.ts +1018 -0
  229. package/src/providers/integrations/buddy/{buddy-media.ts → media.ts} +1 -1
  230. package/src/providers/integrations/claude/claude-quota.ts +14 -17
  231. package/src/providers/integrations/cline/cline-oauth.ts +10 -5
  232. package/src/providers/integrations/cline/cline.ts +5 -6
  233. package/src/providers/integrations/clixad/clixad-oauth.ts +98 -0
  234. package/src/providers/integrations/clixad/clixad-quota.ts +132 -0
  235. package/src/providers/integrations/clixad/provider.ts +145 -0
  236. package/src/providers/integrations/codex/codex-oauth.ts +8 -5
  237. package/src/providers/integrations/commandcode/quota.ts +22 -28
  238. package/src/providers/integrations/cursor/cursor-auth.ts +1 -9
  239. package/src/providers/integrations/cursor/cursor-exec.ts +9 -2
  240. package/src/providers/integrations/cursor/cursor-hardening.ts +279 -0
  241. package/src/providers/integrations/cursor/cursor-http2.ts +605 -6
  242. package/src/providers/integrations/cursor/cursor-request.ts +26 -12
  243. package/src/providers/integrations/cursor/cursor-shared.ts +8 -5
  244. package/src/providers/integrations/cursor/cursor.ts +574 -110
  245. package/src/providers/integrations/cursor/protocol/messages.ts +22 -29
  246. package/src/providers/integrations/cursor/protocol/protobuf-schema.ts +37 -0
  247. package/src/providers/integrations/deepai/deepai-catalog.ts +149 -0
  248. package/src/providers/integrations/deepai/deepai-common.ts +145 -0
  249. package/src/providers/integrations/deepai/deepai-oauth.ts +129 -0
  250. package/src/providers/integrations/deepai/deepai-quota.ts +97 -0
  251. package/src/providers/integrations/deepai/provider.ts +42 -0
  252. package/src/providers/integrations/devin/devin-auth.ts +7 -0
  253. package/src/providers/integrations/devin/protocol/devin-proto.ts +1 -27
  254. package/src/providers/integrations/factory/factory-oauth.ts +33 -51
  255. package/src/providers/integrations/freebuff/assets/official-system-manager.txt +88 -0
  256. package/src/providers/integrations/freebuff/assets/official-system-worker.txt +57 -0
  257. package/src/providers/integrations/freebuff/assets/official-tools.json +1070 -0
  258. package/src/providers/integrations/freebuff/freebuff-catalog.ts +120 -0
  259. package/src/providers/integrations/freebuff/freebuff-constants.ts +1233 -0
  260. package/src/providers/integrations/freebuff/freebuff-discovery.ts +108 -0
  261. package/src/providers/integrations/freebuff/freebuff-oauth.ts +240 -0
  262. package/src/providers/integrations/freebuff/freebuff-quota.ts +260 -0
  263. package/src/providers/integrations/freebuff/freebuff-virtual.ts +89 -0
  264. package/src/providers/integrations/freebuff/freebuff.ts +682 -0
  265. package/src/providers/integrations/freepi/freepi-catalog.ts +5 -0
  266. package/src/providers/integrations/freepi/freepi-discovery.ts +2 -2
  267. package/src/providers/integrations/freepi/freepi-headers.ts +2 -2
  268. package/src/providers/integrations/freepi/freepi-protocol.ts +11 -2
  269. package/src/providers/integrations/freepi/freepi-realm.ts +0 -3
  270. package/src/providers/integrations/freepi/freepi-session.ts +158 -0
  271. package/src/providers/integrations/freepi/freepi.ts +80 -54
  272. package/src/providers/integrations/github/github-discovery.ts +30 -13
  273. package/src/providers/integrations/github/github-oauth.ts +217 -44
  274. package/src/providers/integrations/github/github-quota.ts +22 -5
  275. package/src/providers/integrations/github/github.ts +40 -32
  276. package/src/providers/integrations/grok/grok-oauth.ts +52 -49
  277. package/src/providers/integrations/grok/grok-ratelimit-store.ts +10 -17
  278. package/src/providers/integrations/grok/grok-turn-index.ts +11 -16
  279. package/src/providers/integrations/hermes/hermes-oauth.ts +3 -3
  280. package/src/providers/integrations/{hermes.ts → hermes/hermes.ts} +42 -13
  281. package/src/providers/integrations/hermes/index.ts +2 -0
  282. package/src/providers/integrations/kilo/kilo-oauth.ts +4 -4
  283. package/src/providers/integrations/kilo/kilo.ts +1 -1
  284. package/src/providers/integrations/kimi/kimi-oauth.ts +3 -3
  285. package/src/providers/integrations/kiro/kiro-catalog.ts +17 -1
  286. package/src/providers/integrations/kiro/kiro-discovery.ts +10 -12
  287. package/src/providers/integrations/kiro/kiro-oauth.ts +2 -2
  288. package/src/providers/integrations/kiro/kiro-quota.ts +8 -4
  289. package/src/providers/integrations/kiro/kiro.ts +15 -19
  290. package/src/providers/integrations/muse/muse-oauth.ts +5 -5
  291. package/src/providers/integrations/ollamacloud/index.ts +2 -0
  292. package/src/providers/integrations/{ollamacloud-models.ts → ollamacloud/models.ts} +2 -2
  293. package/src/providers/integrations/{ollamacloud-quota.ts → ollamacloud/quota.ts} +3 -3
  294. package/src/providers/integrations/opencode/fingerprint.ts +1 -1
  295. package/src/providers/integrations/opencode/opencode-go-quota.ts +2 -8
  296. package/src/providers/integrations/openrouter/provider.ts +1 -1
  297. package/src/providers/integrations/perch/perch-credential.ts +25 -0
  298. package/src/providers/integrations/perch/perch-protocol.ts +0 -6
  299. package/src/providers/integrations/perch/perch-quota.ts +2 -16
  300. package/src/providers/integrations/perch/perch.ts +6 -16
  301. package/src/providers/integrations/qoder/claim-qoder-credits.ts +19 -60
  302. package/src/providers/integrations/qoder/qoder-adapter.ts +20 -125
  303. package/src/providers/integrations/qoder/qoder-auth.ts +109 -30
  304. package/src/providers/integrations/qoder/qoder-catalog.ts +21 -6
  305. package/src/providers/integrations/qoder/qoder-chat.ts +32 -29
  306. package/src/providers/integrations/qoder/qoder-checkin.ts +5 -5
  307. package/src/providers/integrations/qoder/qoder-cosy.ts +37 -9
  308. package/src/providers/integrations/qoder/qoder-oauth.ts +9 -2
  309. package/src/providers/integrations/qoder/qoder-realm.ts +13 -36
  310. package/src/providers/integrations/qoder/qoder-sse.ts +447 -68
  311. package/src/providers/integrations/qoder/qoder-types.ts +9 -0
  312. package/src/providers/integrations/qoder/qoder.ts +3 -26
  313. package/src/providers/integrations/sensenova/provider.ts +144 -0
  314. package/src/providers/integrations/trae/trae-protocol.ts +9 -5
  315. package/src/providers/integrations/trae/trae-quota.ts +21 -29
  316. package/src/providers/integrations/trae/trae-realm.ts +38 -0
  317. package/src/providers/integrations/trae/trae.ts +7 -24
  318. package/src/providers/integrations/vercel/provider.ts +117 -0
  319. package/src/providers/integrations/vercel/vercel-quota.ts +96 -0
  320. package/src/providers/integrations/xai/xai-oauth.ts +5 -5
  321. package/src/providers/integrations/zcode-start-plan/gifts.ts +1 -1
  322. package/src/providers/integrations/zcode-start-plan/oauth.ts +3 -3
  323. package/src/providers/integrations/zcode-start-plan/provider.ts +226 -23
  324. package/src/providers/integrations/zcode-start-plan/quota.ts +19 -2
  325. package/src/providers/integrations/zro/zro.ts +205 -0
  326. package/src/providers/operations/account-error-classification.ts +199 -307
  327. package/src/providers/operations/account-health-service.ts +82 -1
  328. package/src/providers/operations/account-refresh-status.ts +36 -37
  329. package/src/providers/operations/account-tier.ts +15 -16
  330. package/src/providers/operations/client-version-resolver.ts +1 -1
  331. package/src/providers/operations/client-versions.ts +100 -81
  332. package/src/providers/operations/cooldown-rules.ts +11 -16
  333. package/src/providers/operations/oauth-refresh-lead.ts +46 -22
  334. package/src/providers/operations/{model-catalog-cache.ts → provider-caches.ts} +68 -16
  335. package/src/providers/operations/provider-catalog-service.ts +1 -1
  336. package/src/providers/operations/provider-credential-service.ts +118 -51
  337. package/src/providers/operations/provider-rules/github.ts +48 -0
  338. package/src/providers/operations/provider-rules/grok.ts +33 -0
  339. package/src/providers/operations/provider-rules/inception.ts +49 -0
  340. package/src/providers/operations/provider-rules/index.ts +32 -0
  341. package/src/providers/operations/provider-rules/perch.ts +37 -0
  342. package/src/providers/operations/provider-rules/qoder.ts +70 -0
  343. package/src/providers/operations/provider-rules/trae.ts +81 -0
  344. package/src/providers/operations/session-resolution.ts +17 -1
  345. package/src/providers/provider-contracts.ts +6 -4
  346. package/src/providers/{provider-credential-resolver.ts → provider-credentials.ts} +40 -3
  347. package/src/providers/provider-metadata.ts +70 -10
  348. package/src/providers/provider-probe.ts +15 -1
  349. package/src/providers/provider-registry.ts +42 -33
  350. package/src/providers/quota/quota-contracts.ts +2 -0
  351. package/src/providers/quota/quota-limit-windows.ts +16 -5
  352. package/src/providers/quota/quota-support.ts +1 -1
  353. package/src/providers/quota/quota-window-parser.ts +90 -18
  354. package/src/providers/quota/refresh.ts +100 -21
  355. package/src/security/api-key-auth-cache.ts +1 -1
  356. package/src/security/api-key-auth.ts +6 -2
  357. package/src/security/ip-boundary.ts +1 -1
  358. package/src/transport/dispatch/attempt-finalize.ts +15 -14
  359. package/src/transport/dispatch/attempt-loop.ts +73 -19
  360. package/src/transport/dispatch/generation.ts +2 -8
  361. package/src/transport/dispatch/handler-deps.ts +1 -1
  362. package/src/transport/dispatch/leases.ts +1 -1
  363. package/src/transport/dispatch/native-shared.ts +25 -0
  364. package/src/transport/dispatch/proxy-request.ts +8 -46
  365. package/src/transport/dispatch/responses-compact.ts +2 -8
  366. package/src/transport/dispatch/retry-policy.ts +1 -1
  367. package/src/transport/dispatch/streaming/finalize.ts +10 -7
  368. package/src/transport/dispatch/streaming/stream.ts +9 -37
  369. package/src/transport/dispatch/systemone.ts +2 -8
  370. package/src/transport/dispatch/token-count.ts +2 -6
  371. package/src/transport/dispatch/upstream.ts +63 -0
  372. package/src/transport/drain-endpoint.ts +31 -4
  373. package/src/transport/failure-policy.ts +16 -30
  374. package/src/transport/guards/body-policy.ts +7 -1
  375. package/src/transport/guards/error-lifecycle.ts +13 -1
  376. package/src/transport/guards/request-context.ts +22 -14
  377. package/src/transport/request/preparer.ts +81 -71
  378. package/src/transport/routing/bounded-lru.ts +14 -0
  379. package/src/transport/routing/drain-reserve.ts +129 -0
  380. package/src/transport/routing/plan-gate.ts +7 -1
  381. package/src/transport/routing/round-robin.ts +60 -0
  382. package/src/transport/routing/route-catalog.ts +123 -111
  383. package/src/transport/routing/route-model.ts +51 -9
  384. package/src/transport/routing/router.ts +393 -32
  385. package/src/transport/shutdown-notice.ts +1 -1
  386. package/src/transport/surface/adapters.ts +11 -2
  387. package/src/transport/surface/chat/adapter.ts +2 -2
  388. package/src/transport/surface/chat/encode.ts +47 -4
  389. package/src/transport/surface/chat/parse.ts +2 -12
  390. package/src/transport/surface/completion.ts +44 -33
  391. package/src/transport/surface/content-parts.ts +21 -0
  392. package/src/transport/surface/messages/adapter.ts +7 -1
  393. package/src/transport/surface/messages/encode.ts +11 -3
  394. package/src/transport/surface/messages/parse.ts +2 -1
  395. package/src/transport/surface/messages/stream.ts +33 -17
  396. package/src/transport/surface/responses/encode.ts +22 -5
  397. package/src/transport/surface/responses/parse.ts +3 -11
  398. package/src/workers/buddy-growth-tasks.ts +8 -8
  399. package/src/workers/daily-checkin.ts +4 -4
  400. package/src/workers/quota-refresh-sweep.ts +1 -1
  401. package/src/workers/zcode-gift-claim.ts +1 -1
  402. package/dist/dashboard/assets/BannedPage-BxoG1MrL.js.gz +0 -0
  403. package/dist/dashboard/assets/CliToolDetailPage-ixwgKk53.js.gz +0 -0
  404. package/dist/dashboard/assets/CliToolsPage-BmttNV3U.js.gz +0 -0
  405. package/dist/dashboard/assets/CombosPage-BE3qwwfC.js.gz +0 -0
  406. package/dist/dashboard/assets/ConsoleLogPage-CRZdmMIX.js.gz +0 -0
  407. package/dist/dashboard/assets/CustomizationPage-Dv_FJ6Er.js.gz +0 -0
  408. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js +0 -1
  409. package/dist/dashboard/assets/HealthEventsModal-CoVrw2sM.js.gz +0 -0
  410. package/dist/dashboard/assets/InjectSystemPromptPanel-BOoO8rpz.js.gz +0 -0
  411. package/dist/dashboard/assets/LoginPage-ChJuNNVN.js.gz +0 -0
  412. package/dist/dashboard/assets/ModelPicker-BZAJtPg1.js.gz +0 -0
  413. package/dist/dashboard/assets/OverviewPage-BE40s3u5.js.gz +0 -0
  414. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js +0 -8
  415. package/dist/dashboard/assets/ProviderDetailPage-sfLoQtPV.js.gz +0 -0
  416. package/dist/dashboard/assets/ProviderIcon-CQ6bPUf_.js.gz +0 -0
  417. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js +0 -1
  418. package/dist/dashboard/assets/ProvidersPage-DcepmPWo.js.gz +0 -0
  419. package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js +0 -9
  420. package/dist/dashboard/assets/ProxyPage-BJ87Pp0U.js.gz +0 -0
  421. package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js +0 -1
  422. package/dist/dashboard/assets/QuotaPage-gkSyRAKa.js.gz +0 -0
  423. package/dist/dashboard/assets/SettingsPage-C5HPWqEv.js.gz +0 -0
  424. package/dist/dashboard/assets/SetupPage-CFNcATJJ.js.gz +0 -0
  425. package/dist/dashboard/assets/StudioPage-YoD4tY5l.js.gz +0 -0
  426. package/dist/dashboard/assets/UsagePage-DxjaAhb_.js.gz +0 -0
  427. package/dist/dashboard/assets/api-keys-BTlkq_Uk.js.gz +0 -0
  428. package/dist/dashboard/assets/app-BX2nnKqs.css +0 -2
  429. package/dist/dashboard/assets/app-BX2nnKqs.css.gz +0 -0
  430. package/dist/dashboard/assets/assert-CndthXFQ.js +0 -1
  431. package/dist/dashboard/assets/assert-CndthXFQ.js.gz +0 -0
  432. package/dist/dashboard/assets/badge-DdbT_7Am.js.gz +0 -0
  433. package/dist/dashboard/assets/banner-CsGN-nbm.js.gz +0 -0
  434. package/dist/dashboard/assets/card-mgZ_TLLZ.js.gz +0 -0
  435. package/dist/dashboard/assets/cli-tools-A1-v8-03.js.gz +0 -0
  436. package/dist/dashboard/assets/clipboard-button-CJ4Zty89.js.gz +0 -0
  437. package/dist/dashboard/assets/dialog-B5L2jPQ_.js.gz +0 -0
  438. package/dist/dashboard/assets/drawer-DkjUouAj.js.gz +0 -0
  439. package/dist/dashboard/assets/entry-B-LVLV6o.js.gz +0 -0
  440. package/dist/dashboard/assets/entry-CAhdYl3B.js.gz +0 -0
  441. package/dist/dashboard/assets/entry-D2xD0Tmd.js +0 -4
  442. package/dist/dashboard/assets/entry-D2xD0Tmd.js.gz +0 -0
  443. package/dist/dashboard/assets/formatters-CrsdLVsn.js.gz +0 -0
  444. package/dist/dashboard/assets/index-BU64Lqvp.js.gz +0 -0
  445. package/dist/dashboard/assets/inline-B2aDLyyg.js.gz +0 -0
  446. package/dist/dashboard/assets/input-BCVkdR9d.js.gz +0 -0
  447. package/dist/dashboard/assets/layout-DNcAdMK-.js.gz +0 -0
  448. package/dist/dashboard/assets/list-row-DgrIH0hw.js.gz +0 -0
  449. package/dist/dashboard/assets/live-Cae01iu8.js.gz +0 -0
  450. package/dist/dashboard/assets/network-CRib7H_2.js.gz +0 -0
  451. package/dist/dashboard/assets/numbers-BKQE8Xpz.js.gz +0 -0
  452. package/dist/dashboard/assets/pagination-ecPvG_8g.js.gz +0 -0
  453. package/dist/dashboard/assets/quota-DJ1QlAOq.js +0 -1
  454. package/dist/dashboard/assets/quota-DJ1QlAOq.js.gz +0 -0
  455. package/dist/dashboard/assets/routing-Ckm1UXuC.js.gz +0 -0
  456. package/dist/dashboard/assets/select-ChoFWyKz.js.gz +0 -0
  457. package/dist/dashboard/assets/settings-CKjFPlKW.js.gz +0 -0
  458. package/dist/dashboard/assets/stack-DWCwU3fh.js.gz +0 -0
  459. package/dist/dashboard/assets/state-Cg3VL5J_.js.gz +0 -0
  460. package/dist/dashboard/assets/switch-Db70BMix.js.gz +0 -0
  461. package/dist/dashboard/assets/useMutation-BqdE0LuM.js.gz +0 -0
  462. package/src/network/pool-health.ts +0 -210
  463. package/src/providers/bundled-discovery-providers.ts +0 -98
  464. package/src/providers/configured-openai-providers.ts +0 -120
  465. package/src/providers/integrations/buddy/buddy-checkin.ts +0 -521
  466. package/src/providers/integrations/buddy/buddy-cli-headers.ts +0 -76
  467. package/src/providers/integrations/buddy/buddy-conversation-headers.ts +0 -130
  468. package/src/providers/integrations/buddy/buddy-discovery-shared.ts +0 -234
  469. package/src/providers/integrations/buddy/buddy-growth-shared.ts +0 -496
  470. package/src/providers/integrations/buddy/buddy-identity.ts +0 -300
  471. package/src/providers/integrations/buddy/buddy-oauth-shared.ts +0 -341
  472. package/src/providers/integrations/buddy/buddy-quota-shared.ts +0 -417
  473. package/src/providers/integrations/buddy/buddy-server-tools.ts +0 -240
  474. package/src/providers/integrations/buddy/buddy-usage-shared.ts +0 -221
  475. package/src/providers/integrations/buddy/buddy-usage-store.ts +0 -181
  476. package/src/providers/integrations/buddy/codebuddy/cn-catalog.ts +0 -37
  477. package/src/providers/integrations/buddy/codebuddy/cn-provider.ts +0 -185
  478. package/src/providers/integrations/buddy/codebuddy/oauth.ts +0 -47
  479. package/src/providers/integrations/buddy/codebuddy/provider.ts +0 -175
  480. package/src/providers/integrations/buddy/codebuddy/quota.ts +0 -154
  481. package/src/providers/integrations/qoder/chat-proto.ts +0 -328
  482. package/src/providers/integrations/qoder/qoder-grpc.ts +0 -871
  483. package/src/providers/integrations/qoder/qoder-ide.ts +0 -588
  484. package/src/providers/operations/model-discovery-cache.ts +0 -34
  485. package/src/providers/operations/probe-fetch.ts +0 -15
  486. package/src/providers/operations/provider-version-cache.ts +0 -30
  487. package/src/providers/provider-capabilities.ts +0 -33
  488. package/src/providers/provider-credential-envelope.ts +0 -43
  489. /package/dist/dashboard/assets/{app-B7kIWFm5.js → app-C0gTXEoN.js} +0 -0
  490. /package/dist/dashboard/assets/{app-B7kIWFm5.js.gz → app-C0gTXEoN.js.gz} +0 -0
  491. /package/src/network/{http2-bidi.ts → bidi.ts} +0 -0
  492. /package/src/network/pool/{pool-scripts.ts → scripts.ts} +0 -0
  493. /package/src/network/pool/{pool-state.ts → state.ts} +0 -0
  494. /package/src/network/{backoff.ts → util/backoff.ts} +0 -0
  495. /package/src/network/{deduplication.ts → util/dedupe.ts} +0 -0
  496. /package/src/network/{ip-utils.ts → util/ip.ts} +0 -0
@@ -3,6 +3,7 @@ import type { CanonicalRequest, WireFamily } from "../protocol/canonical-model";
3
3
  import { GatewayError } from "../protocol/gateway-error";
4
4
  import { OpenAICompatibleAdapter, withBearerAuthentication } from "./adapters/compatible-adapter";
5
5
  import { providerBaseUrl } from "./provider-metadata";
6
+ import type { ProviderModule } from "./provider-registry";
6
7
 
7
8
  export function ensurePayloadModel(
8
9
  payload: Record<string, unknown>,
@@ -15,6 +16,7 @@ export function ensurePayloadModel(
15
16
  payload["model"] = model;
16
17
  return model;
17
18
  }
19
+
18
20
  /**
19
21
  * Declarative description of one bearer-authenticated OpenAI-compatible provider.
20
22
  *
@@ -98,3 +100,149 @@ export function createApiKeyAdapter(
98
100
  }),
99
101
  );
100
102
  }
103
+
104
+ function apiKeySpec(
105
+ providerId: ProviderId,
106
+ paths: Readonly<Partial<Record<"chat" | "responses", string>>>,
107
+ ): ApiKeyProviderSpec {
108
+ return {
109
+ provider_id: providerId,
110
+ endpoint_paths_by_wire_family: paths,
111
+ };
112
+ }
113
+
114
+ const BEARER_PATHS = { chat: "/chat/completions", responses: "/responses" } as const;
115
+
116
+ /**
117
+ * Builtin providers whose entire adapter contract is "bearer auth against the
118
+ * provider's `BUNDLED_PROVIDER_METADATA` base URL, OpenAI-compatible chat +
119
+ * responses, with endpoint paths declared below the base's version root".
120
+ */
121
+ export const GENERIC_API_KEY_SPECS = {
122
+ larprouter: apiKeySpec("larprouter", BEARER_PATHS),
123
+ mistral: apiKeySpec("mistral", BEARER_PATHS),
124
+ fireworks: apiKeySpec("fireworks", BEARER_PATHS),
125
+ nvidia: apiKeySpec("nvidia", BEARER_PATHS),
126
+ gmi: apiKeySpec("gmi", BEARER_PATHS),
127
+ ollamacloud: apiKeySpec("ollamacloud", BEARER_PATHS),
128
+ together: apiKeySpec("together", BEARER_PATHS),
129
+ siliconflow: apiKeySpec("siliconflow", BEARER_PATHS),
130
+ siliconflowcn: apiKeySpec("siliconflowcn", BEARER_PATHS),
131
+ nanogpt: apiKeySpec("nanogpt", BEARER_PATHS),
132
+ baseten: apiKeySpec("baseten", BEARER_PATHS),
133
+ synthetic: apiKeySpec("synthetic", BEARER_PATHS),
134
+ stepfun: apiKeySpec("stepfun", BEARER_PATHS),
135
+ sakana: apiKeySpec("sakana", BEARER_PATHS),
136
+ helmcode: apiKeySpec("helmcode", BEARER_PATHS),
137
+ coralbricks: apiKeySpec("coralbricks", BEARER_PATHS),
138
+ aiand: apiKeySpec("aiand", BEARER_PATHS),
139
+ wafer: apiKeySpec("wafer", BEARER_PATHS),
140
+ coreweave: apiKeySpec("coreweave", BEARER_PATHS),
141
+ dashscope: apiKeySpec("dashscope", BEARER_PATHS),
142
+ "qwen-portal": apiKeySpec("qwen-portal", BEARER_PATHS),
143
+ } satisfies Readonly<Record<string, ApiKeyProviderSpec>>;
144
+
145
+ export type GenericApiKeyProviderId = keyof typeof GENERIC_API_KEY_SPECS;
146
+
147
+ export const GENERIC_API_KEY_PROVIDER_IDS = Object.keys(
148
+ GENERIC_API_KEY_SPECS,
149
+ ) as readonly GenericApiKeyProviderId[];
150
+
151
+ /**
152
+ * Ids whose base URL already ends at a version segment.
153
+ */
154
+ export const VERSIONED_ROOT_API_KEY_SPECS = {
155
+ groq: apiKeySpec("groq", BEARER_PATHS),
156
+ deepinfra: apiKeySpec("deepinfra", BEARER_PATHS),
157
+ novita: apiKeySpec("novita", BEARER_PATHS),
158
+ venice: apiKeySpec("venice", BEARER_PATHS),
159
+ qianfan: apiKeySpec("qianfan", BEARER_PATHS),
160
+ zhipucoding: apiKeySpec("zhipucoding", BEARER_PATHS),
161
+ firepass: apiKeySpec("firepass", BEARER_PATHS),
162
+ } satisfies Readonly<Record<string, ApiKeyProviderSpec>>;
163
+
164
+ export type VersionedRootApiKeyProviderId =
165
+ keyof typeof VERSIONED_ROOT_API_KEY_SPECS;
166
+
167
+ export const VERSIONED_ROOT_API_KEY_PROVIDER_IDS = Object.keys(
168
+ VERSIONED_ROOT_API_KEY_SPECS,
169
+ ) as readonly VersionedRootApiKeyProviderId[];
170
+
171
+ type DiscoveryBackedCapabilities = Pick<
172
+ ProviderModule,
173
+ "endpointPathsByWireFamily" | "loadAdapter" | "loadModelDiscovery"
174
+ >;
175
+
176
+ type ModelDiscoveryFactory = NonNullable<ProviderModule["loadModelDiscovery"]>;
177
+ export type OpenAIModelDiscoveryFactory = (
178
+ providerId: string,
179
+ options?: {
180
+ readonly headers?: (credential: string) => Readonly<Record<string, string>>;
181
+ },
182
+ ) => ModelDiscoveryFactory;
183
+
184
+ const DISCOVERY_BACKED_PROVIDER_SPECS = {
185
+ groq: VERSIONED_ROOT_API_KEY_SPECS.groq,
186
+ larprouter: GENERIC_API_KEY_SPECS.larprouter,
187
+ together: GENERIC_API_KEY_SPECS.together,
188
+ deepinfra: VERSIONED_ROOT_API_KEY_SPECS.deepinfra,
189
+ siliconflow: GENERIC_API_KEY_SPECS.siliconflow,
190
+ siliconflowcn: GENERIC_API_KEY_SPECS.siliconflowcn,
191
+ novita: VERSIONED_ROOT_API_KEY_SPECS.novita,
192
+ venice: VERSIONED_ROOT_API_KEY_SPECS.venice,
193
+ nanogpt: GENERIC_API_KEY_SPECS.nanogpt,
194
+ baseten: GENERIC_API_KEY_SPECS.baseten,
195
+ synthetic: GENERIC_API_KEY_SPECS.synthetic,
196
+ stepfun: GENERIC_API_KEY_SPECS.stepfun,
197
+ sakana: GENERIC_API_KEY_SPECS.sakana,
198
+ helmcode: GENERIC_API_KEY_SPECS.helmcode,
199
+ coralbricks: GENERIC_API_KEY_SPECS.coralbricks,
200
+ aiand: GENERIC_API_KEY_SPECS.aiand,
201
+ wafer: GENERIC_API_KEY_SPECS.wafer,
202
+ firepass: VERSIONED_ROOT_API_KEY_SPECS.firepass,
203
+ zhipucoding: VERSIONED_ROOT_API_KEY_SPECS.zhipucoding,
204
+ dashscope: GENERIC_API_KEY_SPECS.dashscope,
205
+ qianfan: VERSIONED_ROOT_API_KEY_SPECS.qianfan,
206
+ } satisfies Readonly<Record<string, ApiKeyProviderSpec>>;
207
+
208
+ type DiscoveryBackedProviderId = keyof typeof DISCOVERY_BACKED_PROVIDER_SPECS;
209
+
210
+ /** Canonical discovery-backed provider ids, in declaration order. */
211
+ export const DISCOVERY_BACKED_PROVIDER_IDS = Object.keys(
212
+ DISCOVERY_BACKED_PROVIDER_SPECS,
213
+ ) as readonly DiscoveryBackedProviderId[];
214
+
215
+ export function discoveryBackedCapabilities(
216
+ providerId: string,
217
+ spec: ApiKeyProviderSpec,
218
+ openAIModelDiscovery: OpenAIModelDiscoveryFactory,
219
+ ): DiscoveryBackedCapabilities {
220
+ return {
221
+ ...(spec.endpoint_paths_by_wire_family === undefined
222
+ ? {}
223
+ : { endpointPathsByWireFamily: spec.endpoint_paths_by_wire_family }),
224
+ loadAdapter: async () => createApiKeyAdapter(spec),
225
+ loadModelDiscovery: openAIModelDiscovery(providerId, {
226
+ headers: (credential) => ({ authorization: `Bearer ${credential}` }),
227
+ }),
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Creates the standard provider capability table using the registry's shared
233
+ * discovery loader, keeping its lazy import and authentication behavior intact.
234
+ */
235
+ export function createDiscoveryBackedProviderCapabilities(
236
+ openAIModelDiscovery: OpenAIModelDiscoveryFactory,
237
+ ): Readonly<Record<DiscoveryBackedProviderId, DiscoveryBackedCapabilities>> {
238
+ const capabilities = {} as Record<DiscoveryBackedProviderId, DiscoveryBackedCapabilities>;
239
+ for (const providerId of DISCOVERY_BACKED_PROVIDER_IDS) {
240
+ capabilities[providerId] = discoveryBackedCapabilities(
241
+ providerId,
242
+ DISCOVERY_BACKED_PROVIDER_SPECS[providerId],
243
+ openAIModelDiscovery,
244
+ );
245
+ }
246
+ return capabilities;
247
+ }
248
+
@@ -4,13 +4,20 @@
4
4
  // drag every integration into memory at process start.
5
5
  import {
6
6
  GENERIC_API_KEY_SPECS,
7
- } from "./configured-openai-providers";
8
- import { createDiscoveryBackedProviderCapabilities, discoveryBackedCapabilities } from "./bundled-discovery-providers";
9
- import { createApiKeyAdapter } from "./configured-provider";
10
- import type { ApiKeyProviderSpec } from "./configured-provider";
11
- import { oauthCapability, quotaCapability, type ProviderModuleCapabilities } from "./provider-capabilities";
7
+ createDiscoveryBackedProviderCapabilities,
8
+ discoveryBackedCapabilities,
9
+ createApiKeyAdapter,
10
+ type ApiKeyProviderSpec,
11
+ } from "./configured-provider";
12
12
  import { BUDDY_PROVIDER_CAPABILITIES } from "./integrations/buddy/capabilities";
13
- import { ProviderRegistry, toRegistration, type ProviderModule } from "./provider-registry";
13
+ import {
14
+ ProviderRegistry,
15
+ toRegistration,
16
+ oauthCapability,
17
+ quotaCapability,
18
+ type ProviderModule,
19
+ type ProviderModuleCapabilities,
20
+ } from "./provider-registry";
14
21
  import { BUNDLED_PROVIDER_METADATA, PROVIDER_COMPATIBILITY_PROFILES, providerBaseUrl, providerRequiresAccount, providerUpstreamHost, providerDefaultWireFamily, type BundledProviderId } from "./provider-metadata";
15
22
  import { createAnthropicCompatibleAdapter } from "./integrations/anthropic";
16
23
  import { defineModel } from "./provider-model-definition";
@@ -31,6 +38,29 @@ function configuredProvider(
31
38
  };
32
39
  }
33
40
 
41
+ /**
42
+ * Extracts a bearer token from a JSON credential object when the stored secret
43
+ * is a JSON account export, falling back to the raw secret otherwise. Several
44
+ * discovery paths accept both a bare token and a JSON export, and each used to
45
+ * re-implement this same parse + key-pick; this keeps the reading in one place.
46
+ *
47
+ * Preserves the exact fallback semantics: an unparseable secret, or a JSON
48
+ * object with none of the recognized token keys, yields the raw secret.
49
+ */
50
+ function extractJsonCredentialToken(secret: string): string {
51
+ if (!secret.startsWith("{")) return secret;
52
+ try {
53
+ const parsed = JSON.parse(secret) as Record<string, unknown>;
54
+ const found = ["accessToken", "access_token", "token"].find(
55
+ (key) => typeof parsed[key] === "string" && (parsed[key] as string).length > 0,
56
+ );
57
+ if (found !== undefined) return parsed[found] as string;
58
+ } catch {
59
+ // Use the raw secret as the token.
60
+ }
61
+ return secret;
62
+ }
63
+
34
64
  /**
35
65
  * Qoder's live model list for one realm.
36
66
  *
@@ -60,18 +90,7 @@ function traeDiscovery(
60
90
  if (secret.length === 0 || fetcher === undefined) {
61
91
  return realm === "cn" ? TRAE_CN_MODELS : TRAE_INTL_MODELS;
62
92
  }
63
- let token = secret;
64
- if (secret.startsWith("{")) {
65
- try {
66
- const parsed = JSON.parse(secret) as Record<string, unknown>;
67
- const found = ["accessToken", "access_token", "token"].find(
68
- (key) => typeof parsed[key] === "string" && (parsed[key] as string).length > 0,
69
- );
70
- if (found !== undefined) token = parsed[found] as string;
71
- } catch {
72
- // Use the raw secret as the token.
73
- }
74
- }
93
+ const token = extractJsonCredentialToken(secret);
75
94
  const region = request.authState?.["region"];
76
95
  const rows = await discoverTraeModels({
77
96
  realm,
@@ -545,18 +564,7 @@ export const PROVIDER_CAPABILITIES = {
545
564
  const secret = request.credential.trim();
546
565
  const fetcher = request.fetcher as unknown as typeof fetch | undefined;
547
566
  if (secret.length === 0 || fetcher === undefined) return FREEPI_MODELS;
548
- let token = secret;
549
- if (secret.startsWith("{")) {
550
- try {
551
- const parsed = JSON.parse(secret) as Record<string, unknown>;
552
- const found = ["accessToken", "access_token", "token"].find(
553
- (key) => typeof parsed[key] === "string" && (parsed[key] as string).length > 0,
554
- );
555
- if (found !== undefined) token = parsed[found] as string;
556
- } catch {
557
- // Use the raw secret as the token.
558
- }
559
- }
567
+ const token = extractJsonCredentialToken(secret);
560
568
  const rows = await discoverFreepiModels({ token, fetcher });
561
569
  if (rows.length === 0) return FREEPI_MODELS;
562
570
  return rows;
@@ -576,6 +584,43 @@ export const PROVIDER_CAPABILITIES = {
576
584
  return PERCH_MODELS;
577
585
  },
578
586
  },
587
+ clixad: {
588
+ loadAdapter: async () => createApiKeyAdapter((await import("./integrations/clixad/provider")).CLIXAD_SPEC),
589
+ loadModels: async () => (await import("./integrations/clixad/provider")).CLIXAD_DEFAULT_MODELS,
590
+ // Clixad login is a GitHub device flow; the issued token (adg_...) is the
591
+ // credential. The device flow is the only supported login path.
592
+ loadAuthentication: oauthCapability(() => import("./integrations/clixad/clixad-oauth"), "clixadOAuthClient"),
593
+ loadQuotaCollector: quotaCapability(() => import("./integrations/clixad/clixad-quota"), "fetchClixadQuota"),
594
+ // `/v1/models` is unauthenticated and lists all rows; the static roster
595
+ // carries the live-verified free tier and discovery keeps the list current.
596
+ loadModelDiscovery: async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
597
+ const { discoverClixadModels, CLIXAD_DEFAULT_MODELS } = await import("./integrations/clixad/provider");
598
+ const fetcher = request.fetcher as unknown as typeof fetch | undefined;
599
+ if (fetcher === undefined) return CLIXAD_DEFAULT_MODELS;
600
+ const rows = await discoverClixadModels({ baseUrl: request.baseUrl, fetcher });
601
+ if (rows === null || rows.length === 0) return CLIXAD_DEFAULT_MODELS;
602
+ return rows;
603
+ },
604
+ },
605
+ deepai: {
606
+ loadAdapter: async () => createApiKeyAdapter((await import("./integrations/deepai/provider")).DEEPAI_SPEC),
607
+ loadModels: async () => (await import("./integrations/deepai/deepai-catalog")).DEEPAI_DEFAULT_MODELS,
608
+ // DeepAI login is a browser loopback flow; the exchange returns an opaque
609
+ // api_key (the credential). Pasting an api_key is supported via
610
+ // importCredential.
611
+ loadAuthentication: oauthCapability(() => import("./integrations/deepai/deepai-oauth"), "deepAIOAuthClient"),
612
+ loadQuotaCollector: quotaCapability(() => import("./integrations/deepai/deepai-quota"), "fetchDeepAIQuota"),
613
+ // `/deepai_code/models` is unauthenticated; the static roster carries the
614
+ // live-verified free tier and discovery keeps the list current.
615
+ loadModelDiscovery: async () => async (request: Parameters<ProviderModelDiscovery>[0]) => {
616
+ const { discoverDeepAIModels, DEEPAI_DEFAULT_MODELS } = await import("./integrations/deepai/deepai-catalog");
617
+ const fetcher = request.fetcher as unknown as typeof fetch | undefined;
618
+ if (fetcher === undefined) return DEEPAI_DEFAULT_MODELS;
619
+ const rows = await discoverDeepAIModels({ baseUrl: request.baseUrl, fetcher });
620
+ if (rows === null || rows.length === 0) return DEEPAI_DEFAULT_MODELS;
621
+ return rows;
622
+ },
623
+ },
579
624
  inferhub: {
580
625
  loadAdapter: async () => (await import("./integrations/inferhub")).createInferhubAdapter(),
581
626
  // Live `/v1/models` is the primary source: the marketplace republishes its
@@ -618,6 +663,32 @@ export const PROVIDER_CAPABILITIES = {
618
663
  ...(fetcher === undefined ? {} : { fetcher }),
619
664
  }),
620
665
  },
666
+ sensenova: {
667
+ loadAdapter: async () => createApiKeyAdapter((await import("./integrations/sensenova/provider")).SENSENOVA_SPEC),
668
+ loadModels: async () => (await import("./integrations/sensenova/provider")).SENSENOVA_MODELS,
669
+ loadModelDiscovery: async () => async (input) =>
670
+ (await import("./integrations/sensenova/provider")).discoverSensenovaModels({
671
+ baseUrl: input.baseUrl,
672
+ providerId: "sensenova",
673
+ ...(typeof input.credential === "string" && input.credential.trim().length > 0
674
+ ? { credential: input.credential }
675
+ : {}),
676
+ ...(input.fetcher === undefined ? {} : { fetcher: input.fetcher }),
677
+ }),
678
+ },
679
+ "sensenova-intl": {
680
+ loadAdapter: async () => createApiKeyAdapter((await import("./integrations/sensenova/provider")).SENSENOVA_INTL_SPEC),
681
+ loadModels: async () => (await import("./integrations/sensenova/provider")).SENSENOVA_INTL_MODELS,
682
+ loadModelDiscovery: async () => async (input) =>
683
+ (await import("./integrations/sensenova/provider")).discoverSensenovaModels({
684
+ baseUrl: input.baseUrl,
685
+ providerId: "sensenova-intl",
686
+ ...(typeof input.credential === "string" && input.credential.trim().length > 0
687
+ ? { credential: input.credential }
688
+ : {}),
689
+ ...(input.fetcher === undefined ? {} : { fetcher: input.fetcher }),
690
+ }),
691
+ },
621
692
  openrouter: {
622
693
  loadAdapter: async () => createApiKeyAdapter((await import("./integrations/openrouter/provider")).OPENROUTER_SPEC),
623
694
  // One dynamic import for both halves: this registry lazy-loads every
@@ -645,6 +716,19 @@ export const PROVIDER_CAPABILITIES = {
645
716
  // why the same adapter serves the pasted-key and signed-in cases.
646
717
  loadAuthentication: oauthCapability(() => import("./integrations/openrouter/oauth"), "openrouterOAuthClient"),
647
718
  },
719
+ vercel: {
720
+ loadAdapter: async () => createApiKeyAdapter((await import("./integrations/vercel/provider")).VERCEL_SPEC),
721
+ loadModels: async () => (await import("./integrations/vercel/provider")).VERCEL_DEFAULT_MODELS,
722
+ loadModelDiscovery: async () => async (input) =>
723
+ (await import("./integrations/vercel/provider")).discoverVercelModels({
724
+ baseUrl: input.baseUrl,
725
+ ...(typeof input.credential === "string" && input.credential.trim().length > 0
726
+ ? { credential: input.credential }
727
+ : {}),
728
+ ...(input.fetcher === undefined ? {} : { fetcher: input.fetcher }),
729
+ }),
730
+ loadQuotaCollector: quotaCapability(() => import("./integrations/vercel/vercel-quota"), "fetchVercelQuota"),
731
+ },
648
732
  xiaomipg: {
649
733
  loadAdapter: async () => createApiKeyAdapter((await import("./integrations/xiaomi-mimo/xiaomi")).XIAOMIPG_SPEC),
650
734
  loadModels: async () => (await import("./integrations/xiaomi-mimo/xiaomi")).XIAOMI_MODELS,
@@ -670,9 +754,7 @@ export const PROVIDER_CAPABILITIES = {
670
754
  // dressed ZCode client request (see the integration). The credential is a
671
755
  // ZCode login JWT — pasted, or minted by the sign-in flow below.
672
756
  loadAdapter: async () =>
673
- createApiKeyAdapter(
674
- (await import("./integrations/zcode-start-plan/provider")).ZCODE_START_PLAN_SPEC,
675
- ),
757
+ (await import("./integrations/zcode-start-plan/provider")).createZcodeStartPlanAdapter(),
676
758
  loadModels: async () =>
677
759
  (await import("./integrations/zcode-start-plan/provider")).ZCODE_START_PLAN_MODELS,
678
760
  // The device flow stores the issued ZCode login JWT, not a Coding Plan key.
@@ -783,10 +865,29 @@ export const PROVIDER_CAPABILITIES = {
783
865
  responses: "/responses",
784
866
  },
785
867
  loadAdapter: async () => createApiKeyAdapter(GENERIC_API_KEY_SPECS.ollamacloud),
786
- loadModels: async () => (await import("./integrations/ollamacloud-models")).OLLAMACLOUD_MODELS,
787
- loadQuotaCollector: quotaCapability(() => import("./integrations/ollamacloud-quota"), "fetchOllamaQuota"),
868
+ loadModels: async () => (await import("./integrations/ollamacloud")).OLLAMACLOUD_MODELS,
869
+ loadQuotaCollector: quotaCapability(() => import("./integrations/ollamacloud"), "fetchOllamaQuota"),
788
870
  loadModelDiscovery: openAIModelDiscovery("ollamacloud", { headers: (credential) => ({ authorization: `Bearer ${credential}` }) }),
789
871
  },
872
+ freebuff: {
873
+ // Freebuff chat is OpenAI-compatible on `/api/v1/chat/completions`, but the
874
+ // adapter runs a stateful preflight (session admission + agent-runs START)
875
+ // and a device-signature header set — see the integration.
876
+ endpointPathsByWireFamily: { chat: "/api/v1/chat/completions" },
877
+ loadAdapter: async () => (await import("./integrations/freebuff/freebuff")).createFreebuffAdapter(),
878
+ loadModels: async () => (await import("./integrations/freebuff/freebuff-catalog")).FREEBUFF_MODELS,
879
+ loadAuthentication: oauthCapability(() => import("./integrations/freebuff/freebuff-oauth"), "freebuffOAuthClient"),
880
+ loadQuotaCollector: quotaCapability(() => import("./integrations/freebuff/freebuff-quota"), "fetchFreebuffQuota"),
881
+ loadModelDiscovery: async () =>
882
+ (await import("./integrations/freebuff/freebuff-discovery")).freebuffModelDiscovery(),
883
+ },
884
+ zro: {
885
+ endpointPathsByWireFamily: { messages: "/v1/messages" },
886
+ loadAdapter: async () => (await import("./integrations/zro/zro")).createZroAdapter(),
887
+ loadModels: async () => (await import("./integrations/zro/zro")).ZRO_MODELS,
888
+ loadQuotaCollector: quotaCapability(() => import("./integrations/zro/zro"), "fetchZroQuota"),
889
+ loadModelDiscovery: async () => (await import("./integrations/zro/zro")).zroModelDiscovery()(),
890
+ },
790
891
 
791
892
  ...createDiscoveryBackedProviderCapabilities(openAIModelDiscovery),
792
893
 
@@ -835,7 +936,7 @@ export const PROVIDER_CAPABILITIES = {
835
936
  // the provider usable before anyone syncs.
836
937
  dashscope: {
837
938
  ...discoveryBackedCapabilities("dashscope", GENERIC_API_KEY_SPECS.dashscope, openAIModelDiscovery),
838
- loadModels: async () => (await import("./integrations/dashscope-models")).DASHSCOPE_MODELS,
939
+ loadModels: async () => (await import("./integrations/alibabacp/dashscope-models")).DASHSCOPE_MODELS,
839
940
  },
840
941
 
841
942
  // Anthropic-Messages providers reached with a plain key. The wire path is
@@ -74,6 +74,13 @@ export interface ProbeModelRequest {
74
74
  route?: string;
75
75
  wireFamily?: string;
76
76
  accountId?: string;
77
+ /**
78
+ * Restrict a batched probe (`probeAllAccounts`) to these account ids.
79
+ * Absent means every account of the provider. The dashboard's Grok
80
+ * "Test 407" uses it when the operator selected accounts: only the
81
+ * selection is probed then, instead of every active account.
82
+ */
83
+ accountIds?: readonly string[];
77
84
  prompt?: string;
78
85
  /** Omit or `auto` to probe without any reasoning intent. */
79
86
  reasoningEffort?: ProbeReasoningEffort;
@@ -117,14 +117,18 @@ export function grok407ProbeFailure(args: {
117
117
  const providerStatus =
118
118
  typeof priorDetails.providerStatus === "number" ? priorDetails.providerStatus : undefined;
119
119
  const returned202 = normalizedSample === "202" || providerStatus === 202;
120
+ // The sample is the model's literal final answer — that is the "original
121
+ // response" an operator wants to see in the health log, not just the
122
+ // classification. Quote it so the health-event reason records what the
123
+ // upstream actually said.
120
124
  const detail =
121
125
  returned202
122
- ? "Grok 407 feature probe returned 202 instead of 407"
126
+ ? `Grok 407 feature probe returned "202" instead of "407"`
123
127
  : args.dispatchError instanceof Error
124
128
  ? `Grok 407 feature probe failed: ${args.dispatchError.message}`
125
129
  : sample === undefined
126
130
  ? "Grok 407 feature probe returned no exact 407 response"
127
- : `Grok 407 feature probe returned ${sample}`;
131
+ : `Grok 407 feature probe returned "${sample}" (expected "407")`;
128
132
  return new GatewayError(
129
133
  "quota_exceeded",
130
134
  429,
@@ -472,8 +476,9 @@ export async function selectProbeAccount(args: {
472
476
  * back to the generic OpenAI-compatible adapter so probe/dispatch still works.
473
477
  * The low-level compatible adapter is used directly to avoid importing concrete
474
478
  * integrations from discovery (which would violate the provider-architecture
475
- * layering test). `loadOne` returning `undefined` means "no bundled adapter";
476
- * a throw is a registry failure and propagates rather than being reported as
479
+ * layering test). `resolve(..., { force: true })` rebuilds the bundled adapter
480
+ * against the current registration; `undefined` means "no bundled adapter"; a
481
+ * throw is a registry failure and propagates rather than being reported as
477
482
  * "no adapter registered".
478
483
  */
479
484
  export async function resolveProbeAdapter(args: {
@@ -482,7 +487,7 @@ export async function resolveProbeAdapter(args: {
482
487
  readonly providerWireRow: ProbeProviderRow | undefined;
483
488
  }): Promise<ProviderAdapter | undefined> {
484
489
  const { providerRegistry, providerId, providerWireRow } = args;
485
- let adapter = await providerRegistry.loadOne(providerId);
490
+ let adapter = await providerRegistry.resolve(providerId, { force: true });
486
491
  if (!adapter) {
487
492
  try {
488
493
  if (providerWireRow?.baseUrl) {
@@ -665,8 +670,16 @@ export function buildProbeCanonicalRequest(args: {
665
670
  * probe.
666
671
  */
667
672
  readonly providerSystemPrompt?: string | undefined;
673
+ /**
674
+ * A provider-specific default probe prompt, used when the operator sent no
675
+ * prompt. Lets a provider whose policy gate flags repeated identical probes
676
+ * (Freebuff: `prompt_policy_refused` / "same message sent over and over")
677
+ * receive a minimal, per-model-varying probe instead of the shared identity
678
+ * question every provider otherwise sends.
679
+ */
680
+ readonly defaultPromptOverride?: string | undefined;
668
681
  }): CanonicalRequest {
669
- const { modelId, request, probeReasoning, sourceSurface, maxOutputTokens, providerSystemPrompt } = args;
682
+ const { modelId, request, probeReasoning, sourceSurface, maxOutputTokens, providerSystemPrompt, defaultPromptOverride } = args;
670
683
  const fast = maxOutputTokens === PROBE_FAST_MAX_OUTPUT_TOKENS;
671
684
  return {
672
685
  model: modelId,
@@ -681,6 +694,7 @@ export function buildProbeCanonicalRequest(args: {
681
694
  kind: "text",
682
695
  text:
683
696
  request.prompt ??
697
+ defaultPromptOverride ??
684
698
  (fast ? PROBE_FAST_DEFAULT_PROMPT : "What model are you, and what is your knowledge cutoff date? Answer in one sentence."),
685
699
  },
686
700
  ],
@@ -56,7 +56,7 @@ import {
56
56
  wireContextFrom,
57
57
  type ProbeProviderRow,
58
58
  } from "./probe-phases";
59
- import { createProbeFetch } from "../operations/probe-fetch";
59
+ import { createProbeFetch } from "../provider-probe";
60
60
  import { authHeaders } from "../adapters/compatible-adapter";
61
61
  import {
62
62
  byokAuthHeaderShape,
@@ -263,7 +263,20 @@ export class ProviderProbingService {
263
263
  ...(preferences.maxOutputTokens === undefined
264
264
  ? {}
265
265
  : { maxOutputTokens: preferences.maxOutputTokens }),
266
- ...(typeof adapter?.systemPrompt === "function"
266
+ // Freebuff's admission policy gate flags repeated identical probes as
267
+ // automated farming (`prompt_policy_refused` / "same message sent over
268
+ // and over"). Its probe must be minimal and always distinct per model —
269
+ // no worker system template, no shared identity question. `ping` is the
270
+ // same minimal greeting the fast-probe path already uses; the model id
271
+ // keeps every probe distinct so the "same message over and over" gate
272
+ // cannot flag a batch run.
273
+ ...(providerId === "freebuff"
274
+ ? {
275
+ defaultPromptOverride: `ping ${modelId}`,
276
+ providerSystemPrompt: undefined,
277
+ }
278
+ : {}),
279
+ ...(typeof adapter?.systemPrompt === "function" && providerId !== "freebuff"
267
280
  ? { providerSystemPrompt: adapter.systemPrompt() }
268
281
  : {}),
269
282
  });
@@ -1247,6 +1260,13 @@ export class ProviderProbingService {
1247
1260
  and(
1248
1261
  eq(providerAccounts.providerId, providerId),
1249
1262
  globalOrOwnedBy(providerAccounts.tenantId, tenantId),
1263
+ // `accountIds` absent means every account; when present (even
1264
+ // empty) only those ids are probed — the dashboard's "Test 407"
1265
+ // sends the selection and falls back to all when nothing is
1266
+ // selected.
1267
+ ...(request.accountIds !== undefined
1268
+ ? [inArray(providerAccounts.id, request.accountIds)]
1269
+ : []),
1250
1270
  ),
1251
1271
  );
1252
1272
  // Sliding worker pool: workers claim the next account as soon as their
@@ -19,8 +19,7 @@
19
19
  */
20
20
  import { defineModel } from "../../provider-model-definition";
21
21
  import type { ModelDefinition } from "../../provider-model-definition";
22
-
23
- export const ALIBABACP_PROVIDER_ID = "alibabacp" as const;
22
+ import { ALIBABACP_PROVIDER_ID } from "./alibabacp";
24
23
 
25
24
  /** Chat path below the region's `/compatible-mode/v1` base. */
26
25
  const CHAT_ENDPOINT = "/chat/completions";
@@ -17,8 +17,8 @@
17
17
  * does not publish yet arrives through the sync control instead of being
18
18
  * asserted ahead of the upstream.
19
19
  */
20
- import { defineModel } from "../provider-model-definition";
21
- import type { ModelDefinition } from "../provider-model-definition";
20
+ import { defineModel } from "../../provider-model-definition";
21
+ import type { ModelDefinition } from "../../provider-model-definition";
22
22
 
23
23
  export const DASHSCOPE_PROVIDER_ID = "dashscope" as const;
24
24
 
@@ -166,6 +166,16 @@ const ANTIGRAVITY_MODEL_WIRE_PROFILES: Readonly<
166
166
  modelEnum: "MODEL_PLACEHOLDER_M322",
167
167
  maxOutputTokens: 65536,
168
168
  },
169
+ // Gemini 4 Argon effort tiers (real deployment names).
170
+ "gemini-4-argon-low": {
171
+ maxOutputTokens: 65536,
172
+ },
173
+ "gemini-4-argon-medium": {
174
+ maxOutputTokens: 65536,
175
+ },
176
+ "gemini-4-argon-high": {
177
+ maxOutputTokens: 65536,
178
+ },
169
179
  // GPT-OSS via Antigravity (verified live).
170
180
  "gpt-oss-120b-medium": {
171
181
  modelEnum: "MODEL_OPENAI_GPT_OSS_120B_MEDIUM",
@@ -199,6 +209,7 @@ export function antigravityWireModelId(modelId: string): string {
199
209
  if (modelId === "gemini-3.6-flash") return "gemini-3.6-flash-low";
200
210
  if (modelId === "gemini-3.7-flash") return "gemini-3.7-flash-low";
201
211
  if (modelId === "gemini-3.8-flash") return "gemini-3.8-flash-low";
212
+ if (modelId === "gemini-4-argon") return "gemini-4-argon-low";
202
213
  if (modelId === "gpt-oss-120b") return "gpt-oss-120b-medium";
203
214
  return modelId;
204
215
  }
@@ -400,7 +411,11 @@ export function dropAntigravityUnsignedReasoning(
400
411
  if (message.role !== "assistant") return message;
401
412
  const content = message.content.filter((part) => {
402
413
  if (part.kind !== "reasoning") return true;
403
- if (part.signature !== undefined) return true;
414
+ // A present-but-empty signature is still unsigned: upstream rejects a
415
+ // `thinking` part whose `signature` is missing *or* empty with
416
+ // `400 messages.N.content.0.thinking.signature: Field required`. Only a
417
+ // non-empty signature is a real one.
418
+ if (typeof part.signature === "string" && part.signature.length > 0) return true;
404
419
  changed = true;
405
420
  return false;
406
421
  });