bincode-cli 1.0.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 (300) hide show
  1. package/AGENTS.md +27 -0
  2. package/README.md +15 -0
  3. package/bin/bincode +98 -0
  4. package/bunfig.toml +4 -0
  5. package/package.json +124 -0
  6. package/parsers-config.ts +239 -0
  7. package/script/build.ts +167 -0
  8. package/script/postinstall.mjs +206 -0
  9. package/script/publish.ts +99 -0
  10. package/script/schema.ts +47 -0
  11. package/src/acp/README.md +164 -0
  12. package/src/acp/agent.ts +1051 -0
  13. package/src/acp/session.ts +101 -0
  14. package/src/acp/types.ts +22 -0
  15. package/src/agent/agent.ts +398 -0
  16. package/src/agent/generate.txt +75 -0
  17. package/src/agent/prompt/compaction.txt +12 -0
  18. package/src/agent/prompt/explore.txt +18 -0
  19. package/src/agent/prompt/summary.txt +10 -0
  20. package/src/agent/prompt/title.txt +36 -0
  21. package/src/auth/bineric-login.ts +506 -0
  22. package/src/auth/index.ts +70 -0
  23. package/src/bun/index.ts +114 -0
  24. package/src/bus/bus-event.ts +43 -0
  25. package/src/bus/global.ts +10 -0
  26. package/src/bus/index.ts +105 -0
  27. package/src/cli/auth-check.ts +61 -0
  28. package/src/cli/bootstrap.ts +21 -0
  29. package/src/cli/cmd/acp.ts +88 -0
  30. package/src/cli/cmd/agent.ts +256 -0
  31. package/src/cli/cmd/auth.ts +436 -0
  32. package/src/cli/cmd/cmd.ts +7 -0
  33. package/src/cli/cmd/debug/config.ts +15 -0
  34. package/src/cli/cmd/debug/file.ts +91 -0
  35. package/src/cli/cmd/debug/index.ts +43 -0
  36. package/src/cli/cmd/debug/lsp.ts +48 -0
  37. package/src/cli/cmd/debug/ripgrep.ts +83 -0
  38. package/src/cli/cmd/debug/scrap.ts +15 -0
  39. package/src/cli/cmd/debug/skill.ts +15 -0
  40. package/src/cli/cmd/debug/snapshot.ts +48 -0
  41. package/src/cli/cmd/export.ts +88 -0
  42. package/src/cli/cmd/generate.ts +38 -0
  43. package/src/cli/cmd/github.ts +1399 -0
  44. package/src/cli/cmd/import.ts +98 -0
  45. package/src/cli/cmd/login.ts +112 -0
  46. package/src/cli/cmd/logout.ts +38 -0
  47. package/src/cli/cmd/mcp.ts +654 -0
  48. package/src/cli/cmd/models.ts +77 -0
  49. package/src/cli/cmd/pr.ts +112 -0
  50. package/src/cli/cmd/run.ts +368 -0
  51. package/src/cli/cmd/serve.ts +31 -0
  52. package/src/cli/cmd/session.ts +106 -0
  53. package/src/cli/cmd/stats.ts +298 -0
  54. package/src/cli/cmd/tui/app.tsx +669 -0
  55. package/src/cli/cmd/tui/attach.ts +30 -0
  56. package/src/cli/cmd/tui/component/border.tsx +21 -0
  57. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  58. package/src/cli/cmd/tui/component/dialog-command.tsx +123 -0
  59. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  60. package/src/cli/cmd/tui/component/dialog-model.tsx +223 -0
  61. package/src/cli/cmd/tui/component/dialog-provider.tsx +224 -0
  62. package/src/cli/cmd/tui/component/dialog-session-list.tsx +102 -0
  63. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  64. package/src/cli/cmd/tui/component/dialog-status.tsx +162 -0
  65. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  66. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
  67. package/src/cli/cmd/tui/component/logo.tsx +32 -0
  68. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +560 -0
  69. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  70. package/src/cli/cmd/tui/component/prompt/index.tsx +1052 -0
  71. package/src/cli/cmd/tui/context/args.tsx +14 -0
  72. package/src/cli/cmd/tui/context/directory.ts +13 -0
  73. package/src/cli/cmd/tui/context/exit.tsx +23 -0
  74. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  75. package/src/cli/cmd/tui/context/keybind.tsx +101 -0
  76. package/src/cli/cmd/tui/context/kv.tsx +49 -0
  77. package/src/cli/cmd/tui/context/local.tsx +339 -0
  78. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  79. package/src/cli/cmd/tui/context/route.tsx +46 -0
  80. package/src/cli/cmd/tui/context/sdk.tsx +74 -0
  81. package/src/cli/cmd/tui/context/sync.tsx +372 -0
  82. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  83. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  84. package/src/cli/cmd/tui/context/theme/bincode.json +245 -0
  85. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  86. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  87. package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
  88. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  89. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  90. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  91. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  92. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  93. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  94. package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
  95. package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
  96. package/src/cli/cmd/tui/context/theme/lucent-orng.json +227 -0
  97. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  98. package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
  99. package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
  100. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  101. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  102. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  103. package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
  104. package/src/cli/cmd/tui/context/theme/orng.json +245 -0
  105. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  106. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  107. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  108. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  109. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  110. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  111. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  112. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  113. package/src/cli/cmd/tui/context/theme.tsx +1109 -0
  114. package/src/cli/cmd/tui/event.ts +40 -0
  115. package/src/cli/cmd/tui/routes/home.tsx +105 -0
  116. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +64 -0
  117. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +109 -0
  118. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +26 -0
  119. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  120. package/src/cli/cmd/tui/routes/session/footer.tsx +88 -0
  121. package/src/cli/cmd/tui/routes/session/header.tsx +141 -0
  122. package/src/cli/cmd/tui/routes/session/index.tsx +1888 -0
  123. package/src/cli/cmd/tui/routes/session/sidebar.tsx +321 -0
  124. package/src/cli/cmd/tui/spawn.ts +60 -0
  125. package/src/cli/cmd/tui/thread.ts +120 -0
  126. package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
  127. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
  128. package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
  129. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +77 -0
  130. package/src/cli/cmd/tui/ui/dialog-select.tsx +330 -0
  131. package/src/cli/cmd/tui/ui/dialog.tsx +170 -0
  132. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  133. package/src/cli/cmd/tui/ui/toast.tsx +100 -0
  134. package/src/cli/cmd/tui/util/clipboard.ts +127 -0
  135. package/src/cli/cmd/tui/util/editor.ts +32 -0
  136. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  137. package/src/cli/cmd/tui/worker.ts +63 -0
  138. package/src/cli/cmd/uninstall.ts +344 -0
  139. package/src/cli/cmd/upgrade.ts +67 -0
  140. package/src/cli/cmd/web.ts +84 -0
  141. package/src/cli/error.ts +55 -0
  142. package/src/cli/ui.ts +84 -0
  143. package/src/cli/upgrade.ts +25 -0
  144. package/src/command/index.ts +80 -0
  145. package/src/command/template/initialize.txt +10 -0
  146. package/src/command/template/review.txt +97 -0
  147. package/src/config/config.ts +995 -0
  148. package/src/config/markdown.ts +41 -0
  149. package/src/env/index.ts +26 -0
  150. package/src/file/ignore.ts +83 -0
  151. package/src/file/index.ts +328 -0
  152. package/src/file/ripgrep.ts +393 -0
  153. package/src/file/time.ts +64 -0
  154. package/src/file/watcher.ts +103 -0
  155. package/src/flag/flag.ts +46 -0
  156. package/src/format/formatter.ts +315 -0
  157. package/src/format/index.ts +137 -0
  158. package/src/global/index.ts +52 -0
  159. package/src/id/id.ts +73 -0
  160. package/src/ide/index.ts +76 -0
  161. package/src/index.ts +217 -0
  162. package/src/installation/index.ts +196 -0
  163. package/src/lsp/client.ts +229 -0
  164. package/src/lsp/index.ts +485 -0
  165. package/src/lsp/language.ts +116 -0
  166. package/src/lsp/server.ts +1895 -0
  167. package/src/mcp/auth.ts +135 -0
  168. package/src/mcp/index.ts +654 -0
  169. package/src/mcp/oauth-callback.ts +200 -0
  170. package/src/mcp/oauth-provider.ts +154 -0
  171. package/src/patch/index.ts +622 -0
  172. package/src/permission/index.ts +199 -0
  173. package/src/plugin/index.ts +101 -0
  174. package/src/project/bootstrap.ts +31 -0
  175. package/src/project/instance.ts +78 -0
  176. package/src/project/project.ts +221 -0
  177. package/src/project/state.ts +65 -0
  178. package/src/project/vcs.ts +76 -0
  179. package/src/provider/auth.ts +143 -0
  180. package/src/provider/models-macro.ts +11 -0
  181. package/src/provider/models.ts +106 -0
  182. package/src/provider/provider.ts +1071 -0
  183. package/src/provider/sdk/openai-compatible/src/README.md +5 -0
  184. package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
  185. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +101 -0
  186. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
  187. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
  188. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
  189. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
  190. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
  191. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
  192. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
  193. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
  194. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
  195. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
  196. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
  197. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
  198. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
  199. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
  200. package/src/provider/transform.ts +455 -0
  201. package/src/pty/index.ts +231 -0
  202. package/src/server/error.ts +36 -0
  203. package/src/server/project.ts +79 -0
  204. package/src/server/server.ts +2642 -0
  205. package/src/server/tui.ts +71 -0
  206. package/src/session/compaction.ts +223 -0
  207. package/src/session/index.ts +458 -0
  208. package/src/session/llm.ts +201 -0
  209. package/src/session/message-v2.ts +659 -0
  210. package/src/session/message.ts +189 -0
  211. package/src/session/processor.ts +409 -0
  212. package/src/session/prompt/anthropic-20250930.txt +166 -0
  213. package/src/session/prompt/anthropic.txt +104 -0
  214. package/src/session/prompt/anthropic_spoof.txt +1 -0
  215. package/src/session/prompt/beast.txt +147 -0
  216. package/src/session/prompt/build-switch.txt +5 -0
  217. package/src/session/prompt/codex.txt +318 -0
  218. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  219. package/src/session/prompt/gemini.txt +155 -0
  220. package/src/session/prompt/max-steps.txt +16 -0
  221. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  222. package/src/session/prompt/plan.txt +26 -0
  223. package/src/session/prompt/polaris.txt +106 -0
  224. package/src/session/prompt/qwen.txt +109 -0
  225. package/src/session/prompt.ts +1446 -0
  226. package/src/session/retry.ts +86 -0
  227. package/src/session/revert.ts +108 -0
  228. package/src/session/status.ts +76 -0
  229. package/src/session/summary.ts +194 -0
  230. package/src/session/system.ts +120 -0
  231. package/src/session/todo.ts +37 -0
  232. package/src/share/share-next.ts +194 -0
  233. package/src/share/share.ts +87 -0
  234. package/src/shell/shell.ts +67 -0
  235. package/src/skill/index.ts +1 -0
  236. package/src/skill/skill.ts +83 -0
  237. package/src/snapshot/index.ts +197 -0
  238. package/src/storage/storage.ts +226 -0
  239. package/src/tool/bash.ts +306 -0
  240. package/src/tool/bash.txt +158 -0
  241. package/src/tool/batch.ts +175 -0
  242. package/src/tool/batch.txt +24 -0
  243. package/src/tool/codesearch.ts +138 -0
  244. package/src/tool/codesearch.txt +12 -0
  245. package/src/tool/edit.ts +675 -0
  246. package/src/tool/edit.txt +10 -0
  247. package/src/tool/glob.ts +65 -0
  248. package/src/tool/glob.txt +6 -0
  249. package/src/tool/grep.ts +121 -0
  250. package/src/tool/grep.txt +8 -0
  251. package/src/tool/invalid.ts +17 -0
  252. package/src/tool/ls.ts +110 -0
  253. package/src/tool/ls.txt +1 -0
  254. package/src/tool/lsp-diagnostics.ts +26 -0
  255. package/src/tool/lsp-diagnostics.txt +1 -0
  256. package/src/tool/lsp-hover.ts +31 -0
  257. package/src/tool/lsp-hover.txt +1 -0
  258. package/src/tool/lsp.ts +87 -0
  259. package/src/tool/lsp.txt +19 -0
  260. package/src/tool/multiedit.ts +46 -0
  261. package/src/tool/multiedit.txt +41 -0
  262. package/src/tool/patch.ts +233 -0
  263. package/src/tool/patch.txt +1 -0
  264. package/src/tool/read.ts +219 -0
  265. package/src/tool/read.txt +12 -0
  266. package/src/tool/registry.ts +162 -0
  267. package/src/tool/skill.ts +100 -0
  268. package/src/tool/task.ts +136 -0
  269. package/src/tool/task.txt +60 -0
  270. package/src/tool/todo.ts +39 -0
  271. package/src/tool/todoread.txt +14 -0
  272. package/src/tool/todowrite.txt +167 -0
  273. package/src/tool/tool.ts +71 -0
  274. package/src/tool/webfetch.ts +187 -0
  275. package/src/tool/webfetch.txt +13 -0
  276. package/src/tool/websearch.ts +150 -0
  277. package/src/tool/websearch.txt +11 -0
  278. package/src/tool/write.ts +110 -0
  279. package/src/tool/write.txt +8 -0
  280. package/src/util/archive.ts +16 -0
  281. package/src/util/color.ts +19 -0
  282. package/src/util/context.ts +25 -0
  283. package/src/util/defer.ts +12 -0
  284. package/src/util/eventloop.ts +20 -0
  285. package/src/util/filesystem.ts +83 -0
  286. package/src/util/fn.ts +11 -0
  287. package/src/util/iife.ts +3 -0
  288. package/src/util/keybind.ts +102 -0
  289. package/src/util/lazy.ts +11 -0
  290. package/src/util/locale.ts +81 -0
  291. package/src/util/lock.ts +98 -0
  292. package/src/util/log.ts +180 -0
  293. package/src/util/queue.ts +32 -0
  294. package/src/util/rpc.ts +42 -0
  295. package/src/util/scrap.ts +10 -0
  296. package/src/util/signal.ts +12 -0
  297. package/src/util/timeout.ts +14 -0
  298. package/src/util/token.ts +7 -0
  299. package/src/util/wildcard.ts +54 -0
  300. package/tsconfig.json +16 -0
@@ -0,0 +1,103 @@
1
+ import { createProviderDefinedToolFactory } from "@ai-sdk/provider-utils"
2
+ import { z } from "zod/v4"
3
+
4
+ export const webSearchArgsSchema = z.object({
5
+ filters: z
6
+ .object({
7
+ allowedDomains: z.array(z.string()).optional(),
8
+ })
9
+ .optional(),
10
+
11
+ searchContextSize: z.enum(["low", "medium", "high"]).optional(),
12
+
13
+ userLocation: z
14
+ .object({
15
+ type: z.literal("approximate"),
16
+ country: z.string().optional(),
17
+ city: z.string().optional(),
18
+ region: z.string().optional(),
19
+ timezone: z.string().optional(),
20
+ })
21
+ .optional(),
22
+ })
23
+
24
+ export const webSearchToolFactory = createProviderDefinedToolFactory<
25
+ {
26
+ // Web search doesn't take input parameters - it's controlled by the prompt
27
+ },
28
+ {
29
+ /**
30
+ * Filters for the search.
31
+ */
32
+ filters?: {
33
+ /**
34
+ * Allowed domains for the search.
35
+ * If not provided, all domains are allowed.
36
+ * Subdomains of the provided domains are allowed as well.
37
+ */
38
+ allowedDomains?: string[]
39
+ }
40
+
41
+ /**
42
+ * Search context size to use for the web search.
43
+ * - high: Most comprehensive context, highest cost, slower response
44
+ * - medium: Balanced context, cost, and latency (default)
45
+ * - low: Least context, lowest cost, fastest response
46
+ */
47
+ searchContextSize?: "low" | "medium" | "high"
48
+
49
+ /**
50
+ * User location information to provide geographically relevant search results.
51
+ */
52
+ userLocation?: {
53
+ /**
54
+ * Type of location (always 'approximate')
55
+ */
56
+ type: "approximate"
57
+ /**
58
+ * Two-letter ISO country code (e.g., 'US', 'GB')
59
+ */
60
+ country?: string
61
+ /**
62
+ * City name (free text, e.g., 'Minneapolis')
63
+ */
64
+ city?: string
65
+ /**
66
+ * Region name (free text, e.g., 'Minnesota')
67
+ */
68
+ region?: string
69
+ /**
70
+ * IANA timezone (e.g., 'America/Chicago')
71
+ */
72
+ timezone?: string
73
+ }
74
+ }
75
+ >({
76
+ id: "openai.web_search",
77
+ name: "web_search",
78
+ inputSchema: z.object({
79
+ action: z
80
+ .discriminatedUnion("type", [
81
+ z.object({
82
+ type: z.literal("search"),
83
+ query: z.string().nullish(),
84
+ }),
85
+ z.object({
86
+ type: z.literal("open_page"),
87
+ url: z.string(),
88
+ }),
89
+ z.object({
90
+ type: z.literal("find"),
91
+ url: z.string(),
92
+ pattern: z.string(),
93
+ }),
94
+ ])
95
+ .nullish(),
96
+ }),
97
+ })
98
+
99
+ export const webSearch = (
100
+ args: Parameters<typeof webSearchToolFactory>[0] = {}, // default
101
+ ) => {
102
+ return webSearchToolFactory(args)
103
+ }
@@ -0,0 +1,455 @@
1
+ import type { APICallError, ModelMessage } from "ai"
2
+ import { unique } from "remeda"
3
+ import type { JSONSchema } from "zod/v4/core"
4
+ import type { Provider } from "./provider"
5
+ import type { ModelsDev } from "./models"
6
+
7
+ type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
8
+
9
+ function mimeToModality(mime: string): Modality | undefined {
10
+ if (mime.startsWith("image/")) return "image"
11
+ if (mime.startsWith("audio/")) return "audio"
12
+ if (mime.startsWith("video/")) return "video"
13
+ if (mime === "application/pdf") return "pdf"
14
+ return undefined
15
+ }
16
+
17
+ export namespace ProviderTransform {
18
+ function normalizeMessages(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
19
+ if (model.api.id.includes("claude")) {
20
+ return msgs.map((msg) => {
21
+ if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
22
+ msg.content = msg.content.map((part) => {
23
+ if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
24
+ return {
25
+ ...part,
26
+ toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"),
27
+ }
28
+ }
29
+ return part
30
+ })
31
+ }
32
+ return msg
33
+ })
34
+ }
35
+ if (model.providerID === "mistral" || model.api.id.toLowerCase().includes("mistral")) {
36
+ const result: ModelMessage[] = []
37
+ for (let i = 0; i < msgs.length; i++) {
38
+ const msg = msgs[i]
39
+ const nextMsg = msgs[i + 1]
40
+
41
+ if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
42
+ msg.content = msg.content.map((part) => {
43
+ if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
44
+ // Mistral requires alphanumeric tool call IDs with exactly 9 characters
45
+ const normalizedId = part.toolCallId
46
+ .replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters
47
+ .substring(0, 9) // Take first 9 characters
48
+ .padEnd(9, "0") // Pad with zeros if less than 9 characters
49
+
50
+ return {
51
+ ...part,
52
+ toolCallId: normalizedId,
53
+ }
54
+ }
55
+ return part
56
+ })
57
+ }
58
+
59
+ result.push(msg)
60
+
61
+ // Fix message sequence: tool messages cannot be followed by user messages
62
+ if (msg.role === "tool" && nextMsg?.role === "user") {
63
+ result.push({
64
+ role: "assistant",
65
+ content: [
66
+ {
67
+ type: "text",
68
+ text: "Done.",
69
+ },
70
+ ],
71
+ })
72
+ }
73
+ }
74
+ return result
75
+ }
76
+
77
+ if (
78
+ model.capabilities.interleaved &&
79
+ typeof model.capabilities.interleaved === "object" &&
80
+ model.capabilities.interleaved.field === "reasoning_content"
81
+ ) {
82
+ return msgs.map((msg) => {
83
+ if (msg.role === "assistant" && Array.isArray(msg.content)) {
84
+ const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
85
+ const reasoningText = reasoningParts.map((part: any) => part.text).join("")
86
+
87
+ // Filter out reasoning parts from content
88
+ const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
89
+
90
+ // Include reasoning_content directly on the message for all assistant messages
91
+ if (reasoningText) {
92
+ return {
93
+ ...msg,
94
+ content: filteredContent,
95
+ providerOptions: {
96
+ ...msg.providerOptions,
97
+ openaiCompatible: {
98
+ ...(msg.providerOptions as any)?.openaiCompatible,
99
+ reasoning_content: reasoningText,
100
+ },
101
+ },
102
+ }
103
+ }
104
+
105
+ return {
106
+ ...msg,
107
+ content: filteredContent,
108
+ }
109
+ }
110
+
111
+ return msg
112
+ })
113
+ }
114
+
115
+ return msgs
116
+ }
117
+
118
+ function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] {
119
+ const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
120
+ const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
121
+
122
+ const providerOptions = {
123
+ anthropic: {
124
+ cacheControl: { type: "ephemeral" },
125
+ },
126
+ openrouter: {
127
+ cache_control: { type: "ephemeral" },
128
+ },
129
+ bedrock: {
130
+ cachePoint: { type: "ephemeral" },
131
+ },
132
+ openaiCompatible: {
133
+ cache_control: { type: "ephemeral" },
134
+ },
135
+ }
136
+
137
+ for (const msg of unique([...system, ...final])) {
138
+ const shouldUseContentOptions = providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0
139
+
140
+ if (shouldUseContentOptions) {
141
+ const lastContent = msg.content[msg.content.length - 1]
142
+ if (lastContent && typeof lastContent === "object") {
143
+ lastContent.providerOptions = {
144
+ ...lastContent.providerOptions,
145
+ ...providerOptions,
146
+ }
147
+ continue
148
+ }
149
+ }
150
+
151
+ msg.providerOptions = {
152
+ ...msg.providerOptions,
153
+ ...providerOptions,
154
+ }
155
+ }
156
+
157
+ return msgs
158
+ }
159
+
160
+ function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
161
+ return msgs.map((msg) => {
162
+ if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
163
+
164
+ const filtered = msg.content.map((part) => {
165
+ if (part.type !== "file" && part.type !== "image") return part
166
+
167
+ // Check for empty base64 image data
168
+ if (part.type === "image") {
169
+ const imageStr = part.image.toString()
170
+ if (imageStr.startsWith("data:")) {
171
+ const match = imageStr.match(/^data:([^;]+);base64,(.*)$/)
172
+ if (match && (!match[2] || match[2].length === 0)) {
173
+ return {
174
+ type: "text" as const,
175
+ text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
182
+ const filename = part.type === "file" ? part.filename : undefined
183
+ const modality = mimeToModality(mime)
184
+ if (!modality) return part
185
+ if (model.capabilities.input[modality]) return part
186
+
187
+ const name = filename ? `"${filename}"` : modality
188
+ return {
189
+ type: "text" as const,
190
+ text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
191
+ }
192
+ })
193
+
194
+ return { ...msg, content: filtered }
195
+ })
196
+ }
197
+
198
+ export function message(msgs: ModelMessage[], model: Provider.Model) {
199
+ msgs = unsupportedParts(msgs, model)
200
+ msgs = normalizeMessages(msgs, model)
201
+ if (
202
+ model.providerID === "anthropic" ||
203
+ model.api.id.includes("anthropic") ||
204
+ model.api.id.includes("claude") ||
205
+ model.api.npm === "@ai-sdk/anthropic"
206
+ ) {
207
+ msgs = applyCaching(msgs, model.providerID)
208
+ }
209
+
210
+ return msgs
211
+ }
212
+
213
+ export function temperature(model: Provider.Model) {
214
+ const id = model.id.toLowerCase()
215
+ if (id.includes("qwen")) return 0.55
216
+ if (id.includes("claude")) return undefined
217
+ if (id.includes("gemini-3-pro")) return 1.0
218
+ if (id.includes("glm-4.6")) return 1.0
219
+ if (id.includes("glm-4.7")) return 1.0
220
+ if (id.includes("minimax-m2")) return 1.0
221
+ if (id.includes("kimi-k2")) {
222
+ if (id.includes("thinking")) return 1.0
223
+ return 0.6
224
+ }
225
+ return undefined
226
+ }
227
+
228
+ export function topP(model: Provider.Model) {
229
+ const id = model.id.toLowerCase()
230
+ if (id.includes("qwen")) return 1
231
+ if (id.includes("minimax-m2")) {
232
+ if (id.includes("m2.1")) return 0.9
233
+ return 0.95
234
+ }
235
+ return undefined
236
+ }
237
+
238
+ export function topK(model: Provider.Model) {
239
+ const id = model.id.toLowerCase()
240
+ if (id.includes("minimax-m2")) return 20
241
+ return undefined
242
+ }
243
+
244
+ export function options(
245
+ model: Provider.Model,
246
+ sessionID: string,
247
+ providerOptions?: Record<string, any>,
248
+ ): Record<string, any> {
249
+ const result: Record<string, any> = {}
250
+
251
+ if (model.api.npm === "@openrouter/ai-sdk-provider") {
252
+ result["usage"] = {
253
+ include: true,
254
+ }
255
+ if (model.api.id.includes("gemini-3")) {
256
+ result["reasoning"] = { effort: "high" }
257
+ }
258
+ }
259
+
260
+ if (
261
+ model.providerID === "baseten" ||
262
+ (model.providerID === "bincode" && ["kimi-k2-thinking", "glm-4.6"].includes(model.api.id))
263
+ ) {
264
+ result["chat_template_args"] = { enable_thinking: true }
265
+ }
266
+
267
+ if (model.providerID === "openai" || providerOptions?.setCacheKey) {
268
+ result["promptCacheKey"] = sessionID
269
+ }
270
+
271
+ if (model.api.npm === "@ai-sdk/google" || model.api.npm === "@ai-sdk/google-vertex") {
272
+ result["thinkingConfig"] = {
273
+ includeThoughts: true,
274
+ }
275
+ if (model.api.id.includes("gemini-3")) {
276
+ result["thinkingConfig"]["thinkingLevel"] = "high"
277
+ }
278
+ }
279
+
280
+ if (model.api.id.includes("gpt-5") && !model.api.id.includes("gpt-5-chat")) {
281
+ if (model.providerID.includes("codex")) {
282
+ result["store"] = false
283
+ }
284
+
285
+ if (!model.api.id.includes("codex") && !model.api.id.includes("gpt-5-pro")) {
286
+ result["reasoningEffort"] = "medium"
287
+ }
288
+
289
+ if (model.api.id.endsWith("gpt-5.") && model.providerID !== "azure") {
290
+ result["textVerbosity"] = "low"
291
+ }
292
+
293
+ if (model.providerID.startsWith("bincode")) {
294
+ result["promptCacheKey"] = sessionID
295
+ result["include"] = ["reasoning.encrypted_content"]
296
+ result["reasoningSummary"] = "auto"
297
+ }
298
+ }
299
+ return result
300
+ }
301
+
302
+ export function smallOptions(model: Provider.Model) {
303
+ const options: Record<string, any> = {}
304
+
305
+ if (model.providerID === "openai" || model.api.id.includes("gpt-5")) {
306
+ if (model.api.id.includes("5.")) {
307
+ options["reasoningEffort"] = "low"
308
+ } else {
309
+ options["reasoningEffort"] = "minimal"
310
+ }
311
+ }
312
+ if (model.providerID === "google") {
313
+ options["thinkingConfig"] = {
314
+ thinkingBudget: 0,
315
+ }
316
+ }
317
+
318
+ return options
319
+ }
320
+
321
+ export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
322
+ switch (model.api.npm) {
323
+ case "@ai-sdk/openai":
324
+ case "@ai-sdk/azure":
325
+ return {
326
+ ["openai" as string]: options,
327
+ }
328
+ case "@ai-sdk/amazon-bedrock":
329
+ return {
330
+ ["bedrock" as string]: options,
331
+ }
332
+ case "@ai-sdk/anthropic":
333
+ return {
334
+ ["anthropic" as string]: options,
335
+ }
336
+ case "@ai-sdk/google":
337
+ return {
338
+ ["google" as string]: options,
339
+ }
340
+ case "@ai-sdk/gateway":
341
+ return {
342
+ ["gateway" as string]: options,
343
+ }
344
+ case "@openrouter/ai-sdk-provider":
345
+ return {
346
+ ["openrouter" as string]: options,
347
+ }
348
+ default:
349
+ return {
350
+ [model.providerID]: options,
351
+ }
352
+ }
353
+ }
354
+
355
+ export function maxOutputTokens(
356
+ npm: string,
357
+ options: Record<string, any>,
358
+ modelLimit: number,
359
+ globalLimit: number,
360
+ ): number {
361
+ const modelCap = modelLimit || globalLimit
362
+ const standardLimit = Math.min(modelCap, globalLimit)
363
+
364
+ if (npm === "@ai-sdk/anthropic") {
365
+ const thinking = options?.["thinking"]
366
+ const budgetTokens = typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0
367
+ const enabled = thinking?.["type"] === "enabled"
368
+ if (enabled && budgetTokens > 0) {
369
+ // Return text tokens so that text + thinking <= model cap, preferring 32k text when possible.
370
+ if (budgetTokens + standardLimit <= modelCap) {
371
+ return standardLimit
372
+ }
373
+ return modelCap - budgetTokens
374
+ }
375
+ }
376
+
377
+ return standardLimit
378
+ }
379
+
380
+ export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema) {
381
+ /*
382
+ if (["openai", "azure"].includes(providerID)) {
383
+ if (schema.type === "object" && schema.properties) {
384
+ for (const [key, value] of Object.entries(schema.properties)) {
385
+ if (schema.required?.includes(key)) continue
386
+ schema.properties[key] = {
387
+ anyOf: [
388
+ value as JSONSchema.JSONSchema,
389
+ {
390
+ type: "null",
391
+ },
392
+ ],
393
+ }
394
+ }
395
+ }
396
+ }
397
+ */
398
+
399
+ // Convert integer enums to string enums for Google/Gemini
400
+ if (model.providerID === "google" || model.api.id.includes("gemini")) {
401
+ const sanitizeGemini = (obj: any): any => {
402
+ if (obj === null || typeof obj !== "object") {
403
+ return obj
404
+ }
405
+
406
+ if (Array.isArray(obj)) {
407
+ return obj.map(sanitizeGemini)
408
+ }
409
+
410
+ const result: any = {}
411
+ for (const [key, value] of Object.entries(obj)) {
412
+ if (key === "enum" && Array.isArray(value)) {
413
+ // Convert all enum values to strings
414
+ result[key] = value.map((v) => String(v))
415
+ // If we have integer type with enum, change type to string
416
+ if (result.type === "integer" || result.type === "number") {
417
+ result.type = "string"
418
+ }
419
+ } else if (typeof value === "object" && value !== null) {
420
+ result[key] = sanitizeGemini(value)
421
+ } else {
422
+ result[key] = value
423
+ }
424
+ }
425
+
426
+ // Filter required array to only include fields that exist in properties
427
+ if (result.type === "object" && result.properties && Array.isArray(result.required)) {
428
+ result.required = result.required.filter((field: any) => field in result.properties)
429
+ }
430
+
431
+ if (result.type === "array" && result.items == null) {
432
+ result.items = {}
433
+ }
434
+
435
+ return result
436
+ }
437
+
438
+ schema = sanitizeGemini(schema)
439
+ }
440
+
441
+ return schema
442
+ }
443
+
444
+ export function error(providerID: string, error: APICallError) {
445
+ let message = error.message
446
+ if (providerID === "github-copilot" && message.includes("The requested model is not supported")) {
447
+ return (
448
+ message +
449
+ "\n\nMake sure the model is enabled in your copilot settings: https://github.com/settings/copilot/features"
450
+ )
451
+ }
452
+
453
+ return message
454
+ }
455
+ }