mccode-ai 1.18.21

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 (766) hide show
  1. package/AGENTS.md +131 -0
  2. package/Dockerfile +18 -0
  3. package/README.md +15 -0
  4. package/bin/mccode +199 -0
  5. package/bunfig.toml +7 -0
  6. package/git +0 -0
  7. package/migration/20260511173437_session-metadata/migration.sql +1 -0
  8. package/migration/20260511173437_session-metadata/snapshot.json +1500 -0
  9. package/package.json +171 -0
  10. package/parsers-config.ts +1 -0
  11. package/script/bench-search.ts +94 -0
  12. package/script/bench-test-suite.ts +52 -0
  13. package/script/build.ts +246 -0
  14. package/script/generate.ts +14 -0
  15. package/script/httpapi-exercise.ts +1 -0
  16. package/script/postinstall.mjs +189 -0
  17. package/script/profile-test-files.ts +42 -0
  18. package/script/publish.ts +213 -0
  19. package/script/run-workspace-server +106 -0
  20. package/script/schema.ts +77 -0
  21. package/script/time.ts +6 -0
  22. package/script/trace-imports.ts +153 -0
  23. package/specs/effect/error-boundaries-plan.md +235 -0
  24. package/specs/effect/errors.md +207 -0
  25. package/specs/effect/facades.md +218 -0
  26. package/specs/effect/guide.md +247 -0
  27. package/specs/effect/instance-context.md +13 -0
  28. package/specs/effect/loose-ends.md +30 -0
  29. package/specs/effect/migration.md +62 -0
  30. package/specs/effect/routes.md +61 -0
  31. package/specs/effect/schema.md +88 -0
  32. package/specs/effect/server-package.md +58 -0
  33. package/specs/effect/todo.md +241 -0
  34. package/specs/effect/tools.md +88 -0
  35. package/specs/openapi-translation-cleanup.md +204 -0
  36. package/specs/tui-plugins.md +544 -0
  37. package/specs/v2/api.ts +67 -0
  38. package/specs/v2/message-shape.md +136 -0
  39. package/specs/v2/notifications.md +13 -0
  40. package/specs/v2/tui-command-shim.md +67 -0
  41. package/src/account/account.ts +481 -0
  42. package/src/account/repo.ts +171 -0
  43. package/src/account/schema.ts +99 -0
  44. package/src/account/url.ts +8 -0
  45. package/src/acp/agent.ts +95 -0
  46. package/src/acp/config-option.ts +203 -0
  47. package/src/acp/content.ts +269 -0
  48. package/src/acp/directory.ts +212 -0
  49. package/src/acp/error.ts +97 -0
  50. package/src/acp/event.ts +421 -0
  51. package/src/acp/permission.ts +254 -0
  52. package/src/acp/profile.ts +42 -0
  53. package/src/acp/service.ts +1105 -0
  54. package/src/acp/session.ts +232 -0
  55. package/src/acp/tool.ts +364 -0
  56. package/src/acp/usage.ts +243 -0
  57. package/src/agent/agent.ts +476 -0
  58. package/src/agent/generate.txt +75 -0
  59. package/src/agent/prompt/compaction.txt +5 -0
  60. package/src/agent/prompt/explore.txt +18 -0
  61. package/src/agent/prompt/mc.txt +52 -0
  62. package/src/agent/prompt/summary.txt +11 -0
  63. package/src/agent/prompt/title.txt +44 -0
  64. package/src/agent/subagent-permissions.ts +27 -0
  65. package/src/audio.d.ts +14 -0
  66. package/src/auth/index.ts +97 -0
  67. package/src/background/job.ts +37 -0
  68. package/src/bus/global.ts +22 -0
  69. package/src/cli/bootstrap.ts +11 -0
  70. package/src/cli/cmd/account.ts +264 -0
  71. package/src/cli/cmd/acp.ts +73 -0
  72. package/src/cli/cmd/agent.ts +259 -0
  73. package/src/cli/cmd/attach.ts +148 -0
  74. package/src/cli/cmd/cmd.ts +7 -0
  75. package/src/cli/cmd/db.ts +62 -0
  76. package/src/cli/cmd/debug/agent.handler.ts +193 -0
  77. package/src/cli/cmd/debug/agent.ts +27 -0
  78. package/src/cli/cmd/debug/config.ts +14 -0
  79. package/src/cli/cmd/debug/file.ts +73 -0
  80. package/src/cli/cmd/debug/index.ts +87 -0
  81. package/src/cli/cmd/debug/lsp.ts +50 -0
  82. package/src/cli/cmd/debug/ripgrep.ts +79 -0
  83. package/src/cli/cmd/debug/scrap.ts +16 -0
  84. package/src/cli/cmd/debug/skill.ts +15 -0
  85. package/src/cli/cmd/debug/snapshot.ts +50 -0
  86. package/src/cli/cmd/debug/startup.ts +11 -0
  87. package/src/cli/cmd/debug/v2.ts +42 -0
  88. package/src/cli/cmd/export.ts +292 -0
  89. package/src/cli/cmd/generate.ts +54 -0
  90. package/src/cli/cmd/github.handler.ts +1599 -0
  91. package/src/cli/cmd/github.shared.ts +30 -0
  92. package/src/cli/cmd/github.ts +42 -0
  93. package/src/cli/cmd/import.ts +230 -0
  94. package/src/cli/cmd/mcp.ts +840 -0
  95. package/src/cli/cmd/models.ts +66 -0
  96. package/src/cli/cmd/plug.ts +230 -0
  97. package/src/cli/cmd/pr.ts +115 -0
  98. package/src/cli/cmd/prompt-display.ts +1 -0
  99. package/src/cli/cmd/providers.ts +534 -0
  100. package/src/cli/cmd/run/demo.ts +1274 -0
  101. package/src/cli/cmd/run/entry.body.ts +205 -0
  102. package/src/cli/cmd/run/footer.command.tsx +1070 -0
  103. package/src/cli/cmd/run/footer.menu.tsx +351 -0
  104. package/src/cli/cmd/run/footer.permission.tsx +472 -0
  105. package/src/cli/cmd/run/footer.prompt.tsx +1306 -0
  106. package/src/cli/cmd/run/footer.question.tsx +573 -0
  107. package/src/cli/cmd/run/footer.subagent.tsx +175 -0
  108. package/src/cli/cmd/run/footer.ts +1129 -0
  109. package/src/cli/cmd/run/footer.view.tsx +945 -0
  110. package/src/cli/cmd/run/footer.width.ts +27 -0
  111. package/src/cli/cmd/run/permission.shared.ts +256 -0
  112. package/src/cli/cmd/run/prompt.editor.ts +157 -0
  113. package/src/cli/cmd/run/prompt.shared.ts +153 -0
  114. package/src/cli/cmd/run/question.shared.ts +340 -0
  115. package/src/cli/cmd/run/runtime.boot.ts +202 -0
  116. package/src/cli/cmd/run/runtime.lifecycle.ts +406 -0
  117. package/src/cli/cmd/run/runtime.queue.ts +349 -0
  118. package/src/cli/cmd/run/runtime.shared.ts +17 -0
  119. package/src/cli/cmd/run/runtime.stdin.ts +37 -0
  120. package/src/cli/cmd/run/runtime.ts +814 -0
  121. package/src/cli/cmd/run/scrollback.shared.ts +92 -0
  122. package/src/cli/cmd/run/scrollback.surface.ts +431 -0
  123. package/src/cli/cmd/run/scrollback.writer.tsx +352 -0
  124. package/src/cli/cmd/run/session-data.ts +1113 -0
  125. package/src/cli/cmd/run/session-replay.ts +374 -0
  126. package/src/cli/cmd/run/session.shared.ts +196 -0
  127. package/src/cli/cmd/run/splash.ts +280 -0
  128. package/src/cli/cmd/run/stream.transport.ts +1462 -0
  129. package/src/cli/cmd/run/stream.ts +175 -0
  130. package/src/cli/cmd/run/subagent-data.ts +876 -0
  131. package/src/cli/cmd/run/theme.ts +690 -0
  132. package/src/cli/cmd/run/tool.ts +1486 -0
  133. package/src/cli/cmd/run/trace.ts +94 -0
  134. package/src/cli/cmd/run/turn-summary.ts +47 -0
  135. package/src/cli/cmd/run/types.ts +350 -0
  136. package/src/cli/cmd/run/variant.shared.ts +216 -0
  137. package/src/cli/cmd/run.ts +1016 -0
  138. package/src/cli/cmd/serve.ts +24 -0
  139. package/src/cli/cmd/session.ts +147 -0
  140. package/src/cli/cmd/stats.ts +393 -0
  141. package/src/cli/cmd/tui.ts +309 -0
  142. package/src/cli/cmd/uninstall.ts +353 -0
  143. package/src/cli/cmd/upgrade.ts +74 -0
  144. package/src/cli/cmd/web.ts +84 -0
  145. package/src/cli/effect/prompt.ts +37 -0
  146. package/src/cli/effect-cmd.ts +96 -0
  147. package/src/cli/error.ts +130 -0
  148. package/src/cli/heap.ts +45 -0
  149. package/src/cli/logo.ts +1 -0
  150. package/src/cli/network.ts +80 -0
  151. package/src/cli/tui/layer.ts +8 -0
  152. package/src/cli/tui/validate-session.ts +29 -0
  153. package/src/cli/tui/worker.ts +80 -0
  154. package/src/cli/ui.ts +127 -0
  155. package/src/cli/upgrade.ts +53 -0
  156. package/src/command/index.ts +201 -0
  157. package/src/command/template/initialize.txt +66 -0
  158. package/src/command/template/mcstatus.txt +1 -0
  159. package/src/command/template/new.txt +5 -0
  160. package/src/command/template/review.txt +101 -0
  161. package/src/config/agent.ts +59 -0
  162. package/src/config/command.ts +39 -0
  163. package/src/config/config.ts +681 -0
  164. package/src/config/entry-name.ts +19 -0
  165. package/src/config/managed.ts +69 -0
  166. package/src/config/markdown.ts +36 -0
  167. package/src/config/parse.ts +61 -0
  168. package/src/config/paths.ts +45 -0
  169. package/src/config/plugin.ts +79 -0
  170. package/src/config/tui-cwd.ts +5 -0
  171. package/src/config/tui-host-attention.ts +21 -0
  172. package/src/config/tui-migrate.ts +132 -0
  173. package/src/config/tui.ts +276 -0
  174. package/src/config/variable.ts +91 -0
  175. package/src/control-plane/adapters/index.ts +41 -0
  176. package/src/control-plane/adapters/worktree.ts +96 -0
  177. package/src/control-plane/dev/README.md +19 -0
  178. package/src/control-plane/dev/debug-workspace-plugin.ts +73 -0
  179. package/src/control-plane/types.ts +59 -0
  180. package/src/control-plane/util.ts +39 -0
  181. package/src/control-plane/workspace-adapter-runtime.ts +51 -0
  182. package/src/control-plane/workspace-context.ts +26 -0
  183. package/src/control-plane/workspace.ts +966 -0
  184. package/src/effect/app-node-builder-v1.ts +12 -0
  185. package/src/effect/app-runtime.ts +135 -0
  186. package/src/effect/bootstrap-runtime.ts +19 -0
  187. package/src/effect/bridge.ts +84 -0
  188. package/src/effect/config-service.ts +67 -0
  189. package/src/effect/instance-ref.ts +11 -0
  190. package/src/effect/instance-registry.ts +12 -0
  191. package/src/effect/instance-state.ts +69 -0
  192. package/src/effect/promise.ts +17 -0
  193. package/src/effect/run-service.ts +47 -0
  194. package/src/effect/runner.ts +217 -0
  195. package/src/effect/runtime-flags.ts +78 -0
  196. package/src/env/index.ts +41 -0
  197. package/src/event-manifest.ts +3 -0
  198. package/src/event-v2-bridge.ts +71 -0
  199. package/src/format/formatter.ts +404 -0
  200. package/src/format/index.ts +203 -0
  201. package/src/git/index.ts +348 -0
  202. package/src/id/id.ts +80 -0
  203. package/src/ide/index.ts +54 -0
  204. package/src/image/image.ts +172 -0
  205. package/src/index.ts +142 -0
  206. package/src/installation/index.ts +336 -0
  207. package/src/lsp/client.ts +650 -0
  208. package/src/lsp/diagnostic.ts +29 -0
  209. package/src/lsp/language.ts +121 -0
  210. package/src/lsp/launch.ts +21 -0
  211. package/src/lsp/lsp.ts +507 -0
  212. package/src/lsp/server.ts +1983 -0
  213. package/src/markdown.d.ts +4 -0
  214. package/src/mcp/auth.ts +163 -0
  215. package/src/mcp/browser.ts +37 -0
  216. package/src/mcp/catalog.ts +170 -0
  217. package/src/mcp/index.ts +1004 -0
  218. package/src/mcp/oauth-callback.ts +194 -0
  219. package/src/mcp/oauth-provider.ts +259 -0
  220. package/src/node.ts +4 -0
  221. package/src/patch/index.ts +686 -0
  222. package/src/permission/arity.ts +163 -0
  223. package/src/permission/evaluate.ts +1 -0
  224. package/src/permission/index.ts +223 -0
  225. package/src/plugin/azure.ts +26 -0
  226. package/src/plugin/cerebras.ts +11 -0
  227. package/src/plugin/cloudflare.ts +65 -0
  228. package/src/plugin/digitalocean.ts +325 -0
  229. package/src/plugin/github-copilot/copilot.ts +414 -0
  230. package/src/plugin/github-copilot/models.ts +261 -0
  231. package/src/plugin/index.ts +318 -0
  232. package/src/plugin/install.ts +439 -0
  233. package/src/plugin/loader.ts +237 -0
  234. package/src/plugin/meta.ts +188 -0
  235. package/src/plugin/modal/modal.ts +17 -0
  236. package/src/plugin/modal/models.ts +133 -0
  237. package/src/plugin/openai/README.md +31 -0
  238. package/src/plugin/openai/codex.ts +572 -0
  239. package/src/plugin/openai/ws-pool.ts +271 -0
  240. package/src/plugin/openai/ws.ts +383 -0
  241. package/src/plugin/pty-environment.ts +24 -0
  242. package/src/plugin/shared.ts +323 -0
  243. package/src/plugin/snowflake-cortex.ts +507 -0
  244. package/src/plugin/tui/internal.ts +10 -0
  245. package/src/plugin/tui/runtime.ts +1131 -0
  246. package/src/plugin/xai.ts +339 -0
  247. package/src/project/bootstrap-service.ts +9 -0
  248. package/src/project/bootstrap.ts +58 -0
  249. package/src/project/instance-context.ts +24 -0
  250. package/src/project/instance-runtime.ts +16 -0
  251. package/src/project/instance-store.ts +213 -0
  252. package/src/project/project.ts +483 -0
  253. package/src/project/vcs.ts +423 -0
  254. package/src/provider/auth.ts +229 -0
  255. package/src/provider/error.ts +195 -0
  256. package/src/provider/model-status.ts +8 -0
  257. package/src/provider/provider.ts +2047 -0
  258. package/src/provider/transform.ts +1856 -0
  259. package/src/question/index.ts +161 -0
  260. package/src/question/schema.ts +4 -0
  261. package/src/server/auth.ts +48 -0
  262. package/src/server/event.ts +10 -0
  263. package/src/server/global-lifecycle.ts +28 -0
  264. package/src/server/init-projectors.ts +3 -0
  265. package/src/server/mdns.ts +47 -0
  266. package/src/server/projectors.ts +1 -0
  267. package/src/server/proxy-util.ts +48 -0
  268. package/src/server/routes/instance/httpapi/AGENTS.md +39 -0
  269. package/src/server/routes/instance/httpapi/api.ts +97 -0
  270. package/src/server/routes/instance/httpapi/errors.ts +193 -0
  271. package/src/server/routes/instance/httpapi/groups/config.ts +65 -0
  272. package/src/server/routes/instance/httpapi/groups/control-plane.ts +35 -0
  273. package/src/server/routes/instance/httpapi/groups/control.ts +76 -0
  274. package/src/server/routes/instance/httpapi/groups/event.ts +29 -0
  275. package/src/server/routes/instance/httpapi/groups/experimental.ts +275 -0
  276. package/src/server/routes/instance/httpapi/groups/file.ts +185 -0
  277. package/src/server/routes/instance/httpapi/groups/global.ts +136 -0
  278. package/src/server/routes/instance/httpapi/groups/instance.ts +206 -0
  279. package/src/server/routes/instance/httpapi/groups/mcp.ts +156 -0
  280. package/src/server/routes/instance/httpapi/groups/metadata.ts +18 -0
  281. package/src/server/routes/instance/httpapi/groups/permission.ts +61 -0
  282. package/src/server/routes/instance/httpapi/groups/project-copy.ts +32 -0
  283. package/src/server/routes/instance/httpapi/groups/project.ts +93 -0
  284. package/src/server/routes/instance/httpapi/groups/provider.ts +101 -0
  285. package/src/server/routes/instance/httpapi/groups/pty.ts +172 -0
  286. package/src/server/routes/instance/httpapi/groups/query.ts +12 -0
  287. package/src/server/routes/instance/httpapi/groups/question.ts +74 -0
  288. package/src/server/routes/instance/httpapi/groups/session.ts +462 -0
  289. package/src/server/routes/instance/httpapi/groups/sync.ts +113 -0
  290. package/src/server/routes/instance/httpapi/groups/tui.ts +208 -0
  291. package/src/server/routes/instance/httpapi/groups/workspace.ts +141 -0
  292. package/src/server/routes/instance/httpapi/handlers/config.ts +34 -0
  293. package/src/server/routes/instance/httpapi/handlers/control-plane.ts +37 -0
  294. package/src/server/routes/instance/httpapi/handlers/control.ts +43 -0
  295. package/src/server/routes/instance/httpapi/handlers/event.ts +99 -0
  296. package/src/server/routes/instance/httpapi/handlers/experimental.ts +193 -0
  297. package/src/server/routes/instance/httpapi/handlers/file.ts +139 -0
  298. package/src/server/routes/instance/httpapi/handlers/global.ts +156 -0
  299. package/src/server/routes/instance/httpapi/handlers/instance.ts +110 -0
  300. package/src/server/routes/instance/httpapi/handlers/mcp.ts +111 -0
  301. package/src/server/routes/instance/httpapi/handlers/permission.ts +41 -0
  302. package/src/server/routes/instance/httpapi/handlers/project-copy.ts +83 -0
  303. package/src/server/routes/instance/httpapi/handlers/project.ts +63 -0
  304. package/src/server/routes/instance/httpapi/handlers/provider.ts +116 -0
  305. package/src/server/routes/instance/httpapi/handlers/pty.ts +273 -0
  306. package/src/server/routes/instance/httpapi/handlers/question.ts +54 -0
  307. package/src/server/routes/instance/httpapi/handlers/session-errors.ts +21 -0
  308. package/src/server/routes/instance/httpapi/handlers/session.ts +442 -0
  309. package/src/server/routes/instance/httpapi/handlers/sync.ts +89 -0
  310. package/src/server/routes/instance/httpapi/handlers/tui.ts +131 -0
  311. package/src/server/routes/instance/httpapi/handlers/workspace.ts +102 -0
  312. package/src/server/routes/instance/httpapi/lifecycle.ts +54 -0
  313. package/src/server/routes/instance/httpapi/middleware/authorization.ts +150 -0
  314. package/src/server/routes/instance/httpapi/middleware/compression.ts +64 -0
  315. package/src/server/routes/instance/httpapi/middleware/cors-vary.ts +29 -0
  316. package/src/server/routes/instance/httpapi/middleware/error.ts +43 -0
  317. package/src/server/routes/instance/httpapi/middleware/fence.ts +25 -0
  318. package/src/server/routes/instance/httpapi/middleware/instance-context.ts +43 -0
  319. package/src/server/routes/instance/httpapi/middleware/proxy.ts +131 -0
  320. package/src/server/routes/instance/httpapi/middleware/schema-error.ts +41 -0
  321. package/src/server/routes/instance/httpapi/middleware/workspace-routing.ts +250 -0
  322. package/src/server/routes/instance/httpapi/public.ts +537 -0
  323. package/src/server/routes/instance/httpapi/server.ts +325 -0
  324. package/src/server/routes/instance/httpapi/websocket-tracker.ts +60 -0
  325. package/src/server/server.ts +226 -0
  326. package/src/server/shared/fence.ts +60 -0
  327. package/src/server/shared/pty-ticket.ts +15 -0
  328. package/src/server/shared/public-ui.ts +12 -0
  329. package/src/server/shared/tui-control.ts +28 -0
  330. package/src/server/shared/ui.ts +108 -0
  331. package/src/server/shared/workspace-routing.ts +45 -0
  332. package/src/server/tui-event.ts +1 -0
  333. package/src/session/compaction.ts +608 -0
  334. package/src/session/instruction.ts +237 -0
  335. package/src/session/llm/AGENTS.md +90 -0
  336. package/src/session/llm/ai-sdk.ts +291 -0
  337. package/src/session/llm/native-request.ts +196 -0
  338. package/src/session/llm/native-runtime.ts +195 -0
  339. package/src/session/llm/request.ts +226 -0
  340. package/src/session/llm.ts +404 -0
  341. package/src/session/message-error.ts +14 -0
  342. package/src/session/message-v2.ts +737 -0
  343. package/src/session/message.ts +148 -0
  344. package/src/session/overflow.ts +34 -0
  345. package/src/session/processor.ts +718 -0
  346. package/src/session/prompt/anthropic.txt +110 -0
  347. package/src/session/prompt/beast.txt +152 -0
  348. package/src/session/prompt/build-switch.txt +5 -0
  349. package/src/session/prompt/codex.txt +84 -0
  350. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  351. package/src/session/prompt/default.txt +100 -0
  352. package/src/session/prompt/gemini.txt +160 -0
  353. package/src/session/prompt/gpt.txt +112 -0
  354. package/src/session/prompt/kimi.txt +100 -0
  355. package/src/session/prompt/meta.txt +70 -0
  356. package/src/session/prompt/plan-mode.txt +70 -0
  357. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  358. package/src/session/prompt/plan.txt +26 -0
  359. package/src/session/prompt/trinity.txt +102 -0
  360. package/src/session/prompt.ts +1631 -0
  361. package/src/session/reminders.ts +92 -0
  362. package/src/session/retry.ts +209 -0
  363. package/src/session/revert.ts +136 -0
  364. package/src/session/run-state.ts +151 -0
  365. package/src/session/schema.ts +26 -0
  366. package/src/session/session.ts +1016 -0
  367. package/src/session/status.ts +56 -0
  368. package/src/session/summary.ts +160 -0
  369. package/src/session/system.ts +152 -0
  370. package/src/session/todo.ts +74 -0
  371. package/src/session/tools.ts +590 -0
  372. package/src/share/session.ts +58 -0
  373. package/src/share/share-next.ts +371 -0
  374. package/src/skill/discovery.ts +140 -0
  375. package/src/skill/index.ts +354 -0
  376. package/src/snapshot/index.ts +807 -0
  377. package/src/sql.d.ts +4 -0
  378. package/src/storage/schema.ts +5 -0
  379. package/src/storage/storage.ts +327 -0
  380. package/src/sync/README.md +179 -0
  381. package/src/sync/schema.ts +11 -0
  382. package/src/temporary.ts +31 -0
  383. package/src/tool/apply_patch.ts +313 -0
  384. package/src/tool/apply_patch.txt +33 -0
  385. package/src/tool/code-mode.ts +310 -0
  386. package/src/tool/edit.ts +737 -0
  387. package/src/tool/edit.txt +10 -0
  388. package/src/tool/external-directory.ts +49 -0
  389. package/src/tool/glob.ts +76 -0
  390. package/src/tool/glob.txt +6 -0
  391. package/src/tool/grep.ts +115 -0
  392. package/src/tool/grep.txt +8 -0
  393. package/src/tool/invalid.ts +21 -0
  394. package/src/tool/json-schema.ts +164 -0
  395. package/src/tool/lsp.ts +113 -0
  396. package/src/tool/lsp.txt +24 -0
  397. package/src/tool/mcp-websearch.ts +96 -0
  398. package/src/tool/plan-enter.txt +14 -0
  399. package/src/tool/plan-exit.txt +13 -0
  400. package/src/tool/plan.ts +79 -0
  401. package/src/tool/question.ts +44 -0
  402. package/src/tool/question.txt +10 -0
  403. package/src/tool/read.ts +386 -0
  404. package/src/tool/read.txt +14 -0
  405. package/src/tool/registry.ts +455 -0
  406. package/src/tool/schema.ts +14 -0
  407. package/src/tool/shell/id.ts +19 -0
  408. package/src/tool/shell/prompt.ts +293 -0
  409. package/src/tool/shell/shell.txt +21 -0
  410. package/src/tool/shell.ts +645 -0
  411. package/src/tool/skill.ts +70 -0
  412. package/src/tool/skill.txt +5 -0
  413. package/src/tool/task.ts +371 -0
  414. package/src/tool/task.txt +19 -0
  415. package/src/tool/todo.ts +46 -0
  416. package/src/tool/todowrite.txt +44 -0
  417. package/src/tool/tool.ts +183 -0
  418. package/src/tool/truncate.ts +156 -0
  419. package/src/tool/truncation-dir.ts +4 -0
  420. package/src/tool/webfetch.ts +192 -0
  421. package/src/tool/webfetch.txt +13 -0
  422. package/src/tool/websearch.ts +143 -0
  423. package/src/tool/websearch.txt +14 -0
  424. package/src/tool/write.ts +104 -0
  425. package/src/tool/write.txt +8 -0
  426. package/src/util/archive.ts +17 -0
  427. package/src/util/bom.ts +27 -0
  428. package/src/util/data-url.ts +9 -0
  429. package/src/util/defer.ts +10 -0
  430. package/src/util/effect-http-client.ts +11 -0
  431. package/src/util/error.ts +1 -0
  432. package/src/util/filesystem.ts +251 -0
  433. package/src/util/html.ts +8 -0
  434. package/src/util/iife.ts +3 -0
  435. package/src/util/lazy.ts +20 -0
  436. package/src/util/local-context.ts +25 -0
  437. package/src/util/locale.ts +2 -0
  438. package/src/util/media.ts +26 -0
  439. package/src/util/process.ts +177 -0
  440. package/src/util/proxy-env.ts +72 -0
  441. package/src/util/queue.ts +32 -0
  442. package/src/util/record.ts +1 -0
  443. package/src/util/repository.ts +232 -0
  444. package/src/util/rpc.ts +66 -0
  445. package/src/util/signal.ts +12 -0
  446. package/src/util/timeout.ts +13 -0
  447. package/src/util/token.ts +1 -0
  448. package/src/util/wildcard.ts +59 -0
  449. package/src/worktree/index.ts +623 -0
  450. package/sst-env.d.ts +10 -0
  451. package/test/AGENTS.md +204 -0
  452. package/test/EFFECT_TEST_MIGRATION.md +169 -0
  453. package/test/account/repo.test.ts +355 -0
  454. package/test/account/service.test.ts +524 -0
  455. package/test/acp/config-option.test.ts +229 -0
  456. package/test/acp/content.test.ts +235 -0
  457. package/test/acp/directory.test.ts +188 -0
  458. package/test/acp/error.test.ts +67 -0
  459. package/test/acp/event.test.ts +751 -0
  460. package/test/acp/permission.test.ts +401 -0
  461. package/test/acp/service-session.test.ts +1374 -0
  462. package/test/acp/session.test.ts +201 -0
  463. package/test/acp/tool.test.ts +298 -0
  464. package/test/acp/usage.test.ts +318 -0
  465. package/test/agent/agent.test.ts +755 -0
  466. package/test/agent/plan-mode-subagent-bypass.test.ts +160 -0
  467. package/test/agent/plugin-agent-regression.test.ts +51 -0
  468. package/test/auth/auth.test.ts +75 -0
  469. package/test/background/job.test.ts +244 -0
  470. package/test/cli/account.test.ts +30 -0
  471. package/test/cli/acp/acp-test-client.ts +97 -0
  472. package/test/cli/acp/config-options.test.ts +103 -0
  473. package/test/cli/acp/helpers.ts +96 -0
  474. package/test/cli/acp/initialize-auth.test.ts +61 -0
  475. package/test/cli/acp/lifecycle.test.ts +118 -0
  476. package/test/cli/acp/prompt-content.test.ts +97 -0
  477. package/test/cli/acp/skills.test.ts +38 -0
  478. package/test/cli/cmd/tui/attention.test.ts +484 -0
  479. package/test/cli/effect-cmd-instance-als.test.ts +40 -0
  480. package/test/cli/error.test.ts +95 -0
  481. package/test/cli/github-action.test.ts +199 -0
  482. package/test/cli/github-remote.test.ts +90 -0
  483. package/test/cli/help/__snapshots__/help-snapshots.test.ts.snap +623 -0
  484. package/test/cli/help/help-snapshots.test.ts +140 -0
  485. package/test/cli/import.test.ts +90 -0
  486. package/test/cli/mcp-add.test.ts +74 -0
  487. package/test/cli/plugin-auth-picker.test.ts +120 -0
  488. package/test/cli/run/entry.body.test.ts +536 -0
  489. package/test/cli/run/footer.menu.test.ts +43 -0
  490. package/test/cli/run/footer.view.test.tsx +1411 -0
  491. package/test/cli/run/footer.width.test.ts +35 -0
  492. package/test/cli/run/permission.shared.test.ts +144 -0
  493. package/test/cli/run/prompt.editor.test.ts +101 -0
  494. package/test/cli/run/prompt.shared.test.ts +101 -0
  495. package/test/cli/run/question.shared.test.ts +115 -0
  496. package/test/cli/run/run-process.test.ts +338 -0
  497. package/test/cli/run/runtime.boot.test.ts +283 -0
  498. package/test/cli/run/runtime.queue.test.ts +481 -0
  499. package/test/cli/run/runtime.stdin.test.ts +71 -0
  500. package/test/cli/run/runtime.test.ts +238 -0
  501. package/test/cli/run/scrollback.surface.test.ts +1092 -0
  502. package/test/cli/run/session-data.test.ts +593 -0
  503. package/test/cli/run/session-replay.test.ts +691 -0
  504. package/test/cli/run/session.shared.test.ts +247 -0
  505. package/test/cli/run/stream.test.ts +56 -0
  506. package/test/cli/run/stream.transport.test.ts +2363 -0
  507. package/test/cli/run/subagent-data.test.ts +547 -0
  508. package/test/cli/run/theme.test.ts +177 -0
  509. package/test/cli/run/variant.shared.test.ts +218 -0
  510. package/test/cli/serve/serve-process.test.ts +61 -0
  511. package/test/cli/smokes/read-only.test.ts +115 -0
  512. package/test/cli/tui/attach.test.ts +11 -0
  513. package/test/cli/tui/editor-context-zed.test.ts +379 -0
  514. package/test/cli/tui/editor-context.test.tsx +297 -0
  515. package/test/cli/tui/plugin-add.test.ts +110 -0
  516. package/test/cli/tui/plugin-install.test.ts +87 -0
  517. package/test/cli/tui/plugin-lifecycle.test.ts +224 -0
  518. package/test/cli/tui/plugin-loader-entrypoint.test.ts +485 -0
  519. package/test/cli/tui/plugin-loader-pure.test.ts +72 -0
  520. package/test/cli/tui/plugin-loader.test.ts +1332 -0
  521. package/test/cli/tui/plugin-toggle.test.ts +264 -0
  522. package/test/cli/tui/thread.test.ts +101 -0
  523. package/test/config/agent-color.test.ts +47 -0
  524. package/test/config/config.test.ts +2047 -0
  525. package/test/config/entry-name.test.ts +57 -0
  526. package/test/config/fixtures/empty-frontmatter.md +4 -0
  527. package/test/config/fixtures/frontmatter.md +28 -0
  528. package/test/config/fixtures/markdown-header.md +11 -0
  529. package/test/config/fixtures/no-frontmatter.md +1 -0
  530. package/test/config/fixtures/weird-model-id.md +13 -0
  531. package/test/config/lsp.test.ts +69 -0
  532. package/test/config/markdown.test.ts +228 -0
  533. package/test/config/plugin.test.ts +0 -0
  534. package/test/config/tui.test.ts +894 -0
  535. package/test/control-plane/adapters.test.ts +71 -0
  536. package/test/control-plane/workspace.test.ts +1717 -0
  537. package/test/effect/app-runtime-logger.test.ts +101 -0
  538. package/test/effect/config-service.test.ts +65 -0
  539. package/test/effect/instance-state.test.ts +392 -0
  540. package/test/effect/run-service.test.ts +89 -0
  541. package/test/effect/runner.test.ts +514 -0
  542. package/test/effect/runtime-flags.test.ts +374 -0
  543. package/test/event-manifest.test.ts +24 -0
  544. package/test/fake/account.ts +9 -0
  545. package/test/fake/auth.ts +8 -0
  546. package/test/fake/npm.ts +8 -0
  547. package/test/fake/provider.ts +82 -0
  548. package/test/fake/skill.ts +8 -0
  549. package/test/filesystem/filesystem.test.ts +318 -0
  550. package/test/fixture/agent-plugin.constants.ts +6 -0
  551. package/test/fixture/agent-plugin.ts +12 -0
  552. package/test/fixture/config.ts +23 -0
  553. package/test/fixture/db.ts +11 -0
  554. package/test/fixture/fixture.test.ts +26 -0
  555. package/test/fixture/fixture.ts +228 -0
  556. package/test/fixture/flag.ts +20 -0
  557. package/test/fixture/flock-worker.ts +72 -0
  558. package/test/fixture/lsp/fake-lsp-server.js +249 -0
  559. package/test/fixture/mcp-lifecycle-stdio.ts +26 -0
  560. package/test/fixture/mcp-session-recovery.ts +50 -0
  561. package/test/fixture/plug-worker.ts +93 -0
  562. package/test/fixture/plugin-meta-worker.ts +19 -0
  563. package/test/fixture/plugin.ts +10 -0
  564. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  565. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  566. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  567. package/test/fixture/skills/index.json +6 -0
  568. package/test/fixture/tui-environment.tsx +32 -0
  569. package/test/fixture/tui-plugin.ts +355 -0
  570. package/test/fixture/tui-runtime.ts +56 -0
  571. package/test/fixture/tui-sdk.ts +82 -0
  572. package/test/fixture/workspace.ts +34 -0
  573. package/test/fixtures/recordings/session/native-anthropic-tool-loop.json +49 -0
  574. package/test/fixtures/recordings/session/native-openai-oauth-tool-loop.json +45 -0
  575. package/test/fixtures/recordings/session/native-zen-tool-loop.json +49 -0
  576. package/test/format/format.test.ts +235 -0
  577. package/test/git/git.test.ts +179 -0
  578. package/test/ide/ide.test.ts +82 -0
  579. package/test/image/fixtures/picture-5mb-base64.png +0 -0
  580. package/test/image/image.test.ts +121 -0
  581. package/test/installation/installation.test.ts +240 -0
  582. package/test/lib/cli-process.ts +535 -0
  583. package/test/lib/effect.ts +177 -0
  584. package/test/lib/filesystem.ts +10 -0
  585. package/test/lib/llm-server.ts +779 -0
  586. package/test/lib/snapshot.ts +73 -0
  587. package/test/lib/test-provider.ts +37 -0
  588. package/test/lib/websocket.ts +46 -0
  589. package/test/lsp/client.test.ts +488 -0
  590. package/test/lsp/index.test.ts +231 -0
  591. package/test/lsp/jdtls-root.test.ts +459 -0
  592. package/test/lsp/launch.test.ts +22 -0
  593. package/test/lsp/lifecycle.test.ts +160 -0
  594. package/test/mcp/auth.test.ts +78 -0
  595. package/test/mcp/catalog.test.ts +107 -0
  596. package/test/mcp/headers.test.ts +102 -0
  597. package/test/mcp/lifecycle.test.ts +560 -0
  598. package/test/mcp/oauth-auto-connect.test.ts +300 -0
  599. package/test/mcp/oauth-browser.test.ts +225 -0
  600. package/test/mcp/oauth-callback.test.ts +114 -0
  601. package/test/mcp/oauth-provider.test.ts +102 -0
  602. package/test/mcp/session-recovery.test.ts +27 -0
  603. package/test/mcp/transport.test.ts +38 -0
  604. package/test/patch/patch.test.ts +384 -0
  605. package/test/permission/arity.test.ts +33 -0
  606. package/test/permission/next.test.ts +1174 -0
  607. package/test/permission-task.test.ts +319 -0
  608. package/test/plugin/auth-override.test.ts +101 -0
  609. package/test/plugin/cerebras.test.ts +47 -0
  610. package/test/plugin/cloudflare.test.ts +25 -0
  611. package/test/plugin/codex.test.ts +463 -0
  612. package/test/plugin/github-copilot-models.test.ts +492 -0
  613. package/test/plugin/install-concurrency.test.ts +140 -0
  614. package/test/plugin/install.test.ts +570 -0
  615. package/test/plugin/loader-shared.test.ts +1306 -0
  616. package/test/plugin/meta.test.ts +137 -0
  617. package/test/plugin/modal-models.test.ts +198 -0
  618. package/test/plugin/openai-rollout.test.ts +17 -0
  619. package/test/plugin/openai-ws.test.ts +909 -0
  620. package/test/plugin/shared.test.ts +88 -0
  621. package/test/plugin/snowflake-cortex.test.ts +278 -0
  622. package/test/plugin/trigger.test.ts +108 -0
  623. package/test/plugin/workspace-adapter.test.ts +111 -0
  624. package/test/plugin/xai.test.ts +585 -0
  625. package/test/preload.ts +92 -0
  626. package/test/project/instance-bootstrap.test.ts +115 -0
  627. package/test/project/instance.test.ts +248 -0
  628. package/test/project/migrate-global.test.ts +168 -0
  629. package/test/project/project-directory.test.ts +202 -0
  630. package/test/project/project.test.ts +808 -0
  631. package/test/project/vcs.test.ts +335 -0
  632. package/test/project/worktree-remove.test.ts +128 -0
  633. package/test/project/worktree.test.ts +324 -0
  634. package/test/provider/amazon-bedrock.test.ts +361 -0
  635. package/test/provider/cf-ai-gateway-e2e.test.ts +308 -0
  636. package/test/provider/digitalocean.test.ts +124 -0
  637. package/test/provider/error.test.ts +24 -0
  638. package/test/provider/gitlab-duo.test.ts +412 -0
  639. package/test/provider/header-timeout.test.ts +234 -0
  640. package/test/provider/model-status.test.ts +61 -0
  641. package/test/provider/provider.test.ts +2118 -0
  642. package/test/provider/transform.test.ts +5682 -0
  643. package/test/question/question.test.ts +459 -0
  644. package/test/server/AGENTS.md +15 -0
  645. package/test/server/auth.test.ts +59 -0
  646. package/test/server/global-bus.ts +31 -0
  647. package/test/server/global-session-list.test.ts +108 -0
  648. package/test/server/httpapi-authorization.test.ts +174 -0
  649. package/test/server/httpapi-compression.test.ts +151 -0
  650. package/test/server/httpapi-config.test.ts +110 -0
  651. package/test/server/httpapi-control-plane.test.ts +63 -0
  652. package/test/server/httpapi-cors-vary.test.ts +63 -0
  653. package/test/server/httpapi-cors.test.ts +122 -0
  654. package/test/server/httpapi-error-middleware.test.ts +101 -0
  655. package/test/server/httpapi-event.test.ts +94 -0
  656. package/test/server/httpapi-exercise/assertions.ts +64 -0
  657. package/test/server/httpapi-exercise/backend.ts +144 -0
  658. package/test/server/httpapi-exercise/dsl.ts +210 -0
  659. package/test/server/httpapi-exercise/environment.ts +40 -0
  660. package/test/server/httpapi-exercise/index.ts +1802 -0
  661. package/test/server/httpapi-exercise/report.ts +66 -0
  662. package/test/server/httpapi-exercise/routing.ts +96 -0
  663. package/test/server/httpapi-exercise/runner.ts +267 -0
  664. package/test/server/httpapi-exercise/runtime.ts +52 -0
  665. package/test/server/httpapi-exercise/types.ts +127 -0
  666. package/test/server/httpapi-experimental.test.ts +298 -0
  667. package/test/server/httpapi-file.test.ts +83 -0
  668. package/test/server/httpapi-global.test.ts +66 -0
  669. package/test/server/httpapi-instance-context.test.ts +352 -0
  670. package/test/server/httpapi-instance-route-auth.test.ts +81 -0
  671. package/test/server/httpapi-instance.test.ts +265 -0
  672. package/test/server/httpapi-layer.ts +33 -0
  673. package/test/server/httpapi-listen.test.ts +465 -0
  674. package/test/server/httpapi-mcp-oauth.test.ts +73 -0
  675. package/test/server/httpapi-mcp.test.ts +223 -0
  676. package/test/server/httpapi-mdns.test.ts +79 -0
  677. package/test/server/httpapi-promptasync-context.test.ts +212 -0
  678. package/test/server/httpapi-provider.test.ts +401 -0
  679. package/test/server/httpapi-pty.test.ts +299 -0
  680. package/test/server/httpapi-public-openapi.test.ts +350 -0
  681. package/test/server/httpapi-query-schema-drift.test.ts +330 -0
  682. package/test/server/httpapi-reference.test.ts +63 -0
  683. package/test/server/httpapi-schema-error-body.test.ts +166 -0
  684. package/test/server/httpapi-sdk.test.ts +913 -0
  685. package/test/server/httpapi-session.test.ts +1090 -0
  686. package/test/server/httpapi-sync.test.ts +149 -0
  687. package/test/server/httpapi-ui.test.ts +457 -0
  688. package/test/server/httpapi-v2-location.test.ts +126 -0
  689. package/test/server/httpapi-v2-pty.test.ts +250 -0
  690. package/test/server/httpapi-workspace-routing.test.ts +552 -0
  691. package/test/server/httpapi-workspace.test.ts +506 -0
  692. package/test/server/negative-tokens-regression.test.ts +84 -0
  693. package/test/server/project-copy.test.ts +127 -0
  694. package/test/server/project-init-git.test.ts +118 -0
  695. package/test/server/proxy-util.test.ts +113 -0
  696. package/test/server/sdk-error-shape.test.ts +81 -0
  697. package/test/server/sdk-v1-smoke.test.ts +57 -0
  698. package/test/server/session-actions.test.ts +110 -0
  699. package/test/server/session-diff-missing-patch.test.ts +97 -0
  700. package/test/server/session-list.test.ts +302 -0
  701. package/test/server/session-messages.test.ts +180 -0
  702. package/test/server/session-select.test.ts +67 -0
  703. package/test/server/workspace-proxy.test.ts +181 -0
  704. package/test/server/workspace-routing.test.ts +101 -0
  705. package/test/server/worktree-endpoint-repro.test.ts +307 -0
  706. package/test/session/compaction.test.ts +1975 -0
  707. package/test/session/instruction.test.ts +264 -0
  708. package/test/session/llm-native-recorded.test.ts +413 -0
  709. package/test/session/llm-native.test.ts +761 -0
  710. package/test/session/llm.test.ts +2180 -0
  711. package/test/session/message-v2.test.ts +1729 -0
  712. package/test/session/messages-pagination.test.ts +1057 -0
  713. package/test/session/processor-effect.test.ts +1171 -0
  714. package/test/session/prompt.test.ts +2470 -0
  715. package/test/session/retry.test.ts +521 -0
  716. package/test/session/revert-compact.test.ts +683 -0
  717. package/test/session/schema-decoding.test.ts +313 -0
  718. package/test/session/session-schema.test.ts +78 -0
  719. package/test/session/session.test.ts +285 -0
  720. package/test/session/snapshot-tool-race.test.ts +189 -0
  721. package/test/session/structured-output-integration.test.ts +235 -0
  722. package/test/session/structured-output.test.ts +387 -0
  723. package/test/session/system.test.ts +168 -0
  724. package/test/share/share-next.test.ts +324 -0
  725. package/test/skill/discovery.test.ts +186 -0
  726. package/test/skill/skill.test.ts +585 -0
  727. package/test/snapshot/snapshot.test.ts +1218 -0
  728. package/test/storage/storage.test.ts +297 -0
  729. package/test/tool/__snapshots__/parameters.test.ts.snap +466 -0
  730. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  731. package/test/tool/apply_patch.test.ts +529 -0
  732. package/test/tool/code-mode-integration.test.ts +331 -0
  733. package/test/tool/code-mode.test.ts +730 -0
  734. package/test/tool/edit.test.ts +574 -0
  735. package/test/tool/external-directory.test.ts +156 -0
  736. package/test/tool/fixtures/large-image.png +0 -0
  737. package/test/tool/fixtures/models-api.json +172692 -0
  738. package/test/tool/glob.test.ts +132 -0
  739. package/test/tool/grep.test.ts +223 -0
  740. package/test/tool/lsp.test.ts +184 -0
  741. package/test/tool/parameters.test.ts +290 -0
  742. package/test/tool/question.test.ts +133 -0
  743. package/test/tool/read.test.ts +608 -0
  744. package/test/tool/registry.test.ts +572 -0
  745. package/test/tool/shell.test.ts +1199 -0
  746. package/test/tool/skill.test.ts +134 -0
  747. package/test/tool/task.test.ts +1101 -0
  748. package/test/tool/tool-define.test.ts +154 -0
  749. package/test/tool/truncation.test.ts +266 -0
  750. package/test/tool/webfetch.test.ts +119 -0
  751. package/test/tool/websearch.test.ts +100 -0
  752. package/test/tool/write.test.ts +279 -0
  753. package/test/util/data-url.test.ts +14 -0
  754. package/test/util/error.test.ts +16 -0
  755. package/test/util/filesystem.test.ts +656 -0
  756. package/test/util/glob.test.ts +164 -0
  757. package/test/util/html.test.ts +15 -0
  758. package/test/util/iife.test.ts +36 -0
  759. package/test/util/lazy.test.ts +50 -0
  760. package/test/util/module.test.ts +59 -0
  761. package/test/util/process.test.ts +128 -0
  762. package/test/util/repository.test.ts +93 -0
  763. package/test/util/timeout.test.ts +21 -0
  764. package/test/util/wildcard.test.ts +90 -0
  765. package/test/v2/session-message-updater.test.ts +269 -0
  766. package/tsconfig.json +16 -0
@@ -0,0 +1,1856 @@
1
+ import type { ModelMessage, ToolResultPart } from "ai"
2
+ import { mergeDeep, unique } from "remeda"
3
+ import type { JSONSchema7 } from "@ai-sdk/provider"
4
+ import type * as Provider from "./provider"
5
+ import type * as ModelsDev from "@opencode-ai/core/models-dev"
6
+ import { iife } from "@/util/iife"
7
+
8
+ type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
9
+
10
+ function mimeToModality(mime: string): Modality | undefined {
11
+ if (mime.startsWith("image/")) return "image"
12
+ if (mime.startsWith("audio/")) return "audio"
13
+ if (mime.startsWith("video/")) return "video"
14
+ if (mime === "application/pdf") return "pdf"
15
+ return undefined
16
+ }
17
+
18
+ export const OUTPUT_TOKEN_MAX = 32_000
19
+
20
+ // OpenAI Responses `include` value that returns the encrypted reasoning state
21
+ // needed for stateless multi-turn reasoning (store: false). Hoisted so every
22
+ // branch that requests it stays in lockstep.
23
+ const INCLUDE_ENCRYPTED_REASONING = ["reasoning.encrypted_content"] as const
24
+
25
+ export function sanitizeSurrogates(content: string) {
26
+ return content.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "\uFFFD")
27
+ }
28
+
29
+ function isKimiFamily(model: Provider.Model) {
30
+ if (
31
+ [model.providerID, model.api.id].some((id) => {
32
+ const value = id.toLowerCase()
33
+ return value.includes("kimi") || value.includes("moonshot")
34
+ })
35
+ )
36
+ return true
37
+ const url = model.api.url.toLowerCase()
38
+ return ["api.kimi.com", "api.moonshot.ai", "api.moonshot.cn", "api.moonshotai.cn"].some((host) => url.includes(host))
39
+ }
40
+
41
+ // Maps npm package to the key the AI SDK expects for providerOptions
42
+ function sdkKey(npm: string): string | undefined {
43
+ switch (npm) {
44
+ case "@ai-sdk/github-copilot":
45
+ return "copilot"
46
+ case "@ai-sdk/azure":
47
+ return "azure"
48
+ case "@ai-sdk/openai":
49
+ return "openai"
50
+ case "@ai-sdk/amazon-bedrock/mantle":
51
+ return "openai"
52
+ case "@ai-sdk/amazon-bedrock":
53
+ return "bedrock"
54
+ case "@ai-sdk/anthropic":
55
+ case "@ai-sdk/google-vertex/anthropic":
56
+ return "anthropic"
57
+ case "@ai-sdk/google-vertex":
58
+ return "vertex"
59
+ case "@ai-sdk/google":
60
+ return "google"
61
+ case "@ai-sdk/alibaba":
62
+ return "alibaba"
63
+ case "@ai-sdk/cerebras":
64
+ return "cerebras"
65
+ case "@ai-sdk/cohere":
66
+ return "cohere"
67
+ case "@ai-sdk/deepinfra":
68
+ return "deepinfra"
69
+ case "@ai-sdk/groq":
70
+ return "groq"
71
+ case "@ai-sdk/mistral":
72
+ return "mistral"
73
+ case "@ai-sdk/perplexity":
74
+ return "perplexity"
75
+ case "@ai-sdk/togetherai":
76
+ return "togetherai"
77
+ case "@ai-sdk/vercel":
78
+ return "vercel"
79
+ case "@ai-sdk/xai":
80
+ return "xai"
81
+ case "venice-ai-sdk-provider":
82
+ return "venice"
83
+ case "@ai-sdk/gateway":
84
+ return "gateway"
85
+ case "@openrouter/ai-sdk-provider":
86
+ return "openrouter"
87
+ case "merge-gateway-ai-sdk-provider":
88
+ return "mergeGateway"
89
+ case "ai-gateway-provider":
90
+ // ai-gateway-provider/unified wraps createOpenAICompatible({ name: "Unified" }),
91
+ // and @ai-sdk/openai-compatible parses compatibleOptions from one of
92
+ // "openai-compatible" / "openaiCompatible" / "Unified" / "unified". The
93
+ // "openai-compatible" key emits a deprecation warning at runtime, so we
94
+ // pick the camelCase form the SDK now treats as canonical.
95
+ return "openaiCompatible"
96
+ }
97
+ return undefined
98
+ }
99
+
100
+ // TODO: fix this stupid inefficient dogshit function
101
+ function normalizeMessages(
102
+ msgs: ModelMessage[],
103
+ model: Provider.Model,
104
+ _options: Record<string, unknown>,
105
+ ): ModelMessage[] {
106
+ const sanitizeToolResultOutput = (content: ToolResultPart) => {
107
+ if (content.output.type === "text" || content.output.type === "error-text") {
108
+ content.output.value = sanitizeSurrogates(content.output.value)
109
+ }
110
+ if (content.output.type === "content") {
111
+ content.output.value = content.output.value.map((item) => {
112
+ if (item.type === "text") {
113
+ item.text = sanitizeSurrogates(item.text)
114
+ }
115
+ return item
116
+ })
117
+ }
118
+ return content
119
+ }
120
+
121
+ msgs = msgs.map((msg) => {
122
+ switch (msg.role) {
123
+ case "tool":
124
+ if (!Array.isArray(msg.content)) return msg
125
+ msg.content = msg.content.map((content) => {
126
+ if (content.type === "tool-result") {
127
+ return sanitizeToolResultOutput(content)
128
+ }
129
+ return content
130
+ })
131
+ return msg
132
+
133
+ case "system":
134
+ msg.content = sanitizeSurrogates(msg.content)
135
+ return msg
136
+
137
+ case "user":
138
+ if (typeof msg.content === "string") {
139
+ msg.content = sanitizeSurrogates(msg.content)
140
+ } else {
141
+ msg.content = msg.content.map((content) => {
142
+ if (content.type === "text") {
143
+ content.text = sanitizeSurrogates(content.text)
144
+ }
145
+ return content
146
+ })
147
+ }
148
+ return msg
149
+
150
+ case "assistant":
151
+ if (typeof msg.content === "string") {
152
+ msg.content = sanitizeSurrogates(msg.content)
153
+ } else {
154
+ msg.content = msg.content.map((content) => {
155
+ if (content.type === "text" || content.type === "reasoning") {
156
+ content.text = sanitizeSurrogates(content.text)
157
+ }
158
+ if (content.type === "tool-result") {
159
+ return sanitizeToolResultOutput(content)
160
+ }
161
+ return content
162
+ })
163
+ }
164
+ return msg
165
+ }
166
+ })
167
+
168
+ // Anthropic rejects messages with empty content - filter out empty string messages
169
+ // and remove empty text/reasoning parts from array content
170
+ if (model.api.npm === "@ai-sdk/anthropic") {
171
+ msgs = msgs
172
+ .map((msg) => {
173
+ if (typeof msg.content === "string") {
174
+ if (msg.content === "") return undefined
175
+ return msg
176
+ }
177
+ if (!Array.isArray(msg.content)) return msg
178
+ const filtered = msg.content.filter((part) => {
179
+ if (part.type === "text") {
180
+ return part.text !== ""
181
+ }
182
+ if (part.type === "reasoning") {
183
+ return (
184
+ part.text.trim().length > 0 ||
185
+ part.providerOptions?.anthropic?.signature != null ||
186
+ part.providerOptions?.anthropic?.redactedData != null
187
+ )
188
+ }
189
+ return true
190
+ })
191
+ if (filtered.length === 0) return undefined
192
+ return { ...msg, content: filtered }
193
+ })
194
+ .filter((msg): msg is ModelMessage => msg !== undefined && msg.content !== "")
195
+ }
196
+
197
+ // Bedrock specific transforms
198
+ if (model.api.npm === "@ai-sdk/amazon-bedrock") {
199
+ msgs = msgs
200
+ .map((msg) => {
201
+ if (typeof msg.content === "string") {
202
+ if (msg.content === "") return undefined
203
+ return msg
204
+ }
205
+ if (!Array.isArray(msg.content)) return msg
206
+ const filtered = msg.content.filter((part) => {
207
+ if (part.type === "text") {
208
+ return part.text !== ""
209
+ }
210
+ if (part.type === "reasoning") {
211
+ return (
212
+ part.text.trim().length > 0 ||
213
+ part.providerOptions?.bedrock?.signature != null ||
214
+ part.providerOptions?.bedrock?.redactedData != null
215
+ )
216
+ }
217
+ return true
218
+ })
219
+ if (filtered.length === 0) return undefined
220
+ return { ...msg, content: filtered }
221
+ })
222
+ .filter((msg): msg is ModelMessage => msg !== undefined && msg.content !== "")
223
+ }
224
+
225
+ if (model.api.id.includes("claude")) {
226
+ const scrub = (id: string) => id.replace(/[^a-zA-Z0-9_-]/g, "_")
227
+ msgs = msgs.map((msg) => {
228
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
229
+ return {
230
+ ...msg,
231
+ content: msg.content.map((part) => {
232
+ if (part.type === "tool-call" || part.type === "tool-result") {
233
+ return { ...part, toolCallId: scrub(part.toolCallId) }
234
+ }
235
+ return part
236
+ }),
237
+ }
238
+ }
239
+ if (msg.role === "tool" && Array.isArray(msg.content)) {
240
+ return {
241
+ ...msg,
242
+ content: msg.content.map((part) => {
243
+ if (part.type === "tool-result") {
244
+ return { ...part, toolCallId: scrub(part.toolCallId) }
245
+ }
246
+ return part
247
+ }),
248
+ }
249
+ }
250
+ return msg
251
+ })
252
+ }
253
+
254
+ const modelID = model.api.id.toLowerCase()
255
+ if (
256
+ model.providerID === "mistral" ||
257
+ ["mistral", "devstral", "codestral", "pixtral", "mixtral"].some((family) => modelID.includes(family))
258
+ ) {
259
+ const scrub = (id: string) => {
260
+ return id
261
+ .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters
262
+ .substring(0, 9) // Take first 9 characters
263
+ .padEnd(9, "0") // Pad with zeros if less than 9 characters
264
+ }
265
+ const result: ModelMessage[] = []
266
+ for (let i = 0; i < msgs.length; i++) {
267
+ const msg = msgs[i]
268
+ const nextMsg = msgs[i + 1]
269
+
270
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
271
+ msg.content = msg.content.map((part) => {
272
+ if (part.type === "tool-call" || part.type === "tool-result") {
273
+ return { ...part, toolCallId: scrub(part.toolCallId) }
274
+ }
275
+ return part
276
+ })
277
+ }
278
+ if (msg.role === "tool" && Array.isArray(msg.content)) {
279
+ msg.content = msg.content.map((part) => {
280
+ if (part.type === "tool-result") {
281
+ return { ...part, toolCallId: scrub(part.toolCallId) }
282
+ }
283
+ return part
284
+ })
285
+ }
286
+ result.push(msg)
287
+
288
+ // Fix message sequence: tool messages cannot be followed by user messages
289
+ if (msg.role === "tool" && nextMsg?.role === "user") {
290
+ result.push({
291
+ role: "assistant",
292
+ content: [
293
+ {
294
+ type: "text",
295
+ text: "Done.",
296
+ },
297
+ ],
298
+ })
299
+ }
300
+ }
301
+ return result
302
+ }
303
+
304
+ // Deepseek requires all assistant messages to have reasoning on them
305
+ if (model.api.id.toLowerCase().includes("deepseek")) {
306
+ msgs = msgs.map((msg) => {
307
+ if (msg.role !== "assistant") return msg
308
+ if (Array.isArray(msg.content)) {
309
+ if (msg.content.some((part) => part.type === "reasoning")) return msg
310
+ return { ...msg, content: [...msg.content, { type: "reasoning", text: "" }] }
311
+ }
312
+ return {
313
+ ...msg,
314
+ content: [
315
+ ...(msg.content ? [{ type: "text" as const, text: msg.content }] : []),
316
+ { type: "reasoning" as const, text: "" },
317
+ ],
318
+ }
319
+ })
320
+ }
321
+
322
+ if (
323
+ typeof model.capabilities.interleaved === "object" &&
324
+ model.capabilities.interleaved.field &&
325
+ model.api.npm !== "@openrouter/ai-sdk-provider"
326
+ ) {
327
+ const field = model.capabilities.interleaved.field
328
+ return msgs.map((msg) => {
329
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
330
+ const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
331
+ const reasoningText = reasoningParts.map((part: any) => part.text).join("")
332
+
333
+ // Filter out reasoning parts from content
334
+ const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
335
+
336
+ // Include reasoning_content | reasoning_details directly on the message for all assistant messages.
337
+ // Always set the field even when empty — some providers (e.g. DeepSeek) may return empty
338
+ // reasoning_content which still needs to be sent back in subsequent requests.
339
+ return {
340
+ ...msg,
341
+ content: filteredContent,
342
+ providerOptions: {
343
+ ...msg.providerOptions,
344
+ openaiCompatible: {
345
+ ...msg.providerOptions?.openaiCompatible,
346
+ [field]: reasoningText,
347
+ },
348
+ },
349
+ }
350
+ }
351
+
352
+ return msg
353
+ })
354
+ }
355
+
356
+ return msgs
357
+ }
358
+
359
+ function applyCaching(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
360
+ const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
361
+ const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
362
+
363
+ const providerOptions = {
364
+ anthropic: {
365
+ cacheControl: { type: "ephemeral" },
366
+ },
367
+ openrouter: {
368
+ cacheControl: { type: "ephemeral" },
369
+ },
370
+ bedrock: {
371
+ cachePoint: { type: "default" },
372
+ },
373
+ openaiCompatible: {
374
+ cache_control: { type: "ephemeral" },
375
+ },
376
+ copilot: {
377
+ copilot_cache_control: { type: "ephemeral" },
378
+ },
379
+ alibaba: {
380
+ cacheControl: { type: "ephemeral" },
381
+ },
382
+ }
383
+
384
+ for (const msg of unique([...system, ...final])) {
385
+ const useMessageLevelOptions =
386
+ model.providerID === "anthropic" ||
387
+ model.providerID.includes("bedrock") ||
388
+ model.api.npm === "@ai-sdk/amazon-bedrock"
389
+ const shouldUseContentOptions = !useMessageLevelOptions && Array.isArray(msg.content) && msg.content.length > 0
390
+
391
+ if (shouldUseContentOptions) {
392
+ const lastContent = msg.content[msg.content.length - 1]
393
+ if (
394
+ lastContent &&
395
+ typeof lastContent === "object" &&
396
+ lastContent.type !== "tool-approval-request" &&
397
+ lastContent.type !== "tool-approval-response"
398
+ ) {
399
+ lastContent.providerOptions = mergeDeep(lastContent.providerOptions ?? {}, providerOptions)
400
+ continue
401
+ }
402
+ }
403
+
404
+ msg.providerOptions = mergeDeep(msg.providerOptions ?? {}, providerOptions)
405
+ }
406
+
407
+ return msgs
408
+ }
409
+
410
+ function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
411
+ return msgs.map((msg) => {
412
+ if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
413
+
414
+ const filtered = msg.content.map((part) => {
415
+ if (part.type !== "file" && part.type !== "image") return part
416
+
417
+ // Check for empty base64 image data
418
+ if (part.type === "image") {
419
+ const imageStr = String(part.image)
420
+ if (imageStr.startsWith("data:")) {
421
+ const match = imageStr.match(/^data:([^;]+);base64,(.*)$/)
422
+ if (match && (!match[2] || match[2].length === 0)) {
423
+ return {
424
+ type: "text" as const,
425
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
426
+ }
427
+ }
428
+ }
429
+ }
430
+
431
+ const mime = part.type === "image" ? String(part.image).split(";")[0].replace("data:", "") : part.mediaType
432
+ const filename = part.type === "file" ? part.filename : undefined
433
+ const modality = mimeToModality(mime)
434
+ if (!modality) return part
435
+ if (model.capabilities.input[modality]) return part
436
+
437
+ const name = filename ? `"${filename}"` : modality
438
+ return {
439
+ type: "text" as const,
440
+ text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
441
+ }
442
+ })
443
+
444
+ return { ...msg, content: filtered }
445
+ })
446
+ }
447
+
448
+ function mapProviderOptions(
449
+ msgs: ModelMessage[],
450
+ transform: (options: Record<string, any> | undefined) => Record<string, any> | undefined,
451
+ ) {
452
+ return msgs.map((msg) => {
453
+ if (!Array.isArray(msg.content)) return { ...msg, providerOptions: transform(msg.providerOptions) }
454
+ return {
455
+ ...msg,
456
+ providerOptions: transform(msg.providerOptions),
457
+ content: msg.content.map((part) =>
458
+ part.type === "tool-approval-request" || part.type === "tool-approval-response"
459
+ ? part
460
+ : { ...part, providerOptions: transform(part.providerOptions) },
461
+ ),
462
+ } as typeof msg
463
+ })
464
+ }
465
+
466
+ export function message(msgs: ModelMessage[], model: Provider.Model, options: Record<string, unknown>) {
467
+ msgs = unsupportedParts(msgs, model)
468
+ msgs = normalizeMessages(msgs, model, options)
469
+ const usesAnthropicAutomaticCaching =
470
+ options.cacheControl !== undefined &&
471
+ (model.api.npm === "@ai-sdk/anthropic" || model.api.npm === "@ai-sdk/google-vertex/anthropic")
472
+ if (
473
+ (model.providerID === "anthropic" ||
474
+ model.providerID === "google-vertex-anthropic" ||
475
+ model.api.id.includes("anthropic") ||
476
+ model.api.id.includes("claude") ||
477
+ model.id.includes("anthropic") ||
478
+ model.id.includes("claude") ||
479
+ model.api.npm === "@ai-sdk/anthropic" ||
480
+ model.api.npm === "@ai-sdk/alibaba") &&
481
+ model.api.npm !== "@ai-sdk/gateway" &&
482
+ !usesAnthropicAutomaticCaching
483
+ ) {
484
+ msgs = applyCaching(msgs, model)
485
+ }
486
+
487
+ // Remap providerOptions keys from stored providerID to expected SDK key
488
+ const key = sdkKey(model.api.npm)
489
+ if (key && key !== model.providerID) {
490
+ const remap = (opts: Record<string, any> | undefined) => {
491
+ if (!opts) return opts
492
+ if (!(model.providerID in opts)) return opts
493
+ const result = { ...opts }
494
+ result[key] = result[model.providerID]
495
+ delete result[model.providerID]
496
+ return result
497
+ }
498
+
499
+ msgs = mapProviderOptions(msgs, remap)
500
+ }
501
+
502
+ // Strip Responses item IDs before serialization, following Codex and keeping signed request bodies immutable.
503
+ if (
504
+ options.store !== true &&
505
+ key &&
506
+ ["@ai-sdk/openai", "@ai-sdk/azure", "@ai-sdk/amazon-bedrock/mantle", "@ai-sdk/github-copilot"].includes(
507
+ model.api.npm,
508
+ )
509
+ ) {
510
+ msgs = mapProviderOptions(msgs, (options) => {
511
+ if (!options?.[key] || !("itemId" in options[key])) return options
512
+ const metadata = { ...options[key] }
513
+ delete metadata.itemId
514
+ return { ...options, [key]: metadata }
515
+ })
516
+ }
517
+
518
+ return msgs
519
+ }
520
+
521
+ const GEMINI_MODELS_WITH_SAMPLING_DEFAULTS = [
522
+ /gemini-2[.-]5(?:[.-]|$)/,
523
+ /gemini-3-(?:flash|pro)(?:[.-]|$)/,
524
+ /gemini-3[.-]1(?:[.-]|$)/,
525
+ /gemini-3[.-]5-flash(?!-lite)(?:[.-]|$)/,
526
+ ]
527
+
528
+ export function temperature(model: Provider.Model) {
529
+ const id = model.api.id.toLowerCase()
530
+ if (id.includes("north-mini-code")) return 1.0
531
+ if (id.includes("claude")) return undefined
532
+ if (id.includes("gemini"))
533
+ return GEMINI_MODELS_WITH_SAMPLING_DEFAULTS.some((model) => model.test(id)) ? 1.0 : undefined
534
+ if (id.includes("glm-4.6")) return 1.0
535
+ if (id.includes("glm-4.7")) return 1.0
536
+ if (id.includes("minimax-m2")) return 1.0
537
+ if (id.includes("kimi-k2")) {
538
+ // kimi-k2-thinking & kimi-k2.5 && kimi-k2p5 && kimi-k2-5
539
+ if (["thinking", "k2.", "k2p", "k2-5"].some((s) => id.includes(s))) {
540
+ return 1.0
541
+ }
542
+ return 0.6
543
+ }
544
+ return undefined
545
+ }
546
+
547
+ export function topP(model: Provider.Model) {
548
+ const id = model.api.id.toLowerCase()
549
+ if (id.includes("gemini"))
550
+ return GEMINI_MODELS_WITH_SAMPLING_DEFAULTS.some((model) => model.test(id)) ? 0.95 : undefined
551
+ if (["minimax-m2", "kimi-k2.5", "kimi-k2p5", "kimi-k2-5"].some((s) => id.includes(s))) {
552
+ return 0.95
553
+ }
554
+ if (
555
+ ["deepseek-v4-flash-0731", "deepseek-v4-flash:0731"].some((name) => id.includes(name)) ||
556
+ (id.includes("deepseek-v4-flash") && (model.providerID === "deepseek" || model.providerID.startsWith("opencode")))
557
+ ) {
558
+ return 0.95
559
+ }
560
+ return undefined
561
+ }
562
+
563
+ export function topK(model: Provider.Model) {
564
+ const id = model.api.id.toLowerCase()
565
+ if (id.includes("minimax-m2")) {
566
+ if (["m2.", "m25", "m21"].some((s) => id.includes(s))) return 40
567
+ return 20
568
+ }
569
+ if (id.includes("gemini"))
570
+ return GEMINI_MODELS_WITH_SAMPLING_DEFAULTS.some((model) => model.test(id)) ? 64 : undefined
571
+ return undefined
572
+ }
573
+
574
+ const WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]
575
+ const OPENAI_EFFORTS = ["none", "minimal", ...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
576
+ const OPENAI_GPT5_1_EFFORTS = ["none", ...WIDELY_SUPPORTED_EFFORTS]
577
+ const OPENAI_GPT5_2_PLUS_EFFORTS = [...OPENAI_GPT5_1_EFFORTS, "xhigh"]
578
+ const OPENAI_GPT5_PRO_EFFORTS = ["high"]
579
+ const OPENAI_GPT5_PRO_2_PLUS_EFFORTS = ["medium", "high", "xhigh"]
580
+ const OPENAI_GPT5_CHAT_EFFORTS = ["medium"]
581
+ const OPENAI_GPT5_CODEX_XHIGH_EFFORTS = [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
582
+ const OPENAI_GPT5_CODEX_3_PLUS_EFFORTS = ["none", ...OPENAI_GPT5_CODEX_XHIGH_EFFORTS]
583
+
584
+ // OpenAI rolled out the `none` reasoning_effort tier on this date (Responses API).
585
+ // Models released before it 400 on `reasoning_effort: "none"`, so we only expose
586
+ // it as a variant for models new enough to accept it.
587
+ const OPENAI_NONE_EFFORT_RELEASE_DATE = "2025-11-13"
588
+
589
+ // OpenAI rolled out the `xhigh` reasoning_effort tier on this date. Same reasoning.
590
+ const OPENAI_XHIGH_EFFORT_RELEASE_DATE = "2025-12-04"
591
+
592
+ // Matches members of the gpt-5 family across the id formats we encounter:
593
+ // "gpt-5", "gpt-5-nano", "gpt-5.4", "openai/gpt-5.4-codex".
594
+ // Anchored to start-of-string or "/" so it doesn't false-match "gpt-50" or "gpt-5o".
595
+ const GPT5_FAMILY_RE = /(?:^|\/)gpt-5(?:[.-]|$)/
596
+ const GPT5_VERSION_RE = /(?:^|\/)gpt-5[.-](\d+)(?:[.-]|$)/
597
+ const GPT5_PRO_RE = /(?:^|\/)gpt-5[.-]?pro(?:[.-]|$)/
598
+ const GPT5_VERSIONED_PRO_RE = /(?:^|\/)gpt-5[.-]\d+[.-]pro(?:[.-]|$)/
599
+
600
+ function gpt5Version(apiId: string) {
601
+ return Number(GPT5_VERSION_RE.exec(apiId)?.[1]) || undefined
602
+ }
603
+
604
+ function versionedGpt5ReasoningEfforts(apiId: string) {
605
+ if (GPT5_VERSIONED_PRO_RE.test(apiId)) return OPENAI_GPT5_PRO_2_PLUS_EFFORTS
606
+ const version = gpt5Version(apiId)
607
+ if (version === undefined) return undefined
608
+ if (version === 1) return OPENAI_GPT5_1_EFFORTS
609
+ return OPENAI_GPT5_2_PLUS_EFFORTS
610
+ }
611
+
612
+ function gpt5CodexReasoningEfforts(apiId: string) {
613
+ if (!GPT5_FAMILY_RE.test(apiId) || !apiId.includes("codex")) return undefined
614
+ const version = gpt5Version(apiId)
615
+ if (version !== undefined && version >= 3) return OPENAI_GPT5_CODEX_3_PLUS_EFFORTS
616
+ if (apiId.includes("codex-max") || (version !== undefined && version >= 2)) return OPENAI_GPT5_CODEX_XHIGH_EFFORTS
617
+ return WIDELY_SUPPORTED_EFFORTS
618
+ }
619
+
620
+ function gpt5ChatReasoningEfforts(apiId: string) {
621
+ if (!GPT5_FAMILY_RE.test(apiId) || !apiId.includes("-chat")) return undefined
622
+ return gpt5Version(apiId) === undefined ? [] : OPENAI_GPT5_CHAT_EFFORTS
623
+ }
624
+
625
+ // Computes the reasoning_effort tiers an OpenAI (or OpenAI-compatible upstream
626
+ // routed through it, e.g. cf-ai-gateway) model exposes. Effort order: weakest
627
+ // to strongest.
628
+ function openaiReasoningEfforts(apiId: string, releaseDate: string) {
629
+ const id = apiId.toLowerCase()
630
+ if (id.includes("deep-research")) return ["medium"]
631
+ const chatEfforts = gpt5ChatReasoningEfforts(id)
632
+ if (chatEfforts) return chatEfforts
633
+ if (GPT5_PRO_RE.test(id)) return OPENAI_GPT5_PRO_EFFORTS
634
+ const codexEfforts = gpt5CodexReasoningEfforts(id)
635
+ if (codexEfforts) return codexEfforts
636
+ const versionedEfforts = versionedGpt5ReasoningEfforts(id)
637
+ // GPT-5.1 replaced GPT-5's `minimal` effort with `none`; GPT-5.2+
638
+ // additionally accepts `xhigh`. Model pages list the supported subset.
639
+ if (versionedEfforts) return versionedEfforts
640
+ const efforts = [...WIDELY_SUPPORTED_EFFORTS]
641
+ if (GPT5_FAMILY_RE.test(id)) efforts.unshift("minimal")
642
+ if (releaseDate >= OPENAI_NONE_EFFORT_RELEASE_DATE) efforts.unshift("none")
643
+ if (releaseDate >= OPENAI_XHIGH_EFFORT_RELEASE_DATE) efforts.push("xhigh")
644
+ return efforts
645
+ }
646
+
647
+ function openaiCompatibleReasoningEfforts(id: string) {
648
+ const apiId = id.toLowerCase()
649
+ const chatEfforts = gpt5ChatReasoningEfforts(apiId)
650
+ if (chatEfforts) return chatEfforts
651
+ if (GPT5_PRO_RE.test(apiId)) return OPENAI_GPT5_PRO_EFFORTS
652
+ return gpt5CodexReasoningEfforts(apiId) ?? versionedGpt5ReasoningEfforts(apiId) ?? OPENAI_EFFORTS
653
+ }
654
+
655
+ function anthropicUsesModernAdaptiveThinking(apiId: string) {
656
+ if (!apiId.toLowerCase().includes("claude-")) return false
657
+ // Covers family-first IDs such as claude-opus-4.7 and version-first IDs such as claude-4.7-opus.
658
+ // Limit minors to two digits so release dates in IDs such as claude-opus-4-20250514 are not versions.
659
+ const version = /claude-(?:[a-z]+-)?(\d+)(?:[.-](\d{1,2}))?(?:[.@-]|$)/i.exec(apiId)
660
+ if (!version) return true
661
+ const major = Number(version[1])
662
+ const minor = Number(version[2] ?? 0)
663
+ return major > 4 || (major === 4 && minor >= 7)
664
+ }
665
+
666
+ function anthropicOpus45(apiId: string) {
667
+ return ["opus-4-5", "opus-4.5"].some((value) => apiId.includes(value))
668
+ }
669
+
670
+ function anthropicAdaptiveEfforts(apiId: string): string[] | null {
671
+ if (anthropicUsesModernAdaptiveThinking(apiId)) {
672
+ return ["low", "medium", "high", "xhigh", "max"]
673
+ }
674
+ if (
675
+ ["opus-4-6", "opus-4.6", "4-6-opus", "4.6-opus", "sonnet-4-6", "sonnet-4.6", "4-6-sonnet", "4.6-sonnet"].some((v) =>
676
+ apiId.includes(v),
677
+ )
678
+ ) {
679
+ return ["low", "medium", "high", "max"]
680
+ }
681
+ return null
682
+ }
683
+
684
+ function anthropicOmitsThinking(apiId: string) {
685
+ return anthropicUsesModernAdaptiveThinking(apiId)
686
+ }
687
+
688
+ function googleThinkingLevelEfforts(apiId: string) {
689
+ const id = apiId.toLowerCase()
690
+ if (!id.includes("gemini-3")) return ["low", "high"]
691
+ if (id.includes("flash-image")) return ["minimal", "high"]
692
+ if (id.includes("pro-image")) return ["high"]
693
+ if (id.includes("flash")) return ["minimal", "low", "medium", "high"]
694
+ return ["low", "medium", "high"]
695
+ }
696
+
697
+ function googleThinkingBudgetMax(apiId: string) {
698
+ const id = apiId.toLowerCase()
699
+ if (id.includes("2.5") && id.includes("pro") && !id.includes("flash")) return 32_768
700
+ return 24_576
701
+ }
702
+
703
+ // SAP's Zod schema drops unknown top-level keys; reasoning controls survive
704
+ // only via `modelParams` (catchall), forwarded verbatim by the SAP SDKs.
705
+ function wrapInSapModelParams(variants: Record<string, Record<string, any>>): Record<string, Record<string, any>> {
706
+ return Object.fromEntries(Object.entries(variants).map(([k, v]) => [k, { modelParams: v }]))
707
+ }
708
+
709
+ function googleThinkingVariants(model: Provider.Model): Record<string, Record<string, any>> {
710
+ const id = model.api.id.toLowerCase()
711
+ if (id.includes("2.5")) {
712
+ return {
713
+ high: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16000 } },
714
+ max: {
715
+ thinkingConfig: { includeThoughts: true, thinkingBudget: googleThinkingBudgetMax(id) },
716
+ },
717
+ }
718
+ }
719
+ return Object.fromEntries(
720
+ googleThinkingLevelEfforts(id).map((effort) => [
721
+ effort,
722
+ { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } },
723
+ ]),
724
+ )
725
+ }
726
+
727
+ export function variants(model: Provider.Model): Record<string, Record<string, any>> {
728
+ if (!model.capabilities.reasoning) return {}
729
+
730
+ const id = model.id.toLowerCase()
731
+ const glm52 = ["glm-5.2", "glm-5-2", "glm-5p2"].some(
732
+ (name) => id.includes(name) || model.api.id.toLowerCase().includes(name),
733
+ )
734
+ if (
735
+ model.api.id.toLowerCase().includes("minimax-m3") &&
736
+ ["@ai-sdk/anthropic", "@ai-sdk/openai-compatible"].includes(model.api.npm)
737
+ ) {
738
+ if (["nvidia", "lilac"].includes(model.providerID)) {
739
+ return {
740
+ none: { chat_template_kwargs: { thinking_mode: "disabled" } },
741
+ thinking: { chat_template_kwargs: { thinking_mode: "enabled" } },
742
+ }
743
+ }
744
+ return {
745
+ none: { thinking: { type: "disabled" } },
746
+ thinking: { thinking: { type: "adaptive" } },
747
+ }
748
+ }
749
+ const adaptiveThinkingOmitted = anthropicOmitsThinking(model.api.id)
750
+ const adaptiveEfforts = anthropicAdaptiveEfforts(model.api.id)
751
+ if (glm52 && model.api.npm === "@openrouter/ai-sdk-provider") {
752
+ // OpenRouter maps xhigh to GLM-5.2's native max effort.
753
+ return {
754
+ high: { reasoning: { effort: "high" } },
755
+ xhigh: { reasoning: { effort: "xhigh" } },
756
+ }
757
+ }
758
+ if (glm52 && model.api.npm === "@ai-sdk/openai-compatible") {
759
+ return {
760
+ high: { reasoningEffort: "high" },
761
+ max: { reasoningEffort: "max" },
762
+ }
763
+ }
764
+ if (glm52 && model.api.npm === "@ai-sdk/anthropic") {
765
+ return {
766
+ high: { effort: "high" },
767
+ max: { effort: "max" },
768
+ }
769
+ }
770
+ // Kimi's Anthropic-compatible transports implement adaptive thinking effort.
771
+ if (isKimiFamily(model) && ["@ai-sdk/anthropic", "@ai-sdk/google-vertex/anthropic"].includes(model.api.npm)) {
772
+ return Object.fromEntries(
773
+ ["low", "medium", "high", "xhigh", "max"].map((effort) => [
774
+ effort,
775
+ { thinking: { type: "adaptive", display: "summarized" }, effort },
776
+ ]),
777
+ )
778
+ }
779
+ if (
780
+ id.includes("deepseek-chat") ||
781
+ id.includes("deepseek-reasoner") ||
782
+ id.includes("deepseek-r1") ||
783
+ id.includes("deepseek-v3") ||
784
+ id.includes("minimax") ||
785
+ (id.includes("glm") && !glm52) ||
786
+ id.includes("kimi") ||
787
+ id.includes("k2p") ||
788
+ id.includes("qwen") ||
789
+ id.includes("big-pickle")
790
+ )
791
+ return {}
792
+
793
+ // see: https://docs.x.ai/docs/guides/reasoning#control-how-hard-the-model-thinks
794
+ if (id.includes("grok") && id.includes("grok-3-mini")) {
795
+ if (model.api.npm === "@openrouter/ai-sdk-provider") {
796
+ return {
797
+ low: { reasoning: { effort: "low" } },
798
+ high: { reasoning: { effort: "high" } },
799
+ }
800
+ }
801
+ return {
802
+ low: { reasoningEffort: "low" },
803
+ high: { reasoningEffort: "high" },
804
+ }
805
+ }
806
+
807
+ switch (model.api.npm) {
808
+ case "@openrouter/ai-sdk-provider":
809
+ return Object.fromEntries(
810
+ (model.api.id.startsWith("openai/") || id.includes("gpt")
811
+ ? openaiCompatibleReasoningEfforts(model.api.id)
812
+ : WIDELY_SUPPORTED_EFFORTS
813
+ ).map((effort) => [effort, { reasoning: { effort } }]),
814
+ )
815
+
816
+ case "ai-gateway-provider": {
817
+ // Cloudflare AI Gateway routes every upstream through its OpenAI-compatible
818
+ // /v1/compat endpoint, so the body is always OAI-shaped. The gateway
819
+ // translates `reasoning_effort` to the upstream provider's native control
820
+ // (e.g. Anthropic thinking budgets) when needed. Variants therefore stay
821
+ // OAI-style for all upstreams, with an extended effort set for OpenAI
822
+ // models that support it.
823
+ if (model.api.id.startsWith("openai/")) {
824
+ const efforts = openaiReasoningEfforts(model.api.id, model.release_date)
825
+ return Object.fromEntries(efforts.map((effort) => [effort, { reasoningEffort: effort }]))
826
+ }
827
+ return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
828
+ }
829
+
830
+ case "@ai-sdk/gateway":
831
+ if (model.api.id.includes("anthropic")) {
832
+ if (adaptiveEfforts) {
833
+ return Object.fromEntries(
834
+ adaptiveEfforts.map((effort) => [
835
+ effort,
836
+ {
837
+ thinking: {
838
+ type: "adaptive",
839
+ // Newer adaptive-only models default `display` to "omitted", which
840
+ // returns empty thinking blocks. Force "summarized" so summaries
841
+ // survive (4.6/Sonnet 4.6 already default to "summarized").
842
+ ...(adaptiveThinkingOmitted ? { display: "summarized" } : {}),
843
+ },
844
+ effort,
845
+ },
846
+ ]),
847
+ )
848
+ }
849
+ return {
850
+ high: {
851
+ thinking: {
852
+ type: "enabled",
853
+ budgetTokens: 16000,
854
+ },
855
+ },
856
+ max: {
857
+ thinking: {
858
+ type: "enabled",
859
+ budgetTokens: 31999,
860
+ },
861
+ },
862
+ }
863
+ }
864
+ if (model.api.id.includes("google")) {
865
+ if (model.api.id.includes("2.5")) {
866
+ return {
867
+ high: {
868
+ thinkingConfig: {
869
+ includeThoughts: true,
870
+ thinkingBudget: 16000,
871
+ },
872
+ },
873
+ max: {
874
+ thinkingConfig: {
875
+ includeThoughts: true,
876
+ thinkingBudget: googleThinkingBudgetMax(model.api.id.toLowerCase()),
877
+ },
878
+ },
879
+ }
880
+ }
881
+ return Object.fromEntries(
882
+ ["low", "high"].map((effort) => [
883
+ effort,
884
+ {
885
+ includeThoughts: true,
886
+ thinkingLevel: effort,
887
+ },
888
+ ]),
889
+ )
890
+ }
891
+ return Object.fromEntries(
892
+ openaiCompatibleReasoningEfforts(model.api.id).map((effort) => [effort, { reasoningEffort: effort }]),
893
+ )
894
+
895
+ case "@ai-sdk/github-copilot":
896
+ if (model.id.includes("gemini")) {
897
+ // currently github copilot only returns thinking
898
+ return {}
899
+ }
900
+ if (model.id.includes("claude")) {
901
+ return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
902
+ }
903
+ const copilotEfforts = iife(() => {
904
+ if (id.includes("5.1-codex-max") || id.includes("5.2") || id.includes("5.3"))
905
+ return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
906
+ const arr = [...WIDELY_SUPPORTED_EFFORTS]
907
+ if (id.includes("gpt-5") && model.release_date >= "2025-12-04") arr.push("xhigh")
908
+ return arr
909
+ })
910
+ return Object.fromEntries(
911
+ copilotEfforts.map((effort) => [
912
+ effort,
913
+ {
914
+ reasoningEffort: effort,
915
+ reasoningSummary: "auto",
916
+ include: INCLUDE_ENCRYPTED_REASONING,
917
+ },
918
+ ]),
919
+ )
920
+
921
+ case "@ai-sdk/cerebras":
922
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/cerebras
923
+ case "@ai-sdk/togetherai":
924
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/togetherai
925
+ case "@ai-sdk/xai":
926
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/xai
927
+ case "@ai-sdk/deepinfra":
928
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/deepinfra
929
+ case "venice-ai-sdk-provider":
930
+ // https://docs.venice.ai/overview/guides/reasoning-models#reasoning-effort
931
+ case "@ai-sdk/openai-compatible":
932
+ if (model.api.id.toLowerCase().includes("north-mini-code")) {
933
+ return Object.fromEntries(["none", "high"].map((effort) => [effort, { reasoningEffort: effort }]))
934
+ }
935
+ const efforts = [...WIDELY_SUPPORTED_EFFORTS]
936
+ if (model.api.id.toLowerCase().includes("deepseek-v4")) {
937
+ efforts.push("max")
938
+ }
939
+ return Object.fromEntries(efforts.map((effort) => [effort, { reasoningEffort: effort }]))
940
+
941
+ case "@ai-sdk/azure":
942
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/azure
943
+ if (id === "o1-mini") return {}
944
+ return Object.fromEntries(
945
+ openaiReasoningEfforts(id, model.release_date).map((effort) => [
946
+ effort,
947
+ {
948
+ reasoningEffort: effort,
949
+ reasoningSummary: "auto",
950
+ include: INCLUDE_ENCRYPTED_REASONING,
951
+ },
952
+ ]),
953
+ )
954
+ case "@ai-sdk/amazon-bedrock/mantle":
955
+ case "@ai-sdk/openai": {
956
+ if (model.providerID === "meta") {
957
+ return Object.fromEntries(
958
+ OPENAI_EFFORTS.map((effort) => [
959
+ effort,
960
+ {
961
+ reasoningEffort: effort,
962
+ reasoningSummary: "auto",
963
+ include: INCLUDE_ENCRYPTED_REASONING,
964
+ },
965
+ ]),
966
+ )
967
+ }
968
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
969
+ const efforts = openaiReasoningEfforts(model.api.id, model.release_date)
970
+ return Object.fromEntries(
971
+ efforts.map((effort) => [
972
+ effort,
973
+ {
974
+ reasoningEffort: effort,
975
+ reasoningSummary: "auto",
976
+ include: INCLUDE_ENCRYPTED_REASONING,
977
+ },
978
+ ]),
979
+ )
980
+ }
981
+
982
+ case "@ai-sdk/anthropic":
983
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/anthropic
984
+ case "@ai-sdk/google-vertex/anthropic":
985
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-vertex#anthropic-provider
986
+ if (adaptiveEfforts) {
987
+ let efforts = [...adaptiveEfforts]
988
+ if (model.providerID === "github-copilot") {
989
+ if (model.api.id.includes("opus-4.7")) {
990
+ efforts = ["medium"]
991
+ }
992
+ // Efforts currently supported are: low, medium, high
993
+ efforts = efforts.filter((v) => v !== "max" && v !== "xhigh")
994
+ }
995
+ return Object.fromEntries(
996
+ efforts.map((effort) => [
997
+ effort,
998
+ {
999
+ thinking: {
1000
+ type: "adaptive",
1001
+ ...(adaptiveThinkingOmitted ? { display: "summarized" } : {}),
1002
+ },
1003
+ effort,
1004
+ },
1005
+ ]),
1006
+ )
1007
+ }
1008
+
1009
+ if (anthropicOpus45(model.api.id)) {
1010
+ return Object.fromEntries(
1011
+ WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, anthropicOpus45Effort(model, effort)]),
1012
+ )
1013
+ }
1014
+
1015
+ return {
1016
+ high: {
1017
+ thinking: {
1018
+ type: "enabled",
1019
+ budgetTokens: Math.min(16_000, Math.floor(model.limit.output / 2 - 1)),
1020
+ },
1021
+ },
1022
+ max: {
1023
+ thinking: {
1024
+ type: "enabled",
1025
+ budgetTokens: Math.min(31_999, model.limit.output - 1),
1026
+ },
1027
+ },
1028
+ }
1029
+
1030
+ case "@ai-sdk/amazon-bedrock":
1031
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock
1032
+ if (adaptiveEfforts) {
1033
+ return Object.fromEntries(
1034
+ adaptiveEfforts.map((effort) => [
1035
+ effort,
1036
+ {
1037
+ reasoningConfig: {
1038
+ type: "adaptive",
1039
+ maxReasoningEffort: effort,
1040
+ ...(adaptiveThinkingOmitted ? { display: "summarized" } : {}),
1041
+ },
1042
+ },
1043
+ ]),
1044
+ )
1045
+ }
1046
+ // For Anthropic models on Bedrock, use reasoningConfig with budgetTokens
1047
+ if (model.api.id.includes("anthropic")) {
1048
+ return {
1049
+ high: {
1050
+ reasoningConfig: {
1051
+ type: "enabled",
1052
+ budgetTokens: 16000,
1053
+ },
1054
+ },
1055
+ max: {
1056
+ reasoningConfig: {
1057
+ type: "enabled",
1058
+ budgetTokens: 31999,
1059
+ },
1060
+ },
1061
+ }
1062
+ }
1063
+
1064
+ // For Amazon Nova models, use reasoningConfig with maxReasoningEffort
1065
+ return Object.fromEntries(
1066
+ WIDELY_SUPPORTED_EFFORTS.map((effort) => [
1067
+ effort,
1068
+ {
1069
+ reasoningConfig: {
1070
+ type: "enabled",
1071
+ maxReasoningEffort: effort,
1072
+ },
1073
+ },
1074
+ ]),
1075
+ )
1076
+
1077
+ case "@ai-sdk/google-vertex":
1078
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-vertex
1079
+ case "@ai-sdk/google":
1080
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-generative-ai
1081
+ return googleThinkingVariants(model)
1082
+
1083
+ case "@ai-sdk/mistral":
1084
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/mistral
1085
+ // https://docs.mistral.ai/capabilities/reasoning/adjustable
1086
+ if (!model.capabilities.reasoning) return {}
1087
+ // Only Mistral Small 4 and Medium 3.5 support reasoning
1088
+ const MISTRAL_REASONING_IDS = [
1089
+ "mistral-small-2603",
1090
+ "mistral-small-latest",
1091
+ "mistral-medium-3.5",
1092
+ "mistral-medium-2604",
1093
+ ]
1094
+ const mistralId = model.api.id.toLowerCase()
1095
+ if (!MISTRAL_REASONING_IDS.some((id) => mistralId.includes(id))) return {}
1096
+ return {
1097
+ high: { reasoningEffort: "high" },
1098
+ }
1099
+
1100
+ case "@ai-sdk/cohere":
1101
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/cohere
1102
+ return {}
1103
+
1104
+ case "@ai-sdk/groq":
1105
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/groq
1106
+ const groqEffort = ["none", ...WIDELY_SUPPORTED_EFFORTS]
1107
+ return Object.fromEntries(
1108
+ groqEffort.map((effort) => [
1109
+ effort,
1110
+ {
1111
+ reasoningEffort: effort,
1112
+ },
1113
+ ]),
1114
+ )
1115
+
1116
+ case "@ai-sdk/perplexity":
1117
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/perplexity
1118
+ return {}
1119
+
1120
+ case "@jerome-benoit/sap-ai-provider-v2": {
1121
+ if (id.includes("anthropic")) {
1122
+ if (adaptiveEfforts) {
1123
+ // Bedrock adaptive splits `effort` out into `output_config` (vs Anthropic
1124
+ // native which inlines it). Claude 4.7+ defaults `display` to "omitted".
1125
+ return wrapInSapModelParams(
1126
+ Object.fromEntries(
1127
+ adaptiveEfforts.map((effort) => [
1128
+ effort,
1129
+ {
1130
+ thinking: { type: "adaptive", ...(adaptiveThinkingOmitted ? { display: "summarized" } : {}) },
1131
+ output_config: { effort },
1132
+ },
1133
+ ]),
1134
+ ),
1135
+ )
1136
+ }
1137
+ return wrapInSapModelParams({
1138
+ high: { thinking: { type: "enabled", budget_tokens: 16000 } },
1139
+ max: { thinking: { type: "enabled", budget_tokens: 31999 } },
1140
+ })
1141
+ }
1142
+ if (id.includes("gemini") && id.includes("2.5")) {
1143
+ return wrapInSapModelParams(googleThinkingVariants(model))
1144
+ }
1145
+ if (id.includes("gpt") || /\bo[1-9]/.test(id)) {
1146
+ const efforts = openaiReasoningEfforts(id, model.release_date)
1147
+ return wrapInSapModelParams(Object.fromEntries(efforts.map((effort) => [effort, { reasoning_effort: effort }])))
1148
+ }
1149
+ return wrapInSapModelParams(
1150
+ Object.fromEntries(["low", "medium", "high"].map((effort) => [effort, { reasoning_effort: effort }])),
1151
+ )
1152
+ }
1153
+ }
1154
+ return {}
1155
+ }
1156
+
1157
+ export function options(input: {
1158
+ model: Provider.Model
1159
+ sessionID: string
1160
+ providerOptions?: Record<string, any>
1161
+ }): Record<string, any> {
1162
+ const result: Record<string, any> = {}
1163
+
1164
+ if (
1165
+ input.model.api.npm === "@ai-sdk/google-vertex/anthropic" ||
1166
+ (!input.model.api.id.includes("claude") && input.model.api.npm === "@ai-sdk/anthropic")
1167
+ ) {
1168
+ result["toolStreaming"] = false
1169
+ }
1170
+
1171
+ // openai and providers using openai package should set store to false by default.
1172
+ if (
1173
+ input.model.providerID === "openai" ||
1174
+ input.model.api.npm === "@ai-sdk/openai" ||
1175
+ input.model.api.npm === "@ai-sdk/github-copilot" ||
1176
+ input.model.api.npm === "@ai-sdk/amazon-bedrock/mantle" ||
1177
+ input.model.api.npm === "@ai-sdk/xai"
1178
+ ) {
1179
+ result["store"] = false
1180
+ }
1181
+
1182
+ if (input.model.api.npm === "@ai-sdk/azure") {
1183
+ result["store"] = false
1184
+ }
1185
+
1186
+ if (input.model.api.npm === "@openrouter/ai-sdk-provider" || input.model.api.npm === "@llmgateway/ai-sdk-provider") {
1187
+ result["usage"] = {
1188
+ include: true,
1189
+ }
1190
+ if (input.model.api.id.includes("gemini-3")) {
1191
+ result["reasoning"] = { effort: "high" }
1192
+ }
1193
+ }
1194
+
1195
+ if (
1196
+ input.model.providerID === "baseten" ||
1197
+ (input.model.providerID === "opencode" && ["kimi-k2-thinking", "glm-4.6"].includes(input.model.api.id))
1198
+ ) {
1199
+ result["chat_template_args"] = { enable_thinking: true }
1200
+ }
1201
+
1202
+ if (
1203
+ ["zai", "zhipuai"].some((id) => input.model.providerID.includes(id)) &&
1204
+ input.model.api.npm === "@ai-sdk/openai-compatible"
1205
+ ) {
1206
+ result["thinking"] = {
1207
+ type: "enabled",
1208
+ clear_thinking: false,
1209
+ }
1210
+ }
1211
+
1212
+ if (input.model.providerID === "meta" && input.model.api.npm === "@ai-sdk/openai") {
1213
+ result["reasoningSummary"] = "auto"
1214
+ result["include"] = INCLUDE_ENCRYPTED_REASONING
1215
+ }
1216
+
1217
+ if (input.model.api.npm === "@ai-sdk/google" || input.model.api.npm === "@ai-sdk/google-vertex") {
1218
+ if (input.model.capabilities.reasoning) {
1219
+ result["thinkingConfig"] = {
1220
+ includeThoughts: true,
1221
+ }
1222
+ if (input.model.api.id.includes("gemini-3")) {
1223
+ result["thinkingConfig"]["thinkingLevel"] = "high"
1224
+ }
1225
+ }
1226
+ }
1227
+
1228
+ const modelId = input.model.api.id.toLowerCase()
1229
+
1230
+ // MiniMax's Anthropic interface defaults thinking off, unlike Chat Completions.
1231
+ if (modelId.includes("minimax-m3") && input.model.api.npm === "@ai-sdk/anthropic") {
1232
+ result["thinking"] = { type: "adaptive" }
1233
+ }
1234
+
1235
+ // Moonshot's Anthropic-compatible API uses adaptive effort rather than token budgets.
1236
+ // Request summaries so thinking content survives replay on subsequent turns.
1237
+ if (
1238
+ ["@ai-sdk/anthropic", "@ai-sdk/google-vertex/anthropic"].includes(input.model.api.npm) &&
1239
+ isKimiFamily(input.model) &&
1240
+ input.model.capabilities.reasoning
1241
+ ) {
1242
+ result["thinking"] = { type: "adaptive", display: "summarized" }
1243
+ result["effort"] = "high"
1244
+ }
1245
+
1246
+ // Enable thinking for reasoning models on alibaba-cn (DashScope).
1247
+ // DashScope's OpenAI-compatible API requires `enable_thinking: true` in the request body
1248
+ // to return reasoning_content. Without it, models like kimi-k2.5, qwen-plus, qwen3, qwq,
1249
+ // deepseek-r1, etc. never output thinking/reasoning tokens.
1250
+ // Note: kimi-k2-thinking is excluded as it returns reasoning_content by default.
1251
+ if (
1252
+ input.model.providerID === "alibaba-cn" &&
1253
+ input.model.capabilities.reasoning &&
1254
+ input.model.api.npm === "@ai-sdk/openai-compatible" &&
1255
+ !modelId.includes("kimi-k2-thinking")
1256
+ ) {
1257
+ result["enable_thinking"] = true
1258
+ }
1259
+
1260
+ if (input.providerOptions?.setCacheKey !== false) {
1261
+ if (input.model.api.npm === "@ai-sdk/deepinfra" || input.model.api.npm === "@ai-sdk/cerebras") {
1262
+ result["prompt_cache_key"] = input.sessionID
1263
+ } else if (
1264
+ input.model.api.npm === "@ai-sdk/openai" ||
1265
+ input.model.api.npm === "@ai-sdk/azure" ||
1266
+ input.model.api.npm === "@ai-sdk/xai" ||
1267
+ input.model.api.npm === "@ai-sdk/mistral" ||
1268
+ input.model.api.npm === "venice-ai-sdk-provider" ||
1269
+ input.providerOptions?.setCacheKey === true
1270
+ ) {
1271
+ result["promptCacheKey"] = input.sessionID
1272
+ }
1273
+ }
1274
+
1275
+ if (input.model.api.npm === "@ai-sdk/gateway") {
1276
+ result["gateway"] = { caching: "auto" }
1277
+ }
1278
+
1279
+ // Any gpt version above 5.4 in combination with azure does not support reasoningEffort
1280
+ // so we should return early here.
1281
+ const [, gptMajorVersion, gptMinorVersion] = input.model.api.id.match(/gpt-(\d+)\.(\d+)/) ?? []
1282
+ const isGpt55OrNewer = Number(gptMajorVersion) > 5 || (Number(gptMajorVersion) === 5 && Number(gptMinorVersion) >= 5)
1283
+ if (input.model.api.npm === "@ai-sdk/azure" && input.providerOptions?.useCompletionUrls) {
1284
+ if (!isGpt55OrNewer) {
1285
+ result["reasoningEffort"] = "medium"
1286
+ }
1287
+ return result
1288
+ }
1289
+
1290
+ if (input.model.api.id.includes("gpt-5") && !input.model.api.id.includes("gpt-5-chat")) {
1291
+ if (!input.model.api.id.includes("gpt-5-pro")) {
1292
+ result["reasoningEffort"] = "medium"
1293
+ if (
1294
+ input.model.api.npm === "@ai-sdk/openai" ||
1295
+ input.model.api.npm === "@ai-sdk/azure" ||
1296
+ input.model.api.npm === "@ai-sdk/github-copilot" ||
1297
+ input.model.api.npm === "@ai-sdk/amazon-bedrock/mantle"
1298
+ ) {
1299
+ result["reasoningSummary"] = "auto"
1300
+ }
1301
+ if (input.model.api.npm === "@ai-sdk/openai" || input.model.api.npm === "@ai-sdk/amazon-bedrock/mantle") {
1302
+ result["include"] = INCLUDE_ENCRYPTED_REASONING
1303
+ }
1304
+ }
1305
+
1306
+ // Generic OpenAI-compatible APIs do not necessarily support OpenAI's verbosity parameter.
1307
+ // Only enable the default for integrations known to implement it.
1308
+ if (
1309
+ input.model.api.id.includes("gpt-5.") &&
1310
+ !input.model.api.id.includes("codex") &&
1311
+ !input.model.api.id.includes("-chat") &&
1312
+ (input.model.api.npm === "@ai-sdk/openai" || input.model.api.npm === "@ai-sdk/amazon-bedrock/mantle")
1313
+ ) {
1314
+ result["textVerbosity"] = "low"
1315
+ }
1316
+
1317
+ if (input.model.providerID.startsWith("opencode") && input.providerOptions?.setCacheKey !== false) {
1318
+ result["promptCacheKey"] = input.sessionID
1319
+ result["include"] = INCLUDE_ENCRYPTED_REASONING
1320
+ result["reasoningSummary"] = "auto"
1321
+ }
1322
+ }
1323
+
1324
+ return result
1325
+ }
1326
+
1327
+ export function smallOptions(model: Provider.Model) {
1328
+ const small = Object.values(model.variants ?? {})[0] ?? {}
1329
+ if (
1330
+ model.providerID === "openai" ||
1331
+ model.api.npm === "@ai-sdk/openai" ||
1332
+ model.api.npm === "@ai-sdk/github-copilot" ||
1333
+ model.api.npm === "@ai-sdk/xai"
1334
+ ) {
1335
+ const base = { store: false }
1336
+ return mergeDeep(base, small)
1337
+ }
1338
+ if (model.providerID === "openrouter" || model.providerID === "llmgateway") {
1339
+ if (Object.keys(small).length === 0 && model.api.id.includes("google")) {
1340
+ return { reasoning: { enabled: false } }
1341
+ }
1342
+ }
1343
+
1344
+ if (model.providerID === "venice") {
1345
+ if (Object.keys(small).length > 0) return small
1346
+ return { veniceParameters: { disableThinking: true } }
1347
+ }
1348
+
1349
+ return small
1350
+ }
1351
+
1352
+ // Maps model ID prefix to provider slug used in providerOptions.
1353
+ // Example: "amazon/nova-2-lite" → "bedrock"
1354
+ const SLUG_OVERRIDES: Record<string, string> = {
1355
+ amazon: "bedrock",
1356
+ }
1357
+
1358
+ export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
1359
+ const usesOpenAIReasoningGate =
1360
+ model.api.npm === "@ai-sdk/openai" ||
1361
+ model.api.npm === "@ai-sdk/azure" ||
1362
+ model.api.npm === "@ai-sdk/amazon-bedrock/mantle"
1363
+ const normalized =
1364
+ usesOpenAIReasoningGate &&
1365
+ (model.capabilities.reasoning || options.reasoningEffort !== undefined || options.reasoningSummary !== undefined)
1366
+ ? { ...options, forceReasoning: true }
1367
+ : options
1368
+
1369
+ if (model.api.npm === "@ai-sdk/gateway") {
1370
+ // Gateway providerOptions are split across two namespaces:
1371
+ // - `gateway`: gateway-native routing/caching controls (order, only, byok, etc.)
1372
+ // - `<upstream slug>`: provider-specific model options (anthropic/openai/...)
1373
+ // We keep `gateway` as-is and route every other top-level option under the
1374
+ // model-derived upstream slug.
1375
+ const i = model.api.id.indexOf("/")
1376
+ const rawSlug = i > 0 ? model.api.id.slice(0, i) : undefined
1377
+ const slug = rawSlug ? (SLUG_OVERRIDES[rawSlug] ?? rawSlug) : undefined
1378
+ const gateway = normalized.gateway
1379
+ const rest = Object.fromEntries(Object.entries(normalized).filter(([k]) => k !== "gateway"))
1380
+ const has = Object.keys(rest).length > 0
1381
+
1382
+ const result: Record<string, any> = {}
1383
+ if (gateway !== undefined) result.gateway = gateway
1384
+
1385
+ if (has) {
1386
+ if (slug) {
1387
+ // Route model-specific options under the provider slug
1388
+ result[slug] = rest
1389
+ } else if (gateway && typeof gateway === "object" && !Array.isArray(gateway)) {
1390
+ result.gateway = { ...gateway, ...rest }
1391
+ } else {
1392
+ result.gateway = rest
1393
+ }
1394
+ }
1395
+
1396
+ return result
1397
+ }
1398
+
1399
+ // AI SDK packages that resolve providerOptionsName by splitting the
1400
+ // provider name on "." (e.g. "wafer.ai" -> "wafer") need the same
1401
+ // logic here so the key we write matches the key they read.
1402
+ // Other SDKs (xai, mistral, groq, cohere, etc.) use hardcoded keys
1403
+ // like "xai" or "cohere" - applying .split(".")[0] would break those.
1404
+ const usesDotSplitOptions =
1405
+ model.api.npm === "@ai-sdk/openai-compatible" ||
1406
+ model.api.npm === "@ai-sdk/openai" ||
1407
+ model.api.npm === "@ai-sdk/anthropic"
1408
+ const key = sdkKey(model.api.npm) ?? (usesDotSplitOptions ? model.providerID.split(".")[0] : model.providerID)
1409
+ // @ai-sdk/azure delegates to OpenAIChatLanguageModel which reads from
1410
+ // providerOptions["openai"], but OpenAIResponsesLanguageModel checks
1411
+ // "azure" first. Pass both so model options work on either code path.
1412
+ if (model.api.npm === "@ai-sdk/azure") {
1413
+ return { openai: normalized, azure: normalized }
1414
+ }
1415
+ return { [key]: normalized }
1416
+ }
1417
+
1418
+ export function maxOutputTokens(model: Provider.Model, outputTokenMax = OUTPUT_TOKEN_MAX): number {
1419
+ return Math.min(model.limit.output, outputTokenMax) || outputTokenMax
1420
+ }
1421
+
1422
+ type JsonRecord = Record<string, unknown>
1423
+
1424
+ function isPlainObject(value: unknown): value is JsonRecord {
1425
+ return typeof value === "object" && value !== null && !Array.isArray(value)
1426
+ }
1427
+
1428
+ // Mirrors Codex's Rust JSON schema compatibility lowering for OpenAI tool schemas.
1429
+ function sanitizeOpenAISchema(value: unknown): unknown {
1430
+ const types = ["string", "number", "boolean", "integer", "object", "array", "null"]
1431
+ const compositionKeys = ["anyOf", "oneOf", "allOf"]
1432
+
1433
+ // JSON Schema's boolean form (`true`/`false`) is unsupported by OpenAI tool schemas.
1434
+ if (typeof value === "boolean") return { type: "string" }
1435
+ if (Array.isArray(value)) return value.map(sanitizeOpenAISchema)
1436
+ if (!isPlainObject(value)) return value
1437
+
1438
+ const result: JsonRecord = {}
1439
+
1440
+ if (typeof value.$ref === "string") result.$ref = value.$ref
1441
+ if (typeof value.description === "string") result.description = value.description
1442
+ if ("const" in value) result.enum = [value.const]
1443
+ else if (Array.isArray(value.enum)) result.enum = value.enum
1444
+
1445
+ if (isPlainObject(value.properties)) {
1446
+ result.properties = Object.fromEntries(
1447
+ Object.entries(value.properties).map(([key, item]) => [key, sanitizeOpenAISchema(item)]),
1448
+ )
1449
+ }
1450
+
1451
+ if (Array.isArray(value.required)) {
1452
+ result.required = value.required.filter((item) => typeof item === "string")
1453
+ }
1454
+
1455
+ if ("items" in value) result.items = sanitizeOpenAISchema(value.items)
1456
+
1457
+ if ("additionalProperties" in value) {
1458
+ result.additionalProperties =
1459
+ typeof value.additionalProperties === "boolean"
1460
+ ? value.additionalProperties
1461
+ : sanitizeOpenAISchema(value.additionalProperties)
1462
+ }
1463
+
1464
+ for (const key of compositionKeys) {
1465
+ if (Array.isArray(value[key])) result[key] = value[key].map(sanitizeOpenAISchema)
1466
+ }
1467
+
1468
+ for (const key of ["$defs", "definitions"]) {
1469
+ if (isPlainObject(value[key])) {
1470
+ result[key] = Object.fromEntries(
1471
+ Object.entries(value[key]).map(([name, item]) => [name, sanitizeOpenAISchema(item)]),
1472
+ )
1473
+ }
1474
+ }
1475
+
1476
+ const schemaTypes =
1477
+ typeof value.type === "string"
1478
+ ? types.includes(value.type)
1479
+ ? [value.type]
1480
+ : []
1481
+ : Array.isArray(value.type)
1482
+ ? value.type.filter((item) => typeof item === "string" && types.includes(item))
1483
+ : []
1484
+
1485
+ if (schemaTypes.length === 0 && (typeof result.$ref === "string" || compositionKeys.some((key) => key in result))) {
1486
+ return result
1487
+ }
1488
+
1489
+ // MCP schemas may omit `type` while still using keywords that imply one.
1490
+ // Keep the schema usable after unsupported keywords are dropped.
1491
+ const inferredTypes =
1492
+ schemaTypes.length > 0
1493
+ ? schemaTypes
1494
+ : ["properties", "required", "additionalProperties"].some((key) => key in value)
1495
+ ? ["object"]
1496
+ : ["items", "prefixItems"].some((key) => key in value)
1497
+ ? ["array"]
1498
+ : "enum" in result || "format" in value
1499
+ ? ["string"]
1500
+ : ["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf"].some((key) => key in value)
1501
+ ? ["number"]
1502
+ : []
1503
+
1504
+ if (inferredTypes.length === 0) return {}
1505
+
1506
+ result.type = inferredTypes.length === 1 ? inferredTypes[0] : inferredTypes
1507
+ if (inferredTypes.includes("object") && !("properties" in result)) result.properties = {}
1508
+ if (inferredTypes.includes("array") && !("items" in result)) result.items = { type: "string" }
1509
+ return result
1510
+ }
1511
+
1512
+ export function schema(model: Provider.Model, schema: JSONSchema7): JSONSchema7 {
1513
+ /*
1514
+ if (["openai", "azure"].includes(providerID)) {
1515
+ if (schema.type === "object" && schema.properties) {
1516
+ for (const [key, value] of Object.entries(schema.properties)) {
1517
+ if (schema.required?.includes(key)) continue
1518
+ schema.properties[key] = {
1519
+ anyOf: [
1520
+ value as JSONSchema.JSONSchema,
1521
+ {
1522
+ type: "null",
1523
+ },
1524
+ ],
1525
+ }
1526
+ }
1527
+ }
1528
+ }
1529
+ */
1530
+
1531
+ if (model.api.npm === "@ai-sdk/openai" || model.api.npm === "@ai-sdk/azure") {
1532
+ schema = sanitizeOpenAISchema(schema) as JSONSchema7
1533
+ // Codex also applies lossy compaction above 4 KB; defer that until OpenCode needs the same schema budget.
1534
+ }
1535
+
1536
+ if (model.providerID === "moonshotai" || model.api.id.toLowerCase().includes("kimi")) {
1537
+ const sanitizeMoonshot = (obj: unknown): unknown => {
1538
+ if (obj === null || typeof obj !== "object") return obj
1539
+ if (Array.isArray(obj)) return obj.map(sanitizeMoonshot)
1540
+ // Moonshot expands $ref before validation and rejects sibling keywords like description on the same node.
1541
+ if ("$ref" in obj && typeof obj.$ref === "string") return { $ref: obj.$ref }
1542
+ const result = Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, sanitizeMoonshot(value)]))
1543
+ // MFJS does not support tuple-style `items` arrays; it requires one schema object for all array items.
1544
+ if (Array.isArray(result.items)) result.items = result.items[0] ?? {}
1545
+ return result
1546
+ }
1547
+
1548
+ const sanitized = sanitizeMoonshot(schema)
1549
+ if (typeof sanitized === "object" && sanitized !== null && !Array.isArray(sanitized)) {
1550
+ schema = sanitized
1551
+ }
1552
+ }
1553
+
1554
+ // Convert integer enums to string enums for Google/Gemini
1555
+ if (model.providerID === "google" || model.api.id.includes("gemini")) {
1556
+ const isPlainObject = (node: unknown): node is Record<string, any> =>
1557
+ typeof node === "object" && node !== null && !Array.isArray(node)
1558
+ const hasCombiner = (node: unknown) =>
1559
+ isPlainObject(node) && (Array.isArray(node.anyOf) || Array.isArray(node.oneOf) || Array.isArray(node.allOf))
1560
+ const hasSchemaIntent = (node: unknown) => {
1561
+ if (!isPlainObject(node)) return false
1562
+ if (hasCombiner(node)) return true
1563
+ return [
1564
+ "type",
1565
+ "properties",
1566
+ "items",
1567
+ "prefixItems",
1568
+ "enum",
1569
+ "const",
1570
+ "$ref",
1571
+ "additionalProperties",
1572
+ "patternProperties",
1573
+ "required",
1574
+ "not",
1575
+ "if",
1576
+ "then",
1577
+ "else",
1578
+ ].some((key) => key in node)
1579
+ }
1580
+
1581
+ const sanitizeGemini = (obj: any): any => {
1582
+ if (obj === null || typeof obj !== "object") {
1583
+ return obj
1584
+ }
1585
+
1586
+ if (Array.isArray(obj)) {
1587
+ return obj.map(sanitizeGemini)
1588
+ }
1589
+
1590
+ const result: any = {}
1591
+ for (const [key, value] of Object.entries(obj)) {
1592
+ if (key === "enum" && Array.isArray(value)) {
1593
+ // Convert all enum values to strings
1594
+ result[key] = value.map((v) => String(v))
1595
+ // If we have integer type with enum, change type to string
1596
+ if (result.type === "integer" || result.type === "number") {
1597
+ result.type = "string"
1598
+ }
1599
+ } else if (typeof value === "object" && value !== null) {
1600
+ result[key] = sanitizeGemini(value)
1601
+ } else {
1602
+ result[key] = value
1603
+ }
1604
+ }
1605
+
1606
+ // Gemini requires a single `type`, not a JSON Schema type array such as
1607
+ // `["number","string"]` (emitted by some MCP servers). Plain `@ai-sdk/google`
1608
+ // rewrites these into an `anyOf` of single-type schemas, but OpenAI-compatible
1609
+ // transports (e.g. GitHub Copilot proxying to Gemini) forward them verbatim
1610
+ // and the backend rejects the array form. Mirror the SDK: split non-null
1611
+ // types into `anyOf`, and lift `null` into `nullable`.
1612
+ if (Array.isArray(result.type)) {
1613
+ const hasNull = result.type.includes("null")
1614
+ const nonNull = result.type.filter((entry: unknown) => entry !== "null")
1615
+ if (nonNull.length === 0) {
1616
+ result.type = "null"
1617
+ } else {
1618
+ delete result.type
1619
+ result.anyOf = nonNull.map((entry: unknown) => ({ type: entry }))
1620
+ if (hasNull) result.nullable = true
1621
+ }
1622
+ }
1623
+
1624
+ // Filter required array to only include fields that exist in properties
1625
+ if (result.type === "object" && result.properties && Array.isArray(result.required)) {
1626
+ result.required = result.required.filter((field: any) => field in result.properties)
1627
+ }
1628
+
1629
+ if (result.type === "array" && !hasCombiner(result)) {
1630
+ if (result.items == null) {
1631
+ result.items = {}
1632
+ }
1633
+ // Ensure items has a type only when it's still schema-empty.
1634
+ if (isPlainObject(result.items) && !hasSchemaIntent(result.items)) {
1635
+ result.items.type = "string"
1636
+ }
1637
+ }
1638
+
1639
+ // Remove properties/required from non-object types (Gemini rejects these)
1640
+ if (result.type && result.type !== "object" && !hasCombiner(result)) {
1641
+ delete result.properties
1642
+ delete result.required
1643
+ }
1644
+
1645
+ return result
1646
+ }
1647
+
1648
+ schema = sanitizeGemini(schema)
1649
+ }
1650
+
1651
+ return schema
1652
+ }
1653
+
1654
+ export function reasoningVariants(model: ModelsDev.Model, target: Provider.Model): Provider.Model["variants"] {
1655
+ const options = model.reasoning_options
1656
+ if (options === undefined) return
1657
+ if (options.length === 0) return {}
1658
+
1659
+ const effort = options.find((option) => option.type === "effort")
1660
+ if (effort) return effortVariants(target, effort.values)
1661
+
1662
+ const toggle = options.some((option) => option.type === "toggle")
1663
+ const budget = options.find((option) => option.type === "budget_tokens")
1664
+ if (!budget) return toggle ? nonEmptyVariants(reasoningToggle(target)) : undefined
1665
+
1666
+ return nonEmptyVariants({
1667
+ ...(toggle ? reasoningToggle(target) : {}),
1668
+ ...budgetVariants(target, budget.min, budget.max),
1669
+ })
1670
+ }
1671
+
1672
+ function effortVariants(model: Provider.Model, values: readonly unknown[]) {
1673
+ return Object.fromEntries(
1674
+ values.flatMap((value) => {
1675
+ const id = (() => {
1676
+ if (value === null) return "none"
1677
+ if (typeof value === "string") return value
1678
+ })()
1679
+ if (id === undefined) return []
1680
+ const settings = reasoningEffort(model, id)
1681
+ return settings ? [[id, settings]] : []
1682
+ }),
1683
+ )
1684
+ }
1685
+
1686
+ function budgetVariants(model: Provider.Model, min?: number, max?: number) {
1687
+ const maximum = Math.min(max ?? OUTPUT_TOKEN_MAX - 1, model.limit.output - 1, OUTPUT_TOKEN_MAX - 1)
1688
+ if (maximum <= 0) return {}
1689
+ const high = Math.min(Math.max(min ?? 0, Math.floor((maximum + 1) / 2)), maximum)
1690
+ return Object.fromEntries(
1691
+ [
1692
+ { id: "high", budget: high },
1693
+ { id: "max", budget: maximum },
1694
+ ].flatMap((item) => {
1695
+ const settings = reasoningBudget(model, item.budget)
1696
+ return settings ? [[item.id, settings]] : []
1697
+ }),
1698
+ )
1699
+ }
1700
+
1701
+ function nonEmptyVariants(variants: NonNullable<Provider.Model["variants"]>): Provider.Model["variants"] {
1702
+ return Object.keys(variants).length > 0 ? variants : undefined
1703
+ }
1704
+
1705
+ function reasoningToggle(model: Provider.Model): NonNullable<Provider.Model["variants"]> {
1706
+ if (model.api.npm === "@ai-sdk/alibaba")
1707
+ return {
1708
+ none: { enableThinking: false },
1709
+ high: { enableThinking: true },
1710
+ }
1711
+ if (model.api.npm === "@ai-sdk/cohere")
1712
+ return {
1713
+ none: { thinking: { type: "disabled" } },
1714
+ high: { thinking: { type: "enabled" } },
1715
+ }
1716
+ return {}
1717
+ }
1718
+
1719
+ function reasoningEffort(model: Provider.Model, effort: string) {
1720
+ switch (model.api.npm) {
1721
+ case "@openrouter/ai-sdk-provider":
1722
+ return { reasoning: { effort } }
1723
+ case "@ai-sdk/anthropic":
1724
+ case "@ai-sdk/google-vertex/anthropic":
1725
+ return anthropicEffort(model, effort) ?? { effort }
1726
+ case "@ai-sdk/google":
1727
+ case "@ai-sdk/google-vertex":
1728
+ return { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } }
1729
+ case "@ai-sdk/amazon-bedrock":
1730
+ if (anthropicAdaptiveEfforts(model.api.id))
1731
+ return {
1732
+ reasoningConfig: {
1733
+ type: "adaptive",
1734
+ maxReasoningEffort: effort,
1735
+ ...(anthropicOmitsThinking(model.api.id) ? { display: "summarized" } : {}),
1736
+ },
1737
+ }
1738
+ if (anthropicOpus45(model.api.id))
1739
+ return {
1740
+ reasoningConfig: {
1741
+ type: "enabled",
1742
+ budgetTokens: Math.min(16_000, Math.floor(model.limit.output / 2 - 1)),
1743
+ maxReasoningEffort: effort,
1744
+ },
1745
+ }
1746
+ if (model.api.id.includes("anthropic")) return
1747
+ return { reasoningConfig: { type: "enabled", maxReasoningEffort: effort } }
1748
+ case "@ai-sdk/gateway":
1749
+ if (model.id.includes("anthropic")) return { thinking: { type: "adaptive", display: "summarized" }, effort }
1750
+ if (model.id.includes("google")) return { thinkingConfig: { includeThoughts: true, thinkingLevel: effort } }
1751
+ return { reasoningEffort: effort }
1752
+ case "@ai-sdk/github-copilot":
1753
+ // OAuth discovery replaces these with variants from Copilot's /models capabilities.
1754
+ if (model.id.includes("gemini")) return
1755
+ if (model.id.includes("claude")) return { reasoningEffort: effort }
1756
+ return { reasoningEffort: effort, reasoningSummary: "auto", include: INCLUDE_ENCRYPTED_REASONING }
1757
+ case "@ai-sdk/openai":
1758
+ case "@ai-sdk/amazon-bedrock/mantle":
1759
+ return { reasoningEffort: effort, reasoningSummary: "auto", include: INCLUDE_ENCRYPTED_REASONING }
1760
+ case "@ai-sdk/azure":
1761
+ return { reasoningEffort: effort, reasoningSummary: "auto", include: INCLUDE_ENCRYPTED_REASONING }
1762
+ case "@jerome-benoit/sap-ai-provider-v2":
1763
+ if (model.id.includes("anthropic"))
1764
+ return { modelParams: { thinking: { type: "adaptive", display: "summarized" }, output_config: { effort } } }
1765
+ return { modelParams: { reasoning_effort: effort } }
1766
+ case "@ai-sdk/openai-compatible":
1767
+ case "@ai-sdk/xai":
1768
+ case "@ai-sdk/mistral":
1769
+ case "@ai-sdk/groq":
1770
+ case "@ai-sdk/cerebras":
1771
+ case "@ai-sdk/deepinfra":
1772
+ case "@ai-sdk/togetherai":
1773
+ case "venice-ai-sdk-provider":
1774
+ case "ai-gateway-provider":
1775
+ case "merge-gateway-ai-sdk-provider":
1776
+ return { reasoningEffort: effort }
1777
+ case "@ai-sdk/cohere":
1778
+ case "@ai-sdk/perplexity":
1779
+ case "@ai-sdk/vercel":
1780
+ case "@ai-sdk/alibaba":
1781
+ case "gitlab-ai-provider":
1782
+ return
1783
+ }
1784
+ }
1785
+
1786
+ function anthropicEffort(model: Provider.Model, effort: string) {
1787
+ if (anthropicOpus45(model.api.id)) return anthropicOpus45Effort(model, effort)
1788
+ // Kimi defaults to omitting adaptive thinking text unless summarized display is requested.
1789
+ if (isKimiFamily(model)) return { thinking: { type: "adaptive", display: "summarized" }, effort }
1790
+ if (!anthropicAdaptiveEfforts(model.api.id)) return
1791
+ return {
1792
+ thinking: {
1793
+ type: "adaptive",
1794
+ ...(anthropicOmitsThinking(model.api.id) ? { display: "summarized" } : {}),
1795
+ },
1796
+ effort,
1797
+ }
1798
+ }
1799
+
1800
+ function anthropicOpus45Effort(model: Provider.Model, effort: string) {
1801
+ return {
1802
+ thinking: {
1803
+ type: "enabled",
1804
+ budgetTokens: Math.min(16_000, Math.floor(model.limit.output / 2 - 1)),
1805
+ },
1806
+ effort,
1807
+ }
1808
+ }
1809
+
1810
+ function reasoningBudget(model: Provider.Model, budget: number) {
1811
+ switch (model.api.npm) {
1812
+ case "@openrouter/ai-sdk-provider":
1813
+ return { reasoning: { max_tokens: budget } }
1814
+ case "@ai-sdk/anthropic":
1815
+ case "@ai-sdk/google-vertex/anthropic":
1816
+ return { thinking: { type: "enabled", budgetTokens: budget } }
1817
+ case "@ai-sdk/google":
1818
+ case "@ai-sdk/google-vertex":
1819
+ return { thinkingConfig: { includeThoughts: true, thinkingBudget: budget } }
1820
+ case "@ai-sdk/amazon-bedrock":
1821
+ return { reasoningConfig: { type: "enabled", budgetTokens: budget } }
1822
+ case "@ai-sdk/gateway":
1823
+ if (model.id.includes("anthropic")) return { thinking: { type: "enabled", budgetTokens: budget } }
1824
+ if (model.id.includes("google")) return { thinkingConfig: { includeThoughts: true, thinkingBudget: budget } }
1825
+ return
1826
+ case "@ai-sdk/cohere":
1827
+ return { thinking: { type: "enabled", tokenBudget: budget } }
1828
+ case "@ai-sdk/alibaba":
1829
+ return { enableThinking: true, thinkingBudget: budget }
1830
+ case "@jerome-benoit/sap-ai-provider-v2":
1831
+ if (model.id.includes("anthropic"))
1832
+ return { modelParams: { thinking: { type: "enabled", budget_tokens: budget } } }
1833
+ if (model.id.includes("gemini"))
1834
+ return { modelParams: { thinkingConfig: { includeThoughts: true, thinkingBudget: budget } } }
1835
+ return
1836
+ case "@ai-sdk/amazon-bedrock/mantle":
1837
+ case "@ai-sdk/azure":
1838
+ case "@ai-sdk/cerebras":
1839
+ case "@ai-sdk/deepinfra":
1840
+ case "@ai-sdk/github-copilot":
1841
+ case "@ai-sdk/groq":
1842
+ case "@ai-sdk/mistral":
1843
+ case "@ai-sdk/openai":
1844
+ case "@ai-sdk/openai-compatible":
1845
+ case "@ai-sdk/perplexity":
1846
+ case "@ai-sdk/togetherai":
1847
+ case "@ai-sdk/vercel":
1848
+ case "@ai-sdk/xai":
1849
+ case "ai-gateway-provider":
1850
+ case "gitlab-ai-provider":
1851
+ case "venice-ai-sdk-provider":
1852
+ return
1853
+ }
1854
+ }
1855
+
1856
+ export * as ProviderTransform from "./transform"