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
@@ -1,16 +1,41 @@
1
1
  /**
2
- * ZCode Start Plan uses the client's three-block Messages prompt fingerprint.
3
- * Caller instructions remain inside the third block; a fourth block is refused.
4
- * The bundled prompt/version pair is kept together to preserve upstream bytes.
5
- * Reference provenance and bounded live acceptance evidence: provider guide.
2
+ * ZCode Start Plan provider integration.
3
+ *
4
+ * The plan lane is an Anthropic Messages endpoint that only accepts the
5
+ * dressed ZCode client request (see `dress`): the gateway content-inspects the
6
+ * `system` field and refuses a request without the exact three-block identity
7
+ * fingerprint with `405 {code:3012}`. The credential is a ZCode login JWT —
8
+ * pasted, or minted by the sign-in flow (`oauth.ts`).
9
+ *
10
+ * Wire facts mirrored from the donor gateway (verified live 2026-10-30):
11
+ * - `anthropic-beta: mid-conversation-system-2026-04-07` rides every request.
12
+ * - `metadata.user_id` is a JSON string `{"device_id","account_uuid","session_id"}`
13
+ * the gateway reads for attribution; it lives in the body, not a header.
14
+ * - The LLM identity face carries per-request correlation ids: `x-session-id`,
15
+ * `x-request-id`, `x-zcode-trace-id`, `x-query-id`, `x-zcode-query-source`.
16
+ * - Errors inside an HTTP 200 response come as a `{code,msg,logid}` envelope
17
+ * (`1113` grant spent, `3009` model concurrency, `3012` identity gate) and
18
+ * are mapped through the shared `classifyUpstreamError`.
6
19
  */
7
20
  import { randomUUID } from "node:crypto";
8
21
  import { release as osRelease } from "node:os";
9
22
 
10
- import type { ApiKeyProviderSpec } from "../../configured-provider";
11
23
  import { defineModel } from "../../provider-model-definition";
12
24
  import type { ModelDefinition } from "../../provider-model-definition";
13
25
  import { getOrCreateInstallId } from "../shared/install-id";
26
+ import { resolveInboundSessionId } from "../../operations/session-resolution";
27
+ import { assertCredentialKind, assertWireFamily } from "../../provider-contracts";
28
+ import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
29
+ import { GatewayError } from "../../../protocol/gateway-error";
30
+ import { applyParamQuirks } from "../../../protocol/translation/quirks";
31
+ import { buildClaudeMessagesRequest, filterClaudeCustomHeaders } from "../shared/claude-messages";
32
+ import { mapClaudeHttpError } from "../../../protocol/messages-errors";
33
+ import { isRecord } from "../../../protocol/codecs";
34
+ import { classifyUpstreamError, upstreamErrorIdentifier, upstreamMessageAsIs } from "../../../transport/failure-policy";
35
+ import { parseClaudeSseStream, claudeResponseToEvents } from "../../../protocol/response/messages";
36
+ import { createUpstreamDeadlineLifecycle } from "../../operations/upstream-deadline";
37
+ import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
38
+ import { parseJwt } from "../../authentication/jwt-validator";
14
39
  import prompt from "./zcode_prompt.json";
15
40
 
16
41
  const CLI_PREFIX: string = prompt.cliPrefix;
@@ -21,8 +46,18 @@ export const ZCODE_START_PLAN_PROVIDER_ID = "zcode-start" as const;
21
46
  export const ZCODE_START_PLAN_ENDPOINT_PATH = "/v1/messages" as const;
22
47
  export const ZCODE_START_PLAN_BASE_URL = "https://zcode.z.ai/api/v1/zcode-plan/anthropic" as const;
23
48
 
24
- /** Client version the plan endpoint expects in the identity headers. */
49
+ /**
50
+ * Client version the plan endpoint expects in the identity headers. This is
51
+ * kept in step with the bundled prompt asset (`zcode_prompt.json`, 3.14.5):
52
+ * the gateway content-inspects the system blocks, and a version/prompt split
53
+ * (e.g. 3.16.3 headers over 3.14.5 blocks) risks the 3012 identity gate. Bump
54
+ * both together only after re-capturing the live blocks and re-verifying.
55
+ */
25
56
  const APP_VERSION = "3.14.5";
57
+ /** Anthropic beta the desktop client sends on the plan lane (captured live). */
58
+ const ANTHROPIC_BETA = "mid-conversation-system-2026-04-07";
59
+ /** The plan gateway enforces a serial per-account in-flight limit; 8192 is the desktop default. */
60
+ const DEFAULT_MAX_TOKENS = 8192;
26
61
 
27
62
  type Loose = Record<string, unknown>;
28
63
  type TextBlock = { type: "text"; text: string; cache_control?: { type: "ephemeral" } };
@@ -40,26 +75,47 @@ function environmentBlock(provider: string, model: string): string {
40
75
  .replace("{model}", model);
41
76
  }
42
77
 
78
+ /** The account uuid carried by the plan JWT, for metadata attribution. */
79
+ function jwtUserId(credential: { secret?: Uint8Array | undefined } | undefined): string {
80
+ if (!credential?.secret || credential.secret.length === 0) return "";
81
+ try {
82
+ const token = new TextDecoder().decode(credential.secret);
83
+ const parsed = parseJwt(token);
84
+ const userId = parsed?.payload?.["user_id"];
85
+ return typeof userId === "string" ? userId : "";
86
+ } catch {
87
+ return "";
88
+ }
89
+ }
90
+
43
91
  /** Identity headers every dispatch carries; the adapter adds Authorization. */
44
- async function identityHeaders(): Promise<Record<string, string>> {
92
+ async function identityHeaders(context: ProviderDispatchContext): Promise<Record<string, string>> {
93
+ const sessionId = resolveInboundSessionId(context) ?? `session_${randomUUID().replace(/-/g, "").slice(0, 32)}`;
94
+ const requestId = randomUUID();
95
+ const traceId = randomUUID();
96
+ const queryId = `01a1${requestId.slice(4).replace(/-/g, "").slice(0, 28)}`;
97
+ const deviceMid = await getOrCreateInstallId("zcode-start-plan");
45
98
  return {
46
99
  "user-agent": `ZCode/${APP_VERSION} ai-sdk/anthropic/3.0.81`,
47
100
  "http-referer": "https://zcode.z.ai",
48
- "x-title": "Z Code@cli",
101
+ "x-title": "Z Code@electron",
49
102
  "x-zcode-app-version": APP_VERSION,
50
103
  "x-zcode-agent": "glm",
51
104
  "x-release-channel": "production",
52
105
  "x-client-language": "en-US",
53
106
  "x-client-timezone": "Asia/Jakarta",
54
- "x-platform": "linux",
107
+ "x-platform": "linux-x64",
55
108
  "x-os-category": "linux",
56
109
  "x-os-version": osRelease(),
57
- "x-request-id": randomUUID(),
110
+ "x-request-id": requestId,
111
+ "x-query-id": queryId,
112
+ "x-zcode-trace-id": traceId,
58
113
  "x-zcode-session-type": "main",
59
- "x-zcode-trace-id": randomUUID(),
60
- // Keep the persisted install-id filename stable across the provider-ID rename.
61
- "x-device-mid": await getOrCreateInstallId("zcode-start-plan"),
114
+ "x-zcode-query-source": "main_turn",
115
+ "x-session-id": sessionId,
116
+ "x-device-mid": deviceMid,
62
117
  "anthropic-version": "2023-06-01",
118
+ "anthropic-beta": ANTHROPIC_BETA,
63
119
  };
64
120
  }
65
121
 
@@ -119,13 +175,160 @@ export const ZCODE_START_PLAN_MODELS: readonly ModelDefinition[] = [
119
175
  }),
120
176
  ];
121
177
 
122
- /** Start Plan adapter spec: direct upstream, prompt fingerprint, no sidecar. */
123
- export const ZCODE_START_PLAN_SPEC: ApiKeyProviderSpec = {
124
- provider_id: ZCODE_START_PLAN_PROVIDER_ID,
125
- base_url: ZCODE_START_PLAN_BASE_URL,
126
- endpoint_paths_by_wire_family: { messages: ZCODE_START_PLAN_ENDPOINT_PATH },
127
- buildExtraHeaders: () => identityHeaders(),
128
- prePayload: (payload) => {
129
- dress(payload as Loose);
130
- },
131
- };
178
+ /** True when the body is the ZCode `{code,msg,logid}` business-error envelope. */
179
+ function isZcodeEnvelopeError(body: Record<string, unknown>): boolean {
180
+ if (body["success"] === false) return true;
181
+ const code = body["code"];
182
+ return code !== undefined && ![0, 200, "0", "200"].includes(code as string | number);
183
+ }
184
+
185
+ /**
186
+ * Plan-lane Messages adapter. Unlike the plain Anthropic adapter it must (a)
187
+ * dress the three-block system fingerprint, (b) inject `metadata.user_id`, and
188
+ * (c) treat a `{code,msg}` envelope inside an HTTP 200 as a refusal — the
189
+ * gateway reports business errors on success statuses.
190
+ */
191
+ export class ZcodeStartPlanAdapter implements ProviderAdapter {
192
+ readonly provider_id = ZCODE_START_PLAN_PROVIDER_ID;
193
+ private readonly fetchFn: typeof fetch;
194
+ private readonly baseUrl: string;
195
+
196
+ constructor(fetchImpl?: typeof fetch, baseUrl?: string) {
197
+ this.fetchFn = fetchImpl ?? globalThis.fetch;
198
+ this.baseUrl = (baseUrl ?? ZCODE_START_PLAN_BASE_URL).replace(/\/+$/, "");
199
+ }
200
+
201
+ async *dispatch(
202
+ request: CanonicalRequest,
203
+ candidate: ProviderDispatchTarget,
204
+ context: ProviderDispatchContext,
205
+ ): AsyncIterable<CanonicalEvent> {
206
+ if (candidate.wire_family !== "messages") {
207
+ assertWireFamily(candidate, "messages", "zcode-start messages leg");
208
+ }
209
+ if (context.credential.credential_kind !== "api_key") {
210
+ assertCredentialKind(context.credential, "api_key", "zcode-start");
211
+ }
212
+ if (context.credential.secret === undefined || context.credential.secret.length === 0) {
213
+ throw new GatewayError(
214
+ "invalid_request",
215
+ 400,
216
+ "zcode-start: plan JWT is missing a secret value (request {requestId}). Wrong key, right door — check the credential 🔑",
217
+ );
218
+ }
219
+ const planJwt = new TextDecoder().decode(context.credential.secret);
220
+ const sessionId = resolveInboundSessionId(context, request) ?? `session_${randomUUID().replace(/-/g, "").slice(0, 32)}`;
221
+ const deviceMid = await getOrCreateInstallId("zcode-start-plan");
222
+ const accountUuid = jwtUserId(context.credential);
223
+ const customHeaders = filterClaudeCustomHeaders({
224
+ ...context.credential.custom_headers,
225
+ });
226
+ const outbound = buildClaudeMessagesRequest({
227
+ request: applyParamQuirks(request, candidate.provider_id),
228
+ authHeader: "bearer",
229
+ credential: { secret: planJwt, customHeaders },
230
+ baseUrl: this.baseUrl,
231
+ endpointPath: candidate.endpoint_path,
232
+ mutatePayload: (payload) => {
233
+ dress(payload);
234
+ const metadata = (isRecord(payload["metadata"]) ? payload["metadata"] : {}) as Loose;
235
+ metadata["user_id"] = JSON.stringify({
236
+ device_id: deviceMid,
237
+ account_uuid: accountUuid,
238
+ session_id: sessionId,
239
+ });
240
+ payload.metadata = metadata;
241
+ if (payload["max_tokens"] == null) payload["max_tokens"] = DEFAULT_MAX_TOKENS;
242
+ return payload;
243
+ },
244
+ });
245
+ Object.assign(outbound.headers, await identityHeaders(context));
246
+
247
+ const outboundFetch = context.outbound_fetch ?? this.fetchFn;
248
+ const lifecycle = createUpstreamDeadlineLifecycle(context);
249
+ let response: Response;
250
+ try {
251
+ response = await outboundFetch(outbound.url, {
252
+ method: "POST",
253
+ headers: outbound.headers,
254
+ body: outbound.body,
255
+ signal: lifecycle.signal,
256
+ });
257
+ } catch (error: unknown) {
258
+ lifecycle.release();
259
+ if (error instanceof GatewayError) throw error;
260
+ throw new GatewayError(
261
+ "transport_unavailable",
262
+ 502,
263
+ `zcode-start upstream fetch failed: ${(error as Error)?.message ?? String(error)}`,
264
+ {},
265
+ "network",
266
+ );
267
+ }
268
+ lifecycle.release();
269
+
270
+ if (!response.ok) {
271
+ const bodyText = await response.text().catch(() => "");
272
+ throw mapClaudeHttpError(response.status, bodyText, response.headers);
273
+ }
274
+ const contentType = response.headers.get("content-type") ?? "";
275
+ if (contentType.toLowerCase().includes("text/event-stream") || request.stream) {
276
+ if (response.body === null) {
277
+ throw new GatewayError(
278
+ "platform_unavailable",
279
+ 502,
280
+ "zcode-start returned no stream body (request {requestId}). The upstream came back empty-handed — retry 🌙",
281
+ {},
282
+ "upstream",
283
+ );
284
+ }
285
+ yield* parseClaudeSseStream(response.body, context.abort_signal, false);
286
+ return;
287
+ }
288
+ const bodyText = await response.text().catch(() => "");
289
+ let json: unknown;
290
+ try {
291
+ json = JSON.parse(bodyText) as unknown;
292
+ } catch {
293
+ const upstreamText = upstreamMessageAsIs(bodyText, "");
294
+ throw new GatewayError(
295
+ "platform_unavailable",
296
+ 502,
297
+ upstreamText.message || "zcode-start response is not valid JSON (request {requestId}). The upstream came back empty-handed — retry 🌙",
298
+ { raw: bodyText.slice(0, 4096) },
299
+ "upstream",
300
+ );
301
+ }
302
+ if (!isRecord(json)) {
303
+ throw new GatewayError(
304
+ "platform_unavailable",
305
+ 502,
306
+ "zcode-start response must be an object (request {requestId}). The upstream came back empty-handed — retry 🌙",
307
+ {},
308
+ "upstream",
309
+ );
310
+ }
311
+ if (isZcodeEnvelopeError(json)) {
312
+ const identifier = upstreamErrorIdentifier(json);
313
+ const classification = classifyUpstreamError(undefined, identifier);
314
+ const upstreamText = upstreamMessageAsIs(json, "");
315
+ throw new GatewayError(
316
+ classification.code,
317
+ classification.status,
318
+ upstreamText.message || "zcode-start reported an upstream error",
319
+ {
320
+ providerId: this.provider_id,
321
+ ...(identifier === undefined ? {} : { providerCode: identifier }),
322
+ ...(upstreamText.hadUpstreamText ? { upstreamMessageAsIs: true } : {}),
323
+ raw: bodyText.slice(0, 4096),
324
+ },
325
+ classification.origin,
326
+ );
327
+ }
328
+ yield* claudeResponseToEvents(json, request, false);
329
+ }
330
+ }
331
+
332
+ export function createZcodeStartPlanAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
333
+ return new ZcodeStartPlanAdapter(fetchImpl);
334
+ }
@@ -1,9 +1,23 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { asCoercedNumber, asRecord, asTrimmedString } from "../../../shared/coerce";
2
3
  import type { FetchLike, ProviderQuotaResult, ProviderQuotaWindow } from "../../quota/quota-contracts";
3
4
 
4
5
  const BALANCE_URL = "https://zcode.z.ai/api/v1/zcode-plan/billing/balance?app_version=3.16.3";
5
- const DEVICE_MID = "9f1b0d4e-3c2a-4e7b-9f1d-6a2c8b5e0d31";
6
6
  const APP_VERSION = "3.16.3";
7
+ const PLATFORM = "linux-x64";
8
+
9
+ /**
10
+ * Stable per-account device mid. The gateway validates `X-Device-Mid` as a
11
+ * UUID (billing answers `3001 parameter error` without it) and attributes
12
+ * usage to it; a hardcoded shared UUID would lump every account into one
13
+ * billing identity. Derivation matches the gift-claim device id, so quota and
14
+ * claim present the same device per account.
15
+ */
16
+ function deviceMid(accountId: string): string {
17
+ const hash = createHash("sha256").update(`zcode-device\0${accountId}`).digest("hex");
18
+ const variant = ((parseInt(hash[16] as string, 16) & 3) | 8).toString(16);
19
+ return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-4${hash.slice(13, 16)}-${variant}${hash.slice(17, 20)}-${hash.slice(20, 32)}`;
20
+ }
7
21
 
8
22
  function instant(value: unknown): string | null {
9
23
  const seconds = asCoercedNumber(value);
@@ -57,16 +71,19 @@ function samePlan(bucket: Record<string, unknown>, plan: Record<string, unknown>
57
71
  export async function fetchZcodeStartPlanQuota(
58
72
  credential: string,
59
73
  fetcher: FetchLike,
74
+ context?: { accountId?: string },
60
75
  ): Promise<ProviderQuotaResult> {
61
76
  const source = "zcode-start";
62
77
  try {
78
+ const accountId = context?.accountId ?? credential.trim();
63
79
  const response = await fetcher(BALANCE_URL, {
64
80
  headers: {
65
81
  authorization: `Bearer ${credential}`,
66
82
  accept: "application/json",
67
- "x-device-mid": DEVICE_MID,
83
+ "x-device-mid": deviceMid(accountId),
68
84
  "x-zcode-app-version": APP_VERSION,
69
85
  "x-client-language": "en-US",
86
+ "x-platform": PLATFORM,
70
87
  },
71
88
  signal: AbortSignal.timeout(15_000),
72
89
  });
@@ -0,0 +1,205 @@
1
+ // Zro provider integration — TypeScript, Zro (moonmath).
2
+ //
3
+ // Zro exposes three wire formats: OpenAI Chat (`/v1/chat/completions`),
4
+ // OpenAI Responses (`/v1/responses`), and Anthropic Messages
5
+ // (`/v1/messages`). Claude Code talks to it through the Messages wire with a
6
+ // plain `Authorization: Bearer sk-...` key (no `x-api-key`, no CLI
7
+ // fingerprint) — verified live 2026-11-09 that the Anthropic envelope +
8
+ // bearer auth answers 200, and that the full Claude Code header set
9
+ // (`anthropic-version`, Stainless identity, official user-agent) is accepted
10
+ // but not required. Every model is served over Messages in this integration,
11
+ // matching how the provider's own Claude Code docs route traffic.
12
+ //
13
+ // Quota: Zro publishes no billing/quota endpoint (all probe guesses 404).
14
+ // The entitlement surface is `GET /v1/models` itself — a key only sees the
15
+ // models it is allowed to call (verified: a key with 3 models got 403
16
+ // `user_model_access_denied` for a 4th), and an invalid key answers 401 there.
17
+ // The quota collector probes that same `/v1/models` surface, and model
18
+ // discovery owns the entitlement truth.
19
+
20
+ import { assertCredentialKind, assertWireFamily } from "../../provider-contracts";
21
+ import type { ProviderAdapter, ProviderDispatchContext, ProviderDispatchTarget } from "../../provider-contracts";
22
+ import type { ModelDefinition } from "../../provider-model-definition";
23
+ import { defineModel } from "../../provider-model-definition";
24
+ import type { ProviderModelDiscovery } from "../../discovery/discovery-types";
25
+ import type { FetchLike, ProviderQuotaResult } from "../../quota/quota-contracts";
26
+ import type { CanonicalEvent, CanonicalRequest } from "../../../protocol/canonical-model";
27
+ import { GatewayError } from "../../../protocol/gateway-error";
28
+ import { applyParamQuirks } from "../../../protocol/translation/quirks";
29
+ import { buildClaudeMessagesRequest, filterClaudeCustomHeaders } from "../shared/claude-messages";
30
+ import { sendClaudeMessagesRequest } from "../../../protocol/upstream/send-claude-messages";
31
+
32
+ export const ZRO_PROVIDER_ID = "zro" as const;
33
+ export const ZRO_BASE_URL = "https://zro.moonmath.ai";
34
+
35
+ /**
36
+ * Offline fallback for the models this key is entitled to, used when the live
37
+ * `/v1/models` read fails or returns nothing. The three rows are exactly the
38
+ * reachable set of the probe key (each also carries a `zro/` alias on the
39
+ * wire); a live read may show more or fewer and replaces this seed entirely.
40
+ */
41
+ const ZRO_MODELS_RAW: readonly {
42
+ id: string;
43
+ contextLimit: number;
44
+ outputLimit: number;
45
+ }[] = [
46
+ { id: "deepseek-v4-flash-0731", contextLimit: 1_048_576, outputLimit: 64_000 },
47
+ { id: "deepseek-v4.1-flash", contextLimit: 1_048_576, outputLimit: 64_000 },
48
+ ] as const;
49
+
50
+ export const ZRO_MODELS: readonly ModelDefinition[] = ZRO_MODELS_RAW.map((row) =>
51
+ defineModel({
52
+ id: row.id,
53
+ providerId: ZRO_PROVIDER_ID,
54
+ wireFamily: "messages",
55
+ // The Messages wire root is `/v1/messages` on Zro's host, not the
56
+ // family-conventional `/messages` path `defineModel` would otherwise pick.
57
+ endpoint: "/v1/messages",
58
+ ctx: row.contextLimit,
59
+ out: row.outputLimit,
60
+ vision: false,
61
+ reasoning: true,
62
+ toolCall: true,
63
+ // The reachable rows are the free-limited allowance this key can call; the
64
+ // dashboard groups them under "Free models (auto)".
65
+ freeTier: true,
66
+ }),
67
+ );
68
+
69
+ /**
70
+ * Zro model discovery. The live `/v1/models` list is the *entitlement*
71
+ * surface: it returns only the models a key may call (verified live
72
+ * 2026-11-09 — a key with 3 models got 403 for a 4th; the public `/models`
73
+ * catalog without the `/v1` prefix lists everything, including models the key
74
+ * is refused). The `/v1` prefix is therefore mandatory. Each row appears
75
+ * twice on the wire (bare id + `zro/` alias); the alias is folded onto the
76
+ * bare id. Every listed row is forced onto the Messages wire, mirroring the
77
+ * offline catalog.
78
+ */
79
+ export function zroModelDiscovery(): () => Promise<ProviderModelDiscovery> {
80
+ return async () => async (input) => {
81
+ // dynamic-import: cycle-break — model discovery is only imported at call time,
82
+ // so a provider that never runs discovery never pays for the OpenAI discovery graph.
83
+ const { fetchOpenAICompatibleModels } = await import("../../discovery/openai-model-discovery");
84
+ const base = input.baseUrl.replace(/\/+$/, "");
85
+ const models = await fetchOpenAICompatibleModels({
86
+ // `/v1` is the entitlement surface; the bare `/models` path is the
87
+ // public full catalog and would advertise models the key cannot call.
88
+ baseUrl: `${base}/v1`,
89
+ providerId: ZRO_PROVIDER_ID,
90
+ headers: { authorization: `Bearer ${input.credential}` },
91
+ ...(input.fetcher ? { fetcher: input.fetcher } : {}),
92
+ });
93
+ const source: readonly ModelDefinition[] =
94
+ models === null || models.length === 0 ? ZRO_MODELS : models;
95
+ const byId = new Map<string, ModelDefinition>();
96
+ for (const model of source) {
97
+ const raw = model.modelId;
98
+ const bare = raw.toLowerCase().startsWith("zro/") ? raw.slice("zro/".length) : raw;
99
+ byId.set(bare, { ...model, modelId: bare });
100
+ }
101
+ return [...byId.values()].map((model) => ({
102
+ ...model,
103
+ wireFamily: "messages" as const,
104
+ endpointPath: "/v1/messages",
105
+ // The `/v1/models` list is by definition the set this key may call on
106
+ // the free-limited allowance, so every discovered row is free-tier.
107
+ freeTier: true,
108
+ }));
109
+ };
110
+ }
111
+
112
+ /**
113
+ * Messages-wire adapter. Same Claude pipeline as the plain Anthropic adapter,
114
+ * but Zro authenticates with a Bearer key instead of `x-api-key` — the same
115
+ * shape as InferHub's Claude leg.
116
+ */
117
+ export class ZroMessagesAdapter implements ProviderAdapter {
118
+ readonly provider_id = ZRO_PROVIDER_ID;
119
+ private readonly fetchFn: typeof fetch;
120
+ private readonly baseUrl: string;
121
+
122
+ constructor(fetchImpl?: typeof fetch, baseUrl?: string) {
123
+ this.fetchFn = fetchImpl ?? globalThis.fetch;
124
+ this.baseUrl = (baseUrl ?? ZRO_BASE_URL).replace(/\/+$/, "");
125
+ }
126
+
127
+ async *dispatch(
128
+ request: CanonicalRequest,
129
+ candidate: ProviderDispatchTarget,
130
+ context: ProviderDispatchContext,
131
+ ): AsyncIterable<CanonicalEvent> {
132
+ if (candidate.wire_family !== "messages") {
133
+ assertWireFamily(candidate, "messages", "zro messages leg");
134
+ }
135
+ if (context.credential.credential_kind !== "api_key") {
136
+ assertCredentialKind(context.credential, "api_key", "zro");
137
+ }
138
+ if (context.credential.secret === undefined || context.credential.secret.length === 0) {
139
+ throw new GatewayError(
140
+ "invalid_request",
141
+ 400,
142
+ "zro: API key is missing a secret value (request {requestId}). Wrong key, right door — check the key 🔑",
143
+ );
144
+ }
145
+ const apiKey = new TextDecoder().decode(context.credential.secret);
146
+ const customHeaders = filterClaudeCustomHeaders({
147
+ ...context.credential.custom_headers,
148
+ });
149
+ const outbound = buildClaudeMessagesRequest({
150
+ request: applyParamQuirks(request, candidate.provider_id),
151
+ authHeader: "bearer",
152
+ credential: { secret: apiKey, customHeaders },
153
+ baseUrl: this.baseUrl,
154
+ endpointPath: candidate.endpoint_path,
155
+ });
156
+ yield* sendClaudeMessagesRequest(
157
+ outbound.url,
158
+ outbound.headers,
159
+ outbound.body,
160
+ context,
161
+ request,
162
+ this.fetchFn,
163
+ );
164
+ }
165
+ }
166
+
167
+ export function createZroAdapter(fetchImpl?: typeof fetch): ProviderAdapter {
168
+ return new ZroMessagesAdapter(fetchImpl);
169
+ }
170
+
171
+ /**
172
+ * Zro quota collector. Zro publishes no billing/quota endpoint; the
173
+ * entitlement surface is `GET /v1/models` — a key only sees the models it may
174
+ * call, and an invalid key answers 401/403 (verified live 2026-11-09). The
175
+ * bare `/models` path is the public full catalog and does NOT authenticate, so
176
+ * the `/v1` prefix is mandatory here.
177
+ */
178
+ export async function fetchZroQuota(
179
+ credential: string,
180
+ fetcher: FetchLike,
181
+ ): Promise<ProviderQuotaResult> {
182
+ const fetchFn = fetcher ?? globalThis.fetch;
183
+ let response: Response;
184
+ try {
185
+ response = await fetchFn(`${ZRO_BASE_URL}/v1/models`, {
186
+ headers: { accept: "application/json", authorization: `Bearer ${credential.trim()}` },
187
+ signal: AbortSignal.timeout(15_000),
188
+ });
189
+ } catch (error) {
190
+ return {
191
+ source: ZRO_PROVIDER_ID,
192
+ plan: null,
193
+ windows: [],
194
+ error: error instanceof Error ? error.message : String(error),
195
+ };
196
+ }
197
+ if (response.status === 401 || response.status === 403) {
198
+ return { source: ZRO_PROVIDER_ID, plan: null, windows: [], error: "API key is invalid or revoked." };
199
+ }
200
+ if (!response.ok) {
201
+ return { source: ZRO_PROVIDER_ID, plan: null, windows: [], error: `Connectivity check failed: HTTP ${response.status}.` };
202
+ }
203
+ await response.text().catch(() => "");
204
+ return { source: ZRO_PROVIDER_ID, plan: "limited", windows: [], error: null };
205
+ }