@sayknow-cli/ai 0.2.2

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 (361) hide show
  1. package/CHANGELOG.md +2788 -0
  2. package/README.md +1183 -0
  3. package/dist/types/api-registry.d.ts +30 -0
  4. package/dist/types/auth-broker/client.d.ts +66 -0
  5. package/dist/types/auth-broker/index.d.ts +5 -0
  6. package/dist/types/auth-broker/refresher.d.ts +25 -0
  7. package/dist/types/auth-broker/remote-store.d.ts +96 -0
  8. package/dist/types/auth-broker/server.d.ts +32 -0
  9. package/dist/types/auth-broker/types.d.ts +105 -0
  10. package/dist/types/auth-broker/wire-schemas.d.ts +412 -0
  11. package/dist/types/auth-gateway/http.d.ts +39 -0
  12. package/dist/types/auth-gateway/index.d.ts +3 -0
  13. package/dist/types/auth-gateway/server.d.ts +17 -0
  14. package/dist/types/auth-gateway/types.d.ts +115 -0
  15. package/dist/types/auth-storage.d.ts +660 -0
  16. package/dist/types/cli.d.ts +2 -0
  17. package/dist/types/index.d.ts +51 -0
  18. package/dist/types/model-cache.d.ts +17 -0
  19. package/dist/types/model-manager.d.ts +62 -0
  20. package/dist/types/model-thinking.d.ts +74 -0
  21. package/dist/types/models.d.ts +12 -0
  22. package/dist/types/provider-details.d.ts +24 -0
  23. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  24. package/dist/types/provider-models/descriptors.d.ts +48 -0
  25. package/dist/types/provider-models/google.d.ts +20 -0
  26. package/dist/types/provider-models/index.d.ts +5 -0
  27. package/dist/types/provider-models/ollama.d.ts +7 -0
  28. package/dist/types/provider-models/openai-compat.d.ts +244 -0
  29. package/dist/types/provider-models/special.d.ts +16 -0
  30. package/dist/types/providers/amazon-bedrock.d.ts +60 -0
  31. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  32. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  33. package/dist/types/providers/anthropic.d.ts +198 -0
  34. package/dist/types/providers/aws-credentials.d.ts +43 -0
  35. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  36. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  37. package/dist/types/providers/azure-openai-responses.d.ts +15 -0
  38. package/dist/types/providers/composer-discipline.d.ts +26 -0
  39. package/dist/types/providers/cursor/gen/agent_pb.d.ts +13022 -0
  40. package/dist/types/providers/cursor.d.ts +44 -0
  41. package/dist/types/providers/error-message.d.ts +27 -0
  42. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  43. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  44. package/dist/types/providers/google-auth.d.ts +24 -0
  45. package/dist/types/providers/google-gemini-cli.d.ts +72 -0
  46. package/dist/types/providers/google-gemini-headers.d.ts +18 -0
  47. package/dist/types/providers/google-shared.d.ts +173 -0
  48. package/dist/types/providers/google-types.d.ts +138 -0
  49. package/dist/types/providers/google-vertex.d.ts +7 -0
  50. package/dist/types/providers/google.d.ts +4 -0
  51. package/dist/types/providers/grammar.d.ts +1 -0
  52. package/dist/types/providers/kimi.d.ts +27 -0
  53. package/dist/types/providers/mock.d.ts +175 -0
  54. package/dist/types/providers/ollama.d.ts +41 -0
  55. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  56. package/dist/types/providers/openai-chat-server-schema.d.ts +815 -0
  57. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  58. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  59. package/dist/types/providers/openai-codex/request-transformer.d.ts +49 -0
  60. package/dist/types/providers/openai-codex/response-handler.d.ts +17 -0
  61. package/dist/types/providers/openai-codex-responses.d.ts +67 -0
  62. package/dist/types/providers/openai-completions-compat.d.ts +27 -0
  63. package/dist/types/providers/openai-completions.d.ts +33 -0
  64. package/dist/types/providers/openai-request-transform.d.ts +4 -0
  65. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  66. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  67. package/dist/types/providers/openai-responses-shared.d.ts +89 -0
  68. package/dist/types/providers/openai-responses.d.ts +32 -0
  69. package/dist/types/providers/pi-native-client.d.ts +13 -0
  70. package/dist/types/providers/pi-native-server.d.ts +68 -0
  71. package/dist/types/providers/register-builtins.d.ts +31 -0
  72. package/dist/types/providers/synthetic.d.ts +26 -0
  73. package/dist/types/providers/transform-messages.d.ts +14 -0
  74. package/dist/types/providers/vision-guard.d.ts +8 -0
  75. package/dist/types/rate-limit-utils.d.ts +19 -0
  76. package/dist/types/stream.d.ts +43 -0
  77. package/dist/types/types.d.ts +811 -0
  78. package/dist/types/usage/claude.d.ts +3 -0
  79. package/dist/types/usage/gemini.d.ts +2 -0
  80. package/dist/types/usage/github-copilot.d.ts +7 -0
  81. package/dist/types/usage/google-antigravity.d.ts +2 -0
  82. package/dist/types/usage/grok-cli.d.ts +10 -0
  83. package/dist/types/usage/kimi.d.ts +2 -0
  84. package/dist/types/usage/minimax-code.d.ts +2 -0
  85. package/dist/types/usage/openai-codex.d.ts +3 -0
  86. package/dist/types/usage/shared.d.ts +1 -0
  87. package/dist/types/usage/zai.d.ts +2 -0
  88. package/dist/types/usage.d.ts +258 -0
  89. package/dist/types/utils/abort.d.ts +19 -0
  90. package/dist/types/utils/anthropic-auth.d.ts +31 -0
  91. package/dist/types/utils/discovery/antigravity.d.ts +61 -0
  92. package/dist/types/utils/discovery/codex.d.ts +38 -0
  93. package/dist/types/utils/discovery/cursor.d.ts +23 -0
  94. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  95. package/dist/types/utils/discovery/index.d.ts +4 -0
  96. package/dist/types/utils/discovery/openai-compatible.d.ts +74 -0
  97. package/dist/types/utils/event-stream.d.ts +33 -0
  98. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  99. package/dist/types/utils/foundry.d.ts +1 -0
  100. package/dist/types/utils/h2-fetch.d.ts +22 -0
  101. package/dist/types/utils/http-inspector.d.ts +35 -0
  102. package/dist/types/utils/idle-iterator.d.ts +67 -0
  103. package/dist/types/utils/json-parse.d.ts +10 -0
  104. package/dist/types/utils/oauth/alibaba-coding-plan.d.ts +18 -0
  105. package/dist/types/utils/oauth/anthropic.d.ts +22 -0
  106. package/dist/types/utils/oauth/api-key-login.d.ts +35 -0
  107. package/dist/types/utils/oauth/api-key-validation.d.ts +27 -0
  108. package/dist/types/utils/oauth/callback-server.d.ts +60 -0
  109. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  110. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  111. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  112. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  113. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  114. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  115. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  116. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  117. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  118. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  119. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  120. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  121. package/dist/types/utils/oauth/index.d.ts +38 -0
  122. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  123. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  124. package/dist/types/utils/oauth/kimi.d.ts +21 -0
  125. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  126. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  127. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  128. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  129. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  130. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  131. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  132. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  133. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  134. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  135. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  136. package/dist/types/utils/oauth/perplexity.d.ts +9 -0
  137. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  138. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  139. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  140. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  141. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  142. package/dist/types/utils/oauth/together.d.ts +1 -0
  143. package/dist/types/utils/oauth/types.d.ts +45 -0
  144. package/dist/types/utils/oauth/venice.d.ts +18 -0
  145. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  146. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  147. package/dist/types/utils/oauth/xai.d.ts +30 -0
  148. package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
  149. package/dist/types/utils/oauth/zai.d.ts +18 -0
  150. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  151. package/dist/types/utils/overflow.d.ts +54 -0
  152. package/dist/types/utils/parse-bind.d.ts +23 -0
  153. package/dist/types/utils/provider-response.d.ts +3 -0
  154. package/dist/types/utils/retry-after.d.ts +3 -0
  155. package/dist/types/utils/retry-budget.d.ts +1 -0
  156. package/dist/types/utils/retry.d.ts +26 -0
  157. package/dist/types/utils/schema/adapt.d.ts +24 -0
  158. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  159. package/dist/types/utils/schema/dereference.d.ts +11 -0
  160. package/dist/types/utils/schema/draft.d.ts +10 -0
  161. package/dist/types/utils/schema/equality.d.ts +4 -0
  162. package/dist/types/utils/schema/fields.d.ts +49 -0
  163. package/dist/types/utils/schema/index.d.ts +13 -0
  164. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  165. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  166. package/dist/types/utils/schema/normalize.d.ts +93 -0
  167. package/dist/types/utils/schema/spill.d.ts +8 -0
  168. package/dist/types/utils/schema/stamps.d.ts +25 -0
  169. package/dist/types/utils/schema/types.d.ts +4 -0
  170. package/dist/types/utils/schema/wire.d.ts +54 -0
  171. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  172. package/dist/types/utils/sse-debug.d.ts +10 -0
  173. package/dist/types/utils/tool-call-healing.d.ts +71 -0
  174. package/dist/types/utils/tool-choice-capability.d.ts +41 -0
  175. package/dist/types/utils/tool-choice.d.ts +50 -0
  176. package/dist/types/utils/validation.d.ts +17 -0
  177. package/dist/types/utils.d.ts +34 -0
  178. package/package.json +146 -0
  179. package/src/api-registry.ts +96 -0
  180. package/src/auth-broker/client.ts +358 -0
  181. package/src/auth-broker/index.ts +5 -0
  182. package/src/auth-broker/refresher.ts +127 -0
  183. package/src/auth-broker/remote-store.ts +623 -0
  184. package/src/auth-broker/server.ts +644 -0
  185. package/src/auth-broker/types.ts +127 -0
  186. package/src/auth-broker/wire-schemas.ts +200 -0
  187. package/src/auth-gateway/http.ts +194 -0
  188. package/src/auth-gateway/index.ts +3 -0
  189. package/src/auth-gateway/server.ts +717 -0
  190. package/src/auth-gateway/types.ts +134 -0
  191. package/src/auth-storage.ts +4179 -0
  192. package/src/cli.ts +263 -0
  193. package/src/index.ts +56 -0
  194. package/src/model-cache.ts +129 -0
  195. package/src/model-manager.ts +486 -0
  196. package/src/model-thinking.ts +772 -0
  197. package/src/models.json +75437 -0
  198. package/src/models.json.d.ts +9 -0
  199. package/src/models.ts +82 -0
  200. package/src/prompts/turn-aborted-guidance.md +4 -0
  201. package/src/provider-details.ts +90 -0
  202. package/src/provider-models/bundled-references.ts +38 -0
  203. package/src/provider-models/descriptors.ts +327 -0
  204. package/src/provider-models/google.ts +91 -0
  205. package/src/provider-models/index.ts +5 -0
  206. package/src/provider-models/ollama.ts +153 -0
  207. package/src/provider-models/openai-compat.ts +2352 -0
  208. package/src/provider-models/special.ts +67 -0
  209. package/src/providers/amazon-bedrock.ts +937 -0
  210. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  211. package/src/providers/anthropic-messages-server.ts +677 -0
  212. package/src/providers/anthropic.ts +2940 -0
  213. package/src/providers/aws-credentials.ts +501 -0
  214. package/src/providers/aws-eventstream.ts +185 -0
  215. package/src/providers/aws-sigv4.ts +218 -0
  216. package/src/providers/azure-openai-responses.ts +379 -0
  217. package/src/providers/composer-discipline.ts +41 -0
  218. package/src/providers/cursor/gen/agent_pb.ts +15274 -0
  219. package/src/providers/cursor/proto/agent.proto +3526 -0
  220. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  221. package/src/providers/cursor/proto/buf.yaml +17 -0
  222. package/src/providers/cursor.ts +2671 -0
  223. package/src/providers/error-message.ts +21 -0
  224. package/src/providers/github-copilot-headers.ts +140 -0
  225. package/src/providers/gitlab-duo.ts +372 -0
  226. package/src/providers/google-auth.ts +252 -0
  227. package/src/providers/google-gemini-cli.ts +856 -0
  228. package/src/providers/google-gemini-headers.ts +41 -0
  229. package/src/providers/google-shared.ts +951 -0
  230. package/src/providers/google-types.ts +167 -0
  231. package/src/providers/google-vertex.ts +88 -0
  232. package/src/providers/google.ts +41 -0
  233. package/src/providers/grammar.ts +70 -0
  234. package/src/providers/kimi.ts +52 -0
  235. package/src/providers/mock.ts +500 -0
  236. package/src/providers/ollama.ts +603 -0
  237. package/src/providers/openai-anthropic-shim.ts +138 -0
  238. package/src/providers/openai-chat-server-schema.ts +243 -0
  239. package/src/providers/openai-chat-server.ts +635 -0
  240. package/src/providers/openai-codex/constants.ts +43 -0
  241. package/src/providers/openai-codex/request-transformer.ts +161 -0
  242. package/src/providers/openai-codex/response-handler.ts +81 -0
  243. package/src/providers/openai-codex-responses.ts +2774 -0
  244. package/src/providers/openai-completions-compat.ts +289 -0
  245. package/src/providers/openai-completions.ts +1935 -0
  246. package/src/providers/openai-request-transform.ts +136 -0
  247. package/src/providers/openai-responses-server-schema.ts +290 -0
  248. package/src/providers/openai-responses-server.ts +1190 -0
  249. package/src/providers/openai-responses-shared.ts +800 -0
  250. package/src/providers/openai-responses.ts +738 -0
  251. package/src/providers/pi-native-client.ts +227 -0
  252. package/src/providers/pi-native-server.ts +210 -0
  253. package/src/providers/register-builtins.ts +411 -0
  254. package/src/providers/synthetic.ts +50 -0
  255. package/src/providers/transform-messages.ts +319 -0
  256. package/src/providers/vision-guard.ts +31 -0
  257. package/src/rate-limit-utils.ts +93 -0
  258. package/src/stream.ts +960 -0
  259. package/src/types.ts +967 -0
  260. package/src/usage/claude.ts +431 -0
  261. package/src/usage/gemini.ts +250 -0
  262. package/src/usage/github-copilot.ts +421 -0
  263. package/src/usage/google-antigravity.ts +201 -0
  264. package/src/usage/grok-cli.ts +163 -0
  265. package/src/usage/kimi.ts +271 -0
  266. package/src/usage/minimax-code.ts +31 -0
  267. package/src/usage/openai-codex.ts +503 -0
  268. package/src/usage/shared.ts +10 -0
  269. package/src/usage/zai.ts +247 -0
  270. package/src/usage.ts +183 -0
  271. package/src/utils/abort.ts +51 -0
  272. package/src/utils/anthropic-auth.ts +87 -0
  273. package/src/utils/discovery/antigravity.ts +261 -0
  274. package/src/utils/discovery/codex.ts +371 -0
  275. package/src/utils/discovery/cursor.ts +306 -0
  276. package/src/utils/discovery/gemini.ts +248 -0
  277. package/src/utils/discovery/index.ts +4 -0
  278. package/src/utils/discovery/openai-compatible.ts +230 -0
  279. package/src/utils/event-stream.ts +172 -0
  280. package/src/utils/fireworks-model-id.ts +30 -0
  281. package/src/utils/foundry.ts +8 -0
  282. package/src/utils/h2-fetch.ts +60 -0
  283. package/src/utils/http-inspector.ts +255 -0
  284. package/src/utils/idle-iterator.ts +257 -0
  285. package/src/utils/json-parse.ts +148 -0
  286. package/src/utils/oauth/alibaba-coding-plan.ts +59 -0
  287. package/src/utils/oauth/anthropic.ts +200 -0
  288. package/src/utils/oauth/api-key-login.ts +87 -0
  289. package/src/utils/oauth/api-key-validation.ts +92 -0
  290. package/src/utils/oauth/callback-server.ts +281 -0
  291. package/src/utils/oauth/cerebras.ts +16 -0
  292. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  293. package/src/utils/oauth/cursor.ts +157 -0
  294. package/src/utils/oauth/deepseek.ts +53 -0
  295. package/src/utils/oauth/firepass.ts +24 -0
  296. package/src/utils/oauth/fireworks.ts +15 -0
  297. package/src/utils/oauth/github-copilot.ts +362 -0
  298. package/src/utils/oauth/gitlab-duo.ts +123 -0
  299. package/src/utils/oauth/google-antigravity.ts +200 -0
  300. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  301. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  302. package/src/utils/oauth/huggingface.ts +62 -0
  303. package/src/utils/oauth/index.ts +469 -0
  304. package/src/utils/oauth/kagi.ts +47 -0
  305. package/src/utils/oauth/kilo.ts +87 -0
  306. package/src/utils/oauth/kimi.ts +254 -0
  307. package/src/utils/oauth/litellm.ts +47 -0
  308. package/src/utils/oauth/lm-studio.ts +38 -0
  309. package/src/utils/oauth/minimax-code.ts +78 -0
  310. package/src/utils/oauth/moonshot.ts +16 -0
  311. package/src/utils/oauth/nanogpt.ts +15 -0
  312. package/src/utils/oauth/nvidia.ts +70 -0
  313. package/src/utils/oauth/oauth.html +199 -0
  314. package/src/utils/oauth/ollama-cloud.ts +28 -0
  315. package/src/utils/oauth/ollama.ts +47 -0
  316. package/src/utils/oauth/openai-codex.ts +299 -0
  317. package/src/utils/oauth/opencode.ts +49 -0
  318. package/src/utils/oauth/parallel.ts +46 -0
  319. package/src/utils/oauth/perplexity.ts +206 -0
  320. package/src/utils/oauth/pkce.ts +18 -0
  321. package/src/utils/oauth/qianfan.ts +58 -0
  322. package/src/utils/oauth/qwen-portal.ts +60 -0
  323. package/src/utils/oauth/synthetic.ts +16 -0
  324. package/src/utils/oauth/tavily.ts +46 -0
  325. package/src/utils/oauth/together.ts +16 -0
  326. package/src/utils/oauth/types.ts +99 -0
  327. package/src/utils/oauth/venice.ts +59 -0
  328. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  329. package/src/utils/oauth/vllm.ts +40 -0
  330. package/src/utils/oauth/xai.ts +246 -0
  331. package/src/utils/oauth/xiaomi.ts +199 -0
  332. package/src/utils/oauth/zai.ts +60 -0
  333. package/src/utils/oauth/zenmux.ts +15 -0
  334. package/src/utils/overflow.ts +137 -0
  335. package/src/utils/parse-bind.ts +54 -0
  336. package/src/utils/provider-response.ts +30 -0
  337. package/src/utils/retry-after.ts +110 -0
  338. package/src/utils/retry-budget.ts +4 -0
  339. package/src/utils/retry.ts +54 -0
  340. package/src/utils/schema/CONSTRAINTS.md +164 -0
  341. package/src/utils/schema/adapt.ts +36 -0
  342. package/src/utils/schema/compatibility.ts +435 -0
  343. package/src/utils/schema/dereference.ts +98 -0
  344. package/src/utils/schema/draft.ts +341 -0
  345. package/src/utils/schema/equality.ts +97 -0
  346. package/src/utils/schema/fields.ts +190 -0
  347. package/src/utils/schema/index.ts +13 -0
  348. package/src/utils/schema/json-schema-validator.ts +577 -0
  349. package/src/utils/schema/meta-validator.ts +167 -0
  350. package/src/utils/schema/normalize.ts +1588 -0
  351. package/src/utils/schema/spill.ts +43 -0
  352. package/src/utils/schema/stamps.ts +97 -0
  353. package/src/utils/schema/types.ts +11 -0
  354. package/src/utils/schema/wire.ts +213 -0
  355. package/src/utils/schema/zod-decontaminate.ts +331 -0
  356. package/src/utils/sse-debug.ts +289 -0
  357. package/src/utils/tool-call-healing.ts +271 -0
  358. package/src/utils/tool-choice-capability.ts +220 -0
  359. package/src/utils/tool-choice.ts +99 -0
  360. package/src/utils/validation.ts +1019 -0
  361. package/src/utils.ts +178 -0
@@ -0,0 +1,163 @@
1
+ import type {
2
+ CredentialRankingStrategy,
3
+ UsageFetchContext,
4
+ UsageFetchParams,
5
+ UsageLimit,
6
+ UsageProvider,
7
+ UsageReport,
8
+ } from "../usage";
9
+
10
+ interface BillingUsage {
11
+ monthlyLimit: number;
12
+ used: number;
13
+ billingPeriodEnd: string;
14
+ }
15
+ const DEFAULT_GROK_BUILD_BASE_URL = "https://cli-chat-proxy.grok.com/v1";
16
+ const ALLOWED_GROK_BUILD_HOSTS = new Set(["cli-chat-proxy.grok.com"]);
17
+
18
+ function isRecord(value: unknown): value is Record<string, unknown> {
19
+ return !!value && typeof value === "object";
20
+ }
21
+
22
+ function finiteNumber(value: unknown): number | undefined {
23
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
24
+ }
25
+
26
+ function parseValNumber(value: unknown): number | undefined {
27
+ return isRecord(value) ? finiteNumber(value.val) : undefined;
28
+ }
29
+
30
+ export function parseGrokCliBillingUsage(payload: unknown): BillingUsage {
31
+ if (!isRecord(payload) || !isRecord(payload.config)) {
32
+ throw new Error("invalid Grok CLI billing payload");
33
+ }
34
+ const monthlyLimit = parseValNumber(payload.config.monthlyLimit);
35
+ const used = parseValNumber(payload.config.used);
36
+ const billingPeriodEnd = payload.config.billingPeriodEnd;
37
+ if (
38
+ monthlyLimit === undefined ||
39
+ used === undefined ||
40
+ typeof billingPeriodEnd !== "string" ||
41
+ !Number.isFinite(new Date(billingPeriodEnd).getTime())
42
+ ) {
43
+ throw new Error("invalid Grok CLI billing payload");
44
+ }
45
+ return { monthlyLimit, used, billingPeriodEnd };
46
+ }
47
+
48
+ function isAllowedGrokCredentialHost(baseUrl: string): boolean {
49
+ try {
50
+ const url = new URL(baseUrl);
51
+ return url.protocol === "https:" && ALLOWED_GROK_BUILD_HOSTS.has(url.hostname.toLowerCase());
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ function normalizeGrokBaseUrl(baseUrl?: string): string {
58
+ const normalized = (baseUrl?.trim() || DEFAULT_GROK_BUILD_BASE_URL).replace(/\/+$/, "");
59
+ return isAllowedGrokCredentialHost(normalized) ? normalized : DEFAULT_GROK_BUILD_BASE_URL;
60
+ }
61
+ function isUnsafeGrokBaseUrlOverride(baseUrl?: string): boolean {
62
+ const normalized = baseUrl?.trim().replace(/\/+$/, "");
63
+ return !!normalized && !isAllowedGrokCredentialHost(normalized);
64
+ }
65
+
66
+ function resolveAccessToken(params: UsageFetchParams): string | undefined {
67
+ const token = params.credential.accessToken ?? params.credential.apiKey ?? process.env.GROK_CLI_OAUTH_TOKEN;
68
+ return token?.trim() || undefined;
69
+ }
70
+
71
+ function buildMonthlyUsageLimit(usage: BillingUsage, nowMs: number): UsageLimit {
72
+ const usedFraction = usage.monthlyLimit > 0 ? usage.used / usage.monthlyLimit : 0;
73
+ const percent = usedFraction * 100;
74
+ const resetsAt = new Date(usage.billingPeriodEnd).getTime();
75
+ return {
76
+ id: "grok-build:7d",
77
+ label: "SuperGrok monthly credits",
78
+ scope: { provider: "grok-build", shared: true, windowId: "7d" },
79
+ window: {
80
+ id: "7d",
81
+ label: "Monthly credits",
82
+ resetsAt,
83
+ },
84
+ amount: {
85
+ unit: "percent",
86
+ used: percent,
87
+ limit: 100,
88
+ remaining: Math.max(0, 100 - percent),
89
+ usedFraction,
90
+ remainingFraction: Math.max(0, 1 - usedFraction),
91
+ },
92
+ status: percent >= 95 ? "exhausted" : percent >= 80 ? "warning" : "ok",
93
+ notes: [
94
+ `${usage.used}/${usage.monthlyLimit} credits used`,
95
+ `resets in ${Math.max(0, Math.round((resetsAt - nowMs) / 3_600_000))}h`,
96
+ ],
97
+ };
98
+ }
99
+
100
+ export const grokCliUsageProvider: UsageProvider = {
101
+ id: "grok-build",
102
+
103
+ supports(params) {
104
+ return params.provider === "grok-build";
105
+ },
106
+
107
+ async fetchUsage(params: UsageFetchParams, ctx: UsageFetchContext): Promise<UsageReport | null> {
108
+ const accessToken = resolveAccessToken(params);
109
+ if (!accessToken) {
110
+ ctx.logger?.warn("Grok Build usage: no access token", { provider: params.provider });
111
+ return null;
112
+ }
113
+
114
+ if (isUnsafeGrokBaseUrlOverride(params.baseUrl)) {
115
+ ctx.logger?.warn("Grok Build usage: ignoring unsafe base URL override for credential safety", {
116
+ provider: params.provider,
117
+ });
118
+ }
119
+ const billingBaseUrl = normalizeGrokBaseUrl(params.baseUrl);
120
+ const response = await ctx.fetch(`${billingBaseUrl}/billing`, {
121
+ headers: {
122
+ Authorization: `Bearer ${accessToken}`,
123
+ "x-xai-token-auth": "xai-grok-cli",
124
+ accept: "application/json",
125
+ },
126
+ signal: params.signal,
127
+ });
128
+ if (!response.ok) {
129
+ ctx.logger?.warn("Grok Build billing request failed", { status: response.status, provider: params.provider });
130
+ return null;
131
+ }
132
+
133
+ const payload = (await response.json()) as unknown;
134
+ let billing: BillingUsage;
135
+ try {
136
+ billing = parseGrokCliBillingUsage(payload);
137
+ } catch (error) {
138
+ ctx.logger?.warn("Grok Build billing parse failed", { error: String(error) });
139
+ return null;
140
+ }
141
+
142
+ const nowMs = Date.now();
143
+ return {
144
+ provider: "grok-build",
145
+ fetchedAt: nowMs,
146
+ limits: [buildMonthlyUsageLimit(billing, nowMs)],
147
+ metadata: {
148
+ email: params.credential.email,
149
+ accountId: params.credential.accountId,
150
+ subscription: true,
151
+ },
152
+ raw: payload,
153
+ };
154
+ },
155
+ };
156
+
157
+ export const grokCliRankingStrategy: CredentialRankingStrategy = {
158
+ findWindowLimits(report) {
159
+ const monthly = report.limits.find(limit => limit.id === "grok-build:7d");
160
+ return { secondary: monthly };
161
+ },
162
+ windowDefaults: { primaryMs: 5 * 60 * 60 * 1000, secondaryMs: 30 * 24 * 60 * 60 * 1000 },
163
+ };
@@ -0,0 +1,271 @@
1
+ import { $env } from "@sayknow-cli/utils";
2
+ import type {
3
+ UsageAmount,
4
+ UsageFetchContext,
5
+ UsageFetchParams,
6
+ UsageLimit,
7
+ UsageProvider,
8
+ UsageReport,
9
+ UsageStatus,
10
+ UsageWindow,
11
+ } from "../usage";
12
+ import { isRecord } from "../utils";
13
+ import { getKimiCommonHeaders } from "../utils/oauth/kimi";
14
+ // (Refresh is the sole responsibility of AuthStorage; no provider-direct refresh here.)
15
+ import { toNumber } from "./shared";
16
+
17
+ const DEFAULT_BASE_URL = "https://api.kimi.com/coding/v1";
18
+ const USAGE_PATH = "usages";
19
+
20
+ interface KimiUsagePayload {
21
+ usage?: unknown;
22
+ limits?: unknown;
23
+ }
24
+
25
+ type KimiUsageRow = {
26
+ label: string;
27
+ used?: number;
28
+ limit?: number;
29
+ remaining?: number;
30
+ resetsAt?: number;
31
+ window?: UsageWindow;
32
+ };
33
+
34
+ function normalizeBaseUrl(baseUrl?: string): string {
35
+ const envBase = $env.KIMI_CODE_BASE_URL?.trim();
36
+ const candidate = baseUrl?.trim() || envBase || DEFAULT_BASE_URL;
37
+ return candidate.replace(/\/+$/, "");
38
+ }
39
+
40
+ function buildUsageUrl(baseUrl: string): string {
41
+ const normalized = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
42
+ return `${normalized}${USAGE_PATH}`;
43
+ }
44
+
45
+ function parseResetTime(data: Record<string, unknown>, nowMs: number): number | undefined {
46
+ const timeKeys = ["reset_at", "resetAt", "reset_time", "resetTime"] as const;
47
+ for (const key of timeKeys) {
48
+ const value = data[key];
49
+ if (typeof value === "string" && value.trim()) {
50
+ const parsed = Date.parse(value);
51
+ if (Number.isFinite(parsed)) return parsed;
52
+ }
53
+ if (typeof value === "number" && Number.isFinite(value)) {
54
+ return value > 1_000_000_000_000 ? value : value * 1000;
55
+ }
56
+ }
57
+
58
+ const secondsKeys = ["reset_in", "resetIn", "ttl", "window"] as const;
59
+ for (const key of secondsKeys) {
60
+ const seconds = toNumber(data[key]);
61
+ if (seconds !== undefined) return nowMs + seconds * 1000;
62
+ }
63
+
64
+ return undefined;
65
+ }
66
+
67
+ function formatDurationLabel(duration: number, timeUnit: string): string | undefined {
68
+ const upper = timeUnit.toUpperCase();
69
+ if (upper.includes("MINUTE")) {
70
+ if (duration >= 60 && duration % 60 === 0) return `${duration / 60}h limit`;
71
+ return `${duration}m limit`;
72
+ }
73
+ if (upper.includes("HOUR")) return `${duration}h limit`;
74
+ if (upper.includes("DAY")) return `${duration}d limit`;
75
+ if (upper.includes("SECOND")) return `${duration}s limit`;
76
+ return undefined;
77
+ }
78
+
79
+ function buildWindow(windowData: Record<string, unknown>, nowMs: number): UsageWindow | undefined {
80
+ const duration = toNumber(windowData.duration);
81
+ const timeUnit = typeof windowData.timeUnit === "string" ? windowData.timeUnit : "";
82
+ const label = duration !== undefined && timeUnit ? formatDurationLabel(duration, timeUnit) : undefined;
83
+ const resetsAt = parseResetTime(windowData, nowMs);
84
+
85
+ if (duration === undefined && !label && !resetsAt) return undefined;
86
+ let durationMs: number | undefined;
87
+ if (duration !== undefined) {
88
+ if (timeUnit.toUpperCase().includes("MINUTE")) durationMs = duration * 60_000;
89
+ else if (timeUnit.toUpperCase().includes("HOUR")) durationMs = duration * 3_600_000;
90
+ else if (timeUnit.toUpperCase().includes("DAY")) durationMs = duration * 86_400_000;
91
+ else if (timeUnit.toUpperCase().includes("SECOND")) durationMs = duration * 1000;
92
+ }
93
+
94
+ return {
95
+ id: duration !== undefined && timeUnit ? `${duration}${timeUnit.toLowerCase()}` : "default",
96
+ label: label ?? "Usage window",
97
+ durationMs,
98
+ resetsAt,
99
+ };
100
+ }
101
+
102
+ function buildUsageRow(data: Record<string, unknown>, defaultLabel: string, nowMs: number): KimiUsageRow | null {
103
+ const limit = toNumber(data.limit);
104
+ let used = toNumber(data.used);
105
+ const remaining = toNumber(data.remaining);
106
+ if (used === undefined && remaining !== undefined && limit !== undefined) {
107
+ used = limit - remaining;
108
+ }
109
+
110
+ if (used === undefined && limit === undefined) return null;
111
+ const resetsAt = parseResetTime(data, nowMs);
112
+ return {
113
+ label:
114
+ typeof data.name === "string" && data.name
115
+ ? data.name
116
+ : typeof data.title === "string" && data.title
117
+ ? data.title
118
+ : defaultLabel,
119
+ used,
120
+ limit,
121
+ remaining,
122
+ resetsAt,
123
+ };
124
+ }
125
+
126
+ function buildUsageAmount(row: KimiUsageRow): UsageAmount {
127
+ const amount: UsageAmount = { unit: "unknown" };
128
+ if (row.limit !== undefined) amount.limit = row.limit;
129
+ if (row.used !== undefined) amount.used = row.used;
130
+ if (row.remaining !== undefined) amount.remaining = row.remaining;
131
+ if (row.limit !== undefined && row.used !== undefined && row.limit > 0) {
132
+ amount.usedFraction = Math.min(Math.max(row.used / row.limit, 0), 1);
133
+ amount.remainingFraction = Math.min(Math.max((row.limit - row.used) / row.limit, 0), 1);
134
+ amount.remaining = amount.remaining ?? row.limit - row.used;
135
+ }
136
+ return amount;
137
+ }
138
+
139
+ function buildUsageStatus(amount: UsageAmount): UsageStatus {
140
+ if (amount.usedFraction === undefined) return "unknown";
141
+ if (amount.usedFraction >= 1) return "exhausted";
142
+ if (amount.usedFraction >= 0.9) return "warning";
143
+ return "ok";
144
+ }
145
+
146
+ function toUsageLimit(row: KimiUsageRow, provider: string, index: number, accountId?: string): UsageLimit {
147
+ const window: UsageWindow | undefined =
148
+ row.window ??
149
+ (row.resetsAt
150
+ ? {
151
+ id: "default",
152
+ label: "Usage window",
153
+ resetsAt: row.resetsAt,
154
+ }
155
+ : undefined);
156
+
157
+ const amount = buildUsageAmount(row);
158
+ return {
159
+ id: `${provider}:${index}`,
160
+ label: row.label,
161
+ scope: {
162
+ provider,
163
+ accountId,
164
+ windowId: window?.id,
165
+ shared: true,
166
+ },
167
+ window,
168
+ amount,
169
+ status: buildUsageStatus(amount),
170
+ };
171
+ }
172
+
173
+ function parseUsagePayload(payload: unknown, nowMs: number): { rows: KimiUsageRow[]; raw: KimiUsagePayload } | null {
174
+ if (!isRecord(payload)) return null;
175
+ const data = payload as KimiUsagePayload;
176
+ const rows: KimiUsageRow[] = [];
177
+
178
+ if (isRecord(data.usage)) {
179
+ const summary = buildUsageRow(data.usage, "Total quota", nowMs);
180
+ if (summary) rows.push(summary);
181
+ }
182
+
183
+ if (Array.isArray(data.limits)) {
184
+ data.limits.forEach((item, idx) => {
185
+ if (!isRecord(item)) return;
186
+ const detail = isRecord(item.detail) ? item.detail : item;
187
+ const windowData = isRecord(item.window) ? item.window : {};
188
+ const label =
189
+ (typeof item.name === "string" && item.name) ||
190
+ (typeof item.title === "string" && item.title) ||
191
+ (typeof item.scope === "string" && item.scope) ||
192
+ (typeof detail.name === "string" && detail.name) ||
193
+ (typeof detail.title === "string" && detail.title) ||
194
+ formatDurationLabel(toNumber(windowData.duration) ?? 0, String(windowData.timeUnit || "")) ||
195
+ `Limit #${idx + 1}`;
196
+ const row = buildUsageRow(detail, label, nowMs);
197
+ if (row) {
198
+ row.window = buildWindow(windowData, nowMs);
199
+ rows.push(row);
200
+ }
201
+ });
202
+ }
203
+
204
+ return { rows, raw: data };
205
+ }
206
+
207
+ export const kimiUsageProvider: UsageProvider = {
208
+ id: "kimi-code",
209
+ supports(params: UsageFetchParams): boolean {
210
+ return params.provider === "kimi-code" && params.credential.type === "oauth";
211
+ },
212
+ async fetchUsage(params: UsageFetchParams, ctx: UsageFetchContext): Promise<UsageReport | null> {
213
+ if (params.provider !== "kimi-code") return null;
214
+ const { credential } = params;
215
+ if (credential.type !== "oauth") return null;
216
+
217
+ const accessToken = credential.accessToken;
218
+ if (!accessToken) return null;
219
+
220
+ const nowMs = Date.now();
221
+ // AuthStorage refreshes OAuth credentials pre-emptively (60s skew). If the
222
+ // usage probe lands with an expired token, short-circuit rather than POST
223
+ // the broker sentinel back to Kimi — the next cycle will carry a freshly
224
+ // refreshed credential.
225
+ if (credential.expiresAt !== undefined && credential.expiresAt <= nowMs) {
226
+ ctx.logger?.debug("Kimi usage token expired; skipping probe", { provider: params.provider });
227
+ return null;
228
+ }
229
+
230
+ const baseUrl = normalizeBaseUrl(params.baseUrl);
231
+ const url = buildUsageUrl(baseUrl);
232
+ let payload: unknown;
233
+ try {
234
+ const response = await ctx.fetch(url, {
235
+ headers: {
236
+ ...getKimiCommonHeaders(),
237
+ Authorization: `Bearer ${accessToken}`,
238
+ },
239
+ signal: params.signal,
240
+ });
241
+ if (!response.ok) {
242
+ ctx.logger?.warn("Kimi usage request failed", { status: response.status, provider: params.provider });
243
+ return null;
244
+ }
245
+ payload = await response.json();
246
+ } catch (error) {
247
+ ctx.logger?.warn("Kimi usage request error", { provider: params.provider, error: String(error) });
248
+ return null;
249
+ }
250
+
251
+ const parsed = parseUsagePayload(payload, nowMs);
252
+ if (!parsed || parsed.rows.length === 0) {
253
+ ctx.logger?.warn("Kimi usage response invalid", { provider: params.provider });
254
+ return null;
255
+ }
256
+
257
+ const limits = parsed.rows.map((row, index) => toUsageLimit(row, params.provider, index, credential.accountId));
258
+
259
+ const report: UsageReport = {
260
+ provider: params.provider,
261
+ fetchedAt: nowMs,
262
+ limits,
263
+ metadata: {
264
+ endpoint: url,
265
+ },
266
+ raw: parsed.raw,
267
+ };
268
+
269
+ return report;
270
+ },
271
+ };
@@ -0,0 +1,31 @@
1
+ import type { UsageFetchContext, UsageFetchParams, UsageProvider, UsageReport } from "../usage";
2
+
3
+ /**
4
+ * MiniMax Coding Plan usage provider.
5
+ *
6
+ * MiniMax Coding Plan is a subscription-based service with a 5-hour rolling window
7
+ * quota system. The quota resets automatically based on a rolling window.
8
+ *
9
+ * Currently, MiniMax does not expose a usage/quota API endpoint for the Coding Plan.
10
+ * Usage is tracked via the web dashboard at https://platform.minimax.io/user-center/payment/coding-plan
11
+ *
12
+ * This provider exists to register support for the minimax-code provider in the
13
+ * usage system. When MiniMax adds a usage API, this can be implemented.
14
+ */
15
+ async function fetchMiniMaxCodeUsage(params: UsageFetchParams, _ctx: UsageFetchContext): Promise<UsageReport | null> {
16
+ if (params.provider !== "minimax-code" && params.provider !== "minimax-code-cn") {
17
+ return null;
18
+ }
19
+
20
+ // MiniMax Coding Plan does not currently expose a usage API
21
+ // Users can check their usage via the web dashboard
22
+ return null;
23
+ }
24
+
25
+ export const minimaxCodeUsageProvider: UsageProvider = {
26
+ id: "minimax-code",
27
+ fetchUsage: fetchMiniMaxCodeUsage,
28
+ supports: (params: UsageFetchParams) =>
29
+ (params.provider === "minimax-code" || params.provider === "minimax-code-cn") &&
30
+ params.credential.type === "api_key",
31
+ };