@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,230 @@
1
+ import { UNK_CONTEXT_WINDOW, UNK_MAX_TOKENS } from "@sayknow-cli/ai";
2
+ import * as z from "zod/v4";
3
+ import type { Api, FetchImpl, Model, Provider } from "../../types";
4
+
5
+ const MODELS_PATH = "/models";
6
+
7
+ /**
8
+ * Minimal OpenAI-style model entry shape consumed by discovery.
9
+ *
10
+ * Providers may return additional fields; this type only captures
11
+ * fields that are useful for generic normalization.
12
+ */
13
+ export interface OpenAICompatibleModelRecord {
14
+ id?: unknown;
15
+ name?: unknown;
16
+ object?: unknown;
17
+ owned_by?: unknown;
18
+ [key: string]: unknown;
19
+ }
20
+
21
+ /**
22
+ * Tolerant envelope for OpenAI-compatible `/models` responses.
23
+ *
24
+ * Common providers return `{ data: [...] }`, but variants such as
25
+ * `{ models: [...] }`, `{ result: [...] }`, or direct arrays are also
26
+ * accepted during extraction.
27
+ */
28
+ export interface OpenAICompatibleModelsEnvelope {
29
+ data?: unknown;
30
+ models?: unknown;
31
+ result?: unknown;
32
+ items?: unknown;
33
+ [key: string]: unknown;
34
+ }
35
+
36
+ const openAICompatibleModelRecordSchema = z
37
+ .object({
38
+ id: z.string().min(1),
39
+ name: z.string().optional().nullable(),
40
+ object: z.unknown().optional(),
41
+ owned_by: z.unknown().optional(),
42
+ })
43
+ .loose();
44
+
45
+ const openAICompatibleModelsEnvelopeSchema = z
46
+ .object({
47
+ data: z.unknown().optional(),
48
+ models: z.unknown().optional(),
49
+ result: z.unknown().optional(),
50
+ items: z.unknown().optional(),
51
+ })
52
+ .loose();
53
+
54
+ const openAICompatibleModelsPayloadSchema = z.union([z.array(z.unknown()), openAICompatibleModelsEnvelopeSchema]);
55
+
56
+ type ParsedOpenAICompatibleModelRecord = z.infer<typeof openAICompatibleModelRecordSchema>;
57
+
58
+ /**
59
+ * Context passed to custom OpenAI-compatible model mappers.
60
+ */
61
+ export interface OpenAICompatibleModelMapperContext<TApi extends Api> {
62
+ api: TApi;
63
+ provider: Provider;
64
+ baseUrl: string;
65
+ }
66
+
67
+ /**
68
+ * Options for fetching and normalizing OpenAI-compatible `/models` catalogs.
69
+ */
70
+ export interface FetchOpenAICompatibleModelsOptions<TApi extends Api> {
71
+ /** API type assigned to normalized models. */
72
+ api: TApi;
73
+ /** Provider id assigned to normalized models. */
74
+ provider: Provider;
75
+ /** Provider base URL used for both fetch and normalized model records. */
76
+ baseUrl: string;
77
+ /** Optional bearer token for Authorization header. */
78
+ apiKey?: string;
79
+ /** Additional request headers. */
80
+ headers?: Record<string, string>;
81
+ /** Optional AbortSignal for request cancellation. */
82
+ signal?: AbortSignal;
83
+ /** Optional fetch implementation override for testing/custom runtimes. */
84
+ fetch?: FetchImpl;
85
+ /** Optional HTTP status predicate for provider-specific hard failures. */
86
+ throwOnStatus?: (response: Response) => Error | undefined;
87
+ /**
88
+ * Optional post-normalization filter.
89
+ * Return false to skip a model.
90
+ */
91
+ filterModel?: (entry: OpenAICompatibleModelRecord, model: Model<TApi>) => boolean;
92
+ /**
93
+ * Optional mapper override for provider-specific quirks.
94
+ * Return null to skip a model.
95
+ */
96
+ mapModel?: (
97
+ entry: OpenAICompatibleModelRecord,
98
+ defaults: Model<TApi>,
99
+ context: OpenAICompatibleModelMapperContext<TApi>,
100
+ ) => Model<TApi> | null;
101
+ }
102
+
103
+ /**
104
+ * Fetches and normalizes an OpenAI-compatible `/models` catalog.
105
+ *
106
+ * Returns `null` on transport/protocol failures.
107
+ * Returns `[]` only when the endpoint responds successfully with no usable models.
108
+ */
109
+ export async function fetchOpenAICompatibleModels<TApi extends Api>(
110
+ options: FetchOpenAICompatibleModelsOptions<TApi>,
111
+ ): Promise<Model<TApi>[] | null> {
112
+ const baseUrl = normalizeBaseUrl(options.baseUrl);
113
+ if (!baseUrl) {
114
+ return null;
115
+ }
116
+
117
+ const requestHeaders: Record<string, string> = {
118
+ Accept: "application/json",
119
+ ...options.headers,
120
+ };
121
+ if (options.apiKey) {
122
+ requestHeaders.Authorization = `Bearer ${options.apiKey}`;
123
+ }
124
+
125
+ const fetchImpl = options.fetch ?? globalThis.fetch;
126
+ let response: Response;
127
+ try {
128
+ response = await fetchImpl(`${baseUrl}${MODELS_PATH}`, {
129
+ method: "GET",
130
+ headers: requestHeaders,
131
+ signal: options.signal,
132
+ });
133
+ } catch {
134
+ return null;
135
+ }
136
+
137
+ if (!response.ok) {
138
+ const hardFailure = options.throwOnStatus?.(response);
139
+ if (hardFailure) {
140
+ throw hardFailure;
141
+ }
142
+ return null;
143
+ }
144
+
145
+ let payload: unknown;
146
+ try {
147
+ payload = await response.json();
148
+ } catch {
149
+ return null;
150
+ }
151
+
152
+ const entries = extractModelEntries(payload);
153
+ if (entries === null) {
154
+ return null;
155
+ }
156
+
157
+ const context: OpenAICompatibleModelMapperContext<TApi> = {
158
+ api: options.api,
159
+ provider: options.provider,
160
+ baseUrl,
161
+ };
162
+
163
+ const deduped = new Map<string, Model<TApi>>();
164
+ for (const entry of entries) {
165
+ const defaults: Model<TApi> = {
166
+ id: entry.id,
167
+ name: typeof entry.name === "string" && entry.name.length > 0 ? entry.name : entry.id,
168
+ api: options.api,
169
+ provider: options.provider,
170
+ baseUrl,
171
+ reasoning: false,
172
+ input: ["text"],
173
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
174
+ contextWindow: UNK_CONTEXT_WINDOW,
175
+ maxTokens: UNK_MAX_TOKENS,
176
+ };
177
+
178
+ const mapped = options.mapModel?.(entry, defaults, context) ?? defaults;
179
+ if (!mapped || typeof mapped.id !== "string" || mapped.id.length === 0) {
180
+ continue;
181
+ }
182
+ if (options.filterModel && !options.filterModel(entry, mapped)) {
183
+ continue;
184
+ }
185
+ deduped.set(mapped.id, mapped);
186
+ }
187
+
188
+ return Array.from(deduped.values()).sort((left, right) => left.id.localeCompare(right.id));
189
+ }
190
+
191
+ function normalizeBaseUrl(baseUrl: string): string {
192
+ const trimmed = baseUrl.trim();
193
+ if (!trimmed) {
194
+ return "";
195
+ }
196
+ return trimmed.endsWith("/") ? trimmed.slice(0, -1) : trimmed;
197
+ }
198
+
199
+ function extractModelEntries(payload: unknown): ParsedOpenAICompatibleModelRecord[] | null {
200
+ return extractModelEntriesFromNode(payload);
201
+ }
202
+
203
+ function extractModelEntriesFromNode(node: unknown): ParsedOpenAICompatibleModelRecord[] | null {
204
+ const parsedPayload = openAICompatibleModelsPayloadSchema.safeParse(node);
205
+ if (!parsedPayload.success) {
206
+ return null;
207
+ }
208
+ if (Array.isArray(parsedPayload.data)) {
209
+ const parsedEntries = parsedPayload.data
210
+ .map(entry => openAICompatibleModelRecordSchema.safeParse(entry))
211
+ .flatMap(entry => (entry.success ? [entry.data] : []));
212
+ return parsedEntries;
213
+ }
214
+ for (const candidate of [
215
+ parsedPayload.data.data,
216
+ parsedPayload.data.models,
217
+ parsedPayload.data.result,
218
+ parsedPayload.data.items,
219
+ ]) {
220
+ if (candidate === undefined) {
221
+ continue;
222
+ }
223
+ const nested = extractModelEntriesFromNode(candidate);
224
+ if (nested !== null) {
225
+ return nested;
226
+ }
227
+ }
228
+
229
+ return null;
230
+ }
@@ -0,0 +1,172 @@
1
+ import type { AssistantMessage, AssistantMessageEvent } from "../types";
2
+
3
+ // Generic event stream class for async iteration
4
+ export class EventStream<T, R = T> implements AsyncIterable<T> {
5
+ #queue: T[] = [];
6
+ #queueHead = 0;
7
+ waiting: Array<{ resolve: (value: IteratorResult<T>) => void; reject: (err: unknown) => void }> = [];
8
+ done = false;
9
+ #failed = false;
10
+ #error: unknown = undefined;
11
+ finalResultPromise: Promise<R>;
12
+ resolveFinalResult!: (result: R) => void;
13
+ rejectFinalResult!: (err: unknown) => void;
14
+ isComplete: (event: T) => boolean;
15
+ extractResult: (event: T) => R;
16
+
17
+ constructor(isComplete: (event: T) => boolean, extractResult: (event: T) => R) {
18
+ const { promise, resolve, reject } = Promise.withResolvers<R>();
19
+ // Prevent an unhandled rejection when fail() is called but nobody awaits result().
20
+ // Callers who do await result() still receive the rejection normally.
21
+ promise.catch(() => {});
22
+ this.finalResultPromise = promise;
23
+ this.resolveFinalResult = resolve;
24
+ this.rejectFinalResult = reject;
25
+ this.isComplete = isComplete;
26
+ this.extractResult = extractResult;
27
+ }
28
+
29
+ #enqueue(event: T): void {
30
+ this.#queue.push(event);
31
+ }
32
+
33
+ #dequeue(): T | undefined {
34
+ if (this.#queueHead >= this.#queue.length) return undefined;
35
+ const event = this.#queue[this.#queueHead]!;
36
+ this.#queue[this.#queueHead] = undefined as T;
37
+ this.#queueHead++;
38
+ if (this.#queueHead > 1024 && this.#queueHead * 2 >= this.#queue.length) {
39
+ this.#queue = this.#queue.slice(this.#queueHead);
40
+ this.#queueHead = 0;
41
+ }
42
+ return event;
43
+ }
44
+
45
+ get #queueLength(): number {
46
+ return this.#queue.length - this.#queueHead;
47
+ }
48
+
49
+ /**
50
+ * Read-only snapshot of the not-yet-consumed events. Always a fresh copy:
51
+ * external code can never mutate internal queue state or observe head-index
52
+ * tombstones, so the deque cannot desynchronize.
53
+ */
54
+ get queue(): T[] {
55
+ return this.#queue.slice(this.#queueHead);
56
+ }
57
+
58
+ push(event: T): void {
59
+ if (this.done) return;
60
+
61
+ if (this.isComplete(event)) {
62
+ this.done = true;
63
+ this.resolveFinalResult(this.extractResult(event));
64
+ }
65
+
66
+ // Deliver to waiting consumer or queue it
67
+ const waiter = this.waiting.shift();
68
+ if (waiter) {
69
+ waiter.resolve({ value: event, done: false });
70
+ } else {
71
+ this.#enqueue(event);
72
+ }
73
+ }
74
+
75
+ deliver(event: T): void {
76
+ const waiter = this.waiting.shift();
77
+ if (waiter) {
78
+ waiter.resolve({ value: event, done: false });
79
+ } else {
80
+ this.#enqueue(event);
81
+ }
82
+ }
83
+
84
+ end(result?: R): void {
85
+ this.done = true;
86
+ if (result !== undefined) {
87
+ this.resolveFinalResult(result);
88
+ }
89
+ // Notify all waiting consumers that we're done
90
+ while (this.waiting.length > 0) {
91
+ const waiter = this.waiting.shift()!;
92
+ waiter.resolve({ value: undefined as any, done: true });
93
+ }
94
+ }
95
+
96
+ endWaiting(): void {
97
+ while (this.waiting.length > 0) {
98
+ const waiter = this.waiting.shift()!;
99
+ waiter.resolve({ value: undefined as any, done: true });
100
+ }
101
+ }
102
+
103
+ fail(err: unknown): void {
104
+ if (this.done) return;
105
+ this.done = true;
106
+ this.#failed = true;
107
+ this.#error = err;
108
+ this.rejectFinalResult(err);
109
+ while (this.waiting.length > 0) {
110
+ const waiter = this.waiting.shift()!;
111
+ waiter.reject(err);
112
+ }
113
+ }
114
+
115
+ async *[Symbol.asyncIterator](): AsyncIterator<T> {
116
+ while (true) {
117
+ if (this.#queueLength > 0) {
118
+ yield this.#dequeue()!;
119
+ } else if (this.#failed) {
120
+ throw this.#error;
121
+ } else if (this.done) {
122
+ return;
123
+ } else {
124
+ const result = await new Promise<IteratorResult<T>>((resolve, reject) =>
125
+ this.waiting.push({ resolve, reject }),
126
+ );
127
+ if (result.done) return;
128
+ yield result.value;
129
+ }
130
+ }
131
+ }
132
+
133
+ result(): Promise<R> {
134
+ return this.finalResultPromise;
135
+ }
136
+ }
137
+
138
+ export class AssistantMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
139
+ constructor() {
140
+ super(
141
+ event => event.type === "done" || event.type === "error",
142
+ event => {
143
+ if (event.type === "done") {
144
+ return event.message;
145
+ } else if (event.type === "error") {
146
+ return event.error;
147
+ }
148
+ throw new Error("Unexpected event type for final result");
149
+ },
150
+ );
151
+ }
152
+
153
+ override push(event: AssistantMessageEvent): void {
154
+ if (this.done) return;
155
+
156
+ // Completion resolves the final result and still emits the terminal event.
157
+ if (this.isComplete(event)) {
158
+ this.done = true;
159
+ this.resolveFinalResult(this.extractResult(event));
160
+ }
161
+
162
+ this.deliver(event);
163
+ }
164
+
165
+ override end(result?: AssistantMessage): void {
166
+ this.done = true;
167
+ if (result !== undefined) {
168
+ this.resolveFinalResult(result);
169
+ }
170
+ this.endWaiting();
171
+ }
172
+ }
@@ -0,0 +1,30 @@
1
+ const FIREWORKS_WIRE_PREFIX = "accounts/fireworks/models/";
2
+ const FIREPASS_WIRE_PREFIX = "accounts/fireworks/routers/";
3
+ const VERSION_SEPARATOR_PATTERN = /(?<=\d)p(?=\d)/g;
4
+ const VERSION_DOT_PATTERN = /(?<=\d)\.(?=\d)/g;
5
+
6
+ export function toFireworksPublicModelId(modelId: string): string {
7
+ const stripped = modelId.startsWith(FIREWORKS_WIRE_PREFIX) ? modelId.slice(FIREWORKS_WIRE_PREFIX.length) : modelId;
8
+ return stripped.replace(VERSION_SEPARATOR_PATTERN, ".");
9
+ }
10
+
11
+ export function toFireworksWireModelId(modelId: string): string {
12
+ const stripped = modelId.startsWith(FIREWORKS_WIRE_PREFIX) ? modelId.slice(FIREWORKS_WIRE_PREFIX.length) : modelId;
13
+ return `${FIREWORKS_WIRE_PREFIX}${stripped.replace(VERSION_DOT_PATTERN, "p")}`;
14
+ }
15
+
16
+ /**
17
+ * Fire Pass exposes its Kimi K2.6 Turbo subscription through a dedicated router
18
+ * endpoint at `accounts/fireworks/routers/<id>` rather than the `models/` namespace.
19
+ * We keep a friendly public id (e.g. `kimi-k2.6-turbo`) in the catalog and translate
20
+ * to the wire form (`accounts/fireworks/routers/kimi-k2p6-turbo`) at request time.
21
+ */
22
+ export function toFirepassPublicModelId(modelId: string): string {
23
+ const stripped = modelId.startsWith(FIREPASS_WIRE_PREFIX) ? modelId.slice(FIREPASS_WIRE_PREFIX.length) : modelId;
24
+ return stripped.replace(VERSION_SEPARATOR_PATTERN, ".");
25
+ }
26
+
27
+ export function toFirepassWireModelId(modelId: string): string {
28
+ const stripped = modelId.startsWith(FIREPASS_WIRE_PREFIX) ? modelId.slice(FIREPASS_WIRE_PREFIX.length) : modelId;
29
+ return `${FIREPASS_WIRE_PREFIX}${stripped.replace(VERSION_DOT_PATTERN, "p")}`;
30
+ }
@@ -0,0 +1,8 @@
1
+ import { $env } from "@sayknow-cli/utils";
2
+
3
+ export function isFoundryEnabled(): boolean {
4
+ const value = $env.CLAUDE_CODE_USE_FOUNDRY;
5
+ if (!value) return false;
6
+ const normalized = value.trim().toLowerCase();
7
+ return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
8
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Patch `globalThis.fetch` to advertise HTTP/2 in TLS ALPN, with transparent
3
+ * HTTP/1.1 fallback when the server doesn't negotiate `h2`.
4
+ *
5
+ * Bun's HTTP/2 client is gated on `BUN_FEATURE_FLAG_EXPERIMENTAL_HTTP2_CLIENT`,
6
+ * read by the native runtime before any JS executes; assigning to
7
+ * `process.env` from inside JS is a no-op. Per-request `protocol: "http2"`
8
+ * activates h2 over TLS ALPN and rejects with `error.code === "HTTP2Unsupported"`
9
+ * if the server picks anything else, so we catch and retry without the hint.
10
+ *
11
+ * Some HTTPS endpoints (e.g. corporate API gateways behind reverse proxies)
12
+ * advertise h2 via ALPN but then refuse or reset the connection at the HTTP/2
13
+ * framing layer. Bun surfaces these as `ConnectionRefused`, `ConnectionReset`,
14
+ * or `ConnectionClosed` rather than `HTTP2Unsupported`, so we treat those
15
+ * codes as h2-fallback triggers as well.
16
+ *
17
+ * Bun negotiates h2 via ALPN over TLS only (no h2c), so plain `http://` URLs
18
+ * skip the attempt entirely — avoids the throw/retry round-trip for localhost.
19
+ *
20
+ * Idempotent.
21
+ */
22
+
23
+ const installed: unique symbol = Symbol.for("sayknow-cli.h2fetch.installed");
24
+
25
+ interface PatchedFetch {
26
+ [installed]?: true;
27
+ }
28
+
29
+ export function installH2Fetch(): void {
30
+ const original = globalThis.fetch as typeof fetch & PatchedFetch;
31
+ if (original[installed]) return;
32
+
33
+ /** Error codes that indicate h2 negotiation/transport failure (not an application error). */
34
+ const h2FallbackCodes: ReadonlySet<string> = new Set([
35
+ "HTTP2Unsupported", // Server selected h1 in ALPN
36
+ "ConnectionRefused", // Server refused the h2 connection
37
+ "ConnectionReset", // Server reset during h2 handshake
38
+ "ConnectionClosed", // Server closed before h2 response
39
+ ]);
40
+ const wrapper = async function h2fetch(input: string | URL | Request, init?: RequestInit): Promise<Response> {
41
+ if (!isHttps(input)) return original(input, init);
42
+ try {
43
+ return await original(input, { ...init, protocol: "http2" });
44
+ } catch (err) {
45
+ if (!h2FallbackCodes.has((err as { code?: string }).code ?? "")) throw err;
46
+ return original(input, init);
47
+ }
48
+ } as typeof fetch & PatchedFetch;
49
+
50
+ // Preserve `fetch.preconnect` and any other statics SDK code might poke at.
51
+ Object.assign(wrapper, original);
52
+ wrapper[installed] = true;
53
+ globalThis.fetch = wrapper;
54
+ }
55
+
56
+ function isHttps(input: string | URL | Request): boolean {
57
+ if (typeof input === "string") return input.startsWith("https:");
58
+ if (input instanceof URL) return input.protocol === "https:";
59
+ return input.url.startsWith("https:");
60
+ }