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
@@ -25,28 +25,7 @@
25
25
  */
26
26
 
27
27
  import protobuf from "protobufjs"
28
-
29
- // ── Helper: create a root and add a Type with fields ──
30
-
31
- type FieldDef = { id: number; name: string; type: string; repeated?: boolean }
32
- type OneofDef = { name: string; fields: string[] }
33
-
34
- function addType(
35
- root: protobuf.Root,
36
- name: string,
37
- fields: FieldDef[],
38
- oneofs?: OneofDef[],
39
- ): protobuf.Type {
40
- const t = new protobuf.Type(name)
41
- for (const f of fields) {
42
- t.add(new protobuf.Field(f.name, f.id, f.type, f.repeated ? "repeated" : undefined))
43
- }
44
- for (const o of oneofs ?? []) {
45
- t.add(new protobuf.OneOf(o.name, o.fields))
46
- }
47
- root.add(t)
48
- return t
49
- }
28
+ import { addType } from "./protobuf-schema"
50
29
 
51
30
  // ── Utility messages ──
52
31
 
@@ -1809,8 +1788,8 @@ export function createMessageTypes(): protobuf.Root {
1809
1788
  ])
1810
1789
 
1811
1790
  addType(root, "CancelAction", [
1812
- // Cursor CLI CancelAction field #1 is the interruption reason, not an id.
1813
- { id: 1, name: "reason", type: "string" },
1791
+ // `agent.proto` declares CancelAction empty (oneof presence is the signal);
1792
+ // the reason travels on the stream, not in the message.
1814
1793
  ])
1815
1794
 
1816
1795
  // Deferred answers for an AskQuestion the client already replied to with
@@ -1922,8 +1901,24 @@ export function createMessageTypes(): protobuf.Root {
1922
1901
  { id: 8, name: "turns", type: "ConversationTurn", repeated: true },
1923
1902
  ])
1924
1903
 
1904
+ // `agent.proto` ModelDetails.thinking_details — empty in the current build;
1905
+ // declared for wire-shape completeness.
1906
+ addType(root, "ThinkingDetails", [])
1907
+
1908
+ // `agent.proto` AgentRunRequest.skill_options (deprecated upstream; kept for
1909
+ // wire-shape completeness).
1910
+ addType(root, "SkillOptions", [
1911
+ { id: 1, name: "skill_descriptors", type: "SkillDescriptor", repeated: true },
1912
+ ])
1913
+
1925
1914
  addType(root, "ModelDetails", [
1926
1915
  { id: 1, name: "model_id", type: "string" },
1916
+ { id: 2, name: "thinking_details", type: "ThinkingDetails" },
1917
+ { id: 3, name: "display_model_id", type: "string" },
1918
+ { id: 4, name: "display_name", type: "string" },
1919
+ { id: 5, name: "display_name_short", type: "string" },
1920
+ { id: 6, name: "aliases", type: "string", repeated: true },
1921
+ { id: 7, name: "max_mode", type: "bool" },
1927
1922
  ])
1928
1923
 
1929
1924
  addType(root, "McpTools", [
@@ -1933,15 +1928,13 @@ export function createMessageTypes(): protobuf.Root {
1933
1928
  addType(root, "AgentRunRequest", [
1934
1929
  { id: 1, name: "conversation_state", type: "bytes" },
1935
1930
  { id: 2, name: "action", type: "ConversationAction" },
1931
+ { id: 3, name: "model_details", type: "ModelDetails" },
1936
1932
  { id: 4, name: "mcp_tools", type: "McpTools" },
1937
1933
  { id: 5, name: "conversation_id", type: "string" },
1934
+ { id: 6, name: "mcp_file_system_options", type: "McpFileSystemOptions" },
1935
+ { id: 7, name: "skill_options", type: "SkillOptions" },
1938
1936
  { id: 8, name: "custom_system_prompt", type: "string" },
1939
1937
  { id: 9, name: "requested_model", type: "RequestedModel" },
1940
- { id: 10, name: "unknown_flag", type: "uint32" },
1941
- { id: 12, name: "field_12", type: "uint32" },
1942
- { id: 14, name: "selected_subagent_models", type: "RequestedModel", repeated: true },
1943
- { id: 16, name: "conversation_group_id", type: "string" },
1944
- { id: 25, name: "run_id", type: "string" },
1945
1938
  ])
1946
1939
 
1947
1940
  // ── Client heartbeat ──
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared protobufjs schema-builder helpers.
3
+ *
4
+ * Extracted verbatim from the vendored protocol modules that each carried the
5
+ * same implementation: `cursor/protocol/messages.ts` (vendored from
6
+ * `cursor-opencode-provider`, MIT) and `devin/protocol/devin-proto.ts`
7
+ * (vendored from `oh-my-pi`, MIT). The original license texts remain in those
8
+ * files; this module exists so future schema additions have one place to fix.
9
+ */
10
+
11
+ import protobuf from "protobufjs";
12
+
13
+ export type FieldDef = { id: number; name: string; type: string; repeated?: boolean };
14
+ export type OneofDef = { name: string; fields: string[] };
15
+
16
+ /** Create a root Type with fields and optional oneofs, and register it. */
17
+ export function addType(
18
+ root: protobuf.Root,
19
+ name: string,
20
+ fields: FieldDef[],
21
+ oneofs?: OneofDef[],
22
+ ): protobuf.Type {
23
+ const t = new protobuf.Type(name);
24
+ for (const f of fields) {
25
+ t.add(new protobuf.Field(f.name, f.id, f.type, f.repeated ? "repeated" : undefined));
26
+ }
27
+ for (const o of oneofs ?? []) {
28
+ t.add(new protobuf.OneOf(o.name, o.fields));
29
+ }
30
+ root.add(t);
31
+ return t;
32
+ }
33
+
34
+ /** Register an enum on the root. */
35
+ export function addEnum(root: protobuf.Root, name: string, values: Record<string, number>): void {
36
+ root.add(new protobuf.Enum(name, values));
37
+ }
@@ -0,0 +1,149 @@
1
+ // DeepAI model catalog + discovery.
2
+ //
3
+ // All 22 rows below were fetched live from `GET /deepai_code/models` on
4
+ // 2026-11-11 (see `documentation/research/deepai/2026-11-11-deepai-code-live-wire-verification.md`).
5
+ // The 11 zero-Theos rows carry the daily free-tier allowance (`freeTier: true`
6
+ // + `free: true` — they bill zero and do not draw from the balance). The
7
+ // metered rows keep their `theosPerRequest` price as a per-request cost
8
+ // estimate for the operator.
9
+ //
10
+ // Wire routing: every row is a chat-wire model except `gpt-6-astra`, which the
11
+ // upstream serves only on `/responses` (verified live: it answers 400
12
+ // `model_not_found` on `/chat/completions`, and the rest answer 400 on
13
+ // `/responses`).
14
+ import type { ModelDefinition } from "../../provider-model-definition";
15
+ import { defineModel } from "../../provider-model-definition";
16
+ import {
17
+ DEEPAI_CHAT_PATH,
18
+ DEEPAI_HEADER_INSTANCE,
19
+ DEEPAI_HEADER_THEOS,
20
+ DEEPAI_LANE_VERSION,
21
+ DEEPAI_MODELS_PATH,
22
+ DEEPAI_RESPONSES_PATH,
23
+ deepAIInstanceId,
24
+ } from "./deepai-common";
25
+
26
+ interface DeepAIRosterRow {
27
+ readonly id: string;
28
+ readonly name: string;
29
+ readonly reasoning: boolean;
30
+ readonly vision: boolean;
31
+ readonly ctx: number;
32
+ readonly out: number;
33
+ readonly theosPerRequest: number;
34
+ readonly responsesWire?: boolean;
35
+ }
36
+
37
+ const DEEPAI_ROSTER: readonly DeepAIRosterRow[] = [
38
+ { id: "glm-5.3-flash", name: "GLM 5.3 Flash", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
39
+ { id: "deepseek-v4.1-flash", name: "DeepSeek V4.1 Flash 1017", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
40
+ { id: "mimo-2.6-flash", name: "MiMo 2.6 Flash", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
41
+ { id: "qwen-3.8-flash", name: "Qwen 3.8 Flash", reasoning: true, vision: true, ctx: 991_000, out: 128_000, theosPerRequest: 0 },
42
+ { id: "minimax-m3.1-flash", name: "MiniMax M3.1 Flash", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
43
+ { id: "solar-mini-4", name: "Solar Mini 4", reasoning: true, vision: false, ctx: 524_288, out: 131_072, theosPerRequest: 0 },
44
+ { id: "gpt-6-luna", name: "GPT-6 Luna", reasoning: true, vision: true, ctx: 1_048_576, out: 128_000, theosPerRequest: 0 },
45
+ { id: "mimo-2.6-pro", name: "MiMo 2.6 Pro", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
46
+ { id: "crouton-alpha", name: "Crouton Alpha", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
47
+ { id: "glyph-cluster", name: "Glyph Cluster", reasoning: true, vision: false, ctx: 256_000, out: 131_072, theosPerRequest: 0 },
48
+ { id: "deepai-cyber", name: "DeepAI Cyber", reasoning: true, vision: false, ctx: 1_048_576, out: 131_072, theosPerRequest: 0 },
49
+ { id: "minimax-m3", name: "MiniMax M3", reasoning: true, vision: false, ctx: 512_000, out: 131_000, theosPerRequest: 2 },
50
+ { id: "gpt-6.1-sol", name: "GPT-6.1 Sol", reasoning: true, vision: true, ctx: 1_048_576, out: 128_000, theosPerRequest: 10 },
51
+ { id: "gemini-4-argon", name: "Gemini 4 Argon", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 10 },
52
+ { id: "glm-5.3", name: "GLM 5.3", reasoning: true, vision: false, ctx: 1_048_576, out: 131_072, theosPerRequest: 3 },
53
+ { id: "kimi-k3", name: "Kimi K3", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 3 },
54
+ { id: "muse-spark-1.3", name: "Muse Spark 1.3", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 6 },
55
+ { id: "claude-opus-5-5", name: "Claude Opus 5.5", reasoning: true, vision: true, ctx: 1_000_000, out: 64_000, theosPerRequest: 15 },
56
+ { id: "muse-wonder", name: "Muse Wonder", reasoning: true, vision: true, ctx: 1_048_576, out: 131_072, theosPerRequest: 15 },
57
+ { id: "qwen-3.8-max-prime", name: "Qwen 3.8 Max Prime", reasoning: true, vision: true, ctx: 1_000_000, out: 131_072, theosPerRequest: 15 },
58
+ { id: "claude-fable-5-2", name: "Claude Fable 5.2", reasoning: true, vision: true, ctx: 1_000_000, out: 64_000, theosPerRequest: 20 },
59
+ { id: "gpt-6-astra", name: "GPT-6 Astra", reasoning: true, vision: true, ctx: 1_048_576, out: 128_000, theosPerRequest: 50, responsesWire: true },
60
+ ];
61
+
62
+ function rowToModel(row: DeepAIRosterRow): ModelDefinition {
63
+ const free = row.theosPerRequest === 0;
64
+ return defineModel({
65
+ id: row.id,
66
+ providerId: "deepai",
67
+ wireFamily: row.responsesWire === true ? "responses" : "chat",
68
+ endpoint: row.responsesWire === true ? DEEPAI_RESPONSES_PATH : DEEPAI_CHAT_PATH,
69
+ ctx: row.ctx,
70
+ out: row.out,
71
+ vision: row.vision,
72
+ reasoning: row.reasoning,
73
+ toolCall: true,
74
+ ...(free ? { free: true, freeTier: true } : {}),
75
+ });
76
+ }
77
+
78
+ /** Static roster — the live-verified free tier plus metered rows. */
79
+ export const DEEPAI_DEFAULT_MODELS: readonly ModelDefinition[] =
80
+ DEEPAI_ROSTER.map(rowToModel);
81
+
82
+ /** Live `/deepai_code/models` listing. */
83
+ export async function discoverDeepAIModels(options: {
84
+ readonly baseUrl: string;
85
+ readonly fetcher?: typeof fetch;
86
+ }): Promise<readonly ModelDefinition[] | null> {
87
+ const fetcher = options.fetcher ?? fetch;
88
+ const url = `${options.baseUrl.replace(/\/+$/, "")}${DEEPAI_MODELS_PATH}`;
89
+ try {
90
+ const response = await fetcher(url, {
91
+ headers: {
92
+ accept: "application/json",
93
+ // The catalog is lane-aware: the 22-row roster only comes back with the
94
+ // lane headers (verified live 2026-11-11 — bare GET returns a smaller
95
+ // 9-row default roster).
96
+ [DEEPAI_HEADER_THEOS]: DEEPAI_LANE_VERSION,
97
+ [DEEPAI_HEADER_INSTANCE]: deepAIInstanceId(),
98
+ },
99
+ signal: AbortSignal.timeout(10_000),
100
+ });
101
+ if (!response.ok) return null;
102
+ const payload = (await response.json()) as unknown;
103
+ const list = payload !== null && typeof payload === "object" && Array.isArray((payload as { models?: unknown }).models)
104
+ ? ((payload as { models: unknown }).models as readonly Record<string, unknown>[])
105
+ : null;
106
+ if (list === null || list.length === 0) return null;
107
+ const rows: DeepAIRosterRow[] = [];
108
+ for (const entry of list) {
109
+ const id = typeof entry.id === "string" && entry.id.trim() ? entry.id.trim() : null;
110
+ if (id === null) continue;
111
+ // `theosPerRequest` arrives as a string ("0", "2", "50") or a number.
112
+ const theosNumber = parseTheosAmount(entry.theosPerRequest);
113
+ const input = entry.input;
114
+ const hasImage = Array.isArray(input) && input.some((m) => m === "image");
115
+ rows.push({
116
+ id,
117
+ name: typeof entry.name === "string" ? entry.name : id,
118
+ reasoning: entry.reasoning === true,
119
+ vision: hasImage,
120
+ ctx: positiveInt(entry.contextWindow) ?? positiveInt(entry.context_window) ?? 1_048_576,
121
+ out: positiveInt(entry.maxTokens) ?? positiveInt(entry.max_completion_tokens) ?? 131_072,
122
+ theosPerRequest: theosNumber,
123
+ responsesWire: entry.api === "openai-responses",
124
+ });
125
+ }
126
+ if (rows.length === 0) return null;
127
+ return rows.map(rowToModel);
128
+ } catch {
129
+ return null;
130
+ }
131
+ }
132
+
133
+ function positiveInt(value: unknown): number | null {
134
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : null;
135
+ }
136
+
137
+ /** Parses `theosPerRequest` — a numeric string ("0"/"50") or a number. */
138
+ function parseTheosAmount(value: unknown): number {
139
+ if (typeof value === "number" && Number.isFinite(value)) return Math.max(0, value);
140
+ if (typeof value === "string") {
141
+ const trimmed = value.trim();
142
+ if (/^\d+(?:\.\d+)?$/.test(trimmed)) {
143
+ const n = Number(trimmed);
144
+ if (Number.isFinite(n)) return Math.max(0, n);
145
+ }
146
+ }
147
+ // Absent / unparseable means the server did not meter it → free.
148
+ return 0;
149
+ }
@@ -0,0 +1,145 @@
1
+ // DeepAI shared wire helpers.
2
+ //
3
+ // Wire facts reconstructed from the DeepAI Code 0.3.35 bundle and verified
4
+ // live 2026-11-11 (see `documentation/research/deepai/`):
5
+ //
6
+ // - Model base is `https://api.deepai.org/deepai_code`; the sign-in flow
7
+ // (`/deepai_code/desktop_auth/`) returns an opaque `api_key`.
8
+ // - Every model call carries:
9
+ // `X-DeepAI-Code-Theos: 4` (lane version)
10
+ // `X-DeepAI-Code-Instance` (16 random bytes hex, per process)
11
+ // `X-DeepAI-Code-Machine` (sha256hex of the machine id)
12
+ // `Api-Key: <api_key>` (the credential; NOT a Bearer)
13
+ // - The machine header is a digest of a platform identifier (SMBIOS UUID /
14
+ // MachineGuid / `/etc/machine-id`); the raw identifier never leaves the
15
+ // machine. The grant is bound to the account, not the machine, so a
16
+ // missing/mangled machine header is tolerated (verified live).
17
+ import { randomBytes } from "node:crypto";
18
+ import { createHash } from "node:crypto";
19
+ import { execFile } from "node:child_process";
20
+ import { readFileSync } from "node:fs";
21
+
22
+ export const DEEPAI_PROVIDER_ID = "deepai" as const;
23
+ export const DEEPAI_API_ORIGIN = "https://api.deepai.org";
24
+ export const DEEPAI_MODEL_BASE = `${DEEPAI_API_ORIGIN}/deepai_code`;
25
+
26
+ export const DEEPAI_LANE_VERSION = "4";
27
+ export const DEEPAI_HEADER_THEOS = "X-DeepAI-Code-Theos";
28
+ export const DEEPAI_HEADER_INSTANCE = "X-DeepAI-Code-Instance";
29
+ export const DEEPAI_HEADER_MACHINE = "X-DeepAI-Code-Machine";
30
+ export const DEEPAI_HEADER_API_KEY = "Api-Key";
31
+
32
+ export const DEEPAI_CHAT_PATH = "/deepai_code/chat/completions";
33
+ export const DEEPAI_RESPONSES_PATH = "/deepai_code/responses";
34
+ export const DEEPAI_MODELS_PATH = "/deepai_code/models";
35
+ export const DEEPAI_THEOS_PATH = "/deepai_code/theos";
36
+ export const DEEPAI_USAGE_SUMMARY_PATH = "/get_usage_summary";
37
+ export const DEEPAI_SIGNIN_PATH = "/deepai_code/desktop_auth/";
38
+ export const DEEPAI_EXCHANGE_PATH = "/deepai_code/desktop_auth/exchange/";
39
+
40
+ const UUID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
41
+ const SMBIOS_PLACEHOLDERS = new Set([
42
+ "00000000-0000-0000-0000-000000000000",
43
+ "ffffffff-ffff-ffff-ffff-ffffffffffff",
44
+ "03000200-0400-0500-0006-000700080009",
45
+ ]);
46
+
47
+ function run(file: string, args: readonly string[]): Promise<string> {
48
+ return new Promise((resolve) => {
49
+ execFile(
50
+ file,
51
+ [...args],
52
+ { encoding: "utf8", timeout: 10_000, windowsHide: true },
53
+ (error, stdout) => resolve(error ? "" : stdout),
54
+ );
55
+ });
56
+ }
57
+
58
+ function parseSmbiosUUID(output: string): string | null {
59
+ const uuid = UUID_RE.exec(output)?.[0]?.toLowerCase() ?? null;
60
+ return uuid && !SMBIOS_PLACEHOLDERS.has(uuid) ? uuid : null;
61
+ }
62
+
63
+ function parseMachineGuid(regQuery: string): string | null {
64
+ const match = /MachineGuid\s+REG_SZ\s+(\S+)/.exec(regQuery);
65
+ return match?.[1] && UUID_RE.test(match[1]) ? match[1].toLowerCase() : null;
66
+ }
67
+
68
+ function parseLinuxMachineId(file: string): string | null {
69
+ const id = file.trim().toLowerCase();
70
+ return /^[0-9a-f]{32}$/.test(id) && !/^0+$/.test(id) ? id : null;
71
+ }
72
+
73
+ function detectMachineId(): Promise<string | null> {
74
+ try {
75
+ if (process.platform === "win32") {
76
+ return (async () => {
77
+ const smbios = await run("powershell", [
78
+ "-NoProfile",
79
+ "-NonInteractive",
80
+ "-Command",
81
+ "(Get-CimInstance Win32_ComputerSystemProduct).UUID",
82
+ ]);
83
+ const uuid = parseSmbiosUUID(smbios);
84
+ if (uuid) return uuid;
85
+ const guid = await run("reg", [
86
+ "query",
87
+ "HKLM\\SOFTWARE\\Microsoft\\Cryptography",
88
+ "/v",
89
+ "MachineGuid",
90
+ ]);
91
+ return parseMachineGuid(guid);
92
+ })();
93
+ }
94
+ if (process.platform === "darwin") {
95
+ return (async () => {
96
+ const ioreg = await run("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"]);
97
+ const match = /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(ioreg);
98
+ return match?.[1] && UUID_RE.test(match[1]) ? match[1].toLowerCase() : null;
99
+ })();
100
+ }
101
+ for (const path of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
102
+ try {
103
+ const id = parseLinuxMachineId(readFileSync(path, "utf8"));
104
+ if (id) return Promise.resolve(id);
105
+ } catch {
106
+ // try the next path
107
+ }
108
+ }
109
+ return Promise.resolve(null);
110
+ } catch {
111
+ return Promise.resolve(null);
112
+ }
113
+ }
114
+
115
+ let machineDigestPromise: Promise<string | null> | undefined;
116
+
117
+ /** sha256hex(machineId), computed once per process; null when unreadable. */
118
+ export function deepAIMachineDigest(): Promise<string | null> {
119
+ machineDigestPromise ??= detectMachineId().then(
120
+ (raw) => (raw === null ? null : createHash("sha256").update(raw).digest("hex")),
121
+ );
122
+ return machineDigestPromise;
123
+ }
124
+
125
+ /** Fresh per-process instance id (16 random bytes hex). */
126
+ export function deepAIInstanceId(): string {
127
+ return randomBytes(16).toString("hex");
128
+ }
129
+
130
+ /**
131
+ * Baseline DeepAI headers shared by every model API call. `apiKey` is the
132
+ * account credential (the sign-in `api_key`); omit it for unauthenticated
133
+ * reads (model catalog).
134
+ */
135
+ export async function deepAIBaseHeaders(apiKey?: string): Promise<Record<string, string>> {
136
+ const headers: Record<string, string> = {
137
+ "content-type": "application/json",
138
+ [DEEPAI_HEADER_THEOS]: DEEPAI_LANE_VERSION,
139
+ [DEEPAI_HEADER_INSTANCE]: deepAIInstanceId(),
140
+ };
141
+ const machine = await deepAIMachineDigest();
142
+ if (machine !== null) headers[DEEPAI_HEADER_MACHINE] = machine;
143
+ if (apiKey !== undefined && apiKey.length > 0) headers[DEEPAI_HEADER_API_KEY] = apiKey;
144
+ return headers;
145
+ }
@@ -0,0 +1,129 @@
1
+ // DeepAI browser login client.
2
+ //
3
+ // DeepAI's desktop sign-in is a loopback flow: the app builds
4
+ // `https://api.deepai.org/deepai_code/desktop_auth/?state=<state>&port=<port>`,
5
+ // the operator signs in in the browser, and the server redirects to
6
+ // `http://127.0.0.1:<port>/callback?code=<code>&state=<state>`. The code is
7
+ // then exchanged at `/deepai_code/desktop_auth/exchange/` for an opaque
8
+ // `api_key`. There is no PKCE verifier and no refresh token — the key is
9
+ // long-lived and the flow is re-run when needed.
10
+ //
11
+ // Verified live 2026-11-11: the exchange answers 200 with
12
+ // `{ api_key, username, is_pro }`, and the api_key authenticates the model
13
+ // API via the `Api-Key` header (a Bearer or `x-api-key` spelling is rejected
14
+ // with 401).
15
+ import { randomBytes } from "node:crypto";
16
+ import { OAuthClient } from "../../authentication/oauth-client";
17
+ import type {
18
+ OAuthAuthorizeRequest,
19
+ OAuthCodeExchangeContext,
20
+ OAuthExchangeResult,
21
+ OAuthImportInput,
22
+ } from "../../authentication/oauth-flow-store";
23
+ import {
24
+ DEEPAI_API_ORIGIN,
25
+ DEEPAI_EXCHANGE_PATH,
26
+ DEEPAI_THEOS_PATH,
27
+ deepAIBaseHeaders,
28
+ } from "./deepai-common";
29
+
30
+ const DEEPAI_LOGIN_TTL_MS = 365 * 24 * 60 * 60 * 1000;
31
+
32
+ function loopbackPortFromRedirectUri(redirectUri: string): number {
33
+ const url = new URL(redirectUri);
34
+ const port = Number(url.port);
35
+ if (!Number.isInteger(port) || port <= 0 || port > 65_535) {
36
+ throw new Error("deepai: redirect URI names an invalid loopback port");
37
+ }
38
+ return port;
39
+ }
40
+
41
+ export class DeepAIOAuthClient extends OAuthClient {
42
+ override readonly supportsDeviceCode = false;
43
+ override readonly supportsBrowserCode = true;
44
+ override readonly providerLabel = "deepai";
45
+ override readonly clientId = "";
46
+ override readonly tokenUrl = "";
47
+ override readonly scopes = "";
48
+
49
+ /**
50
+ * DeepAI's hosted sign-in validates the state as 32 hex characters; the
51
+ * shared base64url state (which can contain `-`/`_`) is rejected with
52
+ * "Invalid desktop sign-in request".
53
+ */
54
+ override generateState(): string {
55
+ return randomBytes(16).toString("hex");
56
+ }
57
+
58
+ /** DeepAI's hosted sign-in URL, carrying the loopback port + state. */
59
+ override buildAuthorizeUrl(request: OAuthAuthorizeRequest): string {
60
+ const port = loopbackPortFromRedirectUri(request.redirectUri);
61
+ const signIn = new URL(DEEPAI_EXCHANGE_PATH.replace("/desktop_auth/exchange/", "/desktop_auth/"), DEEPAI_API_ORIGIN);
62
+ signIn.search = "";
63
+ signIn.searchParams.set("state", request.state);
64
+ signIn.searchParams.set("port", String(port));
65
+ return signIn.toString();
66
+ }
67
+
68
+ /** Exchanges the callback code for the DeepAI api_key. */
69
+ override async exchangeCode(
70
+ code: string,
71
+ _codeVerifier: string,
72
+ _redirectUri: string,
73
+ _state?: string,
74
+ _context?: OAuthCodeExchangeContext,
75
+ ): Promise<OAuthExchangeResult> {
76
+ const response = await this.fetchFn(new URL(DEEPAI_EXCHANGE_PATH, DEEPAI_API_ORIGIN), {
77
+ method: "POST",
78
+ headers: { "content-type": "application/json", accept: "application/json" },
79
+ body: JSON.stringify({ code }),
80
+ });
81
+ if (!response.ok) {
82
+ const text = await response.text().catch(() => "");
83
+ throw new Error(`deepai sign-in exchange failed: HTTP ${response.status} ${text.slice(0, 300)}`);
84
+ }
85
+ return this.parseExchangeBody(await response.json());
86
+ }
87
+
88
+ /** Accepts a pasted DeepAI api_key, validated against `/theos`. */
89
+ async importCredential(input: OAuthImportInput): Promise<OAuthExchangeResult> {
90
+ const apiKey = input.credential.trim();
91
+ if (!apiKey) throw new Error("deepai: pasted API key is empty");
92
+ const headers = await deepAIBaseHeaders(apiKey);
93
+ const response = await this.fetchFn(new URL(DEEPAI_THEOS_PATH, DEEPAI_API_ORIGIN), {
94
+ method: "GET",
95
+ headers,
96
+ });
97
+ if (!response.ok) {
98
+ throw new Error(
99
+ `deepai: API key validation failed (HTTP ${response.status}) — paste a key minted by the DeepAI sign-in flow`,
100
+ );
101
+ }
102
+ return {
103
+ access: apiKey,
104
+ refresh: apiKey,
105
+ expiresAt: new Date(Date.now() + DEEPAI_LOGIN_TTL_MS),
106
+ accountLabel: input.accountLabel || "deepai",
107
+ auth_state: { via: "import" },
108
+ };
109
+ }
110
+
111
+ private parseExchangeBody(body: unknown): OAuthExchangeResult {
112
+ const record = body !== null && typeof body === "object" ? (body as Record<string, unknown>) : null;
113
+ const apiKey = typeof record?.api_key === "string" ? record.api_key.trim() : "";
114
+ if (!apiKey || /[\r\n]/.test(apiKey)) {
115
+ throw new Error("deepai: sign-in response did not carry a valid api_key");
116
+ }
117
+ const username = typeof record?.username === "string" ? record.username : "";
118
+ return {
119
+ access: apiKey,
120
+ refresh: apiKey,
121
+ expiresAt: new Date(Date.now() + DEEPAI_LOGIN_TTL_MS),
122
+ ...(username ? { accountLabel: username, accountName: username } : {}),
123
+ auth_state: { is_pro: record?.is_pro === true },
124
+ };
125
+ }
126
+ }
127
+
128
+ /** Shared DeepAI browser-login client instance (registry-facing). */
129
+ export const deepAIOAuthClient = new DeepAIOAuthClient();
@@ -0,0 +1,97 @@
1
+ // DeepAI quota collector.
2
+ //
3
+ // Reads the account's DeepAI allowance from `GET /deepai_code/theos`
4
+ // (`balance`/`granted`/`refresh_at`), which is the daily free-tier grant. The
5
+ // entitlement surface (`/get_usage_summary`, `is_pro`) is probed second to
6
+ // distinguish a free vs pro account. Both calls require the `Api-Key` header
7
+ // (not Bearer).
8
+ import type {
9
+ FetchLike,
10
+ ProviderQuotaResult,
11
+ ProviderQuotaWindow,
12
+ } from "../../quota/quota-contracts";
13
+ import { cleanError, number, percentWindow, text } from "../../quota/quota-contracts";
14
+ import type { QuotaCollectionContext } from "../../quota/quota-support";
15
+ import {
16
+ DEEPAI_API_ORIGIN,
17
+ DEEPAI_THEOS_PATH,
18
+ DEEPAI_USAGE_SUMMARY_PATH,
19
+ deepAIBaseHeaders,
20
+ } from "./deepai-common";
21
+
22
+ const LABEL = "DeepAI";
23
+
24
+ async function readJson(
25
+ url: string,
26
+ headers: Record<string, string>,
27
+ fetcher: FetchLike,
28
+ ): Promise<Record<string, unknown> | null> {
29
+ try {
30
+ const res = await fetcher(url, {
31
+ method: "GET",
32
+ headers,
33
+ signal: AbortSignal.timeout(15_000),
34
+ });
35
+ if (!res.ok) return null;
36
+ const parsed = (await res.json()) as unknown;
37
+ return parsed !== null && typeof parsed === "object" ? (parsed as Record<string, unknown>) : null;
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Reads the DeepAI allowance and returns a normalized result.
45
+ *
46
+ * The Daily Theos window is pooled (the balance funds model calls) with the
47
+ * daily grant as the ceiling and the account's `refresh_at` as the reset. The
48
+ * plan is `free` when the allowance is enabled, `pro` when `is_pro` reads
49
+ * true from the usage summary.
50
+ */
51
+ export async function fetchDeepAIQuota(
52
+ credential: string,
53
+ fetcher: FetchLike,
54
+ _context?: QuotaCollectionContext,
55
+ ): Promise<ProviderQuotaResult> {
56
+ try {
57
+ const apiKey = text(credential);
58
+ if (!apiKey) {
59
+ return { source: LABEL, plan: null, windows: [], error: "DeepAI credential missing" };
60
+ }
61
+ const headers = await deepAIBaseHeaders(apiKey);
62
+ const theos = await readJson(`${DEEPAI_API_ORIGIN}${DEEPAI_THEOS_PATH}`, headers, fetcher);
63
+ if (!theos) {
64
+ return { source: LABEL, plan: null, windows: [], error: "DeepAI /theos endpoint unavailable" };
65
+ }
66
+
67
+ const windows: ProviderQuotaWindow[] = [];
68
+ const enabled = theos.enabled === true;
69
+ const granted = number(theos.granted);
70
+ const balance = number(theos.balance);
71
+ if (enabled && granted !== null && granted > 0) {
72
+ const used = balance === null ? null : Math.max(0, granted - balance);
73
+ const resetsAt =
74
+ typeof theos.refresh_at === "string" && Number.isFinite(Date.parse(theos.refresh_at))
75
+ ? new Date(theos.refresh_at).toISOString()
76
+ : null;
77
+ windows.push(
78
+ percentWindow(
79
+ "theos_daily",
80
+ "Daily Theos",
81
+ used === null ? null : (used / granted) * 100,
82
+ resetsAt,
83
+ used,
84
+ granted,
85
+ "pooled",
86
+ ),
87
+ );
88
+ }
89
+
90
+ const summary = await readJson(`${DEEPAI_API_ORIGIN}${DEEPAI_USAGE_SUMMARY_PATH}`, headers, fetcher);
91
+ const isPro = summary?.is_pro === true;
92
+ const plan = enabled ? (isPro ? "pro" : "free") : null;
93
+ return { source: LABEL, plan, windows, error: null };
94
+ } catch (error) {
95
+ return { source: LABEL, plan: null, windows: [], error: cleanError(error) };
96
+ }
97
+ }