@vib-rato/ai 0.16.0

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 (525) hide show
  1. package/CHANGELOG.md +3354 -0
  2. package/README.md +1194 -0
  3. package/dist/types/adapter-internals/provider-safety-stop.d.ts +45 -0
  4. package/dist/types/api-registry.d.ts +30 -0
  5. package/dist/types/auth-broker/client.d.ts +80 -0
  6. package/dist/types/auth-broker/index.d.ts +5 -0
  7. package/dist/types/auth-broker/redact.d.ts +7 -0
  8. package/dist/types/auth-broker/refresher.d.ts +25 -0
  9. package/dist/types/auth-broker/remote-store.d.ts +153 -0
  10. package/dist/types/auth-broker/server.d.ts +32 -0
  11. package/dist/types/auth-broker/types.d.ts +132 -0
  12. package/dist/types/auth-broker/wire-schemas.d.ts +555 -0
  13. package/dist/types/auth-gateway/http.d.ts +40 -0
  14. package/dist/types/auth-gateway/index.d.ts +3 -0
  15. package/dist/types/auth-gateway/server.d.ts +70 -0
  16. package/dist/types/auth-gateway/types.d.ts +129 -0
  17. package/dist/types/auth-storage.d.ts +1074 -0
  18. package/dist/types/cli.d.ts +2 -0
  19. package/dist/types/codex-tools.d.ts +4 -0
  20. package/dist/types/context-cap-policy.d.ts +68 -0
  21. package/dist/types/core.d.ts +35 -0
  22. package/dist/types/index.d.ts +55 -0
  23. package/dist/types/model-cache.d.ts +24 -0
  24. package/dist/types/model-manager.d.ts +77 -0
  25. package/dist/types/model-pricing.d.ts +3 -0
  26. package/dist/types/model-retirements.d.ts +6 -0
  27. package/dist/types/model-thinking.d.ts +100 -0
  28. package/dist/types/models.d.ts +21 -0
  29. package/dist/types/openai-completions-compat.d.ts +34 -0
  30. package/dist/types/provider-details.d.ts +24 -0
  31. package/dist/types/provider-models/bundled-references.d.ts +4 -0
  32. package/dist/types/provider-models/descriptors.d.ts +48 -0
  33. package/dist/types/provider-models/google.d.ts +20 -0
  34. package/dist/types/provider-models/index.d.ts +5 -0
  35. package/dist/types/provider-models/ollama.d.ts +7 -0
  36. package/dist/types/provider-models/openai-compat.d.ts +293 -0
  37. package/dist/types/provider-models/special.d.ts +29 -0
  38. package/dist/types/providers/amazon-bedrock.d.ts +60 -0
  39. package/dist/types/providers/anthropic-messages-server-schema.d.ts +450 -0
  40. package/dist/types/providers/anthropic-messages-server.d.ts +17 -0
  41. package/dist/types/providers/anthropic.d.ts +280 -0
  42. package/dist/types/providers/aws-credential-config.d.ts +19 -0
  43. package/dist/types/providers/aws-credentials.d.ts +43 -0
  44. package/dist/types/providers/aws-eventstream.d.ts +38 -0
  45. package/dist/types/providers/aws-sigv4.d.ts +55 -0
  46. package/dist/types/providers/azure-openai-responses.d.ts +22 -0
  47. package/dist/types/providers/composer-discipline.d.ts +32 -0
  48. package/dist/types/providers/cursor/client-version.d.ts +10 -0
  49. package/dist/types/providers/cursor/exec-modern.d.ts +98 -0
  50. package/dist/types/providers/cursor/gen/agent_pb.d.ts +16769 -0
  51. package/dist/types/providers/cursor-pi-args.d.ts +119 -0
  52. package/dist/types/providers/cursor.d.ts +72 -0
  53. package/dist/types/providers/dashscope-token-plan-headers.d.ts +57 -0
  54. package/dist/types/providers/error-message.d.ts +27 -0
  55. package/dist/types/providers/github-copilot-headers.d.ts +40 -0
  56. package/dist/types/providers/gitlab-duo.d.ts +27 -0
  57. package/dist/types/providers/google-auth.d.ts +26 -0
  58. package/dist/types/providers/google-gemini-cli.d.ts +75 -0
  59. package/dist/types/providers/google-gemini-headers.d.ts +43 -0
  60. package/dist/types/providers/google-shared.d.ts +183 -0
  61. package/dist/types/providers/google-types.d.ts +138 -0
  62. package/dist/types/providers/google-vertex.d.ts +11 -0
  63. package/dist/types/providers/google.d.ts +4 -0
  64. package/dist/types/providers/grammar.d.ts +1 -0
  65. package/dist/types/providers/kimi.d.ts +27 -0
  66. package/dist/types/providers/kiro-api-key.d.ts +50 -0
  67. package/dist/types/providers/kiro-codewhisperer.d.ts +11 -0
  68. package/dist/types/providers/mock.d.ts +189 -0
  69. package/dist/types/providers/ollama.d.ts +41 -0
  70. package/dist/types/providers/openai-anthropic-shim.d.ts +31 -0
  71. package/dist/types/providers/openai-bounded-rate-limits.d.ts +3 -0
  72. package/dist/types/providers/openai-chat-server-schema.d.ts +1733 -0
  73. package/dist/types/providers/openai-chat-server.d.ts +16 -0
  74. package/dist/types/providers/openai-codex/constants.d.ts +26 -0
  75. package/dist/types/providers/openai-codex/request-transformer.d.ts +50 -0
  76. package/dist/types/providers/openai-codex/response-handler.d.ts +18 -0
  77. package/dist/types/providers/openai-codex-responses.d.ts +71 -0
  78. package/dist/types/providers/openai-completions-compat.d.ts +6 -0
  79. package/dist/types/providers/openai-completions.d.ts +35 -0
  80. package/dist/types/providers/openai-opencodex-responses.d.ts +10 -0
  81. package/dist/types/providers/openai-request-transform.d.ts +4 -0
  82. package/dist/types/providers/openai-responses-server-schema.d.ts +392 -0
  83. package/dist/types/providers/openai-responses-server.d.ts +17 -0
  84. package/dist/types/providers/openai-responses-shared.d.ts +106 -0
  85. package/dist/types/providers/openai-responses.d.ts +37 -0
  86. package/dist/types/providers/pi-native-client.d.ts +29 -0
  87. package/dist/types/providers/pi-native-server.d.ts +60 -0
  88. package/dist/types/providers/register-builtins.d.ts +59 -0
  89. package/dist/types/providers/synthetic.d.ts +26 -0
  90. package/dist/types/providers/transform-messages.d.ts +33 -0
  91. package/dist/types/providers/vision-guard.d.ts +8 -0
  92. package/dist/types/rate-limit-utils.d.ts +19 -0
  93. package/dist/types/stream.d.ts +45 -0
  94. package/dist/types/types.d.ts +1073 -0
  95. package/dist/types/usage/claude.d.ts +3 -0
  96. package/dist/types/usage/gemini.d.ts +2 -0
  97. package/dist/types/usage/github-copilot.d.ts +7 -0
  98. package/dist/types/usage/google-antigravity.d.ts +2 -0
  99. package/dist/types/usage/grok-cli.d.ts +17 -0
  100. package/dist/types/usage/kimi.d.ts +4 -0
  101. package/dist/types/usage/minimax-code.d.ts +2 -0
  102. package/dist/types/usage/openai-codex.d.ts +3 -0
  103. package/dist/types/usage/shared.d.ts +1 -0
  104. package/dist/types/usage/zai.d.ts +2 -0
  105. package/dist/types/usage.d.ts +264 -0
  106. package/dist/types/utils/abort.d.ts +19 -0
  107. package/dist/types/utils/anthropic-auth.d.ts +39 -0
  108. package/dist/types/utils/block-symbols.d.ts +6 -0
  109. package/dist/types/utils/discovery/antigravity.d.ts +67 -0
  110. package/dist/types/utils/discovery/codex.d.ts +38 -0
  111. package/dist/types/utils/discovery/cursor.d.ts +49 -0
  112. package/dist/types/utils/discovery/gemini.d.ts +25 -0
  113. package/dist/types/utils/discovery/index.d.ts +4 -0
  114. package/dist/types/utils/discovery/openai-compatible.d.ts +81 -0
  115. package/dist/types/utils/event-stream.d.ts +41 -0
  116. package/dist/types/utils/fallback-transport.d.ts +110 -0
  117. package/dist/types/utils/fireworks-model-id.d.ts +10 -0
  118. package/dist/types/utils/foundry.d.ts +11 -0
  119. package/dist/types/utils/h2-fetch.d.ts +22 -0
  120. package/dist/types/utils/http-inspector.d.ts +59 -0
  121. package/dist/types/utils/idle-iterator.d.ts +122 -0
  122. package/dist/types/utils/json-parse.d.ts +98 -0
  123. package/dist/types/utils/oauth/alibaba-token-plan.d.ts +19 -0
  124. package/dist/types/utils/oauth/anthropic.d.ts +41 -0
  125. package/dist/types/utils/oauth/api-key-login.d.ts +38 -0
  126. package/dist/types/utils/oauth/api-key-validation.d.ts +39 -0
  127. package/dist/types/utils/oauth/bizrouter.d.ts +1 -0
  128. package/dist/types/utils/oauth/callback-server.d.ts +80 -0
  129. package/dist/types/utils/oauth/cerebras.d.ts +1 -0
  130. package/dist/types/utils/oauth/cloudflare-ai-gateway.d.ts +18 -0
  131. package/dist/types/utils/oauth/commandcode.d.ts +1 -0
  132. package/dist/types/utils/oauth/cursor.d.ts +15 -0
  133. package/dist/types/utils/oauth/deepinfra.d.ts +1 -0
  134. package/dist/types/utils/oauth/deepseek.d.ts +10 -0
  135. package/dist/types/utils/oauth/firepass.d.ts +1 -0
  136. package/dist/types/utils/oauth/fireworks.d.ts +1 -0
  137. package/dist/types/utils/oauth/fugu.d.ts +1 -0
  138. package/dist/types/utils/oauth/github-copilot.d.ts +38 -0
  139. package/dist/types/utils/oauth/gitlab-duo.d.ts +3 -0
  140. package/dist/types/utils/oauth/glm-zcode.d.ts +71 -0
  141. package/dist/types/utils/oauth/google-antigravity.d.ts +11 -0
  142. package/dist/types/utils/oauth/google-gemini-cli.d.ts +10 -0
  143. package/dist/types/utils/oauth/google-oauth-shared.d.ts +28 -0
  144. package/dist/types/utils/oauth/huggingface.d.ts +19 -0
  145. package/dist/types/utils/oauth/index.d.ts +39 -0
  146. package/dist/types/utils/oauth/kagi.d.ts +17 -0
  147. package/dist/types/utils/oauth/kilo.d.ts +5 -0
  148. package/dist/types/utils/oauth/kimi.d.ts +17 -0
  149. package/dist/types/utils/oauth/kiro.d.ts +71 -0
  150. package/dist/types/utils/oauth/litellm.d.ts +18 -0
  151. package/dist/types/utils/oauth/lm-studio.d.ts +17 -0
  152. package/dist/types/utils/oauth/mara.d.ts +1 -0
  153. package/dist/types/utils/oauth/minimax-code.d.ts +28 -0
  154. package/dist/types/utils/oauth/moonshot.d.ts +1 -0
  155. package/dist/types/utils/oauth/nanogpt.d.ts +1 -0
  156. package/dist/types/utils/oauth/nvidia.d.ts +18 -0
  157. package/dist/types/utils/oauth/ollama-cloud.d.ts +2 -0
  158. package/dist/types/utils/oauth/ollama.d.ts +18 -0
  159. package/dist/types/utils/oauth/openai-codex.d.ts +21 -0
  160. package/dist/types/utils/oauth/opencode.d.ts +18 -0
  161. package/dist/types/utils/oauth/opengateway.d.ts +1 -0
  162. package/dist/types/utils/oauth/openrouter.d.ts +1 -0
  163. package/dist/types/utils/oauth/parallel.d.ts +17 -0
  164. package/dist/types/utils/oauth/perplexity.d.ts +4 -0
  165. package/dist/types/utils/oauth/pkce.d.ts +8 -0
  166. package/dist/types/utils/oauth/qianfan.d.ts +17 -0
  167. package/dist/types/utils/oauth/qwen-portal.d.ts +19 -0
  168. package/dist/types/utils/oauth/sglang.d.ts +16 -0
  169. package/dist/types/utils/oauth/synthetic.d.ts +1 -0
  170. package/dist/types/utils/oauth/tavily.d.ts +17 -0
  171. package/dist/types/utils/oauth/together.d.ts +1 -0
  172. package/dist/types/utils/oauth/types.d.ts +56 -0
  173. package/dist/types/utils/oauth/venice.d.ts +18 -0
  174. package/dist/types/utils/oauth/vercel-ai-gateway.d.ts +18 -0
  175. package/dist/types/utils/oauth/vllm.d.ts +16 -0
  176. package/dist/types/utils/oauth/xai.d.ts +30 -0
  177. package/dist/types/utils/oauth/xiaomi.d.ts +25 -0
  178. package/dist/types/utils/oauth/zai.d.ts +18 -0
  179. package/dist/types/utils/oauth/zenmux.d.ts +1 -0
  180. package/dist/types/utils/overflow.d.ts +14 -0
  181. package/dist/types/utils/parse-bind.d.ts +26 -0
  182. package/dist/types/utils/provider-response.d.ts +6 -0
  183. package/dist/types/utils/provider-safety-stop.d.ts +8 -0
  184. package/dist/types/utils/proxy.d.ts +7 -0
  185. package/dist/types/utils/retry-after.d.ts +3 -0
  186. package/dist/types/utils/retry-budget.d.ts +1 -0
  187. package/dist/types/utils/retry.d.ts +29 -0
  188. package/dist/types/utils/schema/adapt.d.ts +24 -0
  189. package/dist/types/utils/schema/compatibility.d.ts +30 -0
  190. package/dist/types/utils/schema/dereference.d.ts +11 -0
  191. package/dist/types/utils/schema/draft.d.ts +10 -0
  192. package/dist/types/utils/schema/equality.d.ts +4 -0
  193. package/dist/types/utils/schema/fields.d.ts +49 -0
  194. package/dist/types/utils/schema/index.d.ts +14 -0
  195. package/dist/types/utils/schema/json-schema-validator.d.ts +12 -0
  196. package/dist/types/utils/schema/meta-validator.d.ts +2 -0
  197. package/dist/types/utils/schema/normalize.d.ts +93 -0
  198. package/dist/types/utils/schema/root-combinator.d.ts +12 -0
  199. package/dist/types/utils/schema/spill.d.ts +8 -0
  200. package/dist/types/utils/schema/stamps.d.ts +25 -0
  201. package/dist/types/utils/schema/types.d.ts +4 -0
  202. package/dist/types/utils/schema/wire.d.ts +54 -0
  203. package/dist/types/utils/schema/zod-decontaminate.d.ts +31 -0
  204. package/dist/types/utils/sse-debug.d.ts +10 -0
  205. package/dist/types/utils/tool-call-healing.d.ts +80 -0
  206. package/dist/types/utils/tool-choice-capability.d.ts +57 -0
  207. package/dist/types/utils/tool-choice.d.ts +50 -0
  208. package/dist/types/utils/validation.d.ts +17 -0
  209. package/dist/types/utils.d.ts +117 -0
  210. package/package.json +152 -0
  211. package/src/adapter-internals/provider-safety-stop.d.ts +45 -0
  212. package/src/adapter-internals/provider-safety-stop.ts +156 -0
  213. package/src/api-registry.d.ts +30 -0
  214. package/src/api-registry.ts +96 -0
  215. package/src/auth-broker/client.ts +444 -0
  216. package/src/auth-broker/index.ts +5 -0
  217. package/src/auth-broker/redact.ts +39 -0
  218. package/src/auth-broker/refresher.ts +130 -0
  219. package/src/auth-broker/remote-store.ts +1576 -0
  220. package/src/auth-broker/server.ts +764 -0
  221. package/src/auth-broker/types.ts +164 -0
  222. package/src/auth-broker/wire-schemas.ts +261 -0
  223. package/src/auth-gateway/http.ts +198 -0
  224. package/src/auth-gateway/index.ts +3 -0
  225. package/src/auth-gateway/server.ts +1315 -0
  226. package/src/auth-gateway/types.ts +160 -0
  227. package/src/auth-storage.ts +7312 -0
  228. package/src/cli.ts +269 -0
  229. package/src/codex-tools.d.ts +4 -0
  230. package/src/codex-tools.ts +24 -0
  231. package/src/context-cap-policy.d.ts +68 -0
  232. package/src/context-cap-policy.ts +123 -0
  233. package/src/core.ts +44 -0
  234. package/src/index.ts +61 -0
  235. package/src/model-cache.ts +236 -0
  236. package/src/model-manager.ts +744 -0
  237. package/src/model-pricing.d.ts +3 -0
  238. package/src/model-pricing.ts +68 -0
  239. package/src/model-retirements.d.ts +6 -0
  240. package/src/model-retirements.ts +19 -0
  241. package/src/model-thinking.d.ts +100 -0
  242. package/src/model-thinking.ts +1054 -0
  243. package/src/models.d.ts +21 -0
  244. package/src/models.json +94672 -0
  245. package/src/models.json.d.ts +9 -0
  246. package/src/models.ts +126 -0
  247. package/src/openai-completions-compat.d.ts +34 -0
  248. package/src/openai-completions-compat.ts +383 -0
  249. package/src/prompts/composer-bash-policy-recovery.md +1 -0
  250. package/src/prompts/cursor-composer-bash-policy-recovery.md +1 -0
  251. package/src/prompts/cursor-composer-edit-discipline.md +7 -0
  252. package/src/prompts/turn-aborted-guidance.md +4 -0
  253. package/src/provider-details.ts +90 -0
  254. package/src/provider-models/bundled-references.ts +38 -0
  255. package/src/provider-models/descriptors.ts +392 -0
  256. package/src/provider-models/google.ts +92 -0
  257. package/src/provider-models/index.ts +5 -0
  258. package/src/provider-models/ollama.ts +159 -0
  259. package/src/provider-models/openai-compat.ts +2920 -0
  260. package/src/provider-models/special.ts +185 -0
  261. package/src/providers/amazon-bedrock.d.ts +60 -0
  262. package/src/providers/amazon-bedrock.ts +939 -0
  263. package/src/providers/anthropic-messages-server-schema.ts +229 -0
  264. package/src/providers/anthropic-messages-server.ts +839 -0
  265. package/src/providers/anthropic.d.ts +280 -0
  266. package/src/providers/anthropic.ts +4421 -0
  267. package/src/providers/aws-credential-config.d.ts +19 -0
  268. package/src/providers/aws-credential-config.ts +179 -0
  269. package/src/providers/aws-credentials.d.ts +43 -0
  270. package/src/providers/aws-credentials.ts +457 -0
  271. package/src/providers/aws-eventstream.d.ts +38 -0
  272. package/src/providers/aws-eventstream.ts +185 -0
  273. package/src/providers/aws-sigv4.d.ts +55 -0
  274. package/src/providers/aws-sigv4.ts +218 -0
  275. package/src/providers/azure-openai-responses.d.ts +22 -0
  276. package/src/providers/azure-openai-responses.ts +447 -0
  277. package/src/providers/composer-discipline.d.ts +32 -0
  278. package/src/providers/composer-discipline.ts +95 -0
  279. package/src/providers/cursor/client-version.d.ts +10 -0
  280. package/src/providers/cursor/client-version.ts +10 -0
  281. package/src/providers/cursor/exec-modern.d.ts +98 -0
  282. package/src/providers/cursor/exec-modern.ts +497 -0
  283. package/src/providers/cursor/gen/agent_pb.d.ts +16769 -0
  284. package/src/providers/cursor/gen/agent_pb.ts +19780 -0
  285. package/src/providers/cursor/proto/agent.proto +4533 -0
  286. package/src/providers/cursor/proto/buf.gen.yaml +6 -0
  287. package/src/providers/cursor/proto/buf.yaml +17 -0
  288. package/src/providers/cursor-pi-args.d.ts +119 -0
  289. package/src/providers/cursor-pi-args.ts +187 -0
  290. package/src/providers/cursor.d.ts +72 -0
  291. package/src/providers/cursor.ts +3396 -0
  292. package/src/providers/dashscope-token-plan-headers.d.ts +57 -0
  293. package/src/providers/dashscope-token-plan-headers.ts +84 -0
  294. package/src/providers/error-message.d.ts +27 -0
  295. package/src/providers/error-message.ts +21 -0
  296. package/src/providers/github-copilot-headers.d.ts +40 -0
  297. package/src/providers/github-copilot-headers.ts +140 -0
  298. package/src/providers/gitlab-duo.d.ts +27 -0
  299. package/src/providers/gitlab-duo.ts +393 -0
  300. package/src/providers/google-auth.d.ts +26 -0
  301. package/src/providers/google-auth.ts +262 -0
  302. package/src/providers/google-gemini-cli.d.ts +75 -0
  303. package/src/providers/google-gemini-cli.ts +969 -0
  304. package/src/providers/google-gemini-headers.d.ts +43 -0
  305. package/src/providers/google-gemini-headers.ts +100 -0
  306. package/src/providers/google-shared.d.ts +183 -0
  307. package/src/providers/google-shared.ts +1105 -0
  308. package/src/providers/google-types.d.ts +138 -0
  309. package/src/providers/google-types.ts +167 -0
  310. package/src/providers/google-vertex.d.ts +11 -0
  311. package/src/providers/google-vertex.ts +124 -0
  312. package/src/providers/google.d.ts +4 -0
  313. package/src/providers/google.ts +41 -0
  314. package/src/providers/grammar.d.ts +1 -0
  315. package/src/providers/grammar.ts +70 -0
  316. package/src/providers/kimi.d.ts +27 -0
  317. package/src/providers/kimi.ts +52 -0
  318. package/src/providers/kiro-api-key.d.ts +50 -0
  319. package/src/providers/kiro-api-key.ts +786 -0
  320. package/src/providers/kiro-codewhisperer.d.ts +11 -0
  321. package/src/providers/kiro-codewhisperer.ts +600 -0
  322. package/src/providers/mock.ts +526 -0
  323. package/src/providers/ollama.d.ts +41 -0
  324. package/src/providers/ollama.ts +645 -0
  325. package/src/providers/openai-anthropic-shim.d.ts +31 -0
  326. package/src/providers/openai-anthropic-shim.ts +156 -0
  327. package/src/providers/openai-bounded-rate-limits.d.ts +3 -0
  328. package/src/providers/openai-bounded-rate-limits.ts +57 -0
  329. package/src/providers/openai-chat-server-schema.ts +254 -0
  330. package/src/providers/openai-chat-server.ts +724 -0
  331. package/src/providers/openai-codex/constants.d.ts +26 -0
  332. package/src/providers/openai-codex/constants.ts +43 -0
  333. package/src/providers/openai-codex/request-transformer.d.ts +50 -0
  334. package/src/providers/openai-codex/request-transformer.ts +219 -0
  335. package/src/providers/openai-codex/response-handler.d.ts +18 -0
  336. package/src/providers/openai-codex/response-handler.ts +111 -0
  337. package/src/providers/openai-codex-responses.d.ts +71 -0
  338. package/src/providers/openai-codex-responses.ts +3288 -0
  339. package/src/providers/openai-completions-compat.d.ts +6 -0
  340. package/src/providers/openai-completions-compat.ts +6 -0
  341. package/src/providers/openai-completions.d.ts +35 -0
  342. package/src/providers/openai-completions.ts +2294 -0
  343. package/src/providers/openai-opencodex-responses.ts +174 -0
  344. package/src/providers/openai-request-transform.d.ts +4 -0
  345. package/src/providers/openai-request-transform.ts +136 -0
  346. package/src/providers/openai-responses-server-schema.ts +290 -0
  347. package/src/providers/openai-responses-server.ts +1268 -0
  348. package/src/providers/openai-responses-shared.d.ts +106 -0
  349. package/src/providers/openai-responses-shared.ts +1253 -0
  350. package/src/providers/openai-responses.d.ts +37 -0
  351. package/src/providers/openai-responses.ts +989 -0
  352. package/src/providers/pi-native-client.d.ts +29 -0
  353. package/src/providers/pi-native-client.ts +243 -0
  354. package/src/providers/pi-native-server.ts +488 -0
  355. package/src/providers/register-builtins.d.ts +59 -0
  356. package/src/providers/register-builtins.ts +544 -0
  357. package/src/providers/synthetic.d.ts +26 -0
  358. package/src/providers/synthetic.ts +50 -0
  359. package/src/providers/transform-messages.d.ts +33 -0
  360. package/src/providers/transform-messages.ts +408 -0
  361. package/src/providers/vision-guard.d.ts +8 -0
  362. package/src/providers/vision-guard.ts +31 -0
  363. package/src/rate-limit-utils.d.ts +19 -0
  364. package/src/rate-limit-utils.ts +102 -0
  365. package/src/stream.d.ts +45 -0
  366. package/src/stream.ts +1306 -0
  367. package/src/types.d.ts +1073 -0
  368. package/src/types.ts +1305 -0
  369. package/src/usage/claude.ts +449 -0
  370. package/src/usage/gemini.ts +250 -0
  371. package/src/usage/github-copilot.ts +421 -0
  372. package/src/usage/google-antigravity.ts +201 -0
  373. package/src/usage/grok-cli.ts +259 -0
  374. package/src/usage/kimi.ts +285 -0
  375. package/src/usage/minimax-code.ts +31 -0
  376. package/src/usage/openai-codex.ts +503 -0
  377. package/src/usage/shared.ts +10 -0
  378. package/src/usage/zai.ts +247 -0
  379. package/src/usage.ts +190 -0
  380. package/src/utils/abort.d.ts +19 -0
  381. package/src/utils/abort.ts +51 -0
  382. package/src/utils/anthropic-auth.ts +95 -0
  383. package/src/utils/block-symbols.d.ts +6 -0
  384. package/src/utils/block-symbols.ts +11 -0
  385. package/src/utils/discovery/antigravity.ts +275 -0
  386. package/src/utils/discovery/codex.ts +362 -0
  387. package/src/utils/discovery/cursor.ts +388 -0
  388. package/src/utils/discovery/gemini.ts +248 -0
  389. package/src/utils/discovery/index.ts +4 -0
  390. package/src/utils/discovery/openai-compatible.ts +379 -0
  391. package/src/utils/event-stream.d.ts +41 -0
  392. package/src/utils/event-stream.ts +269 -0
  393. package/src/utils/fallback-transport.d.ts +110 -0
  394. package/src/utils/fallback-transport.ts +411 -0
  395. package/src/utils/fireworks-model-id.d.ts +10 -0
  396. package/src/utils/fireworks-model-id.ts +30 -0
  397. package/src/utils/foundry.d.ts +11 -0
  398. package/src/utils/foundry.ts +18 -0
  399. package/src/utils/h2-fetch.ts +60 -0
  400. package/src/utils/http-inspector.d.ts +59 -0
  401. package/src/utils/http-inspector.ts +380 -0
  402. package/src/utils/idle-iterator.d.ts +122 -0
  403. package/src/utils/idle-iterator.ts +410 -0
  404. package/src/utils/json-parse.d.ts +98 -0
  405. package/src/utils/json-parse.ts +607 -0
  406. package/src/utils/oauth/alibaba-token-plan.ts +60 -0
  407. package/src/utils/oauth/anthropic.ts +233 -0
  408. package/src/utils/oauth/api-key-login.ts +98 -0
  409. package/src/utils/oauth/api-key-validation.ts +344 -0
  410. package/src/utils/oauth/bizrouter.ts +15 -0
  411. package/src/utils/oauth/callback-server.d.ts +80 -0
  412. package/src/utils/oauth/callback-server.ts +359 -0
  413. package/src/utils/oauth/cerebras.ts +16 -0
  414. package/src/utils/oauth/cloudflare-ai-gateway.ts +48 -0
  415. package/src/utils/oauth/commandcode.ts +17 -0
  416. package/src/utils/oauth/cursor.ts +157 -0
  417. package/src/utils/oauth/deepinfra.ts +15 -0
  418. package/src/utils/oauth/deepseek.ts +53 -0
  419. package/src/utils/oauth/firepass.ts +24 -0
  420. package/src/utils/oauth/fireworks.ts +15 -0
  421. package/src/utils/oauth/fugu.ts +15 -0
  422. package/src/utils/oauth/github-copilot.d.ts +38 -0
  423. package/src/utils/oauth/github-copilot.ts +362 -0
  424. package/src/utils/oauth/gitlab-duo.ts +123 -0
  425. package/src/utils/oauth/glm-zcode.d.ts +71 -0
  426. package/src/utils/oauth/glm-zcode.ts +433 -0
  427. package/src/utils/oauth/google-antigravity.ts +200 -0
  428. package/src/utils/oauth/google-gemini-cli.ts +256 -0
  429. package/src/utils/oauth/google-oauth-shared.ts +110 -0
  430. package/src/utils/oauth/huggingface.ts +62 -0
  431. package/src/utils/oauth/index.ts +558 -0
  432. package/src/utils/oauth/kagi.ts +47 -0
  433. package/src/utils/oauth/kilo.ts +87 -0
  434. package/src/utils/oauth/kimi.d.ts +17 -0
  435. package/src/utils/oauth/kimi.ts +275 -0
  436. package/src/utils/oauth/kiro.ts +448 -0
  437. package/src/utils/oauth/litellm.ts +47 -0
  438. package/src/utils/oauth/lm-studio.ts +38 -0
  439. package/src/utils/oauth/mara.ts +16 -0
  440. package/src/utils/oauth/minimax-code.ts +78 -0
  441. package/src/utils/oauth/moonshot.ts +16 -0
  442. package/src/utils/oauth/nanogpt.ts +15 -0
  443. package/src/utils/oauth/nvidia.ts +70 -0
  444. package/src/utils/oauth/oauth.html +199 -0
  445. package/src/utils/oauth/ollama-cloud.ts +28 -0
  446. package/src/utils/oauth/ollama.ts +47 -0
  447. package/src/utils/oauth/openai-codex.ts +299 -0
  448. package/src/utils/oauth/opencode.ts +49 -0
  449. package/src/utils/oauth/opengateway.ts +15 -0
  450. package/src/utils/oauth/openrouter.ts +16 -0
  451. package/src/utils/oauth/parallel.ts +46 -0
  452. package/src/utils/oauth/perplexity.ts +225 -0
  453. package/src/utils/oauth/pkce.ts +18 -0
  454. package/src/utils/oauth/qianfan.ts +58 -0
  455. package/src/utils/oauth/qwen-portal.ts +60 -0
  456. package/src/utils/oauth/sglang.ts +42 -0
  457. package/src/utils/oauth/synthetic.ts +15 -0
  458. package/src/utils/oauth/tavily.ts +46 -0
  459. package/src/utils/oauth/together.ts +16 -0
  460. package/src/utils/oauth/types.d.ts +56 -0
  461. package/src/utils/oauth/types.ts +122 -0
  462. package/src/utils/oauth/venice.ts +59 -0
  463. package/src/utils/oauth/vercel-ai-gateway.ts +47 -0
  464. package/src/utils/oauth/vllm.ts +42 -0
  465. package/src/utils/oauth/xai.ts +246 -0
  466. package/src/utils/oauth/xiaomi.ts +199 -0
  467. package/src/utils/oauth/zai.ts +60 -0
  468. package/src/utils/oauth/zenmux.ts +15 -0
  469. package/src/utils/overflow.ts +275 -0
  470. package/src/utils/parse-bind.ts +81 -0
  471. package/src/utils/provider-response.d.ts +6 -0
  472. package/src/utils/provider-response.ts +30 -0
  473. package/src/utils/provider-safety-stop.ts +8 -0
  474. package/src/utils/proxy.d.ts +7 -0
  475. package/src/utils/proxy.ts +652 -0
  476. package/src/utils/retry-after.d.ts +3 -0
  477. package/src/utils/retry-after.ts +110 -0
  478. package/src/utils/retry-budget.d.ts +1 -0
  479. package/src/utils/retry-budget.ts +4 -0
  480. package/src/utils/retry.d.ts +29 -0
  481. package/src/utils/retry.ts +67 -0
  482. package/src/utils/schema/CONSTRAINTS.md +164 -0
  483. package/src/utils/schema/adapt.d.ts +24 -0
  484. package/src/utils/schema/adapt.ts +36 -0
  485. package/src/utils/schema/compatibility.d.ts +30 -0
  486. package/src/utils/schema/compatibility.ts +435 -0
  487. package/src/utils/schema/dereference.d.ts +11 -0
  488. package/src/utils/schema/dereference.ts +98 -0
  489. package/src/utils/schema/draft.d.ts +10 -0
  490. package/src/utils/schema/draft.ts +341 -0
  491. package/src/utils/schema/equality.d.ts +4 -0
  492. package/src/utils/schema/equality.ts +97 -0
  493. package/src/utils/schema/fields.d.ts +49 -0
  494. package/src/utils/schema/fields.ts +190 -0
  495. package/src/utils/schema/index.d.ts +14 -0
  496. package/src/utils/schema/index.ts +14 -0
  497. package/src/utils/schema/json-schema-validator.d.ts +12 -0
  498. package/src/utils/schema/json-schema-validator.ts +577 -0
  499. package/src/utils/schema/meta-validator.d.ts +2 -0
  500. package/src/utils/schema/meta-validator.ts +167 -0
  501. package/src/utils/schema/normalize.d.ts +93 -0
  502. package/src/utils/schema/normalize.ts +1588 -0
  503. package/src/utils/schema/root-combinator.d.ts +12 -0
  504. package/src/utils/schema/root-combinator.ts +143 -0
  505. package/src/utils/schema/spill.d.ts +8 -0
  506. package/src/utils/schema/spill.ts +43 -0
  507. package/src/utils/schema/stamps.d.ts +25 -0
  508. package/src/utils/schema/stamps.ts +97 -0
  509. package/src/utils/schema/types.d.ts +4 -0
  510. package/src/utils/schema/types.ts +11 -0
  511. package/src/utils/schema/wire.d.ts +54 -0
  512. package/src/utils/schema/wire.ts +213 -0
  513. package/src/utils/schema/zod-decontaminate.d.ts +31 -0
  514. package/src/utils/schema/zod-decontaminate.ts +331 -0
  515. package/src/utils/sse-debug.d.ts +10 -0
  516. package/src/utils/sse-debug.ts +289 -0
  517. package/src/utils/tool-call-healing.d.ts +80 -0
  518. package/src/utils/tool-call-healing.ts +298 -0
  519. package/src/utils/tool-choice-capability.d.ts +57 -0
  520. package/src/utils/tool-choice-capability.ts +633 -0
  521. package/src/utils/tool-choice.d.ts +50 -0
  522. package/src/utils/tool-choice.ts +99 -0
  523. package/src/utils/validation.ts +1080 -0
  524. package/src/utils.d.ts +117 -0
  525. package/src/utils.ts +523 -0
package/src/stream.ts ADDED
@@ -0,0 +1,1306 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import {
4
+ $credentialEnv,
5
+ $env,
6
+ $pickCredentialEnv,
7
+ extractHttpStatusFromError,
8
+ getTrustedHomeDir,
9
+ } from "@vib-rato/utils";
10
+ import {
11
+ copyProviderSafetyStopAdapterInvocation,
12
+ isProviderSafetyStopModelTrusted,
13
+ withProviderSafetyStopAdapterInvocation,
14
+ } from "./adapter-internals/provider-safety-stop";
15
+ import { assertManagedAttempt, classifyFallbackTrigger, type TransportFailureFacts } from "./utils/fallback-transport";
16
+
17
+ const managedAttemptValidated = Symbol("managedAttemptValidated");
18
+
19
+ function hasValidatedManagedAttempt(options: object | undefined): boolean {
20
+ return (options as Record<symbol, unknown> | undefined)?.[managedAttemptValidated] === true;
21
+ }
22
+
23
+ function markManagedAttemptValidated<T extends object>(options: T): T {
24
+ return Object.assign(options, { [managedAttemptValidated]: true });
25
+ }
26
+
27
+ import { getCustomApi } from "./api-registry";
28
+ import type { Effort } from "./model-thinking";
29
+ import {
30
+ mapEffortToAnthropicAdaptiveEffort,
31
+ mapEffortToGoogleThinkingLevel,
32
+ requireSupportedEffort,
33
+ } from "./model-thinking";
34
+ import type { BedrockOptions } from "./providers/amazon-bedrock";
35
+ import type { AnthropicOptions } from "./providers/anthropic";
36
+ import {
37
+ hasResolvableAwsProfileSource,
38
+ isValidBedrockBearerToken,
39
+ readAwsStaticEnvironmentCredentials,
40
+ } from "./providers/aws-credential-config";
41
+ import type { CursorOptions } from "./providers/cursor";
42
+ import type { GoogleOptions } from "./providers/google";
43
+ import type { GoogleGeminiCliOptions } from "./providers/google-gemini-cli";
44
+ import type { GoogleVertexOptions } from "./providers/google-vertex";
45
+ import type { KiroCodeWhispererOptions } from "./providers/kiro-codewhisperer";
46
+ import type { OllamaChatOptions } from "./providers/ollama";
47
+ import type { OpenAICompletionsOptions } from "./providers/openai-completions";
48
+ // Heavy provider stream functions are imported lazily via register-builtins,
49
+ // which wraps each provider module in a dynamic import. Thin provider routing
50
+ // modules are also loaded lazily below by returning an outer stream and piping
51
+ // the dynamically imported inner stream into it.
52
+ import {
53
+ streamAnthropic,
54
+ streamAzureOpenAIResponses,
55
+ streamBedrock,
56
+ streamCursor,
57
+ streamGoogle,
58
+ streamGoogleGeminiCli,
59
+ streamGoogleVertex,
60
+ streamKiroCodeWhisperer,
61
+ streamOllama,
62
+ streamOpenAICodexResponses,
63
+ streamOpenAICompletions,
64
+ streamOpenAIResponses,
65
+ } from "./providers/register-builtins";
66
+ import type {
67
+ Api,
68
+ AssistantMessage,
69
+ AssistantMessageEvent,
70
+ AuthRetryCredential,
71
+ Context,
72
+ Model,
73
+ OptionsForApi,
74
+ SimpleStreamOptions,
75
+ StreamOptions,
76
+ ThinkingBudgets,
77
+ ToolChoice,
78
+ } from "./types";
79
+ import { AssistantMessageEventStream } from "./utils/event-stream";
80
+ import { isFoundryEnabled } from "./utils/foundry";
81
+
82
+ let cachedVertexAdcCredentialsExists: boolean | null = null;
83
+
84
+ function hasVertexAdcCredentials(): boolean {
85
+ if (cachedVertexAdcCredentialsExists === null) {
86
+ const gacPath = $credentialEnv("GOOGLE_APPLICATION_CREDENTIALS");
87
+ if (gacPath) {
88
+ cachedVertexAdcCredentialsExists = fs.existsSync(gacPath);
89
+ } else {
90
+ cachedVertexAdcCredentialsExists = fs.existsSync(
91
+ path.join(getTrustedHomeDir(), ".config", "gcloud", "application_default_credentials.json"),
92
+ );
93
+ }
94
+ }
95
+ return cachedVertexAdcCredentialsExists;
96
+ }
97
+
98
+ type KeyResolver = string | (() => string | undefined);
99
+
100
+ const serviceProviderMap: Record<string, KeyResolver> = {
101
+ "alibaba-token-plan": "ALIBABA_TOKEN_PLAN_API_KEY",
102
+ openai: () => $credentialEnv("OPENAI_API_KEY"),
103
+ google: "GEMINI_API_KEY",
104
+ groq: "GROQ_API_KEY",
105
+ cerebras: "CEREBRAS_API_KEY",
106
+ xai: "XAI_API_KEY",
107
+ fireworks: "FIREWORKS_API_KEY",
108
+ firepass: "FIREPASS_API_KEY",
109
+ fugu: "FUGU_API_KEY",
110
+ openrouter: "OPENROUTER_API_KEY",
111
+ kilo: "KILO_API_KEY",
112
+ "vercel-ai-gateway": "AI_GATEWAY_API_KEY",
113
+ zai: "ZAI_API_KEY",
114
+ "glm-zcode": "GLM_ZCODE_API_KEY",
115
+ "jetbrains-junie": "JUNIE_API_KEY",
116
+ mistral: "MISTRAL_API_KEY",
117
+ minimax: "MINIMAX_API_KEY",
118
+ "minimax-code": "MINIMAX_CODE_API_KEY",
119
+ "commandcode-goat": "CMD_API_KEY",
120
+ "minimax-code-cn": "MINIMAX_CODE_CN_API_KEY",
121
+ "opencode-go": "OPENCODE_API_KEY",
122
+ "opencode-zen": "OPENCODE_API_KEY",
123
+ cursor: "CURSOR_ACCESS_TOKEN",
124
+ deepseek: "DEEPSEEK_API_KEY",
125
+ deepinfra: "DEEPINFRA_API_KEY",
126
+ "openai-codex": "OPENAI_CODEX_OAUTH_TOKEN",
127
+ "azure-openai": "AZURE_OPENAI_API_KEY",
128
+ "azure-openai-responses": "AZURE_OPENAI_API_KEY",
129
+ exa: "EXA_API_KEY",
130
+ jina: "JINA_API_KEY",
131
+ brave: "BRAVE_API_KEY",
132
+ perplexity: "PERPLEXITY_API_KEY",
133
+ tavily: "TAVILY_API_KEY",
134
+ parallel: "PARALLEL_API_KEY",
135
+ kagi: "KAGI_API_KEY",
136
+ // Kiro API keys use the ksk_ prefix; preserve the AWS bearer fallback for OAuth.
137
+ kiro: () => {
138
+ const apiKey = $credentialEnv("KIRO_API_KEY");
139
+ return apiKey?.trim().startsWith("ksk_") && !/[\x00-\x1f\x7f]/.test(apiKey)
140
+ ? apiKey
141
+ : $credentialEnv("AWS_BEARER_TOKEN_KIRO");
142
+ },
143
+ // GitHub Copilot uses GitHub personal access token
144
+ "github-copilot": () => $pickCredentialEnv("COPILOT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"),
145
+ // Foundry mode optionally switches Anthropic auth to enterprise gateway credentials.
146
+ anthropic: () =>
147
+ isFoundryEnabled()
148
+ ? $pickCredentialEnv("ANTHROPIC_FOUNDRY_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY")
149
+ : $pickCredentialEnv("ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"),
150
+ "gitlab-duo": "GITLAB_TOKEN",
151
+ // Vertex AI supports either GOOGLE_CLOUD_API_KEY or Application Default Credentials.
152
+ "google-vertex": () => {
153
+ const googleCloudApiKey = $credentialEnv("GOOGLE_CLOUD_API_KEY");
154
+ if (googleCloudApiKey) return googleCloudApiKey;
155
+
156
+ const hasCredentials = hasVertexAdcCredentials();
157
+ const hasProject = !!($env.GOOGLE_CLOUD_PROJECT || $env.GCLOUD_PROJECT);
158
+ const hasLocation = !!$env.GOOGLE_CLOUD_LOCATION;
159
+ if (hasCredentials && hasProject && hasLocation) {
160
+ return "<authenticated>";
161
+ }
162
+ },
163
+ // Advertise only credential sources implemented by the Bedrock request path.
164
+ // ECS and IRSA remain unavailable until matching resolvers are implemented.
165
+ "amazon-bedrock": () => {
166
+ const bearerToken = $credentialEnv("AWS_BEARER_TOKEN_BEDROCK");
167
+ if (bearerToken) return isValidBedrockBearerToken(bearerToken) ? "<authenticated>" : undefined;
168
+ if (readAwsStaticEnvironmentCredentials() || hasResolvableAwsProfileSource()) {
169
+ return "<authenticated>";
170
+ }
171
+ },
172
+ synthetic: "SYNTHETIC_API_KEY",
173
+ "cloudflare-ai-gateway": "CLOUDFLARE_AI_GATEWAY_API_KEY",
174
+ huggingface: () => $pickCredentialEnv("HUGGINGFACE_HUB_TOKEN", "HF_TOKEN"),
175
+ litellm: "LITELLM_API_KEY",
176
+ moonshot: "MOONSHOT_API_KEY",
177
+ nvidia: "NVIDIA_API_KEY",
178
+ nanogpt: "NANO_GPT_API_KEY",
179
+ "lm-studio": "LM_STUDIO_API_KEY",
180
+ omlx: "OMLX_API_KEY",
181
+ ollama: "OLLAMA_API_KEY",
182
+ "ollama-cloud": "OLLAMA_CLOUD_API_KEY",
183
+ "llama.cpp": "LLAMA_CPP_API_KEY",
184
+ qianfan: "QIANFAN_API_KEY",
185
+ "qwen-portal": () => $pickCredentialEnv("QWEN_OAUTH_TOKEN", "QWEN_PORTAL_API_KEY"),
186
+ together: "TOGETHER_API_KEY",
187
+ zenmux: "ZENMUX_API_KEY",
188
+ opengateway: "OPENGATEWAY_API_KEY",
189
+ bizrouter: "BIZROUTER_API_KEY",
190
+ mara: "MARA_API_KEY",
191
+ venice: "VENICE_API_KEY",
192
+ vllm: "VLLM_API_KEY",
193
+ sglang: "SGLANG_API_KEY",
194
+ xiaomi: "XIAOMI_API_KEY",
195
+ };
196
+
197
+ /**
198
+ * Get API key for provider from known environment variables, e.g. OPENAI_API_KEY.
199
+ *
200
+ * Provider authentication intentionally excludes cwd/.env values. Project dotenv files are
201
+ * loaded into $env for app/tool execution, but must not silently fund Vibrato model requests.
202
+ */
203
+ export function getEnvApiKey(provider: string): string | undefined {
204
+ const resolver = serviceProviderMap[provider];
205
+ if (typeof resolver === "string") {
206
+ return $credentialEnv(resolver);
207
+ }
208
+ return resolver?.();
209
+ }
210
+
211
+ /**
212
+ * Enumerate every provider that has an env-var fallback for `getEnvApiKey`.
213
+ * Used by `vib auth-broker migrate --include-env` to discover env-sourced keys
214
+ * that should be uploaded to the broker.
215
+ */
216
+ export function listProvidersWithEnvKey(): string[] {
217
+ return Object.keys(serviceProviderMap);
218
+ }
219
+
220
+ /**
221
+ * Subscription-style providers whose "subscription" is delivered as an API key
222
+ * (created at https://opencode.ai/auth), not a separate OAuth/session token.
223
+ * Used to give OpenCode users an accurate headless auth diagnostic (#755).
224
+ */
225
+ const OPENCODE_SUBSCRIPTION_PROVIDERS = new Set(["opencode-go", "opencode-zen"]);
226
+ const API_KEY_LOGIN_PROVIDERS = new Set(["commandcode-goat"]);
227
+
228
+ /**
229
+ * Provider-specific credential guidance appended to "no credential" errors.
230
+ *
231
+ * Headless Vibrato has no interactive `/login` TUI, so a bare "No API key" /
232
+ * "No credentials" error left users — OpenCode Go subscribers especially
233
+ * (#755) — unsure what signal Vibrato actually reads. OpenCode subscriptions are
234
+ * themselves API keys, so this names the env var Vibrato reads for the provider,
235
+ * warns that a project `.env` is intentionally ignored for provider
236
+ * credentials, and points OpenCode users at one-time interactive CLI credential capture.
237
+ *
238
+ * Returns an empty string when the provider has no env-var key and no special
239
+ * handling, so callers can append it unconditionally.
240
+ */
241
+ export function formatProviderCredentialHint(provider: string): string {
242
+ const resolver = serviceProviderMap[provider];
243
+ const envVar = typeof resolver === "string" ? resolver : undefined;
244
+ const isOpenCodeSubscription = OPENCODE_SUBSCRIPTION_PROVIDERS.has(provider);
245
+ const isApiKeyLoginProvider = API_KEY_LOGIN_PROVIDERS.has(provider);
246
+ const parts: string[] = [];
247
+ if (isOpenCodeSubscription) {
248
+ parts.push(
249
+ "OpenCode subscriptions authenticate with an API key (created at https://opencode.ai/auth), not a separate session/OAuth token.",
250
+ );
251
+ }
252
+ if (isApiKeyLoginProvider) {
253
+ parts.push("Command Code GOAT uses an API key from https://commandcode.ai/studio/#api-keys.");
254
+ }
255
+ if (provider === "jetbrains-junie") {
256
+ parts.push(
257
+ "JetBrains AI (Junie) authenticates with an access token generated at https://junie.jetbrains.com/cli; there is no OAuth login for this provider.",
258
+ );
259
+ }
260
+ if (envVar) {
261
+ parts.push(
262
+ `Headless Vibrato reads this provider's key from ${envVar} (exported in your shell or set in ~/.vib/.env).`,
263
+ );
264
+ parts.push("A value set only in a project .env is intentionally ignored for provider credentials.");
265
+ }
266
+ if (isOpenCodeSubscription) {
267
+ parts.push(
268
+ `Or run \`vib auth-broker login ${provider}\` once before headless/print mode to store the key interactively.`,
269
+ );
270
+ }
271
+ return parts.join(" ");
272
+ }
273
+ function pipeAssistantStream(
274
+ outer: AssistantMessageEventStream,
275
+ inner: AssistantMessageEventStream,
276
+ signal?: AbortSignal,
277
+ onStreamCreated?: () => void,
278
+ ): void {
279
+ void (async () => {
280
+ try {
281
+ let admitted = false;
282
+ const markAdmission = (): void => {
283
+ if (admitted) return;
284
+ admitted = true;
285
+ onStreamCreated?.();
286
+ };
287
+ for await (const event of inner) {
288
+ if (event.type !== "start") markAdmission();
289
+ outer.push(event);
290
+ // The inner provider stream owns abort semantics (it receives the
291
+ // same signal), but stop forwarding as soon as the consumer
292
+ // aborted so a misbehaving inner stream cannot keep the pipe
293
+ // buffering events indefinitely.
294
+ if (signal?.aborted && !outer.done) {
295
+ outer.end(await inner.result());
296
+ return;
297
+ }
298
+ }
299
+ if (!outer.done) outer.end(await inner.result());
300
+ } catch (error) {
301
+ outer.fail(error);
302
+ }
303
+ })();
304
+ }
305
+
306
+ export function streamFromLazyImport(
307
+ createInner: () => Promise<AssistantMessageEventStream>,
308
+ signal?: AbortSignal,
309
+ onStreamCreated?: () => void,
310
+ ): AssistantMessageEventStream {
311
+ const outer = new AssistantMessageEventStream();
312
+ void (async () => {
313
+ try {
314
+ const inner = await createInner();
315
+ pipeAssistantStream(outer, inner, signal, onStreamCreated);
316
+ } catch (error) {
317
+ outer.fail(error);
318
+ }
319
+ })();
320
+ return outer;
321
+ }
322
+
323
+ /**
324
+ * Build an actionable "missing API key" error for a provider, used by the
325
+ * low-level `stream`/`complete` entry points (#755).
326
+ */
327
+ export function formatMissingApiKeyError(provider: string): string {
328
+ const base = `No API key for provider: ${provider}.`;
329
+ const hint = formatProviderCredentialHint(provider);
330
+ return hint ? `${base} ${hint}` : base;
331
+ }
332
+
333
+ export function stream<TApi extends Api>(
334
+ model: Model<TApi>,
335
+ context: Context,
336
+ options?: OptionsForApi<TApi>,
337
+ onStreamCreated?: () => void,
338
+ ): AssistantMessageEventStream {
339
+ if (!hasValidatedManagedAttempt(options)) assertManagedAttempt(options);
340
+ if (options?.fallbackManaged) {
341
+ options = { ...options, requestMaxRetries: 0, streamMaxRetries: 0 } as OptionsForApi<TApi>;
342
+ }
343
+ // Canonical low-level boundary: the request budget must be a positive safe
344
+ // integer. Provider options arrive here unvalidated (unlike `streamSimple`,
345
+ // whose resolver already normalizes), so an unsafe value is dropped to
346
+ // unspecified here once for every dispatch below — integer-only provider
347
+ // fields can never receive a fractional or MAX_SAFE_INTEGER+1 budget.
348
+ if (options?.maxTokens !== undefined && !(Number.isSafeInteger(options.maxTokens) && options.maxTokens > 0)) {
349
+ options = { ...options, maxTokens: undefined } as OptionsForApi<TApi>;
350
+ }
351
+ // Check custom API registry first (extension-provided APIs like "vertex-Anthropic model-api")
352
+ const customApiProvider = getCustomApi(model.api);
353
+ if (customApiProvider) {
354
+ return customApiProvider.stream(model, context, options as StreamOptions);
355
+ }
356
+
357
+ if (model.provider === "gitlab-duo") {
358
+ const apiKey = (options as StreamOptions | undefined)?.apiKey || getEnvApiKey(model.provider);
359
+ if (!apiKey) {
360
+ throw new Error(formatMissingApiKeyError(model.provider));
361
+ }
362
+ const adapterOptions = isProviderSafetyStopModelTrusted(model)
363
+ ? withProviderSafetyStopAdapterInvocation({ ...(options as SimpleStreamOptions | undefined), apiKey })
364
+ : { ...(options as SimpleStreamOptions | undefined), apiKey };
365
+ return streamFromLazyImport(
366
+ async () => {
367
+ const { streamGitLabDuo } = await import("./providers/gitlab-duo");
368
+ return streamGitLabDuo(model, context, adapterOptions);
369
+ },
370
+ (options as StreamOptions | undefined)?.signal,
371
+ onStreamCreated,
372
+ );
373
+ }
374
+
375
+ // Vertex AI uses Application Default Credentials, not API keys
376
+ if (model.api === "google-vertex") {
377
+ const vertexOptions = (options || {}) as GoogleVertexOptions;
378
+ return streamGoogleVertex(
379
+ model as Model<"google-vertex">,
380
+ context,
381
+ isProviderSafetyStopModelTrusted(model)
382
+ ? withProviderSafetyStopAdapterInvocation(vertexOptions)
383
+ : vertexOptions,
384
+ onStreamCreated,
385
+ );
386
+ } else if (model.api === "bedrock-converse-stream") {
387
+ // Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
388
+ return streamBedrock(
389
+ model as Model<"bedrock-converse-stream">,
390
+ context,
391
+ (options || {}) as BedrockOptions,
392
+ onStreamCreated,
393
+ );
394
+ } else if (model.api === "kiro-codewhisperer-stream") {
395
+ return streamKiroCodeWhisperer(
396
+ model as Model<"kiro-codewhisperer-stream">,
397
+ context,
398
+ (options || {}) as KiroCodeWhispererOptions,
399
+ onStreamCreated,
400
+ );
401
+ }
402
+
403
+ const apiKey = options?.apiKey || (model.provider === "opencodex" ? "local" : getEnvApiKey(model.provider));
404
+ if (!apiKey) {
405
+ throw new Error(formatMissingApiKeyError(model.provider));
406
+ }
407
+ const providerOptions = { ...options, apiKey };
408
+ const adapterProviderOptions = isProviderSafetyStopModelTrusted(model)
409
+ ? withProviderSafetyStopAdapterInvocation(providerOptions)
410
+ : providerOptions;
411
+
412
+ const api: Api = model.api;
413
+ switch (api) {
414
+ case "anthropic-messages": {
415
+ const anthropicOptions = adapterProviderOptions as AnthropicOptions;
416
+ return streamAnthropic(
417
+ model as Model<"anthropic-messages">,
418
+ context,
419
+ {
420
+ ...anthropicOptions,
421
+ isOAuth: anthropicOptions.isOAuth ?? model.isOAuth,
422
+ },
423
+ onStreamCreated,
424
+ );
425
+ }
426
+
427
+ case "openai-completions":
428
+ return streamOpenAICompletions(
429
+ model as Model<"openai-completions">,
430
+ context,
431
+ adapterProviderOptions as any,
432
+ onStreamCreated,
433
+ );
434
+
435
+ case "openai-responses":
436
+ return streamOpenAIResponses(
437
+ model as Model<"openai-responses">,
438
+ context,
439
+ adapterProviderOptions as any,
440
+ onStreamCreated,
441
+ );
442
+
443
+ case "azure-openai-responses":
444
+ return streamAzureOpenAIResponses(
445
+ model as Model<"azure-openai-responses">,
446
+ context,
447
+ adapterProviderOptions as any,
448
+ onStreamCreated,
449
+ );
450
+
451
+ case "openai-codex-responses":
452
+ return streamOpenAICodexResponses(
453
+ model as Model<"openai-codex-responses">,
454
+ context,
455
+ adapterProviderOptions as any,
456
+ onStreamCreated,
457
+ );
458
+
459
+ case "google-generative-ai":
460
+ return streamGoogle(model as Model<"google-generative-ai">, context, adapterProviderOptions, onStreamCreated);
461
+
462
+ case "google-gemini-cli":
463
+ return streamGoogleGeminiCli(
464
+ model as Model<"google-gemini-cli">,
465
+ context,
466
+ adapterProviderOptions as GoogleGeminiCliOptions,
467
+ onStreamCreated,
468
+ );
469
+
470
+ case "ollama-chat":
471
+ return streamOllama(
472
+ model as Model<"ollama-chat">,
473
+ context,
474
+ adapterProviderOptions as OllamaChatOptions,
475
+ onStreamCreated,
476
+ );
477
+
478
+ case "cursor-agent":
479
+ return streamCursor(
480
+ model as Model<"cursor-agent">,
481
+ context,
482
+ adapterProviderOptions as CursorOptions,
483
+ onStreamCreated,
484
+ );
485
+
486
+ default:
487
+ throw new Error(`Unhandled API: ${api}`);
488
+ }
489
+ }
490
+
491
+ export async function complete<TApi extends Api>(
492
+ model: Model<TApi>,
493
+ context: Context,
494
+ options?: OptionsForApi<TApi>,
495
+ ): Promise<AssistantMessage> {
496
+ const s = stream(model, context, options);
497
+ return s.result();
498
+ }
499
+
500
+ type AuthRetryFailure = {
501
+ error: unknown;
502
+ bufferedEvents: AssistantMessageEvent[];
503
+ terminalEvent?: Extract<AssistantMessageEvent, { type: "error" }>;
504
+ };
505
+
506
+ function extractStatusFromAssistantError(message: AssistantMessage): number | undefined {
507
+ if (message.errorStatus !== undefined) return message.errorStatus;
508
+ if (!message.errorMessage) return undefined;
509
+ return extractHttpStatusFromError({ message: message.errorMessage });
510
+ }
511
+
512
+ function createAssistantAuthError(
513
+ message: AssistantMessage,
514
+ ): Error & { status?: number; transportFailure?: TransportFailureFacts } {
515
+ const error: Error & { status?: number; transportFailure?: TransportFailureFacts } = new Error(
516
+ message.errorMessage ?? "Provider authentication failed",
517
+ );
518
+ const status = extractStatusFromAssistantError(message);
519
+ if (status !== undefined) error.status = status;
520
+ // Preserve the structured facts. Without this the callback receives a
521
+ // status-only error and every downstream `auth` consumer loses the provider
522
+ // code it needs to tell a credential problem from a plain `forbidden`.
523
+ if (message.transportFailure) error.transportFailure = message.transportFailure;
524
+ return error;
525
+ }
526
+
527
+ /**
528
+ * Unwraps a nested `error.transportFailure` carrier.
529
+ *
530
+ * `transportFailureFacts` dereferences `value`, `value.response`, `value.error`
531
+ * and the captured response, but NOT `value.transportFailure` — and that is the
532
+ * shape this repository actually throws for transport errors. Reading the
533
+ * carrier here keeps the shared extractor untouched (its ten production call
534
+ * sites and its idempotence invariant stay as they are) while still letting the
535
+ * auth veto below see the provider code.
536
+ */
537
+ function carriedTransportFailure(candidate: unknown): unknown {
538
+ if (!candidate || typeof candidate !== "object") return undefined;
539
+ const carried = (candidate as { transportFailure?: unknown }).transportFailure;
540
+ return carried && typeof carried === "object" ? carried : undefined;
541
+ }
542
+
543
+ /** Auth-relevant facts for a thrown error or an assistant error, carrier first. */
544
+ function authFailureFacts(candidate: unknown): unknown {
545
+ return carriedTransportFailure(candidate) ?? candidate;
546
+ }
547
+
548
+ /**
549
+ * Whether this failure is a credential problem worth retrying with a different
550
+ * credential.
551
+ *
552
+ * Consulted by BOTH capture exits below, and it is the ONLY auth predicate they
553
+ * use. Gating on HTTP 401 alone would contradict the classifier: a typed
554
+ * provider code is supposed to win over the status, so `403 + invalid_api_key`
555
+ * must be captured and `401 + forbidden` must not. A `forbidden` failure is an
556
+ * authorization or configuration defect — handing it to `onAuthError` lets the
557
+ * gateway and SDK consumers invalidate a perfectly healthy credential.
558
+ */
559
+ function shouldCaptureAuthFailure(candidate: unknown, statusHint: number | undefined): boolean {
560
+ const trigger = classifyFallbackTrigger(authFailureFacts(candidate));
561
+ // Typed auth facts are authoritative and already encode code-over-status.
562
+ if (trigger.class === "auth") return trigger.authDisposition !== "forbidden";
563
+ // Nothing classifiable: keep the historical bare-401 admission.
564
+ return statusHint === 401;
565
+ }
566
+
567
+ function emitBufferedEvents(stream: AssistantMessageEventStream, events: AssistantMessageEvent[]): void {
568
+ for (const event of events) {
569
+ stream.push(event);
570
+ }
571
+ }
572
+
573
+ export function streamSimple<TApi extends Api>(
574
+ model: Model<TApi>,
575
+ context: Context,
576
+ options?: SimpleStreamOptions,
577
+ ): AssistantMessageEventStream {
578
+ assertManagedAttempt(options);
579
+ if (options?.fallbackManaged) {
580
+ options = {
581
+ ...options,
582
+ requestMaxRetries: 0,
583
+ streamMaxRetries: 0,
584
+ onAuthError: undefined,
585
+ };
586
+ options = markManagedAttemptValidated(options);
587
+ }
588
+ const retryApiKey = options?.onAuthError ? (options.apiKey ?? getEnvApiKey(model.provider)) : undefined;
589
+ if (retryApiKey) {
590
+ const consumerAbortController = new AbortController();
591
+ const outer = new AssistantMessageEventStream(() => consumerAbortController.abort());
592
+ const requestSignal = options?.signal
593
+ ? AbortSignal.any([options.signal, consumerAbortController.signal])
594
+ : consumerAbortController.signal;
595
+ const onAuthError = options!.onAuthError!;
596
+ const runAttempt = async (
597
+ apiKey: string,
598
+ captureAuthFailure: boolean,
599
+ onStreamCreated?: () => void,
600
+ ): Promise<AuthRetryFailure | undefined> => {
601
+ const bufferedEvents: AssistantMessageEvent[] = [];
602
+ let emittedReplayUnsafeEvent = false;
603
+ let admitted = false;
604
+ const markAdmission = (): void => {
605
+ if (admitted) return;
606
+ admitted = true;
607
+ onStreamCreated?.();
608
+ };
609
+ const flushBuffered = (): void => {
610
+ emitBufferedEvents(outer, bufferedEvents);
611
+ bufferedEvents.length = 0;
612
+ };
613
+
614
+ try {
615
+ const inner = streamSimple(model, context, {
616
+ ...options,
617
+ apiKey,
618
+ onAuthError: undefined,
619
+ onStreamCreated: markAdmission,
620
+ signal: requestSignal,
621
+ });
622
+ for await (const event of inner) {
623
+ if (!emittedReplayUnsafeEvent && event.type === "start") {
624
+ bufferedEvents.push(event);
625
+ continue;
626
+ }
627
+ if (
628
+ !emittedReplayUnsafeEvent &&
629
+ captureAuthFailure &&
630
+ event.type === "error" &&
631
+ // L0 gate, event exit. Classification decides; a typed
632
+ // `forbidden` never becomes an auth retry.
633
+ shouldCaptureAuthFailure(event.error, extractStatusFromAssistantError(event.error))
634
+ ) {
635
+ return { error: createAssistantAuthError(event.error), bufferedEvents, terminalEvent: event };
636
+ }
637
+ flushBuffered();
638
+ emittedReplayUnsafeEvent = true;
639
+ outer.push(event);
640
+ if (outer.done) return undefined;
641
+ }
642
+ flushBuffered();
643
+ if (!outer.done) outer.end(await inner.result());
644
+ } catch (error) {
645
+ if (
646
+ !emittedReplayUnsafeEvent &&
647
+ captureAuthFailure &&
648
+ // L0 gate, throw exit: same rule, carrier-aware.
649
+ shouldCaptureAuthFailure(error, extractHttpStatusFromError(error))
650
+ ) {
651
+ return { error, bufferedEvents };
652
+ }
653
+ flushBuffered();
654
+ outer.fail(error);
655
+ } finally {
656
+ // A lazy import or a synchronous provider failure can happen before
657
+ // the admission hook is reached. Release that attempt's lease in
658
+ // the failure path without extending a successful request's lease
659
+ // through the response lifetime.
660
+ if (!admitted) markAdmission();
661
+ }
662
+ return undefined;
663
+ };
664
+ const emitFailure = (failure: AuthRetryFailure): void => {
665
+ emitBufferedEvents(outer, failure.bufferedEvents);
666
+ if (failure.terminalEvent) {
667
+ outer.push(failure.terminalEvent);
668
+ } else {
669
+ outer.fail(failure.error);
670
+ }
671
+ };
672
+
673
+ void (async () => {
674
+ const failure = await runAttempt(retryApiKey, true, options?.onStreamCreated);
675
+ if (!failure) return;
676
+ let nextCredential: string | AuthRetryCredential | undefined;
677
+ try {
678
+ nextCredential = await onAuthError(model.provider, retryApiKey, failure.error);
679
+ } catch {
680
+ nextCredential = undefined;
681
+ }
682
+ const retryCredential: AuthRetryCredential | undefined =
683
+ typeof nextCredential === "string" ? { apiKey: nextCredential } : nextCredential;
684
+ if (!retryCredential?.apiKey || retryCredential.apiKey === retryApiKey) {
685
+ if (retryCredential) retryCredential.onStreamCreated?.();
686
+ emitFailure(failure);
687
+ return;
688
+ }
689
+ await runAttempt(retryCredential.apiKey, false, retryCredential.onStreamCreated);
690
+ })();
691
+ return outer;
692
+ }
693
+
694
+ // Pi-native transport short-circuits the per-provider dispatch entirely:
695
+ // the gateway resolves provider + credential server-side, so we don't
696
+ // need an `apiKey` from `getEnvApiKey` here — `options.apiKey` carries
697
+ // the gateway bearer instead. Comes BEFORE the custom-API check so
698
+ // extension-registered APIs can't accidentally override a configured
699
+ // pi-native transport.
700
+ const resolvedRequestMaxTokens = resolveDefaultRequestMaxTokens(model, options?.maxTokens);
701
+ if (model.transport === "pi-native") {
702
+ return streamFromLazyImport(
703
+ async () => {
704
+ const { streamPiNative } = await import("./providers/pi-native-client");
705
+ return streamPiNative(model, context, { ...options, maxTokens: resolvedRequestMaxTokens });
706
+ },
707
+ options?.signal,
708
+ options?.onStreamCreated,
709
+ );
710
+ }
711
+
712
+ // Check custom API registry (extension-provided APIs)
713
+ const customApiProvider = getCustomApi(model.api);
714
+ if (customApiProvider) {
715
+ const events = customApiProvider.streamSimple(model, context, {
716
+ ...options,
717
+ maxTokens: resolvedRequestMaxTokens,
718
+ });
719
+ if (!options?.onStreamCreated) return events;
720
+ const forwarded = new AssistantMessageEventStream();
721
+ pipeAssistantStream(forwarded, events, options.signal, options.onStreamCreated);
722
+ return forwarded;
723
+ }
724
+
725
+ // Vertex AI uses Application Default Credentials, not API keys
726
+ if (model.api === "google-vertex") {
727
+ const providerOptions = mapOptionsForApi(model, options, undefined);
728
+ const events = stream(model, context, providerOptions, options?.onStreamCreated);
729
+ return events;
730
+ } else if (model.api === "bedrock-converse-stream") {
731
+ // Bedrock doesn't have any API keys instead it sources credentials from standard AWS env variables or from given AWS profile.
732
+ const providerOptions = mapOptionsForApi(model, options, undefined);
733
+ const events = stream(model, context, providerOptions, options?.onStreamCreated);
734
+ return events;
735
+ }
736
+
737
+ const apiKey = options?.apiKey || getEnvApiKey(model.provider);
738
+ if (!apiKey) {
739
+ throw new Error(formatMissingApiKeyError(model.provider));
740
+ }
741
+ const adapterOptions = isProviderSafetyStopModelTrusted(model)
742
+ ? withProviderSafetyStopAdapterInvocation(options ?? {})
743
+ : options;
744
+ const resolvedSpecialProviderMaxTokens = resolvedRequestMaxTokens;
745
+
746
+ // GitLab Duo - wraps Anthropic/OpenAI behind GitLab AI Gateway direct access tokens
747
+ if (model.provider === "gitlab-duo") {
748
+ return streamFromLazyImport(
749
+ async () => {
750
+ const { streamGitLabDuo } = await import("./providers/gitlab-duo");
751
+ return streamGitLabDuo(
752
+ model,
753
+ context,
754
+ copyProviderSafetyStopAdapterInvocation(adapterOptions, {
755
+ ...adapterOptions,
756
+ apiKey,
757
+ maxTokens: resolvedSpecialProviderMaxTokens,
758
+ }),
759
+ );
760
+ },
761
+ options?.signal,
762
+ options?.onStreamCreated,
763
+ );
764
+ }
765
+
766
+ // Kimi Code - route to dedicated handler that wraps OpenAI or Anthropic API
767
+ if (model.provider === "kimi-code") {
768
+ return streamFromLazyImport(
769
+ async () => {
770
+ const { streamKimi } = await import("./providers/kimi");
771
+ // Pass raw SimpleStreamOptions - streamKimi handles mapping internally
772
+ return streamKimi(
773
+ model as Model<"openai-completions">,
774
+ context,
775
+ copyProviderSafetyStopAdapterInvocation(adapterOptions, {
776
+ ...adapterOptions,
777
+ apiKey,
778
+ maxTokens: resolvedSpecialProviderMaxTokens,
779
+ format: options?.kimiApiFormat ?? "anthropic",
780
+ }),
781
+ );
782
+ },
783
+ options?.signal,
784
+ options?.onStreamCreated,
785
+ );
786
+ }
787
+
788
+ // Synthetic - route to dedicated handler that wraps OpenAI or Anthropic API
789
+ if (model.provider === "synthetic") {
790
+ return streamFromLazyImport(
791
+ async () => {
792
+ const { streamSynthetic } = await import("./providers/synthetic");
793
+ // Pass raw SimpleStreamOptions - streamSynthetic handles mapping internally
794
+ return streamSynthetic(
795
+ model as Model<"openai-completions">,
796
+ context,
797
+ copyProviderSafetyStopAdapterInvocation(adapterOptions, {
798
+ ...adapterOptions,
799
+ apiKey,
800
+ maxTokens: resolvedSpecialProviderMaxTokens,
801
+ format: options?.syntheticApiFormat ?? "openai", // Default to OpenAI format
802
+ }),
803
+ );
804
+ },
805
+ options?.signal,
806
+ options?.onStreamCreated,
807
+ );
808
+ }
809
+
810
+ const providerOptions = mapOptionsForApi(model, options, apiKey);
811
+ const events = stream(model, context, providerOptions, options?.onStreamCreated);
812
+ return events;
813
+ }
814
+
815
+ export async function completeSimple<TApi extends Api>(
816
+ model: Model<TApi>,
817
+ context: Context,
818
+ options?: SimpleStreamOptions,
819
+ ): Promise<AssistantMessage> {
820
+ const s = streamSimple(model, context, options);
821
+ return s.result();
822
+ }
823
+
824
+ const MIN_OUTPUT_TOKENS = 1024;
825
+ const DEFAULT_REQUEST_MAX_TOKENS = 32000;
826
+ export const OUTPUT_FALLBACK_BUFFER = 4000;
827
+ const ANTHROPIC_USE_INTERLEAVED_THINKING = Bun.env.PI_NO_INTERLEAVED_THINKING !== "1";
828
+
829
+ export const ANTHROPIC_THINKING: Record<Effort, number> = {
830
+ minimal: 1024,
831
+ low: 4096,
832
+ medium: 8192,
833
+ high: 16384,
834
+ xhigh: 32768,
835
+ max: 65536,
836
+ };
837
+
838
+ const GOOGLE_THINKING: Record<Effort, number> = {
839
+ minimal: 1024,
840
+ low: 4096,
841
+ medium: 8192,
842
+ high: 16384,
843
+ xhigh: 24575,
844
+ max: 24575,
845
+ };
846
+
847
+ const BEDROCK_CLAUDE_THINKING: Record<Effort, number> = {
848
+ minimal: 1024,
849
+ low: 2048,
850
+ medium: 8192,
851
+ high: 16384,
852
+ xhigh: 16384,
853
+ max: 32768,
854
+ };
855
+
856
+ function resolveBedrockThinkingBudget(
857
+ model: Model<"bedrock-converse-stream">,
858
+ options?: SimpleStreamOptions,
859
+ ): { budget: number; level: Effort } | null {
860
+ if (!options?.reasoning || !model.reasoning) return null;
861
+ const level = requireSupportedEffort(model, options.reasoning);
862
+ const budget = options.thinkingBudgets?.[level] ?? BEDROCK_CLAUDE_THINKING[level];
863
+ return { budget, level };
864
+ }
865
+
866
+ export function mapAnthropicToolChoice(choice?: ToolChoice): AnthropicOptions["toolChoice"] {
867
+ if (!choice) return undefined;
868
+ if (typeof choice === "string") {
869
+ if (choice === "required") return "any";
870
+ if (choice === "auto" || choice === "none" || choice === "any") return choice;
871
+ return undefined;
872
+ }
873
+ if (choice.type === "tool") {
874
+ return choice.name ? { type: "tool", name: choice.name } : undefined;
875
+ }
876
+ if (choice.type === "function") {
877
+ const name = "function" in choice ? choice.function?.name : choice.name;
878
+ return name ? { type: "tool", name } : undefined;
879
+ }
880
+ return undefined;
881
+ }
882
+
883
+ function mapGoogleToolChoice(
884
+ choice?: ToolChoice,
885
+ ): GoogleOptions["toolChoice"] | GoogleGeminiCliOptions["toolChoice"] | GoogleVertexOptions["toolChoice"] {
886
+ if (!choice) return undefined;
887
+ if (typeof choice === "string") {
888
+ if (choice === "required") return "any";
889
+ if (choice === "auto" || choice === "none" || choice === "any") return choice;
890
+ return undefined;
891
+ }
892
+ return "any";
893
+ }
894
+
895
+ function mapOpenAiToolChoice(choice?: ToolChoice): OpenAICompletionsOptions["toolChoice"] {
896
+ if (!choice) return undefined;
897
+ if (typeof choice === "string") {
898
+ if (choice === "any") return "required";
899
+ if (choice === "auto" || choice === "none" || choice === "required") return choice;
900
+ return undefined;
901
+ }
902
+ if (choice.type === "tool") {
903
+ return choice.name ? { type: "function", function: { name: choice.name } } : undefined;
904
+ }
905
+ if (choice.type === "function") {
906
+ const name = "function" in choice ? choice.function?.name : choice.name;
907
+ return name ? { type: "function", function: { name } } : undefined;
908
+ }
909
+ return undefined;
910
+ }
911
+
912
+ function resolveOpenAiReasoningEffort<TApi extends Api>(
913
+ model: Model<TApi>,
914
+ options?: SimpleStreamOptions,
915
+ ): Effort | undefined {
916
+ const reasoning = options?.reasoning;
917
+ if (!reasoning || !model.reasoning) return undefined;
918
+ return requireSupportedEffort(model, reasoning);
919
+ }
920
+
921
+ const castApi = <TApi extends Api>(api: OptionsForApi<TApi>): OptionsForApi<Api> => api as OptionsForApi<Api>;
922
+
923
+ export function resolveDefaultRequestMaxTokens<TApi extends Api>(model: Model<TApi>, requested?: number): number {
924
+ if (requested !== undefined && Number.isSafeInteger(requested) && requested > 0) return requested;
925
+ if (model.maxTokensSource === "configured" && Number.isSafeInteger(model.maxTokens) && model.maxTokens > 0) {
926
+ return model.maxTokens;
927
+ }
928
+ return Number.isSafeInteger(model.maxTokens) && model.maxTokens > 0
929
+ ? Math.min(model.maxTokens, DEFAULT_REQUEST_MAX_TOKENS)
930
+ : DEFAULT_REQUEST_MAX_TOKENS;
931
+ }
932
+
933
+ function mapOptionsForApi<TApi extends Api>(
934
+ model: Model<TApi>,
935
+ options?: SimpleStreamOptions,
936
+ apiKey?: string,
937
+ ): OptionsForApi<TApi> {
938
+ const base = copyProviderSafetyStopAdapterInvocation(options, {
939
+ temperature: options?.temperature,
940
+ topP: options?.topP,
941
+ topK: options?.topK,
942
+ minP: options?.minP,
943
+ presencePenalty: options?.presencePenalty,
944
+ repetitionPenalty: options?.repetitionPenalty,
945
+ maxTokens: resolveDefaultRequestMaxTokens(model, options?.maxTokens),
946
+ signal: options?.signal,
947
+ apiKey: apiKey || options?.apiKey,
948
+ fallbackManaged: options?.fallbackManaged,
949
+ fallbackAttempt: options?.fallbackAttempt,
950
+ cacheRetention: options?.cacheRetention ?? model.cacheRetention,
951
+ headers: options?.headers,
952
+ initiatorOverride: options?.initiatorOverride,
953
+ maxRetryDelayMs: options?.maxRetryDelayMs,
954
+ requestMaxRetries: options?.fallbackManaged ? 0 : options?.requestMaxRetries,
955
+ streamMaxRetries: options?.fallbackManaged ? 0 : options?.streamMaxRetries,
956
+ metadata: options?.metadata,
957
+ sessionId: options?.sessionId,
958
+ providerSessionState: options?.providerSessionState,
959
+ onPayload: options?.onPayload,
960
+ onResponse: options?.onResponse,
961
+ onStreamCreated: options?.onStreamCreated,
962
+ disableProviderRetries: options?.disableProviderRetries,
963
+ onSseEvent: options?.onSseEvent,
964
+ attemptScope: options?.attemptScope,
965
+ execHandlers: options?.execHandlers,
966
+ [managedAttemptValidated]: hasValidatedManagedAttempt(options),
967
+ });
968
+
969
+ switch (model.api) {
970
+ case "anthropic-messages": {
971
+ // Explicitly disable thinking when reasoning is not specified or model doesn't support it
972
+ const reasoning = options?.reasoning;
973
+ if (!reasoning || !model.reasoning) {
974
+ return castApi<"anthropic-messages">({
975
+ ...base,
976
+ thinkingEnabled: false,
977
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
978
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
979
+ serviceTier: options?.serviceTier,
980
+ });
981
+ }
982
+
983
+ let thinkingBudget = options.thinkingBudgets?.[reasoning] ?? ANTHROPIC_THINKING[reasoning];
984
+ if (thinkingBudget <= 0) {
985
+ return castApi<"anthropic-messages">({
986
+ ...base,
987
+ thinkingEnabled: false,
988
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
989
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
990
+ serviceTier: options?.serviceTier,
991
+ });
992
+ }
993
+
994
+ // For Opus 4.6+ and Sonnet 4.6+: use adaptive thinking with effort level
995
+ // For older models: use budget-based thinking
996
+ if (model.thinking?.mode === "anthropic-adaptive") {
997
+ const effort = mapEffortToAnthropicAdaptiveEffort(model, reasoning);
998
+ return castApi<"anthropic-messages">({
999
+ ...base,
1000
+ thinkingEnabled: true,
1001
+ effort,
1002
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
1003
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
1004
+ serviceTier: options?.serviceTier,
1005
+ });
1006
+ }
1007
+
1008
+ if (ANTHROPIC_USE_INTERLEAVED_THINKING) {
1009
+ return castApi<"anthropic-messages">({
1010
+ ...base,
1011
+ thinkingEnabled: true,
1012
+ thinkingBudgetTokens: thinkingBudget,
1013
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
1014
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
1015
+ serviceTier: options?.serviceTier,
1016
+ });
1017
+ }
1018
+
1019
+ // Caller's maxTokens is the desired output; add thinking budget on top,
1020
+ // capped at the model limit. `base.maxTokens` is already resolver-sanitized,
1021
+ // so only a finite positive model cap participates (malformed metadata
1022
+ // cannot reintroduce NaN into the wire budget).
1023
+ const modelCap =
1024
+ Number.isSafeInteger(model.maxTokens) && model.maxTokens > 0 ? model.maxTokens : base.maxTokens;
1025
+ const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, modelCap);
1026
+
1027
+ // If not enough room for thinking + output, reduce thinking budget
1028
+ if (maxTokens <= thinkingBudget) {
1029
+ thinkingBudget = maxTokens - MIN_OUTPUT_TOKENS;
1030
+ }
1031
+
1032
+ // If thinking budget is too low, disable thinking
1033
+ if (thinkingBudget <= 0) {
1034
+ return castApi<"anthropic-messages">({
1035
+ ...base,
1036
+ thinkingEnabled: false,
1037
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
1038
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
1039
+ serviceTier: options?.serviceTier,
1040
+ });
1041
+ } else {
1042
+ return castApi<"anthropic-messages">({
1043
+ ...base,
1044
+ maxTokens,
1045
+ thinkingEnabled: true,
1046
+ thinkingBudgetTokens: thinkingBudget,
1047
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
1048
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
1049
+ serviceTier: options?.serviceTier,
1050
+ });
1051
+ }
1052
+ }
1053
+
1054
+ case "bedrock-converse-stream": {
1055
+ const bedrockBase: BedrockOptions = {
1056
+ ...base,
1057
+ reasoning: options?.reasoning,
1058
+ thinkingBudgets: options?.thinkingBudgets,
1059
+ toolChoice: mapAnthropicToolChoice(options?.toolChoice),
1060
+ thinkingDisplay: options?.hideThinkingSummary ? "omitted" : undefined,
1061
+ };
1062
+ // Adaptive mode sends effort directly, no budget_tokens — skip budget inflation.
1063
+ if (model.thinking?.mode === "anthropic-adaptive") {
1064
+ return castApi<"bedrock-converse-stream">(bedrockBase);
1065
+ }
1066
+ const budgetInfo = resolveBedrockThinkingBudget(model as Model<"bedrock-converse-stream">, options);
1067
+ if (!budgetInfo) return bedrockBase as OptionsForApi<TApi>;
1068
+ let maxTokens = bedrockBase.maxTokens ?? model.maxTokens;
1069
+ let thinkingBudgets = bedrockBase.thinkingBudgets;
1070
+ if (maxTokens <= budgetInfo.budget) {
1071
+ const desiredMaxTokens = Math.min(model.maxTokens, budgetInfo.budget + MIN_OUTPUT_TOKENS);
1072
+ if (desiredMaxTokens > maxTokens) {
1073
+ maxTokens = desiredMaxTokens;
1074
+ }
1075
+ }
1076
+ if (maxTokens <= budgetInfo.budget) {
1077
+ const adjustedBudget = Math.max(0, maxTokens - MIN_OUTPUT_TOKENS);
1078
+ thinkingBudgets = { ...(thinkingBudgets ?? {}), [budgetInfo.level]: adjustedBudget };
1079
+ }
1080
+ return castApi<"bedrock-converse-stream">({ ...bedrockBase, maxTokens, thinkingBudgets });
1081
+ }
1082
+
1083
+ case "openai-completions":
1084
+ return castApi<"openai-completions">({
1085
+ ...base,
1086
+ reasoning: resolveOpenAiReasoningEffort(model, options),
1087
+ disableReasoning: options?.disableReasoning,
1088
+ toolChoice: mapOpenAiToolChoice(options?.toolChoice),
1089
+ serviceTier: options?.serviceTier,
1090
+ });
1091
+
1092
+ case "openai-responses":
1093
+ return castApi<"openai-responses">({
1094
+ ...base,
1095
+ reasoning: resolveOpenAiReasoningEffort(model, options),
1096
+ toolChoice: mapOpenAiToolChoice(options?.toolChoice),
1097
+ serviceTier: options?.serviceTier,
1098
+ reasoningSummary: options?.hideThinkingSummary ? null : undefined,
1099
+ });
1100
+
1101
+ case "azure-openai-responses":
1102
+ return castApi<"azure-openai-responses">({
1103
+ ...base,
1104
+ reasoning: resolveOpenAiReasoningEffort(model, options),
1105
+ toolChoice: mapOpenAiToolChoice(options?.toolChoice),
1106
+ serviceTier: options?.serviceTier,
1107
+ reasoningSummary: options?.hideThinkingSummary ? null : undefined,
1108
+ });
1109
+
1110
+ case "openai-codex-responses":
1111
+ return castApi<"openai-codex-responses">({
1112
+ ...base,
1113
+ reasoning: resolveOpenAiReasoningEffort(model, options),
1114
+ toolChoice: mapOpenAiToolChoice(options?.toolChoice),
1115
+ serviceTier: options?.serviceTier,
1116
+ preferWebsockets: options?.preferWebsockets,
1117
+ reasoningSummary: options?.hideThinkingSummary ? null : undefined,
1118
+ });
1119
+
1120
+ case "google-generative-ai": {
1121
+ // Explicitly disable thinking when reasoning is not specified or model doesn't support it
1122
+ // This is needed because Gemini has "dynamic thinking" enabled by default
1123
+ const reasoning = options?.reasoning;
1124
+ if (!reasoning || !model.reasoning) {
1125
+ return castApi<"google-generative-ai">({
1126
+ ...base,
1127
+ thinking: { enabled: false },
1128
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1129
+ });
1130
+ }
1131
+
1132
+ const googleModel = model as Model<"google-generative-ai">;
1133
+ const effort = requireSupportedEffort(googleModel, reasoning);
1134
+
1135
+ // Gemini 3+ models use thinkingLevel exclusively instead of thinkingBudget.
1136
+ // https://ai.google.dev/gemini-api/docs/thinking#set-budget
1137
+ if (googleModel.thinking?.mode === "google-level") {
1138
+ return castApi<"google-generative-ai">({
1139
+ ...base,
1140
+ thinking: {
1141
+ enabled: true,
1142
+ level: mapEffortToGoogleThinkingLevel(googleModel, effort),
1143
+ },
1144
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1145
+ });
1146
+ }
1147
+
1148
+ return castApi<"google-gemini-cli">({
1149
+ ...base,
1150
+ thinking: {
1151
+ enabled: true,
1152
+ budgetTokens: getGoogleBudget(googleModel, effort, options?.thinkingBudgets),
1153
+ },
1154
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1155
+ });
1156
+ }
1157
+
1158
+ case "google-gemini-cli": {
1159
+ const reasoning = options?.reasoning;
1160
+ if (!reasoning || !model.reasoning) {
1161
+ return castApi<"google-gemini-cli">({
1162
+ ...base,
1163
+ thinking: { enabled: false },
1164
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1165
+ });
1166
+ }
1167
+
1168
+ const effort = requireSupportedEffort(model, reasoning);
1169
+
1170
+ // Gemini 3+ models use thinkingLevel instead of thinkingBudget
1171
+ if (model.thinking?.mode === "google-level") {
1172
+ return castApi<"google-gemini-cli">({
1173
+ ...base,
1174
+ thinking: {
1175
+ enabled: true,
1176
+ level: mapEffortToGoogleThinkingLevel(model, effort),
1177
+ },
1178
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1179
+ });
1180
+ }
1181
+
1182
+ let thinkingBudget = options.thinkingBudgets?.[effort] ?? GOOGLE_THINKING[effort];
1183
+
1184
+ // Caller's maxTokens is the desired output; add thinking budget on top,
1185
+ // capped at the model limit. `base.maxTokens` is already resolver-sanitized,
1186
+ // so only a finite positive model cap participates (malformed metadata
1187
+ // cannot reintroduce NaN into the wire budget).
1188
+ const modelCap =
1189
+ Number.isSafeInteger(model.maxTokens) && model.maxTokens > 0 ? model.maxTokens : base.maxTokens;
1190
+ const maxTokens = Math.min((base.maxTokens || 0) + thinkingBudget, modelCap);
1191
+
1192
+ // If not enough room for thinking + output, reduce thinking budget
1193
+ if (maxTokens <= thinkingBudget) {
1194
+ thinkingBudget = Math.max(0, maxTokens - MIN_OUTPUT_TOKENS);
1195
+ }
1196
+
1197
+ // If thinking budget is too low, disable thinking
1198
+ if (thinkingBudget <= 0) {
1199
+ return castApi<"google-gemini-cli">({
1200
+ ...base,
1201
+ thinking: { enabled: false },
1202
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1203
+ });
1204
+ } else {
1205
+ return castApi<"google-gemini-cli">({
1206
+ ...base,
1207
+ maxTokens,
1208
+ thinking: { enabled: true, budgetTokens: thinkingBudget },
1209
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1210
+ });
1211
+ }
1212
+ }
1213
+
1214
+ case "google-vertex": {
1215
+ // Explicitly disable thinking when reasoning is not specified or model doesn't support it
1216
+ const reasoning = options?.reasoning;
1217
+ if (!reasoning || !model.reasoning) {
1218
+ return castApi<"google-vertex">({
1219
+ ...base,
1220
+ thinking: { enabled: false },
1221
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1222
+ });
1223
+ }
1224
+
1225
+ const vertexModel = model as Model<"google-vertex">;
1226
+ const effort = requireSupportedEffort(vertexModel, reasoning);
1227
+ const geminiModel = vertexModel as unknown as Model<"google-generative-ai">;
1228
+
1229
+ if (geminiModel.thinking?.mode === "google-level") {
1230
+ return castApi<"google-vertex">({
1231
+ ...base,
1232
+ thinking: {
1233
+ enabled: true,
1234
+ level: mapEffortToGoogleThinkingLevel(geminiModel, effort),
1235
+ },
1236
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1237
+ });
1238
+ }
1239
+
1240
+ return castApi<"google-vertex">({
1241
+ ...base,
1242
+ thinking: {
1243
+ enabled: true,
1244
+ budgetTokens: getGoogleBudget(geminiModel, effort, options?.thinkingBudgets),
1245
+ },
1246
+ toolChoice: mapGoogleToolChoice(options?.toolChoice),
1247
+ });
1248
+ }
1249
+
1250
+ case "ollama-chat":
1251
+ return castApi<"ollama-chat">({
1252
+ ...base,
1253
+ reasoning: resolveOpenAiReasoningEffort(model, options),
1254
+ toolChoice: options?.toolChoice,
1255
+ });
1256
+
1257
+ case "cursor-agent": {
1258
+ const execHandlers = options?.cursorExecHandlers ?? options?.execHandlers;
1259
+ const onToolResult = options?.cursorOnToolResult ?? execHandlers?.onToolResult;
1260
+ return castApi<"cursor-agent">({
1261
+ ...base,
1262
+ execHandlers,
1263
+ onToolResult,
1264
+ });
1265
+ }
1266
+
1267
+ case "kiro-codewhisperer-stream":
1268
+ return castApi<"kiro-codewhisperer-stream">({
1269
+ ...base,
1270
+ reasoning: options?.reasoning,
1271
+ });
1272
+
1273
+ default:
1274
+ throw new Error(`Unhandled API in mapOptionsForApi: ${model.api}`);
1275
+ }
1276
+ }
1277
+
1278
+ function getGoogleBudget(
1279
+ model: Model<"google-generative-ai">,
1280
+ effort: Effort,
1281
+ customBudgets?: ThinkingBudgets,
1282
+ ): number {
1283
+ requireSupportedEffort(model, effort);
1284
+
1285
+ // Custom budgets take precedence if provided for this level
1286
+ if (customBudgets?.[effort] !== undefined) {
1287
+ return customBudgets[effort]!;
1288
+ }
1289
+
1290
+ // See https://ai.google.dev/gemini-api/docs/thinking#set-budget
1291
+ if (model.id.includes("2.5-")) {
1292
+ switch (effort) {
1293
+ case "minimal":
1294
+ return 128;
1295
+ case "low":
1296
+ return 2048;
1297
+ case "medium":
1298
+ return 8192;
1299
+ default:
1300
+ return model.id.includes("2.5-flash") ? 24576 : 32768;
1301
+ }
1302
+ }
1303
+
1304
+ // Unknown model - use dynamic
1305
+ return -1;
1306
+ }