neurocode-ai 1.18.5

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