@stonerzju/opencode 1.2.16-offline.1

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 (496) hide show
  1. package/AGENTS.md +10 -0
  2. package/BUN_SHELL_MIGRATION_PLAN.md +136 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +15 -0
  5. package/bin/opencode +179 -0
  6. package/bunfig.toml +7 -0
  7. package/drizzle.config.ts +10 -0
  8. package/migration/20260127222353_familiar_lady_ursula/migration.sql +90 -0
  9. package/migration/20260127222353_familiar_lady_ursula/snapshot.json +796 -0
  10. package/migration/20260211171708_add_project_commands/migration.sql +1 -0
  11. package/migration/20260211171708_add_project_commands/snapshot.json +806 -0
  12. package/migration/20260213144116_wakeful_the_professor/migration.sql +11 -0
  13. package/migration/20260213144116_wakeful_the_professor/snapshot.json +897 -0
  14. package/migration/20260225215848_workspace/migration.sql +7 -0
  15. package/migration/20260225215848_workspace/snapshot.json +959 -0
  16. package/package.json +140 -0
  17. package/package.json.bak +140 -0
  18. package/parsers-config.ts +254 -0
  19. package/script/build.ts +224 -0
  20. package/script/check-migrations.ts +16 -0
  21. package/script/postinstall.mjs +131 -0
  22. package/script/publish.ts +181 -0
  23. package/script/schema.ts +63 -0
  24. package/script/seed-e2e.ts +50 -0
  25. package/src/acp/README.md +174 -0
  26. package/src/acp/agent.ts +1741 -0
  27. package/src/acp/session.ts +116 -0
  28. package/src/acp/types.ts +23 -0
  29. package/src/agent/agent.ts +339 -0
  30. package/src/agent/generate.txt +75 -0
  31. package/src/agent/prompt/compaction.txt +14 -0
  32. package/src/agent/prompt/explore.txt +18 -0
  33. package/src/agent/prompt/summary.txt +11 -0
  34. package/src/agent/prompt/title.txt +44 -0
  35. package/src/auth/index.ts +68 -0
  36. package/src/bun/index.ts +131 -0
  37. package/src/bun/registry.ts +50 -0
  38. package/src/bus/bus-event.ts +43 -0
  39. package/src/bus/global.ts +10 -0
  40. package/src/bus/index.ts +105 -0
  41. package/src/cli/bootstrap.ts +17 -0
  42. package/src/cli/cmd/acp.ts +70 -0
  43. package/src/cli/cmd/agent.ts +257 -0
  44. package/src/cli/cmd/auth.ts +449 -0
  45. package/src/cli/cmd/cmd.ts +7 -0
  46. package/src/cli/cmd/db.ts +118 -0
  47. package/src/cli/cmd/debug/agent.ts +167 -0
  48. package/src/cli/cmd/debug/config.ts +16 -0
  49. package/src/cli/cmd/debug/file.ts +97 -0
  50. package/src/cli/cmd/debug/index.ts +48 -0
  51. package/src/cli/cmd/debug/lsp.ts +52 -0
  52. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  53. package/src/cli/cmd/debug/scrap.ts +16 -0
  54. package/src/cli/cmd/debug/skill.ts +16 -0
  55. package/src/cli/cmd/debug/snapshot.ts +52 -0
  56. package/src/cli/cmd/export.ts +88 -0
  57. package/src/cli/cmd/generate.ts +38 -0
  58. package/src/cli/cmd/github.ts +1631 -0
  59. package/src/cli/cmd/import.ts +170 -0
  60. package/src/cli/cmd/mcp.ts +754 -0
  61. package/src/cli/cmd/models.ts +77 -0
  62. package/src/cli/cmd/pr.ts +112 -0
  63. package/src/cli/cmd/run.ts +625 -0
  64. package/src/cli/cmd/serve.ts +31 -0
  65. package/src/cli/cmd/session.ts +156 -0
  66. package/src/cli/cmd/stats.ts +410 -0
  67. package/src/cli/cmd/tui/app.tsx +845 -0
  68. package/src/cli/cmd/tui/attach.ts +88 -0
  69. package/src/cli/cmd/tui/component/border.tsx +21 -0
  70. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  71. package/src/cli/cmd/tui/component/dialog-command.tsx +147 -0
  72. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  73. package/src/cli/cmd/tui/component/dialog-model.tsx +165 -0
  74. package/src/cli/cmd/tui/component/dialog-provider.tsx +259 -0
  75. package/src/cli/cmd/tui/component/dialog-session-list.tsx +108 -0
  76. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  77. package/src/cli/cmd/tui/component/dialog-skill.tsx +36 -0
  78. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  79. package/src/cli/cmd/tui/component/dialog-status.tsx +167 -0
  80. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  81. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  82. package/src/cli/cmd/tui/component/logo.tsx +85 -0
  83. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +667 -0
  84. package/src/cli/cmd/tui/component/prompt/frecency.tsx +90 -0
  85. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  86. package/src/cli/cmd/tui/component/prompt/index.tsx +1155 -0
  87. package/src/cli/cmd/tui/component/prompt/stash.tsx +101 -0
  88. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  89. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  90. package/src/cli/cmd/tui/component/tips.tsx +152 -0
  91. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  92. package/src/cli/cmd/tui/context/args.tsx +15 -0
  93. package/src/cli/cmd/tui/context/directory.ts +13 -0
  94. package/src/cli/cmd/tui/context/exit.tsx +53 -0
  95. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  96. package/src/cli/cmd/tui/context/keybind.tsx +102 -0
  97. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  98. package/src/cli/cmd/tui/context/local.tsx +406 -0
  99. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  100. package/src/cli/cmd/tui/context/route.tsx +46 -0
  101. package/src/cli/cmd/tui/context/sdk.tsx +101 -0
  102. package/src/cli/cmd/tui/context/sync.tsx +488 -0
  103. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  104. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  105. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  106. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  107. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  108. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  109. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  110. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  111. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  112. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  113. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  114. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  115. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  116. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  117. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  118. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  119. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  120. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  121. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  122. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  123. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  124. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  125. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  126. package/src/cli/cmd/tui/context/theme/osaka-jade.json +93 -0
  127. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  128. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  129. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  130. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  131. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  132. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  133. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  134. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  135. package/src/cli/cmd/tui/context/theme.tsx +1152 -0
  136. package/src/cli/cmd/tui/context/tui-config.tsx +9 -0
  137. package/src/cli/cmd/tui/event.ts +48 -0
  138. package/src/cli/cmd/tui/routes/home.tsx +145 -0
  139. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  140. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  141. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  142. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  143. package/src/cli/cmd/tui/routes/session/footer.tsx +91 -0
  144. package/src/cli/cmd/tui/routes/session/header.tsx +135 -0
  145. package/src/cli/cmd/tui/routes/session/index.tsx +2219 -0
  146. package/src/cli/cmd/tui/routes/session/permission.tsx +685 -0
  147. package/src/cli/cmd/tui/routes/session/question.tsx +466 -0
  148. package/src/cli/cmd/tui/routes/session/sidebar.tsx +321 -0
  149. package/src/cli/cmd/tui/thread.ts +199 -0
  150. package/src/cli/cmd/tui/ui/dialog-alert.tsx +59 -0
  151. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +85 -0
  152. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +207 -0
  153. package/src/cli/cmd/tui/ui/dialog-help.tsx +40 -0
  154. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +80 -0
  155. package/src/cli/cmd/tui/ui/dialog-select.tsx +401 -0
  156. package/src/cli/cmd/tui/ui/dialog.tsx +182 -0
  157. package/src/cli/cmd/tui/ui/link.tsx +28 -0
  158. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  159. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  160. package/src/cli/cmd/tui/util/clipboard.ts +164 -0
  161. package/src/cli/cmd/tui/util/editor.ts +33 -0
  162. package/src/cli/cmd/tui/util/selection.ts +25 -0
  163. package/src/cli/cmd/tui/util/signal.ts +7 -0
  164. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  165. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  166. package/src/cli/cmd/tui/win32.ts +129 -0
  167. package/src/cli/cmd/tui/worker.ts +157 -0
  168. package/src/cli/cmd/uninstall.ts +356 -0
  169. package/src/cli/cmd/upgrade.ts +73 -0
  170. package/src/cli/cmd/web.ts +81 -0
  171. package/src/cli/cmd/workspace-serve.ts +16 -0
  172. package/src/cli/error.ts +57 -0
  173. package/src/cli/logo.ts +6 -0
  174. package/src/cli/network.ts +60 -0
  175. package/src/cli/ui.ts +116 -0
  176. package/src/cli/upgrade.ts +25 -0
  177. package/src/command/index.ts +150 -0
  178. package/src/command/template/initialize.txt +10 -0
  179. package/src/command/template/review.txt +101 -0
  180. package/src/config/config.ts +1408 -0
  181. package/src/config/markdown.ts +99 -0
  182. package/src/config/migrate-tui-config.ts +155 -0
  183. package/src/config/paths.ts +174 -0
  184. package/src/config/tui-schema.ts +34 -0
  185. package/src/config/tui.ts +118 -0
  186. package/src/control/control.sql.ts +22 -0
  187. package/src/control/index.ts +67 -0
  188. package/src/control-plane/adaptors/index.ts +10 -0
  189. package/src/control-plane/adaptors/types.ts +7 -0
  190. package/src/control-plane/adaptors/worktree.ts +26 -0
  191. package/src/control-plane/config.ts +10 -0
  192. package/src/control-plane/session-proxy-middleware.ts +46 -0
  193. package/src/control-plane/sse.ts +66 -0
  194. package/src/control-plane/workspace-server/routes.ts +33 -0
  195. package/src/control-plane/workspace-server/server.ts +24 -0
  196. package/src/control-plane/workspace.sql.ts +12 -0
  197. package/src/control-plane/workspace.ts +160 -0
  198. package/src/env/index.ts +28 -0
  199. package/src/file/ignore.ts +82 -0
  200. package/src/file/index.ts +646 -0
  201. package/src/file/ripgrep.ts +372 -0
  202. package/src/file/time.ts +71 -0
  203. package/src/file/watcher.ts +128 -0
  204. package/src/flag/flag.ts +109 -0
  205. package/src/format/formatter.ts +395 -0
  206. package/src/format/index.ts +140 -0
  207. package/src/global/index.ts +54 -0
  208. package/src/id/id.ts +84 -0
  209. package/src/ide/index.ts +76 -0
  210. package/src/index.ts +210 -0
  211. package/src/installation/index.ts +266 -0
  212. package/src/lsp/client.ts +251 -0
  213. package/src/lsp/index.ts +485 -0
  214. package/src/lsp/language.ts +120 -0
  215. package/src/lsp/server.ts +2142 -0
  216. package/src/mcp/auth.ts +130 -0
  217. package/src/mcp/index.ts +937 -0
  218. package/src/mcp/oauth-callback.ts +200 -0
  219. package/src/mcp/oauth-provider.ts +176 -0
  220. package/src/patch/index.ts +680 -0
  221. package/src/permission/arity.ts +163 -0
  222. package/src/permission/index.ts +210 -0
  223. package/src/permission/next.ts +286 -0
  224. package/src/plugin/codex.ts +624 -0
  225. package/src/plugin/copilot.ts +327 -0
  226. package/src/plugin/index.ts +143 -0
  227. package/src/project/bootstrap.ts +33 -0
  228. package/src/project/instance.ts +114 -0
  229. package/src/project/project.sql.ts +15 -0
  230. package/src/project/project.ts +441 -0
  231. package/src/project/state.ts +70 -0
  232. package/src/project/vcs.ts +76 -0
  233. package/src/provider/auth.ts +147 -0
  234. package/src/provider/error.ts +189 -0
  235. package/src/provider/models.ts +146 -0
  236. package/src/provider/provider.ts +1338 -0
  237. package/src/provider/sdk/copilot/README.md +5 -0
  238. package/src/provider/sdk/copilot/chat/convert-to-openai-compatible-chat-messages.ts +164 -0
  239. package/src/provider/sdk/copilot/chat/get-response-metadata.ts +15 -0
  240. package/src/provider/sdk/copilot/chat/map-openai-compatible-finish-reason.ts +17 -0
  241. package/src/provider/sdk/copilot/chat/openai-compatible-api-types.ts +64 -0
  242. package/src/provider/sdk/copilot/chat/openai-compatible-chat-language-model.ts +780 -0
  243. package/src/provider/sdk/copilot/chat/openai-compatible-chat-options.ts +28 -0
  244. package/src/provider/sdk/copilot/chat/openai-compatible-metadata-extractor.ts +44 -0
  245. package/src/provider/sdk/copilot/chat/openai-compatible-prepare-tools.ts +87 -0
  246. package/src/provider/sdk/copilot/copilot-provider.ts +100 -0
  247. package/src/provider/sdk/copilot/index.ts +2 -0
  248. package/src/provider/sdk/copilot/openai-compatible-error.ts +27 -0
  249. package/src/provider/sdk/copilot/responses/convert-to-openai-responses-input.ts +303 -0
  250. package/src/provider/sdk/copilot/responses/map-openai-responses-finish-reason.ts +22 -0
  251. package/src/provider/sdk/copilot/responses/openai-config.ts +18 -0
  252. package/src/provider/sdk/copilot/responses/openai-error.ts +22 -0
  253. package/src/provider/sdk/copilot/responses/openai-responses-api-types.ts +207 -0
  254. package/src/provider/sdk/copilot/responses/openai-responses-language-model.ts +1732 -0
  255. package/src/provider/sdk/copilot/responses/openai-responses-prepare-tools.ts +177 -0
  256. package/src/provider/sdk/copilot/responses/openai-responses-settings.ts +1 -0
  257. package/src/provider/sdk/copilot/responses/tool/code-interpreter.ts +88 -0
  258. package/src/provider/sdk/copilot/responses/tool/file-search.ts +128 -0
  259. package/src/provider/sdk/copilot/responses/tool/image-generation.ts +115 -0
  260. package/src/provider/sdk/copilot/responses/tool/local-shell.ts +65 -0
  261. package/src/provider/sdk/copilot/responses/tool/web-search-preview.ts +104 -0
  262. package/src/provider/sdk/copilot/responses/tool/web-search.ts +103 -0
  263. package/src/provider/transform.ts +955 -0
  264. package/src/pty/index.ts +324 -0
  265. package/src/question/index.ts +171 -0
  266. package/src/scheduler/index.ts +61 -0
  267. package/src/server/error.ts +36 -0
  268. package/src/server/event.ts +7 -0
  269. package/src/server/mdns.ts +60 -0
  270. package/src/server/routes/config.ts +92 -0
  271. package/src/server/routes/experimental.ts +270 -0
  272. package/src/server/routes/file.ts +197 -0
  273. package/src/server/routes/global.ts +185 -0
  274. package/src/server/routes/mcp.ts +225 -0
  275. package/src/server/routes/permission.ts +68 -0
  276. package/src/server/routes/project.ts +82 -0
  277. package/src/server/routes/provider.ts +165 -0
  278. package/src/server/routes/pty.ts +200 -0
  279. package/src/server/routes/question.ts +98 -0
  280. package/src/server/routes/session.ts +974 -0
  281. package/src/server/routes/tui.ts +379 -0
  282. package/src/server/routes/workspace.ts +104 -0
  283. package/src/server/server.ts +623 -0
  284. package/src/session/compaction.ts +261 -0
  285. package/src/session/index.ts +877 -0
  286. package/src/session/instruction.ts +192 -0
  287. package/src/session/llm.ts +279 -0
  288. package/src/session/message-v2.ts +899 -0
  289. package/src/session/message.ts +189 -0
  290. package/src/session/processor.ts +421 -0
  291. package/src/session/prompt/anthropic-20250930.txt +166 -0
  292. package/src/session/prompt/anthropic.txt +105 -0
  293. package/src/session/prompt/beast.txt +147 -0
  294. package/src/session/prompt/build-switch.txt +5 -0
  295. package/src/session/prompt/codex_header.txt +79 -0
  296. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  297. package/src/session/prompt/gemini.txt +155 -0
  298. package/src/session/prompt/max-steps.txt +16 -0
  299. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  300. package/src/session/prompt/plan.txt +26 -0
  301. package/src/session/prompt/qwen.txt +109 -0
  302. package/src/session/prompt/trinity.txt +97 -0
  303. package/src/session/prompt.ts +1959 -0
  304. package/src/session/retry.ts +101 -0
  305. package/src/session/revert.ts +138 -0
  306. package/src/session/session.sql.ts +88 -0
  307. package/src/session/status.ts +76 -0
  308. package/src/session/summary.ts +161 -0
  309. package/src/session/system.ts +54 -0
  310. package/src/session/todo.ts +56 -0
  311. package/src/share/share-next.ts +210 -0
  312. package/src/share/share.sql.ts +13 -0
  313. package/src/shell/shell.ts +68 -0
  314. package/src/skill/discovery.ts +98 -0
  315. package/src/skill/index.ts +1 -0
  316. package/src/skill/skill.ts +189 -0
  317. package/src/snapshot/index.ts +297 -0
  318. package/src/sql.d.ts +4 -0
  319. package/src/storage/db.ts +155 -0
  320. package/src/storage/json-migration.ts +425 -0
  321. package/src/storage/schema.sql.ts +10 -0
  322. package/src/storage/schema.ts +5 -0
  323. package/src/storage/storage.ts +220 -0
  324. package/src/tool/apply_patch.ts +281 -0
  325. package/src/tool/apply_patch.txt +33 -0
  326. package/src/tool/bash.ts +274 -0
  327. package/src/tool/bash.txt +115 -0
  328. package/src/tool/batch.ts +181 -0
  329. package/src/tool/batch.txt +24 -0
  330. package/src/tool/codesearch.ts +132 -0
  331. package/src/tool/codesearch.txt +12 -0
  332. package/src/tool/edit.ts +654 -0
  333. package/src/tool/edit.txt +10 -0
  334. package/src/tool/external-directory.ts +32 -0
  335. package/src/tool/glob.ts +78 -0
  336. package/src/tool/glob.txt +6 -0
  337. package/src/tool/grep.ts +156 -0
  338. package/src/tool/grep.txt +8 -0
  339. package/src/tool/invalid.ts +17 -0
  340. package/src/tool/ls.ts +121 -0
  341. package/src/tool/ls.txt +1 -0
  342. package/src/tool/lsp.ts +97 -0
  343. package/src/tool/lsp.txt +19 -0
  344. package/src/tool/multiedit.ts +46 -0
  345. package/src/tool/multiedit.txt +41 -0
  346. package/src/tool/plan-enter.txt +14 -0
  347. package/src/tool/plan-exit.txt +13 -0
  348. package/src/tool/plan.ts +131 -0
  349. package/src/tool/question.ts +33 -0
  350. package/src/tool/question.txt +10 -0
  351. package/src/tool/read.ts +293 -0
  352. package/src/tool/read.txt +14 -0
  353. package/src/tool/registry.ts +173 -0
  354. package/src/tool/skill.ts +123 -0
  355. package/src/tool/task.ts +165 -0
  356. package/src/tool/task.txt +60 -0
  357. package/src/tool/todo.ts +53 -0
  358. package/src/tool/todoread.txt +14 -0
  359. package/src/tool/todowrite.txt +167 -0
  360. package/src/tool/tool.ts +89 -0
  361. package/src/tool/truncation.ts +107 -0
  362. package/src/tool/webfetch.ts +206 -0
  363. package/src/tool/webfetch.txt +13 -0
  364. package/src/tool/websearch.ts +150 -0
  365. package/src/tool/websearch.txt +14 -0
  366. package/src/tool/write.ts +84 -0
  367. package/src/tool/write.txt +8 -0
  368. package/src/util/abort.ts +35 -0
  369. package/src/util/archive.ts +16 -0
  370. package/src/util/color.ts +19 -0
  371. package/src/util/context.ts +25 -0
  372. package/src/util/defer.ts +12 -0
  373. package/src/util/eventloop.ts +20 -0
  374. package/src/util/filesystem.ts +189 -0
  375. package/src/util/fn.ts +11 -0
  376. package/src/util/format.ts +20 -0
  377. package/src/util/git.ts +35 -0
  378. package/src/util/glob.ts +34 -0
  379. package/src/util/iife.ts +3 -0
  380. package/src/util/keybind.ts +103 -0
  381. package/src/util/lazy.ts +23 -0
  382. package/src/util/locale.ts +81 -0
  383. package/src/util/lock.ts +98 -0
  384. package/src/util/log.ts +182 -0
  385. package/src/util/process.ts +126 -0
  386. package/src/util/proxied.ts +3 -0
  387. package/src/util/queue.ts +32 -0
  388. package/src/util/rpc.ts +66 -0
  389. package/src/util/scrap.ts +10 -0
  390. package/src/util/signal.ts +12 -0
  391. package/src/util/timeout.ts +14 -0
  392. package/src/util/token.ts +7 -0
  393. package/src/util/wildcard.ts +59 -0
  394. package/src/worktree/index.ts +643 -0
  395. package/sst-env.d.ts +10 -0
  396. package/test/AGENTS.md +81 -0
  397. package/test/acp/agent-interface.test.ts +51 -0
  398. package/test/acp/event-subscription.test.ts +683 -0
  399. package/test/agent/agent.test.ts +689 -0
  400. package/test/bun.test.ts +53 -0
  401. package/test/cli/github-action.test.ts +197 -0
  402. package/test/cli/github-remote.test.ts +80 -0
  403. package/test/cli/import.test.ts +38 -0
  404. package/test/cli/plugin-auth-picker.test.ts +120 -0
  405. package/test/cli/tui/transcript.test.ts +322 -0
  406. package/test/config/agent-color.test.ts +71 -0
  407. package/test/config/config.test.ts +1886 -0
  408. package/test/config/fixtures/empty-frontmatter.md +4 -0
  409. package/test/config/fixtures/frontmatter.md +28 -0
  410. package/test/config/fixtures/markdown-header.md +11 -0
  411. package/test/config/fixtures/no-frontmatter.md +1 -0
  412. package/test/config/fixtures/weird-model-id.md +13 -0
  413. package/test/config/markdown.test.ts +228 -0
  414. package/test/config/tui.test.ts +510 -0
  415. package/test/control-plane/session-proxy-middleware.test.ts +147 -0
  416. package/test/control-plane/sse.test.ts +56 -0
  417. package/test/control-plane/workspace-server-sse.test.ts +65 -0
  418. package/test/control-plane/workspace-sync.test.ts +97 -0
  419. package/test/file/ignore.test.ts +10 -0
  420. package/test/file/index.test.ts +394 -0
  421. package/test/file/path-traversal.test.ts +198 -0
  422. package/test/file/ripgrep.test.ts +39 -0
  423. package/test/file/time.test.ts +361 -0
  424. package/test/fixture/db.ts +11 -0
  425. package/test/fixture/fixture.ts +45 -0
  426. package/test/fixture/lsp/fake-lsp-server.js +77 -0
  427. package/test/fixture/skills/agents-sdk/SKILL.md +152 -0
  428. package/test/fixture/skills/agents-sdk/references/callable.md +92 -0
  429. package/test/fixture/skills/cloudflare/SKILL.md +211 -0
  430. package/test/fixture/skills/index.json +6 -0
  431. package/test/ide/ide.test.ts +82 -0
  432. package/test/keybind.test.ts +421 -0
  433. package/test/lsp/client.test.ts +95 -0
  434. package/test/mcp/headers.test.ts +153 -0
  435. package/test/mcp/oauth-browser.test.ts +249 -0
  436. package/test/memory/abort-leak.test.ts +136 -0
  437. package/test/patch/patch.test.ts +348 -0
  438. package/test/permission/arity.test.ts +33 -0
  439. package/test/permission/next.test.ts +689 -0
  440. package/test/permission-task.test.ts +319 -0
  441. package/test/plugin/auth-override.test.ts +44 -0
  442. package/test/plugin/codex.test.ts +123 -0
  443. package/test/preload.ts +80 -0
  444. package/test/project/project.test.ts +348 -0
  445. package/test/project/worktree-remove.test.ts +65 -0
  446. package/test/provider/amazon-bedrock.test.ts +446 -0
  447. package/test/provider/copilot/convert-to-copilot-messages.test.ts +523 -0
  448. package/test/provider/copilot/copilot-chat-model.test.ts +592 -0
  449. package/test/provider/gitlab-duo.test.ts +262 -0
  450. package/test/provider/provider.test.ts +2220 -0
  451. package/test/provider/transform.test.ts +2353 -0
  452. package/test/pty/pty-output-isolation.test.ts +140 -0
  453. package/test/question/question.test.ts +300 -0
  454. package/test/scheduler.test.ts +73 -0
  455. package/test/server/global-session-list.test.ts +89 -0
  456. package/test/server/session-list.test.ts +90 -0
  457. package/test/server/session-select.test.ts +78 -0
  458. package/test/session/compaction.test.ts +423 -0
  459. package/test/session/instruction.test.ts +170 -0
  460. package/test/session/llm.test.ts +667 -0
  461. package/test/session/message-v2.test.ts +924 -0
  462. package/test/session/prompt.test.ts +211 -0
  463. package/test/session/retry.test.ts +188 -0
  464. package/test/session/revert-compact.test.ts +285 -0
  465. package/test/session/session.test.ts +71 -0
  466. package/test/session/structured-output-integration.test.ts +233 -0
  467. package/test/session/structured-output.test.ts +385 -0
  468. package/test/skill/discovery.test.ts +110 -0
  469. package/test/skill/skill.test.ts +388 -0
  470. package/test/snapshot/snapshot.test.ts +1180 -0
  471. package/test/storage/json-migration.test.ts +846 -0
  472. package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
  473. package/test/tool/apply_patch.test.ts +566 -0
  474. package/test/tool/bash.test.ts +402 -0
  475. package/test/tool/edit.test.ts +496 -0
  476. package/test/tool/external-directory.test.ts +127 -0
  477. package/test/tool/fixtures/large-image.png +0 -0
  478. package/test/tool/fixtures/models-api.json +38413 -0
  479. package/test/tool/grep.test.ts +110 -0
  480. package/test/tool/question.test.ts +107 -0
  481. package/test/tool/read.test.ts +504 -0
  482. package/test/tool/registry.test.ts +122 -0
  483. package/test/tool/skill.test.ts +112 -0
  484. package/test/tool/truncation.test.ts +160 -0
  485. package/test/tool/webfetch.test.ts +100 -0
  486. package/test/tool/write.test.ts +348 -0
  487. package/test/util/filesystem.test.ts +443 -0
  488. package/test/util/format.test.ts +59 -0
  489. package/test/util/glob.test.ts +164 -0
  490. package/test/util/iife.test.ts +36 -0
  491. package/test/util/lazy.test.ts +50 -0
  492. package/test/util/lock.test.ts +72 -0
  493. package/test/util/process.test.ts +59 -0
  494. package/test/util/timeout.test.ts +21 -0
  495. package/test/util/wildcard.test.ts +90 -0
  496. package/tsconfig.json +16 -0
@@ -0,0 +1,955 @@
1
+ import type { ModelMessage } from "ai"
2
+ import { mergeDeep, unique } from "remeda"
3
+ import type { JSONSchema7 } from "@ai-sdk/provider"
4
+ import type { JSONSchema } from "zod/v4/core"
5
+ import type { Provider } from "./provider"
6
+ import type { ModelsDev } from "./models"
7
+ import { iife } from "@/util/iife"
8
+ import { Flag } from "@/flag/flag"
9
+
10
+ type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
11
+
12
+ function mimeToModality(mime: string): Modality | undefined {
13
+ if (mime.startsWith("image/")) return "image"
14
+ if (mime.startsWith("audio/")) return "audio"
15
+ if (mime.startsWith("video/")) return "video"
16
+ if (mime === "application/pdf") return "pdf"
17
+ return undefined
18
+ }
19
+
20
+ export namespace ProviderTransform {
21
+ export const OUTPUT_TOKEN_MAX = Flag.OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX || 32_000
22
+
23
+ // Maps npm package to the key the AI SDK expects for providerOptions
24
+ function sdkKey(npm: string): string | undefined {
25
+ switch (npm) {
26
+ case "@ai-sdk/github-copilot":
27
+ return "copilot"
28
+ case "@ai-sdk/openai":
29
+ case "@ai-sdk/azure":
30
+ return "openai"
31
+ case "@ai-sdk/amazon-bedrock":
32
+ return "bedrock"
33
+ case "@ai-sdk/anthropic":
34
+ case "@ai-sdk/google-vertex/anthropic":
35
+ return "anthropic"
36
+ case "@ai-sdk/google-vertex":
37
+ case "@ai-sdk/google":
38
+ return "google"
39
+ case "@ai-sdk/gateway":
40
+ return "gateway"
41
+ case "@openrouter/ai-sdk-provider":
42
+ return "openrouter"
43
+ }
44
+ return undefined
45
+ }
46
+
47
+ function normalizeMessages(
48
+ msgs: ModelMessage[],
49
+ model: Provider.Model,
50
+ options: Record<string, unknown>,
51
+ ): ModelMessage[] {
52
+ // Anthropic rejects messages with empty content - filter out empty string messages
53
+ // and remove empty text/reasoning parts from array content
54
+ if (model.api.npm === "@ai-sdk/anthropic") {
55
+ msgs = msgs
56
+ .map((msg) => {
57
+ if (typeof msg.content === "string") {
58
+ if (msg.content === "") return undefined
59
+ return msg
60
+ }
61
+ if (!Array.isArray(msg.content)) return msg
62
+ const filtered = msg.content.filter((part) => {
63
+ if (part.type === "text" || part.type === "reasoning") {
64
+ return part.text !== ""
65
+ }
66
+ return true
67
+ })
68
+ if (filtered.length === 0) return undefined
69
+ return { ...msg, content: filtered }
70
+ })
71
+ .filter((msg): msg is ModelMessage => msg !== undefined && msg.content !== "")
72
+ }
73
+
74
+ if (model.api.id.includes("claude")) {
75
+ return msgs.map((msg) => {
76
+ if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
77
+ msg.content = msg.content.map((part) => {
78
+ if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
79
+ return {
80
+ ...part,
81
+ toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"),
82
+ }
83
+ }
84
+ return part
85
+ })
86
+ }
87
+ return msg
88
+ })
89
+ }
90
+ if (
91
+ model.providerID === "mistral" ||
92
+ model.api.id.toLowerCase().includes("mistral") ||
93
+ model.api.id.toLocaleLowerCase().includes("devstral")
94
+ ) {
95
+ const result: ModelMessage[] = []
96
+ for (let i = 0; i < msgs.length; i++) {
97
+ const msg = msgs[i]
98
+ const nextMsg = msgs[i + 1]
99
+
100
+ if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
101
+ msg.content = msg.content.map((part) => {
102
+ if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
103
+ // Mistral requires alphanumeric tool call IDs with exactly 9 characters
104
+ const normalizedId = part.toolCallId
105
+ .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters
106
+ .substring(0, 9) // Take first 9 characters
107
+ .padEnd(9, "0") // Pad with zeros if less than 9 characters
108
+
109
+ return {
110
+ ...part,
111
+ toolCallId: normalizedId,
112
+ }
113
+ }
114
+ return part
115
+ })
116
+ }
117
+
118
+ result.push(msg)
119
+
120
+ // Fix message sequence: tool messages cannot be followed by user messages
121
+ if (msg.role === "tool" && nextMsg?.role === "user") {
122
+ result.push({
123
+ role: "assistant",
124
+ content: [
125
+ {
126
+ type: "text",
127
+ text: "Done.",
128
+ },
129
+ ],
130
+ })
131
+ }
132
+ }
133
+ return result
134
+ }
135
+
136
+ if (typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field) {
137
+ const field = model.capabilities.interleaved.field
138
+ return msgs.map((msg) => {
139
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
140
+ const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
141
+ const reasoningText = reasoningParts.map((part: any) => part.text).join("")
142
+
143
+ // Filter out reasoning parts from content
144
+ const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
145
+
146
+ // Include reasoning_content | reasoning_details directly on the message for all assistant messages
147
+ if (reasoningText) {
148
+ return {
149
+ ...msg,
150
+ content: filteredContent,
151
+ providerOptions: {
152
+ ...msg.providerOptions,
153
+ openaiCompatible: {
154
+ ...(msg.providerOptions as any)?.openaiCompatible,
155
+ [field]: reasoningText,
156
+ },
157
+ },
158
+ }
159
+ }
160
+
161
+ return {
162
+ ...msg,
163
+ content: filteredContent,
164
+ }
165
+ }
166
+
167
+ return msg
168
+ })
169
+ }
170
+
171
+ return msgs
172
+ }
173
+
174
+ function applyCaching(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
175
+ const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
176
+ const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
177
+
178
+ const providerOptions = {
179
+ anthropic: {
180
+ cacheControl: { type: "ephemeral" },
181
+ },
182
+ openrouter: {
183
+ cacheControl: { type: "ephemeral" },
184
+ },
185
+ bedrock: {
186
+ cachePoint: { type: "default" },
187
+ },
188
+ openaiCompatible: {
189
+ cache_control: { type: "ephemeral" },
190
+ },
191
+ copilot: {
192
+ copilot_cache_control: { type: "ephemeral" },
193
+ },
194
+ }
195
+
196
+ for (const msg of unique([...system, ...final])) {
197
+ const useMessageLevelOptions = model.providerID === "anthropic" || model.providerID.includes("bedrock")
198
+ const shouldUseContentOptions = !useMessageLevelOptions && Array.isArray(msg.content) && msg.content.length > 0
199
+
200
+ if (shouldUseContentOptions) {
201
+ const lastContent = msg.content[msg.content.length - 1]
202
+ if (lastContent && typeof lastContent === "object") {
203
+ lastContent.providerOptions = mergeDeep(lastContent.providerOptions ?? {}, providerOptions)
204
+ continue
205
+ }
206
+ }
207
+
208
+ msg.providerOptions = mergeDeep(msg.providerOptions ?? {}, providerOptions)
209
+ }
210
+
211
+ return msgs
212
+ }
213
+
214
+ function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
215
+ return msgs.map((msg) => {
216
+ if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
217
+
218
+ const filtered = msg.content.map((part) => {
219
+ if (part.type !== "file" && part.type !== "image") return part
220
+
221
+ // Check for empty base64 image data
222
+ if (part.type === "image") {
223
+ const imageStr = part.image.toString()
224
+ if (imageStr.startsWith("data:")) {
225
+ const match = imageStr.match(/^data:([^;]+);base64,(.*)$/)
226
+ if (match && (!match[2] || match[2].length === 0)) {
227
+ return {
228
+ type: "text" as const,
229
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
236
+ const filename = part.type === "file" ? part.filename : undefined
237
+ const modality = mimeToModality(mime)
238
+ if (!modality) return part
239
+ if (model.capabilities.input[modality]) return part
240
+
241
+ const name = filename ? `"${filename}"` : modality
242
+ return {
243
+ type: "text" as const,
244
+ text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
245
+ }
246
+ })
247
+
248
+ return { ...msg, content: filtered }
249
+ })
250
+ }
251
+
252
+ export function message(msgs: ModelMessage[], model: Provider.Model, options: Record<string, unknown>) {
253
+ msgs = unsupportedParts(msgs, model)
254
+ msgs = normalizeMessages(msgs, model, options)
255
+ if (
256
+ (model.providerID === "anthropic" ||
257
+ model.api.id.includes("anthropic") ||
258
+ model.api.id.includes("claude") ||
259
+ model.id.includes("anthropic") ||
260
+ model.id.includes("claude") ||
261
+ model.api.npm === "@ai-sdk/anthropic") &&
262
+ model.api.npm !== "@ai-sdk/gateway"
263
+ ) {
264
+ msgs = applyCaching(msgs, model)
265
+ }
266
+
267
+ // Remap providerOptions keys from stored providerID to expected SDK key
268
+ const key = sdkKey(model.api.npm)
269
+ if (key && key !== model.providerID && model.api.npm !== "@ai-sdk/azure") {
270
+ const remap = (opts: Record<string, any> | undefined) => {
271
+ if (!opts) return opts
272
+ if (!(model.providerID in opts)) return opts
273
+ const result = { ...opts }
274
+ result[key] = result[model.providerID]
275
+ delete result[model.providerID]
276
+ return result
277
+ }
278
+
279
+ msgs = msgs.map((msg) => {
280
+ if (!Array.isArray(msg.content)) return { ...msg, providerOptions: remap(msg.providerOptions) }
281
+ return {
282
+ ...msg,
283
+ providerOptions: remap(msg.providerOptions),
284
+ content: msg.content.map((part) => ({ ...part, providerOptions: remap(part.providerOptions) })),
285
+ } as typeof msg
286
+ })
287
+ }
288
+
289
+ return msgs
290
+ }
291
+
292
+ export function temperature(model: Provider.Model) {
293
+ const id = model.id.toLowerCase()
294
+ if (id.includes("qwen")) return 0.55
295
+ if (id.includes("claude")) return undefined
296
+ if (id.includes("gemini")) return 1.0
297
+ if (id.includes("glm-4.6")) return 1.0
298
+ if (id.includes("glm-4.7")) return 1.0
299
+ if (id.includes("minimax-m2")) return 1.0
300
+ if (id.includes("kimi-k2")) {
301
+ // kimi-k2-thinking & kimi-k2.5 && kimi-k2p5 && kimi-k2-5
302
+ if (["thinking", "k2.", "k2p", "k2-5"].some((s) => id.includes(s))) {
303
+ return 1.0
304
+ }
305
+ return 0.6
306
+ }
307
+ return undefined
308
+ }
309
+
310
+ export function topP(model: Provider.Model) {
311
+ const id = model.id.toLowerCase()
312
+ if (id.includes("qwen")) return 1
313
+ if (["minimax-m2", "gemini", "kimi-k2.5", "kimi-k2p5", "kimi-k2-5"].some((s) => id.includes(s))) {
314
+ return 0.95
315
+ }
316
+ return undefined
317
+ }
318
+
319
+ export function topK(model: Provider.Model) {
320
+ const id = model.id.toLowerCase()
321
+ if (id.includes("minimax-m2")) {
322
+ if (["m2.", "m25", "m21"].some((s) => id.includes(s))) return 40
323
+ return 20
324
+ }
325
+ if (id.includes("gemini")) return 64
326
+ return undefined
327
+ }
328
+
329
+ const WIDELY_SUPPORTED_EFFORTS = ["low", "medium", "high"]
330
+ const OPENAI_EFFORTS = ["none", "minimal", ...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
331
+
332
+ export function variants(model: Provider.Model): Record<string, Record<string, any>> {
333
+ if (!model.capabilities.reasoning) return {}
334
+
335
+ const id = model.id.toLowerCase()
336
+ const isAnthropicAdaptive = ["opus-4-6", "opus-4.6", "sonnet-4-6", "sonnet-4.6"].some((v) =>
337
+ model.api.id.includes(v),
338
+ )
339
+ const adaptiveEfforts = ["low", "medium", "high", "max"]
340
+ if (
341
+ id.includes("deepseek") ||
342
+ id.includes("minimax") ||
343
+ id.includes("glm") ||
344
+ id.includes("mistral") ||
345
+ id.includes("kimi") ||
346
+ // TODO: Remove this after models.dev data is fixed to use "kimi-k2.5" instead of "k2p5"
347
+ id.includes("k2p5")
348
+ )
349
+ return {}
350
+
351
+ // see: https://docs.x.ai/docs/guides/reasoning#control-how-hard-the-model-thinks
352
+ if (id.includes("grok") && id.includes("grok-3-mini")) {
353
+ if (model.api.npm === "@openrouter/ai-sdk-provider") {
354
+ return {
355
+ low: { reasoning: { effort: "low" } },
356
+ high: { reasoning: { effort: "high" } },
357
+ }
358
+ }
359
+ return {
360
+ low: { reasoningEffort: "low" },
361
+ high: { reasoningEffort: "high" },
362
+ }
363
+ }
364
+ if (id.includes("grok")) return {}
365
+
366
+ switch (model.api.npm) {
367
+ case "@openrouter/ai-sdk-provider":
368
+ if (!model.id.includes("gpt") && !model.id.includes("gemini-3") && !model.id.includes("claude")) return {}
369
+ return Object.fromEntries(OPENAI_EFFORTS.map((effort) => [effort, { reasoning: { effort } }]))
370
+
371
+ case "@ai-sdk/gateway":
372
+ if (model.id.includes("anthropic")) {
373
+ if (isAnthropicAdaptive) {
374
+ return Object.fromEntries(
375
+ adaptiveEfforts.map((effort) => [
376
+ effort,
377
+ {
378
+ thinking: {
379
+ type: "adaptive",
380
+ },
381
+ effort,
382
+ },
383
+ ]),
384
+ )
385
+ }
386
+ return {
387
+ high: {
388
+ thinking: {
389
+ type: "enabled",
390
+ budgetTokens: 16000,
391
+ },
392
+ },
393
+ max: {
394
+ thinking: {
395
+ type: "enabled",
396
+ budgetTokens: 31999,
397
+ },
398
+ },
399
+ }
400
+ }
401
+ if (model.id.includes("google")) {
402
+ if (id.includes("2.5")) {
403
+ return {
404
+ high: {
405
+ thinkingConfig: {
406
+ includeThoughts: true,
407
+ thinkingBudget: 16000,
408
+ },
409
+ },
410
+ max: {
411
+ thinkingConfig: {
412
+ includeThoughts: true,
413
+ thinkingBudget: 24576,
414
+ },
415
+ },
416
+ }
417
+ }
418
+ return Object.fromEntries(
419
+ ["low", "high"].map((effort) => [
420
+ effort,
421
+ {
422
+ includeThoughts: true,
423
+ thinkingLevel: effort,
424
+ },
425
+ ]),
426
+ )
427
+ }
428
+ return Object.fromEntries(OPENAI_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
429
+
430
+ case "@ai-sdk/github-copilot":
431
+ if (model.id.includes("gemini")) {
432
+ // currently github copilot only returns thinking
433
+ return {}
434
+ }
435
+ if (model.id.includes("claude")) {
436
+ return {
437
+ thinking: { thinking_budget: 4000 },
438
+ }
439
+ }
440
+ const copilotEfforts = iife(() => {
441
+ if (id.includes("5.1-codex-max") || id.includes("5.2") || id.includes("5.3"))
442
+ return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
443
+ return WIDELY_SUPPORTED_EFFORTS
444
+ })
445
+ return Object.fromEntries(
446
+ copilotEfforts.map((effort) => [
447
+ effort,
448
+ {
449
+ reasoningEffort: effort,
450
+ reasoningSummary: "auto",
451
+ include: ["reasoning.encrypted_content"],
452
+ },
453
+ ]),
454
+ )
455
+
456
+ case "@ai-sdk/cerebras":
457
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/cerebras
458
+ case "@ai-sdk/togetherai":
459
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/togetherai
460
+ case "@ai-sdk/xai":
461
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/xai
462
+ case "@ai-sdk/deepinfra":
463
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/deepinfra
464
+ case "venice-ai-sdk-provider":
465
+ // https://docs.venice.ai/overview/guides/reasoning-models#reasoning-effort
466
+ case "@ai-sdk/openai-compatible":
467
+ return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
468
+
469
+ case "@ai-sdk/azure":
470
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/azure
471
+ if (id === "o1-mini") return {}
472
+ const azureEfforts = ["low", "medium", "high"]
473
+ if (id.includes("gpt-5-") || id === "gpt-5") {
474
+ azureEfforts.unshift("minimal")
475
+ }
476
+ return Object.fromEntries(
477
+ azureEfforts.map((effort) => [
478
+ effort,
479
+ {
480
+ reasoningEffort: effort,
481
+ reasoningSummary: "auto",
482
+ include: ["reasoning.encrypted_content"],
483
+ },
484
+ ]),
485
+ )
486
+ case "@ai-sdk/openai":
487
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/openai
488
+ if (id === "gpt-5-pro") return {}
489
+ const openaiEfforts = iife(() => {
490
+ if (id.includes("codex")) {
491
+ if (id.includes("5.2") || id.includes("5.3")) return [...WIDELY_SUPPORTED_EFFORTS, "xhigh"]
492
+ return WIDELY_SUPPORTED_EFFORTS
493
+ }
494
+ const arr = [...WIDELY_SUPPORTED_EFFORTS]
495
+ if (id.includes("gpt-5-") || id === "gpt-5") {
496
+ arr.unshift("minimal")
497
+ }
498
+ if (model.release_date >= "2025-11-13") {
499
+ arr.unshift("none")
500
+ }
501
+ if (model.release_date >= "2025-12-04") {
502
+ arr.push("xhigh")
503
+ }
504
+ return arr
505
+ })
506
+ return Object.fromEntries(
507
+ openaiEfforts.map((effort) => [
508
+ effort,
509
+ {
510
+ reasoningEffort: effort,
511
+ reasoningSummary: "auto",
512
+ include: ["reasoning.encrypted_content"],
513
+ },
514
+ ]),
515
+ )
516
+
517
+ case "@ai-sdk/anthropic":
518
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/anthropic
519
+ case "@ai-sdk/google-vertex/anthropic":
520
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-vertex#anthropic-provider
521
+
522
+ if (isAnthropicAdaptive) {
523
+ return Object.fromEntries(
524
+ adaptiveEfforts.map((effort) => [
525
+ effort,
526
+ {
527
+ thinking: {
528
+ type: "adaptive",
529
+ },
530
+ effort,
531
+ },
532
+ ]),
533
+ )
534
+ }
535
+
536
+ return {
537
+ high: {
538
+ thinking: {
539
+ type: "enabled",
540
+ budgetTokens: Math.min(16_000, Math.floor(model.limit.output / 2 - 1)),
541
+ },
542
+ },
543
+ max: {
544
+ thinking: {
545
+ type: "enabled",
546
+ budgetTokens: Math.min(31_999, model.limit.output - 1),
547
+ },
548
+ },
549
+ }
550
+
551
+ case "@ai-sdk/amazon-bedrock":
552
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/amazon-bedrock
553
+ if (isAnthropicAdaptive) {
554
+ return Object.fromEntries(
555
+ adaptiveEfforts.map((effort) => [
556
+ effort,
557
+ {
558
+ reasoningConfig: {
559
+ type: "adaptive",
560
+ maxReasoningEffort: effort,
561
+ },
562
+ },
563
+ ]),
564
+ )
565
+ }
566
+ // For Anthropic models on Bedrock, use reasoningConfig with budgetTokens
567
+ if (model.api.id.includes("anthropic")) {
568
+ return {
569
+ high: {
570
+ reasoningConfig: {
571
+ type: "enabled",
572
+ budgetTokens: 16000,
573
+ },
574
+ },
575
+ max: {
576
+ reasoningConfig: {
577
+ type: "enabled",
578
+ budgetTokens: 31999,
579
+ },
580
+ },
581
+ }
582
+ }
583
+
584
+ // For Amazon Nova models, use reasoningConfig with maxReasoningEffort
585
+ return Object.fromEntries(
586
+ WIDELY_SUPPORTED_EFFORTS.map((effort) => [
587
+ effort,
588
+ {
589
+ reasoningConfig: {
590
+ type: "enabled",
591
+ maxReasoningEffort: effort,
592
+ },
593
+ },
594
+ ]),
595
+ )
596
+
597
+ case "@ai-sdk/google-vertex":
598
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-vertex
599
+ case "@ai-sdk/google":
600
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/google-generative-ai
601
+ if (id.includes("2.5")) {
602
+ return {
603
+ high: {
604
+ thinkingConfig: {
605
+ includeThoughts: true,
606
+ thinkingBudget: 16000,
607
+ },
608
+ },
609
+ max: {
610
+ thinkingConfig: {
611
+ includeThoughts: true,
612
+ thinkingBudget: 24576,
613
+ },
614
+ },
615
+ }
616
+ }
617
+ let levels = ["low", "high"]
618
+ if (id.includes("3.1")) {
619
+ levels = ["low", "medium", "high"]
620
+ }
621
+
622
+ return Object.fromEntries(
623
+ levels.map((effort) => [
624
+ effort,
625
+ {
626
+ thinkingConfig: {
627
+ includeThoughts: true,
628
+ thinkingLevel: effort,
629
+ },
630
+ },
631
+ ]),
632
+ )
633
+
634
+ case "@ai-sdk/mistral":
635
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/mistral
636
+ return {}
637
+
638
+ case "@ai-sdk/cohere":
639
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/cohere
640
+ return {}
641
+
642
+ case "@ai-sdk/groq":
643
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/groq
644
+ const groqEffort = ["none", ...WIDELY_SUPPORTED_EFFORTS]
645
+ return Object.fromEntries(
646
+ groqEffort.map((effort) => [
647
+ effort,
648
+ {
649
+ reasoningEffort: effort,
650
+ },
651
+ ]),
652
+ )
653
+
654
+ case "@ai-sdk/perplexity":
655
+ // https://v5.ai-sdk.dev/providers/ai-sdk-providers/perplexity
656
+ return {}
657
+
658
+ case "@mymediset/sap-ai-provider":
659
+ case "@jerome-benoit/sap-ai-provider-v2":
660
+ if (model.api.id.includes("anthropic")) {
661
+ return {
662
+ high: {
663
+ thinking: {
664
+ type: "enabled",
665
+ budgetTokens: 16000,
666
+ },
667
+ },
668
+ max: {
669
+ thinking: {
670
+ type: "enabled",
671
+ budgetTokens: 31999,
672
+ },
673
+ },
674
+ }
675
+ }
676
+ return Object.fromEntries(WIDELY_SUPPORTED_EFFORTS.map((effort) => [effort, { reasoningEffort: effort }]))
677
+ }
678
+ return {}
679
+ }
680
+
681
+ export function options(input: {
682
+ model: Provider.Model
683
+ sessionID: string
684
+ providerOptions?: Record<string, any>
685
+ }): Record<string, any> {
686
+ const result: Record<string, any> = {}
687
+
688
+ // openai and providers using openai package should set store to false by default.
689
+ if (
690
+ input.model.providerID === "openai" ||
691
+ input.model.api.npm === "@ai-sdk/openai" ||
692
+ input.model.api.npm === "@ai-sdk/github-copilot"
693
+ ) {
694
+ result["store"] = false
695
+ }
696
+
697
+ if (input.model.api.npm === "@openrouter/ai-sdk-provider") {
698
+ result["usage"] = {
699
+ include: true,
700
+ }
701
+ if (input.model.api.id.includes("gemini-3")) {
702
+ result["reasoning"] = { effort: "high" }
703
+ }
704
+ }
705
+
706
+ if (
707
+ input.model.providerID === "baseten" ||
708
+ (input.model.providerID === "opencode" && ["kimi-k2-thinking", "glm-4.6"].includes(input.model.api.id))
709
+ ) {
710
+ result["chat_template_args"] = { enable_thinking: true }
711
+ }
712
+
713
+ if (["zai", "zhipuai"].includes(input.model.providerID) && input.model.api.npm === "@ai-sdk/openai-compatible") {
714
+ result["thinking"] = {
715
+ type: "enabled",
716
+ clear_thinking: false,
717
+ }
718
+ }
719
+
720
+ if (input.model.providerID === "openai" || input.providerOptions?.setCacheKey) {
721
+ result["promptCacheKey"] = input.sessionID
722
+ }
723
+
724
+ if (input.model.api.npm === "@ai-sdk/google" || input.model.api.npm === "@ai-sdk/google-vertex") {
725
+ result["thinkingConfig"] = {
726
+ includeThoughts: true,
727
+ }
728
+ if (input.model.api.id.includes("gemini-3")) {
729
+ result["thinkingConfig"]["thinkingLevel"] = "high"
730
+ }
731
+ }
732
+
733
+ // Enable thinking by default for kimi-k2.5/k2p5 models using anthropic SDK
734
+ const modelId = input.model.api.id.toLowerCase()
735
+ if (
736
+ (input.model.api.npm === "@ai-sdk/anthropic" || input.model.api.npm === "@ai-sdk/google-vertex/anthropic") &&
737
+ (modelId.includes("k2p5") || modelId.includes("kimi-k2.5") || modelId.includes("kimi-k2p5"))
738
+ ) {
739
+ result["thinking"] = {
740
+ type: "enabled",
741
+ budgetTokens: Math.min(16_000, Math.floor(input.model.limit.output / 2 - 1)),
742
+ }
743
+ }
744
+
745
+ // Enable thinking for reasoning models on alibaba-cn (DashScope).
746
+ // DashScope's OpenAI-compatible API requires `enable_thinking: true` in the request body
747
+ // to return reasoning_content. Without it, models like kimi-k2.5, qwen-plus, qwen3, qwq,
748
+ // deepseek-r1, etc. never output thinking/reasoning tokens.
749
+ // Note: kimi-k2-thinking is excluded as it returns reasoning_content by default.
750
+ if (
751
+ input.model.providerID === "alibaba-cn" &&
752
+ input.model.capabilities.reasoning &&
753
+ input.model.api.npm === "@ai-sdk/openai-compatible" &&
754
+ !modelId.includes("kimi-k2-thinking")
755
+ ) {
756
+ result["enable_thinking"] = true
757
+ }
758
+
759
+ if (input.model.api.id.includes("gpt-5") && !input.model.api.id.includes("gpt-5-chat")) {
760
+ if (!input.model.api.id.includes("gpt-5-pro")) {
761
+ result["reasoningEffort"] = "medium"
762
+ result["reasoningSummary"] = "auto"
763
+ }
764
+
765
+ // Only set textVerbosity for non-chat gpt-5.x models
766
+ // Chat models (e.g. gpt-5.2-chat-latest) only support "medium" verbosity
767
+ if (
768
+ input.model.api.id.includes("gpt-5.") &&
769
+ !input.model.api.id.includes("codex") &&
770
+ !input.model.api.id.includes("-chat") &&
771
+ input.model.providerID !== "azure"
772
+ ) {
773
+ result["textVerbosity"] = "low"
774
+ }
775
+
776
+ if (input.model.providerID.startsWith("opencode")) {
777
+ result["promptCacheKey"] = input.sessionID
778
+ result["include"] = ["reasoning.encrypted_content"]
779
+ result["reasoningSummary"] = "auto"
780
+ }
781
+ }
782
+
783
+ if (input.model.providerID === "venice") {
784
+ result["promptCacheKey"] = input.sessionID
785
+ }
786
+
787
+ if (input.model.providerID === "openrouter") {
788
+ result["prompt_cache_key"] = input.sessionID
789
+ }
790
+ if (input.model.api.npm === "@ai-sdk/gateway") {
791
+ result["gateway"] = {
792
+ caching: "auto",
793
+ }
794
+ }
795
+
796
+ return result
797
+ }
798
+
799
+ export function smallOptions(model: Provider.Model) {
800
+ if (
801
+ model.providerID === "openai" ||
802
+ model.api.npm === "@ai-sdk/openai" ||
803
+ model.api.npm === "@ai-sdk/github-copilot"
804
+ ) {
805
+ if (model.api.id.includes("gpt-5")) {
806
+ if (model.api.id.includes("5.")) {
807
+ return { store: false, reasoningEffort: "low" }
808
+ }
809
+ return { store: false, reasoningEffort: "minimal" }
810
+ }
811
+ return { store: false }
812
+ }
813
+ if (model.providerID === "google") {
814
+ // gemini-3 uses thinkingLevel, gemini-2.5 uses thinkingBudget
815
+ if (model.api.id.includes("gemini-3")) {
816
+ return { thinkingConfig: { thinkingLevel: "minimal" } }
817
+ }
818
+ return { thinkingConfig: { thinkingBudget: 0 } }
819
+ }
820
+ if (model.providerID === "openrouter") {
821
+ if (model.api.id.includes("google")) {
822
+ return { reasoning: { enabled: false } }
823
+ }
824
+ return { reasoningEffort: "minimal" }
825
+ }
826
+
827
+ if (model.providerID === "venice") {
828
+ return { veniceParameters: { disableThinking: true } }
829
+ }
830
+
831
+ return {}
832
+ }
833
+
834
+ // Maps model ID prefix to provider slug used in providerOptions.
835
+ // Example: "amazon/nova-2-lite" → "bedrock"
836
+ const SLUG_OVERRIDES: Record<string, string> = {
837
+ amazon: "bedrock",
838
+ }
839
+
840
+ export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
841
+ if (model.api.npm === "@ai-sdk/gateway") {
842
+ // Gateway providerOptions are split across two namespaces:
843
+ // - `gateway`: gateway-native routing/caching controls (order, only, byok, etc.)
844
+ // - `<upstream slug>`: provider-specific model options (anthropic/openai/...)
845
+ // We keep `gateway` as-is and route every other top-level option under the
846
+ // model-derived upstream slug.
847
+ const i = model.api.id.indexOf("/")
848
+ const rawSlug = i > 0 ? model.api.id.slice(0, i) : undefined
849
+ const slug = rawSlug ? (SLUG_OVERRIDES[rawSlug] ?? rawSlug) : undefined
850
+ const gateway = options.gateway
851
+ const rest = Object.fromEntries(Object.entries(options).filter(([k]) => k !== "gateway"))
852
+ const has = Object.keys(rest).length > 0
853
+
854
+ const result: Record<string, any> = {}
855
+ if (gateway !== undefined) result.gateway = gateway
856
+
857
+ if (has) {
858
+ if (slug) {
859
+ // Route model-specific options under the provider slug
860
+ result[slug] = rest
861
+ } else if (gateway && typeof gateway === "object" && !Array.isArray(gateway)) {
862
+ result.gateway = { ...gateway, ...rest }
863
+ } else {
864
+ result.gateway = rest
865
+ }
866
+ }
867
+
868
+ return result
869
+ }
870
+
871
+ const key = sdkKey(model.api.npm) ?? model.providerID
872
+ return { [key]: options }
873
+ }
874
+
875
+ export function maxOutputTokens(model: Provider.Model): number {
876
+ return Math.min(model.limit.output, OUTPUT_TOKEN_MAX) || OUTPUT_TOKEN_MAX
877
+ }
878
+
879
+ export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema | JSONSchema7): JSONSchema7 {
880
+ /*
881
+ if (["openai", "azure"].includes(providerID)) {
882
+ if (schema.type === "object" && schema.properties) {
883
+ for (const [key, value] of Object.entries(schema.properties)) {
884
+ if (schema.required?.includes(key)) continue
885
+ schema.properties[key] = {
886
+ anyOf: [
887
+ value as JSONSchema.JSONSchema,
888
+ {
889
+ type: "null",
890
+ },
891
+ ],
892
+ }
893
+ }
894
+ }
895
+ }
896
+ */
897
+
898
+ // Convert integer enums to string enums for Google/Gemini
899
+ if (model.providerID === "google" || model.api.id.includes("gemini")) {
900
+ const sanitizeGemini = (obj: any): any => {
901
+ if (obj === null || typeof obj !== "object") {
902
+ return obj
903
+ }
904
+
905
+ if (Array.isArray(obj)) {
906
+ return obj.map(sanitizeGemini)
907
+ }
908
+
909
+ const result: any = {}
910
+ for (const [key, value] of Object.entries(obj)) {
911
+ if (key === "enum" && Array.isArray(value)) {
912
+ // Convert all enum values to strings
913
+ result[key] = value.map((v) => String(v))
914
+ // If we have integer type with enum, change type to string
915
+ if (result.type === "integer" || result.type === "number") {
916
+ result.type = "string"
917
+ }
918
+ } else if (typeof value === "object" && value !== null) {
919
+ result[key] = sanitizeGemini(value)
920
+ } else {
921
+ result[key] = value
922
+ }
923
+ }
924
+
925
+ // Filter required array to only include fields that exist in properties
926
+ if (result.type === "object" && result.properties && Array.isArray(result.required)) {
927
+ result.required = result.required.filter((field: any) => field in result.properties)
928
+ }
929
+
930
+ if (result.type === "array") {
931
+ if (result.items == null) {
932
+ result.items = {}
933
+ }
934
+ // Ensure items has at least a type if it's an empty object
935
+ // This handles nested arrays like { type: "array", items: { type: "array", items: {} } }
936
+ if (typeof result.items === "object" && !Array.isArray(result.items) && !result.items.type) {
937
+ result.items.type = "string"
938
+ }
939
+ }
940
+
941
+ // Remove properties/required from non-object types (Gemini rejects these)
942
+ if (result.type && result.type !== "object") {
943
+ delete result.properties
944
+ delete result.required
945
+ }
946
+
947
+ return result
948
+ }
949
+
950
+ schema = sanitizeGemini(schema)
951
+ }
952
+
953
+ return schema as JSONSchema7
954
+ }
955
+ }