@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
@@ -0,0 +1,1054 @@
1
+ import {
2
+ CODEX_GENERIC_CONTEXT_WINDOW,
3
+ CODEX_GPT_5_6_CONTEXT_CAP,
4
+ isCodexGpt56Tier,
5
+ isCodexProductTransport,
6
+ } from "./context-cap-policy";
7
+ import { applyOpenAIModelPricing } from "./model-pricing";
8
+ import { isAuditedOpenAIReasoningTransport, resolveOpenAICompat } from "./openai-completions-compat";
9
+ import type { Api, Model as ApiModel, ThinkingConfig } from "./types";
10
+ import { isClaudeForcedToolChoiceIncapableModelId } from "./utils/tool-choice-capability";
11
+
12
+ /** User-facing thinking levels, ordered least to most intensive. */
13
+ export const enum Effort {
14
+ Minimal = "minimal",
15
+ Low = "low",
16
+ Medium = "medium",
17
+ High = "high",
18
+ XHigh = "xhigh",
19
+ Max = "max",
20
+ }
21
+
22
+ export const THINKING_EFFORTS: readonly Effort[] = [
23
+ Effort.Minimal,
24
+ Effort.Low,
25
+ Effort.Medium,
26
+ Effort.High,
27
+ Effort.XHigh,
28
+ Effort.Max,
29
+ ];
30
+
31
+ const DEFAULT_REASONING_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
32
+ const DEFAULT_REASONING_EFFORTS_WITH_XHIGH: readonly Effort[] = [
33
+ Effort.Minimal,
34
+ Effort.Low,
35
+ Effort.Medium,
36
+ Effort.High,
37
+ Effort.XHigh,
38
+ ];
39
+ const DEFAULT_REASONING_EFFORTS_WITH_MAX: readonly Effort[] = [
40
+ Effort.Minimal,
41
+ Effort.Low,
42
+ Effort.Medium,
43
+ Effort.High,
44
+ Effort.Max,
45
+ ];
46
+ const DEFAULT_REASONING_EFFORTS_WITH_XHIGH_AND_MAX: readonly Effort[] = [
47
+ Effort.Minimal,
48
+ Effort.Low,
49
+ Effort.Medium,
50
+ Effort.High,
51
+ Effort.XHigh,
52
+ Effort.Max,
53
+ ];
54
+ const GEMINI_3_PRO_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High];
55
+ const GEMINI_3_FLASH_EFFORTS: readonly Effort[] = [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High];
56
+ // Gemini 3.7 Flash dropped `minimal`; the official API returns an error for it.
57
+ // https://ai.google.dev/gemini-api/docs/models/gemini-3.7-flash
58
+ const GEMINI_3_7_FLASH_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
59
+ const GPT_5_2_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
60
+ const GPT_5_6_PLUS_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh, Effort.Max];
61
+ const GPT_5_5_DEFAULT_EFFORT = Effort.XHigh;
62
+ const KIMI_K3_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High, Effort.Max];
63
+ const DEEPSEEK_V4_FLASH_0731_EFFORTS: readonly Effort[] = [Effort.Low, Effort.High, Effort.Max];
64
+ const GROK_4_5_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High];
65
+ const GROK_4_6_EFFORTS: readonly Effort[] = [Effort.Low, Effort.Medium, Effort.High, Effort.XHigh];
66
+
67
+ const GPT_5_1_CODEX_MINI_EFFORTS: readonly Effort[] = [Effort.Medium, Effort.High];
68
+ const CLOUDFLARE_AI_GATEWAY_BASE_URL = "https://gateway.ai.cloudflare.com/v1/<account>/<gateway>/anthropic";
69
+
70
+ type SemVer = {
71
+ major: number;
72
+ minor: number;
73
+ patch: number;
74
+ };
75
+
76
+ type GeminiKind = "pro" | "flash";
77
+ type AnthropicKind = "opus" | "sonnet" | "fable";
78
+ type OpenAIVariant =
79
+ | "base"
80
+ | "codex"
81
+ | "codex-max"
82
+ | "codex-mini"
83
+ | "codex-spark"
84
+ | "luna"
85
+ | "mini"
86
+ | "max"
87
+ | "nano"
88
+ | "sol"
89
+ | "terra";
90
+
91
+ const CODEX_GPT_5_4_PRIORITY_BY_VARIANT: Partial<Record<OpenAIVariant, number>> = {
92
+ base: 0,
93
+ mini: 1,
94
+ nano: 2,
95
+ };
96
+
97
+ const COPILOT_GENERATED_LIMITS: Record<string, { contextWindow: number; maxTokens: number }> = {
98
+ "claude-opus-4.6": { contextWindow: 168000, maxTokens: 32000 },
99
+ "gpt-5.2": { contextWindow: 272000, maxTokens: 128000 },
100
+ "gpt-5.4": { contextWindow: 272000, maxTokens: 128000 },
101
+ "gpt-5.4-mini": { contextWindow: 272000, maxTokens: 128000 },
102
+ "grok-code-fast-1": { contextWindow: 192000, maxTokens: 64000 },
103
+ };
104
+
105
+ interface GeminiModel {
106
+ family: "gemini";
107
+ kind: GeminiKind;
108
+ version: SemVer;
109
+ }
110
+
111
+ interface AnthropicModel {
112
+ family: "anthropic";
113
+ kind: AnthropicKind;
114
+ version: SemVer;
115
+ }
116
+
117
+ interface OpenAIModel {
118
+ family: "openai";
119
+ variant: OpenAIVariant;
120
+ version: SemVer;
121
+ }
122
+
123
+ interface UnknownModel {
124
+ family: "unknown";
125
+ id: string;
126
+ }
127
+
128
+ type ParsedModel = GeminiModel | AnthropicModel | OpenAIModel | UnknownModel;
129
+
130
+ /**
131
+ * Static fallback model injected when Cloudflare AI Gateway discovery
132
+ * returns no results. Ensures the provider always has at least one usable
133
+ * model entry in the catalog.
134
+ */
135
+ export const CLOUDFLARE_FALLBACK_MODEL: ApiModel<"anthropic-messages"> = {
136
+ id: "claude-sonnet-4-5",
137
+ name: "Anthropic Sonnet 4.5",
138
+ api: "anthropic-messages",
139
+ provider: "cloudflare-ai-gateway",
140
+ baseUrl: CLOUDFLARE_AI_GATEWAY_BASE_URL,
141
+ reasoning: true,
142
+ input: ["text", "image"],
143
+ cost: {
144
+ input: 3,
145
+ output: 15,
146
+ cacheRead: 0.3,
147
+ cacheWrite: 3.75,
148
+ },
149
+ contextWindow: 200000,
150
+ maxTokens: 64000,
151
+ };
152
+
153
+ const kEnrichedModel = Symbol("model-thinking.enrichedModel");
154
+ type ModelWithEnriched = ApiModel<Api> & { [kEnrichedModel]?: ApiModel<Api> };
155
+
156
+ export function isGroqCompoundReasoningUnsupported(model: Pick<ApiModel<Api>, "provider" | "id">): boolean {
157
+ return model.provider === "groq" && (model.id === "groq/compound" || model.id === "groq/compound-mini");
158
+ }
159
+
160
+ /**
161
+ * Returns a copy of the model with canonical thinking metadata attached.
162
+ *
163
+ * This helper belongs to catalog enrichment only. Runtime consumers should
164
+ * trust `model.thinking` and avoid inferring capabilities on demand.
165
+ */
166
+ export function enrichModelThinking<TApi extends Api>(model: ApiModel<TApi>): ApiModel<TApi> {
167
+ const tagged = model as ModelWithEnriched;
168
+ const cached = tagged[kEnrichedModel];
169
+ if (cached !== undefined) {
170
+ return cached as ApiModel<TApi>;
171
+ }
172
+ const normalizedThinking = normalizeThinkingConfig(model.thinking);
173
+ let result: ApiModel<TApi>;
174
+ if (isGroqCompoundReasoningUnsupported(model)) {
175
+ result =
176
+ !model.reasoning && normalizedThinking === undefined
177
+ ? model
178
+ : { ...model, reasoning: false, thinking: undefined };
179
+ } else if (!model.reasoning || !modelSupportsReasoningControl(model)) {
180
+ result =
181
+ normalizedThinking === undefined && model.thinking === undefined ? model : { ...model, thinking: undefined };
182
+ } else {
183
+ const thinking = normalizedThinking ?? inferModelThinking(model);
184
+ result = thinkingsEqual(normalizedThinking, thinking) ? model : { ...model, thinking };
185
+ }
186
+ // Stash the enriched copy on a non-enumerable slot so callers that hand us
187
+ // the same reference twice skip the work. `enumerable: false` is critical:
188
+ // many call sites build derived models via `{ ...model, ...overrides }`,
189
+ // which would otherwise copy this cache slot and trick us into returning
190
+ // the *original* enriched model — silently discarding the overrides.
191
+ Object.defineProperty(tagged, kEnrichedModel, {
192
+ value: result,
193
+ enumerable: false,
194
+ configurable: true,
195
+ writable: true,
196
+ });
197
+ return result;
198
+ }
199
+
200
+ /**
201
+ * Returns a copy of the model with thinking metadata recomputed from the
202
+ * canonical rules, replacing any existing `thinking`.
203
+ */
204
+ export function refreshModelThinking<TApi extends Api>(model: ApiModel<TApi>): ApiModel<TApi> {
205
+ if (isGroqCompoundReasoningUnsupported(model)) {
206
+ return !model.reasoning && model.thinking === undefined
207
+ ? model
208
+ : { ...model, reasoning: false, thinking: undefined };
209
+ }
210
+ if (!model.reasoning || !modelSupportsReasoningControl(model)) {
211
+ const normalizedThinking = normalizeThinkingConfig(model.thinking);
212
+ return normalizedThinking === undefined && model.thinking === undefined
213
+ ? model
214
+ : { ...model, thinking: undefined };
215
+ }
216
+ return { ...model, thinking: inferModelThinking(model) };
217
+ }
218
+
219
+ /**
220
+ * Returns whether the configured transport has an audited user-facing reasoning control.
221
+ *
222
+ * Custom OpenAI-compatible endpoints fail closed: declaring a model as reasoning-capable
223
+ * is not enough to prove that the proxy accepts OpenAI reasoning parameters. Unknown
224
+ * endpoints must opt in with `compat.supportsReasoningEffort: true`; providers using a
225
+ * non-OpenAI request shape must also declare `compat.thinkingFormat`. Bundled providers
226
+ * remain governed by their catalog and compatibility metadata.
227
+ */
228
+ export function modelSupportsReasoningControl<TApi extends Api>(
229
+ model: ApiModel<TApi>,
230
+ resolvedBaseUrl?: string,
231
+ ): boolean {
232
+ if (!model.reasoning) return false;
233
+
234
+ if (model.api === "openai-completions") {
235
+ const completionsModel = model as ApiModel<"openai-completions">;
236
+ const explicitSupport = completionsModel.compat?.supportsReasoningEffort;
237
+ if (explicitSupport === false) return false;
238
+ if (explicitSupport !== true && !isAuditedOpenAIReasoningTransport(completionsModel, resolvedBaseUrl))
239
+ return false;
240
+ const compat = resolveOpenAICompat(completionsModel, resolvedBaseUrl);
241
+ return compat.thinkingFormat !== "openai" || compat.supportsReasoningEffort;
242
+ }
243
+
244
+ if (
245
+ model.api === "openai-responses" ||
246
+ model.api === "openai-codex-responses" ||
247
+ model.api === "azure-openai-responses"
248
+ ) {
249
+ const explicitSupport =
250
+ model.compat !== undefined && "supportsReasoningEffort" in model.compat
251
+ ? model.compat.supportsReasoningEffort
252
+ : undefined;
253
+ return explicitSupport ?? isAuditedOpenAIReasoningTransport(model);
254
+ }
255
+
256
+ return true;
257
+ }
258
+
259
+ /**
260
+ * Apply upstream metadata corrections to a mutable array of models.
261
+ *
262
+ * Each model is first normalized through `refreshModelThinking()` so generated
263
+ * catalogs keep canonical thinking metadata and policy fixes in one pass.
264
+ */
265
+ export function applyGeneratedModelPolicies(models: ApiModel<Api>[]): void {
266
+ for (let index = 0; index < models.length; index++) {
267
+ const source = models[index]!;
268
+ if (source.provider === "xai" && (source.id === "grok-4.5" || source.id === "grok-4.6")) {
269
+ source.reasoning = true;
270
+ }
271
+ if (source.provider === "alibaba-token-plan" && source.id === "deepseek-v4-flash-0731") {
272
+ source.reasoning = true;
273
+ source.name = "DeepSeek V4 Flash 0731";
274
+ }
275
+ if (source.id.split("/").at(-1)?.toLowerCase() === "muse-spark-1.2") {
276
+ source.reasoning = true;
277
+ }
278
+ if (source.provider === "omlx") {
279
+ source.reasoning = true;
280
+ }
281
+ const model = refreshModelThinking(source);
282
+ applyGeneratedModelPolicy(model);
283
+ models[index] = model;
284
+ }
285
+ }
286
+
287
+ /**
288
+ * Link OpenAI model variants to their context promotion targets.
289
+ *
290
+ * When a model's context is exhausted, the agent can promote to a sibling
291
+ * model with a larger context window on the same provider:
292
+ * - `OpenAI code backend-spark` variants promote to `gpt-5.5`.
293
+ *
294
+ * `gpt-5.5` itself is a 1M-context model and is not demoted to `gpt-5.4`
295
+ * (which has a smaller window), so it has no promotion target.
296
+ */
297
+ export function linkOpenAIPromotionTargets(models: ApiModel<Api>[]): void {
298
+ for (const candidate of models) {
299
+ const parsedCandidate = parseKnownModel(candidate.id);
300
+ if (parsedCandidate.family !== "openai") continue;
301
+ let targetId: string | undefined;
302
+ if (parsedCandidate.variant === "codex-spark") {
303
+ targetId = "gpt-5.5";
304
+ } else {
305
+ continue;
306
+ }
307
+ const fallback = models.find(
308
+ model => model.provider === candidate.provider && model.api === candidate.api && model.id === targetId,
309
+ );
310
+ if (!fallback) continue;
311
+ candidate.contextPromotionTarget = `${fallback.provider}/${fallback.id}`;
312
+ }
313
+ }
314
+
315
+ /**
316
+ * Returns the supported thinking efforts declared on the model metadata.
317
+ *
318
+ * Catalog enrichment is responsible for normalizing bundled model metadata up front.
319
+ * Runtime callers must treat explicit `model.thinking` on custom models as authoritative
320
+ * so proxy-specific overrides from `models.yml` survive request construction.
321
+ *
322
+ * @throws Error when a reasoning-capable model is missing thinking metadata
323
+ */
324
+ export function getSupportedEfforts<TApi extends Api>(model: ApiModel<TApi>): readonly Effort[] {
325
+ if (!modelSupportsReasoningControl(model)) {
326
+ return [];
327
+ }
328
+ if (!model.thinking) {
329
+ throw new Error(`Model ${model.provider}/${model.id} is missing thinking metadata`);
330
+ }
331
+ return expandEffortRange(model.thinking);
332
+ }
333
+
334
+ /**
335
+ * Clamps a requested thinking level against explicit model metadata.
336
+ *
337
+ * Non-reasoning models always resolve to `undefined`.
338
+ */
339
+ export function clampThinkingLevelForModel<TApi extends Api>(
340
+ model: ApiModel<TApi> | undefined,
341
+ requested: Effort | undefined,
342
+ ): Effort | undefined {
343
+ if (!model) {
344
+ return requested;
345
+ }
346
+ if (!modelSupportsReasoningControl(model) || requested === undefined) {
347
+ return undefined;
348
+ }
349
+
350
+ const levels = getSupportedEfforts(model);
351
+ if (levels.includes(requested)) {
352
+ return requested;
353
+ }
354
+
355
+ const requestedIndex = THINKING_EFFORTS.indexOf(requested);
356
+ if (requestedIndex === -1) {
357
+ return undefined;
358
+ }
359
+
360
+ let clamped: Effort | undefined;
361
+ for (const effort of levels) {
362
+ if (THINKING_EFFORTS.indexOf(effort) > requestedIndex) {
363
+ break;
364
+ }
365
+ clamped = effort;
366
+ }
367
+
368
+ return clamped ?? levels[0];
369
+ }
370
+
371
+ export function requireSupportedEffort<TApi extends Api>(model: ApiModel<TApi>, effort: Effort): Effort {
372
+ if (!modelSupportsReasoningControl(model)) {
373
+ throw new Error(`Model ${model.provider}/${model.id} does not support thinking`);
374
+ }
375
+ const levels = getSupportedEfforts(model);
376
+ if (!levels.includes(effort)) {
377
+ throw new Error(
378
+ `Thinking effort ${effort} is not supported by ${model.provider}/${model.id}. Supported efforts: ${levels.join(", ")}`,
379
+ );
380
+ }
381
+ return effort;
382
+ }
383
+
384
+ /** Maps a normalized thinking effort to Google's `thinkingLevel` enum values. */
385
+ export function mapEffortToGoogleThinkingLevel<TApi extends Api>(
386
+ model: ApiModel<TApi>,
387
+ effort: Effort,
388
+ ): "MINIMAL" | "LOW" | "MEDIUM" | "HIGH" {
389
+ switch (requireSupportedEffort(model, effort)) {
390
+ case Effort.Minimal:
391
+ return "MINIMAL";
392
+ case Effort.Low:
393
+ return "LOW";
394
+ case Effort.Medium:
395
+ return "MEDIUM";
396
+ case Effort.High:
397
+ case Effort.XHigh:
398
+ case Effort.Max:
399
+ return "HIGH";
400
+ }
401
+ }
402
+
403
+ /** Maps a normalized thinking effort to Anthropic adaptive effort values. */
404
+ export function mapEffortToAnthropicAdaptiveEffort<TApi extends Api>(
405
+ model: ApiModel<TApi>,
406
+ effort: Effort,
407
+ ): "low" | "medium" | "high" | "xhigh" | "max" {
408
+ switch (requireSupportedEffort(model, effort)) {
409
+ case Effort.Minimal:
410
+ case Effort.Low:
411
+ return "low";
412
+ case Effort.Medium:
413
+ return "medium";
414
+ case Effort.High:
415
+ return "high";
416
+ case Effort.XHigh:
417
+ case Effort.Max:
418
+ return effort === Effort.XHigh ? "xhigh" : "max";
419
+ }
420
+ }
421
+
422
+ /**
423
+ * Returns true for Anthropic models with Opus 4.7 API restrictions:
424
+ * - Sampling parameters (temperature/top_p/top_k) return 400 error
425
+ * - Thinking content is omitted by default (needs display: "summarized")
426
+ */
427
+ export function hasOpus47ApiRestrictions(modelId: string): boolean {
428
+ const parsed = parseAnthropicModel(getCanonicalModelId(modelId));
429
+ if (!parsed) return false;
430
+ return semverGte(parsed.version, "4.7") && parsed.kind === "opus";
431
+ }
432
+
433
+ /**
434
+ * Adaptive thinking `display` is supported starting with Anthropic Opus 4.7.
435
+ * Older adaptive-thinking models (Opus 4.6, Sonnet 4.6+) reject the field.
436
+ * Fable (5+) postdates Opus 4.7, accepts `display`, and defaults it to
437
+ * "omitted" — thinking tokens are billed but no content streams back — so it
438
+ * must opt in like Opus 4.7+ (issue #2791).
439
+ *
440
+ * Shares `hasOpus47ApiRestrictions` version parsing on purpose: the two
441
+ * predicates describe the same API generation, and a private `claude-opus-(\d+)-(\d+)`
442
+ * regex silently disagreed with it for single-component aliases (`claude-opus-5`
443
+ * matched nothing while `claude-opus-5-20260101` matched), so the same model sent
444
+ * a different thinking shape and beta set depending on which id string was used.
445
+ * Bedrock region/inference-profile prefixes are handled by the canonical parser.
446
+ */
447
+ export function supportsAnthropicAdaptiveThinkingDisplay(modelId: string): boolean {
448
+ if (/claude-fable-\d/.test(modelId)) return true;
449
+ return hasOpus47ApiRestrictions(modelId);
450
+ }
451
+
452
+ function anthropicModelHasRealXHighEffort<TApi extends Api>(model: ApiModel<TApi>): boolean {
453
+ if (model.api !== "anthropic-messages") return false;
454
+ const parsedModel = parseKnownModel(model.id);
455
+ if (parsedModel.family !== "anthropic") return false;
456
+ // Explicit capability predicate instead of a generic `kind === opus` gate:
457
+ // Sonnet 5 officially exposes Anthropic's real xhigh and max presets on
458
+ // the Messages API just like Opus 4.7+. Older Sonnet generations do not,
459
+ // so the predicate stays fail-closed for them.
460
+ if (parsedModel.kind === "opus") {
461
+ return semverGte(parsedModel.version, "4.7");
462
+ }
463
+ if (parsedModel.kind === "sonnet") {
464
+ return semverGte(parsedModel.version, "5.0");
465
+ }
466
+ return false;
467
+ }
468
+
469
+ function applyGeneratedModelPolicy(model: ApiModel<Api>): void {
470
+ applyOpenAIModelPricing(model);
471
+ const copilotLimits = model.provider === "github-copilot" ? COPILOT_GENERATED_LIMITS[model.id] : undefined;
472
+ if (copilotLimits) {
473
+ model.contextWindow = copilotLimits.contextWindow;
474
+ model.maxTokens = copilotLimits.maxTokens;
475
+ }
476
+
477
+ if (
478
+ model.api === "openai-completions" &&
479
+ (model.provider === "minimax-code" || model.provider === "minimax-code-cn")
480
+ ) {
481
+ model.compat = {
482
+ ...(model.compat ?? {}),
483
+ supportsStore: false,
484
+ supportsDeveloperRole: false,
485
+ supportsReasoningEffort: false,
486
+ reasoningContentField: "reasoning_content",
487
+ };
488
+ delete model.compat.thinkingFormat;
489
+ }
490
+ if (model.provider === "omlx" && model.api === "openai-completions") {
491
+ model.compat = {
492
+ ...(model.compat ?? {}),
493
+ supportsStore: false,
494
+ supportsDeveloperRole: false,
495
+ supportsReasoningEffort: true,
496
+ thinkingFormat: "qwen-chat-template",
497
+ reasoningContentField: "reasoning_content",
498
+ };
499
+ }
500
+ model.name = scrubGeneratedModelName(model.name);
501
+ if (
502
+ model.api === "openai-completions" &&
503
+ model.provider === "opencode-go" &&
504
+ (model.id === "deepseek-v4-flash" || model.id === "deepseek-v4-pro")
505
+ ) {
506
+ model.compat = {
507
+ ...(model.compat ?? {}),
508
+ supportsToolChoice: false,
509
+ reasoningContentField: "reasoning_content",
510
+ requiresReasoningContentForToolCalls: true,
511
+ };
512
+ }
513
+ const parsedModel = parseKnownModel(model.id);
514
+ const applyPatchToolType = inferGeneratedApplyPatchToolType(model, parsedModel);
515
+ if (applyPatchToolType) {
516
+ model.applyPatchToolType = applyPatchToolType;
517
+ } else {
518
+ delete model.applyPatchToolType;
519
+ }
520
+ if (
521
+ (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") &&
522
+ isClaudeForcedToolChoiceIncapableModelId(model.id)
523
+ ) {
524
+ // Claude Mythos accepts tools but rejects forced tool use (Anthropic
525
+ // 400: "tool_choice forces tool use is not compatible with this model").
526
+ model.compat = { ...(model.compat ?? {}), toolChoiceSupport: "auto" } as typeof model.compat;
527
+ }
528
+ if (parsedModel.family === "anthropic") {
529
+ applyAnthropicCatalogPolicy(model, parsedModel);
530
+ }
531
+ if (parsedModel.family === "openai") {
532
+ applyOpenAICatalogPolicy(model, parsedModel);
533
+ }
534
+ // GLM-5.2 (Zhipu/ZAI): ships a 1M lossless context window, but the bundled
535
+ // catalog copied GLM-5.1's 200K and that stale value survives generate-models
536
+ // (provider-scoped models bypass the models.dev refresh in applyGlobalModelsDevFallback).
537
+ // Pin to the true 1M so context-cap / auto-compaction thresholds aren't tripped ~5x early.
538
+ if (model.provider === "zai" && model.id === "glm-5.2") {
539
+ model.contextWindow = 1_000_000;
540
+ }
541
+ // GLM-5.3 always thinks and exposes only low/high/max reasoning_effort.
542
+ // https://z.ai/blog/glm-5.3#api-changes-in-glm-5-3
543
+ if (model.provider === "zai" && model.id === "glm-5.3") {
544
+ model.thinking = {
545
+ mode: "effort",
546
+ minLevel: Effort.Low,
547
+ maxLevel: Effort.Max,
548
+ defaultLevel: Effort.Max,
549
+ levels: [Effort.Low, Effort.High, Effort.Max],
550
+ };
551
+ }
552
+ // GLM-5.3-Flash keeps GLM-5.3's text contract: 1M context, 128K output, and
553
+ // the same always-on low/high/max reasoning_effort. models.dev currently
554
+ // lists it with null limits, so pin the contract the same way.
555
+ // https://docs.z.ai/guides/llm/glm-5.3-flash ("Text parameters are
556
+ // consistent with GLM-5.3, with support for a 1M-token context window.")
557
+ if (model.provider === "zai" && model.id === "glm-5.3-flash") {
558
+ model.contextWindow = 1_000_000;
559
+ model.maxTokens = 131_072;
560
+ model.thinking = {
561
+ mode: "effort",
562
+ minLevel: Effort.Low,
563
+ maxLevel: Effort.Max,
564
+ defaultLevel: Effort.Max,
565
+ levels: [Effort.Low, Effort.High, Effort.Max],
566
+ };
567
+ }
568
+ // Groq's agentic `compound` systems reject `reasoning_effort` outright
569
+ // (400 "`reasoning_effort` is not supported with this model", verified
570
+ // 2026-08-23), yet models.dev advertises them as reasoning models. Drop the
571
+ // thinking config so Vibrato never sends the field.
572
+ if (isGroqCompoundReasoningUnsupported(model)) {
573
+ model.reasoning = false;
574
+ delete model.thinking;
575
+ }
576
+ // Kilo's Ox Alpha catalog row advertises reasoning, vision, a 1,048,576-token
577
+ // context, a 131,072-token output ceiling, and low/high/max variants. Its
578
+ // OpenAI-compatible `/models` shape exposes those fields outside the generic
579
+ // discovery parser, so pin the reviewed provider-specific contract here.
580
+ if (model.provider === "kilo" && model.id === "stealth/ox-alpha") {
581
+ model.reasoning = true;
582
+ model.input = ["text", "image"];
583
+ model.contextWindow = 1_048_576;
584
+ model.maxTokens = 131_072;
585
+ model.thinking = {
586
+ mode: "effort",
587
+ minLevel: Effort.Low,
588
+ maxLevel: Effort.Max,
589
+ defaultLevel: Effort.Max,
590
+ levels: [Effort.Low, Effort.High, Effort.Max],
591
+ };
592
+ }
593
+ if (model.provider === "alibaba-token-plan" && model.id === "deepseek-v4-flash-0731") {
594
+ model.contextWindow = 1_000_000;
595
+ model.maxTokens = 384_000;
596
+ model.compat = {
597
+ ...(model.compat ?? {}),
598
+ supportsDeveloperRole: false,
599
+ supportsReasoningEffort: true,
600
+ reasoningContentField: "reasoning_content",
601
+ requiresReasoningContentForToolCalls: true,
602
+ };
603
+ }
604
+ if (model.provider === "xai" && (model.id === "grok-4.5" || model.id === "grok-4.6")) {
605
+ model.maxTokens = Math.min(model.maxTokens, 64_000);
606
+ }
607
+ // MiniMax-M3's official Token Plan routes expose a 1M context window.
608
+ // Scope the correction to the four first-class regional MiniMax routes
609
+ // (canonical id plus the Anthropic Token Plan `[1m]` id); unrelated
610
+ // catalog aliases and providers keep their own contracts.
611
+ if (
612
+ (model.id === "MiniMax-M3" || model.id === "MiniMax-M3[1m]") &&
613
+ (model.provider === "minimax" ||
614
+ model.provider === "minimax-cn" ||
615
+ model.provider === "minimax-code" ||
616
+ model.provider === "minimax-code-cn")
617
+ ) {
618
+ model.contextWindow = 1_000_000;
619
+ }
620
+ }
621
+
622
+ function scrubGeneratedModelName(name: string): string {
623
+ return name
624
+ .replaceAll("Claude", "Anthropic")
625
+ .replaceAll("claude", "anthropic")
626
+ .replaceAll("Codex", "OpenAI code")
627
+ .replaceAll("codex", "openai-code");
628
+ }
629
+
630
+ function applyAnthropicCatalogPolicy(model: ApiModel<Api>, parsedModel: AnthropicModel): void {
631
+ // Anthropic model Opus 4.5: models.dev reports 3x the correct cache pricing.
632
+ if (model.provider === "anthropic" && parsedModel.kind === "opus" && semverEqual(parsedModel.version, "4.5")) {
633
+ model.cost.cacheRead = 0.5;
634
+ model.cost.cacheWrite = 6.25;
635
+ }
636
+
637
+ // Bedrock Opus 4.6: upstream metadata is stale for cache pricing and context.
638
+ if (model.provider === "amazon-bedrock" && parsedModel.kind === "opus" && semverEqual(parsedModel.version, "4.6")) {
639
+ model.cost.cacheRead = 0.5;
640
+ model.cost.cacheWrite = 6.25;
641
+ model.contextWindow = 1000000;
642
+ model.maxTokens = 128000;
643
+ }
644
+ }
645
+
646
+ function inferGeneratedApplyPatchToolType(
647
+ model: ApiModel<Api>,
648
+ parsedModel: ParsedModel,
649
+ ): ApiModel<Api>["applyPatchToolType"] {
650
+ if (parsedModel.family !== "openai" || parsedModel.version.major !== 5) {
651
+ return undefined;
652
+ }
653
+ if (model.provider === "openai" && model.api === "openai-responses") {
654
+ return "freeform";
655
+ }
656
+ if (model.provider === "openai-codex" && model.api === "openai-codex-responses") {
657
+ return "freeform";
658
+ }
659
+ return undefined;
660
+ }
661
+
662
+ function applyGpt55ContextWindow(model: ApiModel<Api>, parsedModel: OpenAIModel): boolean {
663
+ if (parsedModel.variant === "base" && semverEqual(parsedModel.version, "5.5")) {
664
+ // JetBrains AI serves GPT through its own gateway, which enforces a probed
665
+ // 922K prompt cap for every GPT model regardless of the first-party figure.
666
+ // Its bundled value is measured, so leave it alone.
667
+ if (model.provider === "jetbrains-junie") {
668
+ return true;
669
+ }
670
+ // The first-party OpenAI GPT-5.5 model advertises a 1M total window, but
671
+ // the OpenAI code backend request path still enforces the smaller prompt
672
+ // budget. Vibrato's `contextWindow` is the usable prompt/input cap, not the
673
+ // marketing total window; using 1M here delays compaction and makes the UI
674
+ // promise space that `/responses/compact`/agent turns cannot actually use.
675
+ model.contextWindow =
676
+ model.provider === "openai-codex" || model.api === "openai-codex-responses"
677
+ ? CODEX_GENERIC_CONTEXT_WINDOW
678
+ : 1_000_000;
679
+ return true;
680
+ }
681
+ return false;
682
+ }
683
+ function applyGpt56ContextWindow(model: ApiModel<Api>): boolean {
684
+ if (!isCodexGpt56Tier(model) || !isCodexProductTransport(model)) {
685
+ return false;
686
+ }
687
+ // Force the enforced 372K window: the OpenAI code backend metadata still
688
+ // under-reports the GPT-5.6 tier budget, and smaller observed values would
689
+ // otherwise keep the tier at the old 272K cap. First-party OpenAI is untouched.
690
+ model.contextWindow = CODEX_GPT_5_6_CONTEXT_CAP.enforced;
691
+ return true;
692
+ }
693
+
694
+ function applyOpenAICatalogPolicy(model: ApiModel<Api>, parsedModel: OpenAIModel): void {
695
+ if (applyGpt55ContextWindow(model, parsedModel)) {
696
+ return;
697
+ }
698
+ if (applyGpt56ContextWindow(model)) {
699
+ return;
700
+ }
701
+ // OpenAI code backend models: 400K figure includes output budget; input window is 272K.
702
+ if (parsedModel.variant.startsWith("codex") && parsedModel.variant !== "codex-spark") {
703
+ model.contextWindow = CODEX_GENERIC_CONTEXT_WINDOW;
704
+ return;
705
+ }
706
+ // GPT-5.4 mini/nano use plain OpenAI IDs on the OpenAI code backend transport, but OpenAI code backend still
707
+ // enforces the lower prompt budget for these variants. OpenAI code backend discovery can also
708
+ // report inconsistent priorities for the GPT-5.4 family, so normalize by parsed
709
+ // variant instead of special-casing raw model ids.
710
+ if (model.api === "openai-codex-responses" && semverEqual(parsedModel.version, "5.4")) {
711
+ const normalizedPriority = CODEX_GPT_5_4_PRIORITY_BY_VARIANT[parsedModel.variant];
712
+ if (normalizedPriority !== undefined) {
713
+ model.priority = normalizedPriority;
714
+ }
715
+ if (parsedModel.variant === "mini" || parsedModel.variant === "nano") {
716
+ model.contextWindow = CODEX_GENERIC_CONTEXT_WINDOW;
717
+ }
718
+ }
719
+ }
720
+
721
+ function inferDefaultEffort<TApi extends Api>(model: ApiModel<TApi>, parsedModel: ParsedModel): Effort | undefined {
722
+ if (model.provider === "kimi-code" && model.id === "k3") {
723
+ return Effort.High;
724
+ }
725
+ if (
726
+ parsedModel.family === "openai" &&
727
+ model.provider === "openai-codex" &&
728
+ semverEqual(parsedModel.version, "5.5")
729
+ ) {
730
+ return GPT_5_5_DEFAULT_EFFORT;
731
+ }
732
+ if (model.provider === "omlx") {
733
+ return Effort.Medium;
734
+ }
735
+ return undefined;
736
+ }
737
+
738
+ function inferModelThinking<TApi extends Api>(model: ApiModel<TApi>): ThinkingConfig {
739
+ const parsedModel = parseKnownModel(model.id);
740
+ const efforts = inferSupportedEfforts(parsedModel, model);
741
+ const minLevel = efforts[0];
742
+ const maxLevel = efforts.at(-1);
743
+ if (!minLevel || !maxLevel) {
744
+ throw new Error(`Model ${model.provider}/${model.id} resolved to an empty thinking range`);
745
+ }
746
+ const config: ThinkingConfig = {
747
+ mode: inferThinkingControlMode(model, parsedModel),
748
+ minLevel,
749
+ maxLevel,
750
+ };
751
+ const defaultLevel = inferDefaultEffort(model, parsedModel);
752
+ if (defaultLevel && efforts.includes(defaultLevel)) {
753
+ config.defaultLevel = defaultLevel;
754
+ }
755
+ // Encode explicit levels only when the inferred set has gaps the min..max range cannot represent.
756
+ const minIndex = THINKING_EFFORTS.indexOf(minLevel);
757
+ const maxIndex = THINKING_EFFORTS.indexOf(maxLevel);
758
+ const expandedRange = THINKING_EFFORTS.slice(minIndex, maxIndex + 1);
759
+ if (expandedRange.length !== efforts.length) {
760
+ config.levels = efforts;
761
+ }
762
+ return config;
763
+ }
764
+
765
+ function normalizeThinkingConfig(thinking: ThinkingConfig | undefined): ThinkingConfig | undefined {
766
+ if (!thinking || expandEffortRange(thinking).length === 0) {
767
+ return undefined;
768
+ }
769
+ return thinking;
770
+ }
771
+
772
+ function thinkingsEqual(left: ThinkingConfig | undefined, right: ThinkingConfig | undefined): boolean {
773
+ if (left === right) return true;
774
+ if (!left || !right) return false;
775
+ if (
776
+ left.mode !== right.mode ||
777
+ left.minLevel !== right.minLevel ||
778
+ left.maxLevel !== right.maxLevel ||
779
+ left.defaultLevel !== right.defaultLevel
780
+ )
781
+ return false;
782
+ const leftLevels = left.levels;
783
+ const rightLevels = right.levels;
784
+ if (leftLevels === rightLevels) return true;
785
+ if (!leftLevels || !rightLevels) return false;
786
+ if (leftLevels.length !== rightLevels.length) return false;
787
+ return leftLevels.every((level, index) => level === rightLevels[index]);
788
+ }
789
+
790
+ function expandEffortRange(thinking: ThinkingConfig): readonly Effort[] {
791
+ if (thinking.levels && thinking.levels.length > 0) {
792
+ return thinking.levels;
793
+ }
794
+ const minIndex = THINKING_EFFORTS.indexOf(thinking.minLevel);
795
+ const maxIndex = THINKING_EFFORTS.indexOf(thinking.maxLevel);
796
+ if (minIndex === -1 || maxIndex === -1 || minIndex > maxIndex) {
797
+ return [];
798
+ }
799
+ return THINKING_EFFORTS.slice(minIndex, maxIndex + 1);
800
+ }
801
+
802
+ function inferSupportedEfforts<TApi extends Api>(parsedModel: ParsedModel, model: ApiModel<TApi>): readonly Effort[] {
803
+ if (model.provider === "xai" && model.id === "grok-4.5") {
804
+ return GROK_4_5_EFFORTS;
805
+ }
806
+ if (model.provider === "xai" && model.id === "grok-4.6") {
807
+ return GROK_4_6_EFFORTS;
808
+ }
809
+ if (model.provider === "kimi-code" && model.id === "k3") {
810
+ return KIMI_K3_EFFORTS;
811
+ }
812
+ if (model.provider === "alibaba-token-plan" && model.id === "deepseek-v4-flash-0731") {
813
+ return DEEPSEEK_V4_FLASH_0731_EFFORTS;
814
+ }
815
+ switch (parsedModel.family) {
816
+ case "openai":
817
+ return inferOpenAISupportedEfforts(parsedModel);
818
+ case "gemini":
819
+ return inferGeminiSupportedEfforts(parsedModel);
820
+ case "anthropic":
821
+ return inferAnthropicSupportedEfforts(parsedModel, model);
822
+ case "unknown":
823
+ return inferFallbackEfforts(model);
824
+ }
825
+ }
826
+
827
+ function inferOpenAISupportedEfforts(model: OpenAIModel): readonly Effort[] {
828
+ if (model.variant === "codex-mini" && semverEqual(model.version, "5.1")) {
829
+ return GPT_5_1_CODEX_MINI_EFFORTS;
830
+ }
831
+ if (semverGte(model.version, "5.6")) {
832
+ return GPT_5_6_PLUS_EFFORTS;
833
+ }
834
+ if (semverGte(model.version, "5.2")) {
835
+ return GPT_5_2_PLUS_EFFORTS;
836
+ }
837
+ return DEFAULT_REASONING_EFFORTS;
838
+ }
839
+
840
+ function inferGeminiSupportedEfforts(model: GeminiModel): readonly Effort[] {
841
+ if (!semverGte(model.version, "3.0")) {
842
+ return DEFAULT_REASONING_EFFORTS;
843
+ }
844
+ if (model.kind === "pro") {
845
+ return GEMINI_3_PRO_EFFORTS;
846
+ }
847
+ if (semverGte(model.version, "3.7")) {
848
+ return GEMINI_3_7_FLASH_EFFORTS;
849
+ }
850
+ return GEMINI_3_FLASH_EFFORTS;
851
+ }
852
+
853
+ function inferAnthropicSupportedEfforts<TApi extends Api>(
854
+ parsedModel: AnthropicModel,
855
+ model: ApiModel<TApi>,
856
+ ): readonly Effort[] {
857
+ if (
858
+ (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") &&
859
+ semverGte(parsedModel.version, "4.6")
860
+ ) {
861
+ if (parsedModel.kind === "fable") {
862
+ // Fable exposes Anthropic's Messages-only xhigh preset; Bedrock
863
+ // Converse lacks it (same split as Opus 4.7+ below).
864
+ return model.api === "anthropic-messages" ? DEFAULT_REASONING_EFFORTS_WITH_XHIGH : DEFAULT_REASONING_EFFORTS;
865
+ }
866
+ if (anthropicModelHasRealXHighEffort(model)) {
867
+ // Opus 4.7+ and Sonnet 5 expose both Anthropic's real xhigh and
868
+ // max presets on the Messages API.
869
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH_AND_MAX;
870
+ }
871
+ if (parsedModel.kind === "opus") {
872
+ // Opus 4.6 exposes max but not the newer xhigh literal.
873
+ return DEFAULT_REASONING_EFFORTS_WITH_MAX;
874
+ }
875
+ return DEFAULT_REASONING_EFFORTS;
876
+ }
877
+ return inferFallbackEfforts(model);
878
+ }
879
+
880
+ function inferFallbackEfforts<TApi extends Api>(model: ApiModel<TApi>): readonly Effort[] {
881
+ // Meta documents Muse Spark 1.2 as accepting the full minimal..xhigh
882
+ // reasoning range. Keep that capability provider-independent so runtime
883
+ // model discovery/merge cannot downgrade the bundled OpenRouter entry to
884
+ // the generic openai-completions ceiling of `high`.
885
+ if (model.id.split("/").at(-1)?.toLowerCase() === "muse-spark-1.2") {
886
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
887
+ }
888
+ if (model.api === "anthropic-messages") {
889
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
890
+ }
891
+ if (model.name.includes("deepseek-v4")) {
892
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
893
+ }
894
+ if (model.api === "bedrock-converse-stream") {
895
+ return DEFAULT_REASONING_EFFORTS;
896
+ }
897
+ if (model.api === "openai-completions") {
898
+ if (model.provider === "omlx") {
899
+ return [Effort.Low, Effort.Medium, Effort.High];
900
+ }
901
+ const compat = resolveOpenAICompat(model as ApiModel<"openai-completions">);
902
+ if (compat.thinkingFormat === "openai" && compat.supportsReasoningEffort) {
903
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
904
+ }
905
+ return DEFAULT_REASONING_EFFORTS;
906
+ }
907
+ // OpenAI Responses APIs encode discrete effort levels, including xhigh.
908
+ if (model.api === "openai-responses" || model.api === "openai-codex-responses") {
909
+ return DEFAULT_REASONING_EFFORTS_WITH_XHIGH;
910
+ }
911
+ return DEFAULT_REASONING_EFFORTS;
912
+ }
913
+
914
+ function inferThinkingControlMode<TApi extends Api>(
915
+ model: ApiModel<TApi>,
916
+ parsedModel: ParsedModel,
917
+ ): ThinkingConfig["mode"] {
918
+ switch (model.api) {
919
+ case "google-generative-ai":
920
+ case "google-gemini-cli":
921
+ case "google-vertex":
922
+ return parsedModel.family === "gemini" &&
923
+ semverGte(parsedModel.version, "3.0") &&
924
+ parsedModel.version.major === 3
925
+ ? "google-level"
926
+ : "budget";
927
+
928
+ case "anthropic-messages":
929
+ if (parsedModel.family === "anthropic") {
930
+ if (semverGte(parsedModel.version, "4.6")) {
931
+ return "anthropic-adaptive";
932
+ }
933
+ if (semverGte(parsedModel.version, "4.5")) {
934
+ return "anthropic-budget-effort";
935
+ }
936
+ }
937
+ return "budget";
938
+
939
+ case "bedrock-converse-stream":
940
+ if (parsedModel.family === "anthropic") {
941
+ if (
942
+ semverGte(parsedModel.version, "4.6") &&
943
+ (parsedModel.kind === "opus" || parsedModel.kind === "fable")
944
+ ) {
945
+ return "anthropic-adaptive";
946
+ }
947
+ if (semverGte(parsedModel.version, "4.5")) {
948
+ return "anthropic-budget-effort";
949
+ }
950
+ }
951
+ return "budget";
952
+
953
+ default:
954
+ return "effort";
955
+ }
956
+ }
957
+
958
+ function parseKnownModel(modelId: string): ParsedModel {
959
+ const canonicalId = getCanonicalModelId(modelId);
960
+ return (
961
+ parseGeminiModel(canonicalId) ??
962
+ parseAnthropicModel(canonicalId) ??
963
+ parseOpenAIModel(canonicalId) ?? { family: "unknown", id: canonicalId }
964
+ );
965
+ }
966
+
967
+ const GEMINI_SUFFIX = "-preview";
968
+ function parseGeminiModel(modelId: string): GeminiModel | null {
969
+ if (modelId.endsWith(GEMINI_SUFFIX)) {
970
+ modelId = modelId.slice(0, -GEMINI_SUFFIX.length);
971
+ }
972
+ const match = /gemini-(\d+(?:\.\d+){0,2})-(pro|flash)\b/.exec(modelId);
973
+ if (!match) {
974
+ return null;
975
+ }
976
+ const version = parseSemVer(match[1]);
977
+ if (!version) {
978
+ return null;
979
+ }
980
+ return { family: "gemini", kind: match[2] as GeminiKind, version };
981
+ }
982
+
983
+ function parseAnthropicModel(modelId: string): AnthropicModel | null {
984
+ const match = /claude-(opus|sonnet|fable)-(\d{1,2}(?:[.-]\d{1,2}){0,2})\b/.exec(modelId);
985
+ if (!match) {
986
+ return null;
987
+ }
988
+ const version = parseSemVer(match[2]);
989
+ if (!version) {
990
+ return null;
991
+ }
992
+ return { family: "anthropic", kind: match[1] as AnthropicKind, version };
993
+ }
994
+
995
+ function parseOpenAIModel(modelId: string): OpenAIModel | null {
996
+ const match =
997
+ /gpt-(\d+(?:\.\d+){0,2})(?:-(codex-spark|codex-mini|codex-max|codex|luna|mini|max|nano|sol|terra))?$/.exec(
998
+ modelId,
999
+ );
1000
+ if (!match) {
1001
+ return null;
1002
+ }
1003
+ const version = parseSemVer(match[1]);
1004
+ if (!version) {
1005
+ return null;
1006
+ }
1007
+ return { family: "openai", variant: (match[2] as OpenAIVariant | undefined) ?? "base", version };
1008
+ }
1009
+
1010
+ function createSemVer(major: number, minor: number, patch = 0): SemVer {
1011
+ return { major, minor, patch };
1012
+ }
1013
+
1014
+ // extend this table if we need anything more than 9.10
1015
+ const precomputeTable: Record<string, SemVer> = {};
1016
+ for (let major = 0; major <= 9; major++) {
1017
+ for (let minor = 0; minor <= 10; minor++) {
1018
+ const version = createSemVer(major, minor, 0);
1019
+ precomputeTable[`${major}.${minor}`] = version;
1020
+ precomputeTable[`${major}-${minor}`] = version;
1021
+ }
1022
+ precomputeTable[`${major}`] = createSemVer(major, 0, 0);
1023
+ }
1024
+
1025
+ function parseSemVer(version: string): SemVer | null {
1026
+ return precomputeTable[version] ?? null;
1027
+ }
1028
+
1029
+ function semverGte(left: SemVer | string, right: SemVer | string): boolean {
1030
+ return compareSemVer(left, right) >= 0;
1031
+ }
1032
+
1033
+ function semverEqual(left: SemVer | string, right: SemVer | string): boolean {
1034
+ return compareSemVer(left, right) === 0;
1035
+ }
1036
+
1037
+ function compareSemVer(left: SemVer | string | null, right: SemVer | string | null): number {
1038
+ left = typeof left === "string" ? parseSemVer(left) : left;
1039
+ right = typeof right === "string" ? parseSemVer(right) : right;
1040
+ if (!left || !right) return (left ? 1 : 0) - (right ? 1 : 0);
1041
+
1042
+ if (left.major !== right.major) {
1043
+ return left.major - right.major;
1044
+ }
1045
+ if (left.minor !== right.minor) {
1046
+ return left.minor - right.minor;
1047
+ }
1048
+ return left.patch - right.patch;
1049
+ }
1050
+
1051
+ function getCanonicalModelId(modelId: string): string {
1052
+ const p = modelId.lastIndexOf("/");
1053
+ return p !== -1 ? modelId.slice(p + 1) : modelId;
1054
+ }