ai 6.0.32 → 6.0.34

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 (353) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.js +12 -2
  3. package/dist/index.js.map +1 -1
  4. package/dist/index.mjs +12 -2
  5. package/dist/index.mjs.map +1 -1
  6. package/dist/internal/index.js +1 -1
  7. package/dist/internal/index.mjs +1 -1
  8. package/docs/02-foundations/03-prompts.mdx +2 -2
  9. package/docs/03-ai-sdk-core/15-tools-and-tool-calling.mdx +1 -1
  10. package/docs/07-reference/01-ai-sdk-core/28-output.mdx +1 -1
  11. package/package.json +6 -4
  12. package/src/agent/agent.ts +116 -0
  13. package/src/agent/create-agent-ui-stream-response.test.ts +258 -0
  14. package/src/agent/create-agent-ui-stream-response.ts +50 -0
  15. package/src/agent/create-agent-ui-stream.ts +73 -0
  16. package/src/agent/index.ts +33 -0
  17. package/src/agent/infer-agent-tools.ts +7 -0
  18. package/src/agent/infer-agent-ui-message.test-d.ts +54 -0
  19. package/src/agent/infer-agent-ui-message.ts +11 -0
  20. package/src/agent/pipe-agent-ui-stream-to-response.ts +52 -0
  21. package/src/agent/tool-loop-agent-on-finish-callback.ts +31 -0
  22. package/src/agent/tool-loop-agent-on-step-finish-callback.ts +11 -0
  23. package/src/agent/tool-loop-agent-settings.ts +182 -0
  24. package/src/agent/tool-loop-agent.test-d.ts +114 -0
  25. package/src/agent/tool-loop-agent.test.ts +442 -0
  26. package/src/agent/tool-loop-agent.ts +114 -0
  27. package/src/embed/__snapshots__/embed-many.test.ts.snap +191 -0
  28. package/src/embed/__snapshots__/embed.test.ts.snap +81 -0
  29. package/src/embed/embed-many-result.ts +53 -0
  30. package/src/embed/embed-many.test.ts +653 -0
  31. package/src/embed/embed-many.ts +378 -0
  32. package/src/embed/embed-result.ts +50 -0
  33. package/src/embed/embed.test.ts +298 -0
  34. package/src/embed/embed.ts +211 -0
  35. package/src/embed/index.ts +4 -0
  36. package/src/error/index.ts +34 -0
  37. package/src/error/invalid-argument-error.ts +34 -0
  38. package/src/error/invalid-stream-part-error.ts +28 -0
  39. package/src/error/invalid-tool-approval-error.ts +26 -0
  40. package/src/error/invalid-tool-input-error.ts +33 -0
  41. package/src/error/no-image-generated-error.ts +39 -0
  42. package/src/error/no-object-generated-error.ts +70 -0
  43. package/src/error/no-output-generated-error.ts +26 -0
  44. package/src/error/no-speech-generated-error.ts +18 -0
  45. package/src/error/no-such-tool-error.ts +35 -0
  46. package/src/error/no-transcript-generated-error.ts +20 -0
  47. package/src/error/tool-call-not-found-for-approval-error.ts +32 -0
  48. package/src/error/tool-call-repair-error.ts +30 -0
  49. package/src/error/unsupported-model-version-error.ts +23 -0
  50. package/src/error/verify-no-object-generated-error.ts +27 -0
  51. package/src/generate-image/generate-image-result.ts +42 -0
  52. package/src/generate-image/generate-image.test.ts +1420 -0
  53. package/src/generate-image/generate-image.ts +360 -0
  54. package/src/generate-image/index.ts +18 -0
  55. package/src/generate-object/__snapshots__/generate-object.test.ts.snap +133 -0
  56. package/src/generate-object/__snapshots__/stream-object.test.ts.snap +297 -0
  57. package/src/generate-object/generate-object-result.ts +67 -0
  58. package/src/generate-object/generate-object.test-d.ts +49 -0
  59. package/src/generate-object/generate-object.test.ts +1191 -0
  60. package/src/generate-object/generate-object.ts +518 -0
  61. package/src/generate-object/index.ts +9 -0
  62. package/src/generate-object/inject-json-instruction.test.ts +181 -0
  63. package/src/generate-object/inject-json-instruction.ts +30 -0
  64. package/src/generate-object/output-strategy.ts +415 -0
  65. package/src/generate-object/parse-and-validate-object-result.ts +111 -0
  66. package/src/generate-object/repair-text.ts +12 -0
  67. package/src/generate-object/stream-object-result.ts +120 -0
  68. package/src/generate-object/stream-object.test-d.ts +74 -0
  69. package/src/generate-object/stream-object.test.ts +1950 -0
  70. package/src/generate-object/stream-object.ts +986 -0
  71. package/src/generate-object/validate-object-generation-input.ts +144 -0
  72. package/src/generate-speech/generate-speech-result.ts +30 -0
  73. package/src/generate-speech/generate-speech.test.ts +300 -0
  74. package/src/generate-speech/generate-speech.ts +190 -0
  75. package/src/generate-speech/generated-audio-file.ts +65 -0
  76. package/src/generate-speech/index.ts +3 -0
  77. package/src/generate-text/__snapshots__/generate-text.test.ts.snap +1872 -0
  78. package/src/generate-text/__snapshots__/stream-text.test.ts.snap +1255 -0
  79. package/src/generate-text/collect-tool-approvals.test.ts +553 -0
  80. package/src/generate-text/collect-tool-approvals.ts +116 -0
  81. package/src/generate-text/content-part.ts +25 -0
  82. package/src/generate-text/execute-tool-call.ts +129 -0
  83. package/src/generate-text/extract-reasoning-content.ts +17 -0
  84. package/src/generate-text/extract-text-content.ts +15 -0
  85. package/src/generate-text/generate-text-result.ts +168 -0
  86. package/src/generate-text/generate-text.test-d.ts +68 -0
  87. package/src/generate-text/generate-text.test.ts +7011 -0
  88. package/src/generate-text/generate-text.ts +1223 -0
  89. package/src/generate-text/generated-file.ts +70 -0
  90. package/src/generate-text/index.ts +57 -0
  91. package/src/generate-text/is-approval-needed.ts +29 -0
  92. package/src/generate-text/output-utils.ts +23 -0
  93. package/src/generate-text/output.test.ts +698 -0
  94. package/src/generate-text/output.ts +590 -0
  95. package/src/generate-text/parse-tool-call.test.ts +570 -0
  96. package/src/generate-text/parse-tool-call.ts +188 -0
  97. package/src/generate-text/prepare-step.ts +103 -0
  98. package/src/generate-text/prune-messages.test.ts +720 -0
  99. package/src/generate-text/prune-messages.ts +167 -0
  100. package/src/generate-text/reasoning-output.ts +20 -0
  101. package/src/generate-text/reasoning.ts +8 -0
  102. package/src/generate-text/response-message.ts +10 -0
  103. package/src/generate-text/run-tools-transformation.test.ts +1143 -0
  104. package/src/generate-text/run-tools-transformation.ts +420 -0
  105. package/src/generate-text/smooth-stream.test.ts +2101 -0
  106. package/src/generate-text/smooth-stream.ts +162 -0
  107. package/src/generate-text/step-result.ts +238 -0
  108. package/src/generate-text/stop-condition.ts +29 -0
  109. package/src/generate-text/stream-text-result.ts +463 -0
  110. package/src/generate-text/stream-text.test-d.ts +200 -0
  111. package/src/generate-text/stream-text.test.ts +19979 -0
  112. package/src/generate-text/stream-text.ts +2505 -0
  113. package/src/generate-text/to-response-messages.test.ts +922 -0
  114. package/src/generate-text/to-response-messages.ts +163 -0
  115. package/src/generate-text/tool-approval-request-output.ts +21 -0
  116. package/src/generate-text/tool-call-repair-function.ts +27 -0
  117. package/src/generate-text/tool-call.ts +47 -0
  118. package/src/generate-text/tool-error.ts +34 -0
  119. package/src/generate-text/tool-output-denied.ts +21 -0
  120. package/src/generate-text/tool-output.ts +7 -0
  121. package/src/generate-text/tool-result.ts +36 -0
  122. package/src/generate-text/tool-set.ts +14 -0
  123. package/src/global.ts +24 -0
  124. package/src/index.ts +50 -0
  125. package/src/logger/index.ts +6 -0
  126. package/src/logger/log-warnings.test.ts +351 -0
  127. package/src/logger/log-warnings.ts +119 -0
  128. package/src/middleware/__snapshots__/simulate-streaming-middleware.test.ts.snap +64 -0
  129. package/src/middleware/add-tool-input-examples-middleware.test.ts +476 -0
  130. package/src/middleware/add-tool-input-examples-middleware.ts +90 -0
  131. package/src/middleware/default-embedding-settings-middleware.test.ts +126 -0
  132. package/src/middleware/default-embedding-settings-middleware.ts +22 -0
  133. package/src/middleware/default-settings-middleware.test.ts +388 -0
  134. package/src/middleware/default-settings-middleware.ts +33 -0
  135. package/src/middleware/extract-json-middleware.test.ts +827 -0
  136. package/src/middleware/extract-json-middleware.ts +197 -0
  137. package/src/middleware/extract-reasoning-middleware.test.ts +1028 -0
  138. package/src/middleware/extract-reasoning-middleware.ts +238 -0
  139. package/src/middleware/index.ts +10 -0
  140. package/src/middleware/simulate-streaming-middleware.test.ts +911 -0
  141. package/src/middleware/simulate-streaming-middleware.ts +79 -0
  142. package/src/middleware/wrap-embedding-model.test.ts +358 -0
  143. package/src/middleware/wrap-embedding-model.ts +86 -0
  144. package/src/middleware/wrap-image-model.test.ts +423 -0
  145. package/src/middleware/wrap-image-model.ts +85 -0
  146. package/src/middleware/wrap-language-model.test.ts +518 -0
  147. package/src/middleware/wrap-language-model.ts +104 -0
  148. package/src/middleware/wrap-provider.test.ts +120 -0
  149. package/src/middleware/wrap-provider.ts +51 -0
  150. package/src/model/as-embedding-model-v3.test.ts +319 -0
  151. package/src/model/as-embedding-model-v3.ts +24 -0
  152. package/src/model/as-image-model-v3.test.ts +409 -0
  153. package/src/model/as-image-model-v3.ts +24 -0
  154. package/src/model/as-language-model-v3.test.ts +508 -0
  155. package/src/model/as-language-model-v3.ts +103 -0
  156. package/src/model/as-provider-v3.ts +36 -0
  157. package/src/model/as-speech-model-v3.test.ts +356 -0
  158. package/src/model/as-speech-model-v3.ts +24 -0
  159. package/src/model/as-transcription-model-v3.test.ts +529 -0
  160. package/src/model/as-transcription-model-v3.ts +24 -0
  161. package/src/model/resolve-model.test.ts +244 -0
  162. package/src/model/resolve-model.ts +126 -0
  163. package/src/prompt/call-settings.ts +148 -0
  164. package/src/prompt/content-part.ts +209 -0
  165. package/src/prompt/convert-to-language-model-prompt.test.ts +2018 -0
  166. package/src/prompt/convert-to-language-model-prompt.ts +442 -0
  167. package/src/prompt/create-tool-model-output.test.ts +508 -0
  168. package/src/prompt/create-tool-model-output.ts +34 -0
  169. package/src/prompt/data-content.test.ts +15 -0
  170. package/src/prompt/data-content.ts +134 -0
  171. package/src/prompt/index.ts +27 -0
  172. package/src/prompt/invalid-data-content-error.ts +29 -0
  173. package/src/prompt/invalid-message-role-error.ts +27 -0
  174. package/src/prompt/message-conversion-error.ts +28 -0
  175. package/src/prompt/message.ts +68 -0
  176. package/src/prompt/prepare-call-settings.test.ts +159 -0
  177. package/src/prompt/prepare-call-settings.ts +108 -0
  178. package/src/prompt/prepare-tools-and-tool-choice.test.ts +461 -0
  179. package/src/prompt/prepare-tools-and-tool-choice.ts +86 -0
  180. package/src/prompt/prompt.ts +43 -0
  181. package/src/prompt/split-data-url.ts +17 -0
  182. package/src/prompt/standardize-prompt.test.ts +82 -0
  183. package/src/prompt/standardize-prompt.ts +99 -0
  184. package/src/prompt/wrap-gateway-error.ts +29 -0
  185. package/src/registry/custom-provider.test.ts +211 -0
  186. package/src/registry/custom-provider.ts +155 -0
  187. package/src/registry/index.ts +7 -0
  188. package/src/registry/no-such-provider-error.ts +41 -0
  189. package/src/registry/provider-registry.test.ts +691 -0
  190. package/src/registry/provider-registry.ts +328 -0
  191. package/src/rerank/index.ts +2 -0
  192. package/src/rerank/rerank-result.ts +70 -0
  193. package/src/rerank/rerank.test.ts +516 -0
  194. package/src/rerank/rerank.ts +237 -0
  195. package/src/telemetry/assemble-operation-name.ts +21 -0
  196. package/src/telemetry/get-base-telemetry-attributes.ts +53 -0
  197. package/src/telemetry/get-tracer.ts +20 -0
  198. package/src/telemetry/noop-tracer.ts +69 -0
  199. package/src/telemetry/record-span.ts +63 -0
  200. package/src/telemetry/select-telemetry-attributes.ts +78 -0
  201. package/src/telemetry/select-temetry-attributes.test.ts +114 -0
  202. package/src/telemetry/stringify-for-telemetry.test.ts +114 -0
  203. package/src/telemetry/stringify-for-telemetry.ts +33 -0
  204. package/src/telemetry/telemetry-settings.ts +44 -0
  205. package/src/test/mock-embedding-model-v2.ts +35 -0
  206. package/src/test/mock-embedding-model-v3.ts +48 -0
  207. package/src/test/mock-image-model-v2.ts +28 -0
  208. package/src/test/mock-image-model-v3.ts +28 -0
  209. package/src/test/mock-language-model-v2.ts +72 -0
  210. package/src/test/mock-language-model-v3.ts +77 -0
  211. package/src/test/mock-provider-v2.ts +68 -0
  212. package/src/test/mock-provider-v3.ts +80 -0
  213. package/src/test/mock-reranking-model-v3.ts +25 -0
  214. package/src/test/mock-server-response.ts +69 -0
  215. package/src/test/mock-speech-model-v2.ts +24 -0
  216. package/src/test/mock-speech-model-v3.ts +24 -0
  217. package/src/test/mock-tracer.ts +156 -0
  218. package/src/test/mock-transcription-model-v2.ts +24 -0
  219. package/src/test/mock-transcription-model-v3.ts +24 -0
  220. package/src/test/mock-values.ts +4 -0
  221. package/src/test/not-implemented.ts +3 -0
  222. package/src/text-stream/create-text-stream-response.test.ts +38 -0
  223. package/src/text-stream/create-text-stream-response.ts +18 -0
  224. package/src/text-stream/index.ts +2 -0
  225. package/src/text-stream/pipe-text-stream-to-response.test.ts +38 -0
  226. package/src/text-stream/pipe-text-stream-to-response.ts +26 -0
  227. package/src/transcribe/index.ts +2 -0
  228. package/src/transcribe/transcribe-result.ts +60 -0
  229. package/src/transcribe/transcribe.test.ts +313 -0
  230. package/src/transcribe/transcribe.ts +173 -0
  231. package/src/types/embedding-model-middleware.ts +3 -0
  232. package/src/types/embedding-model.ts +18 -0
  233. package/src/types/image-model-middleware.ts +3 -0
  234. package/src/types/image-model-response-metadata.ts +16 -0
  235. package/src/types/image-model.ts +19 -0
  236. package/src/types/index.ts +29 -0
  237. package/src/types/json-value.ts +15 -0
  238. package/src/types/language-model-middleware.ts +3 -0
  239. package/src/types/language-model-request-metadata.ts +6 -0
  240. package/src/types/language-model-response-metadata.ts +21 -0
  241. package/src/types/language-model.ts +104 -0
  242. package/src/types/provider-metadata.ts +16 -0
  243. package/src/types/provider.ts +55 -0
  244. package/src/types/reranking-model.ts +6 -0
  245. package/src/types/speech-model-response-metadata.ts +21 -0
  246. package/src/types/speech-model.ts +6 -0
  247. package/src/types/transcription-model-response-metadata.ts +16 -0
  248. package/src/types/transcription-model.ts +9 -0
  249. package/src/types/usage.ts +200 -0
  250. package/src/types/warning.ts +7 -0
  251. package/src/ui/__snapshots__/append-response-messages.test.ts.snap +416 -0
  252. package/src/ui/__snapshots__/convert-to-model-messages.test.ts.snap +419 -0
  253. package/src/ui/__snapshots__/process-chat-text-response.test.ts.snap +142 -0
  254. package/src/ui/call-completion-api.ts +157 -0
  255. package/src/ui/chat-transport.ts +83 -0
  256. package/src/ui/chat.test-d.ts +233 -0
  257. package/src/ui/chat.test.ts +2695 -0
  258. package/src/ui/chat.ts +716 -0
  259. package/src/ui/convert-file-list-to-file-ui-parts.ts +36 -0
  260. package/src/ui/convert-to-model-messages.test.ts +2775 -0
  261. package/src/ui/convert-to-model-messages.ts +373 -0
  262. package/src/ui/default-chat-transport.ts +36 -0
  263. package/src/ui/direct-chat-transport.test.ts +446 -0
  264. package/src/ui/direct-chat-transport.ts +118 -0
  265. package/src/ui/http-chat-transport.test.ts +185 -0
  266. package/src/ui/http-chat-transport.ts +292 -0
  267. package/src/ui/index.ts +71 -0
  268. package/src/ui/last-assistant-message-is-complete-with-approval-responses.ts +44 -0
  269. package/src/ui/last-assistant-message-is-complete-with-tool-calls.test.ts +371 -0
  270. package/src/ui/last-assistant-message-is-complete-with-tool-calls.ts +39 -0
  271. package/src/ui/process-text-stream.test.ts +38 -0
  272. package/src/ui/process-text-stream.ts +16 -0
  273. package/src/ui/process-ui-message-stream.test.ts +8052 -0
  274. package/src/ui/process-ui-message-stream.ts +713 -0
  275. package/src/ui/text-stream-chat-transport.ts +23 -0
  276. package/src/ui/transform-text-to-ui-message-stream.test.ts +124 -0
  277. package/src/ui/transform-text-to-ui-message-stream.ts +27 -0
  278. package/src/ui/ui-messages.test.ts +48 -0
  279. package/src/ui/ui-messages.ts +534 -0
  280. package/src/ui/use-completion.ts +84 -0
  281. package/src/ui/validate-ui-messages.test.ts +1428 -0
  282. package/src/ui/validate-ui-messages.ts +476 -0
  283. package/src/ui-message-stream/create-ui-message-stream-response.test.ts +266 -0
  284. package/src/ui-message-stream/create-ui-message-stream-response.ts +32 -0
  285. package/src/ui-message-stream/create-ui-message-stream.test.ts +639 -0
  286. package/src/ui-message-stream/create-ui-message-stream.ts +124 -0
  287. package/src/ui-message-stream/get-response-ui-message-id.test.ts +55 -0
  288. package/src/ui-message-stream/get-response-ui-message-id.ts +24 -0
  289. package/src/ui-message-stream/handle-ui-message-stream-finish.test.ts +429 -0
  290. package/src/ui-message-stream/handle-ui-message-stream-finish.ts +135 -0
  291. package/src/ui-message-stream/index.ts +13 -0
  292. package/src/ui-message-stream/json-to-sse-transform-stream.ts +12 -0
  293. package/src/ui-message-stream/pipe-ui-message-stream-to-response.test.ts +90 -0
  294. package/src/ui-message-stream/pipe-ui-message-stream-to-response.ts +40 -0
  295. package/src/ui-message-stream/read-ui-message-stream.test.ts +122 -0
  296. package/src/ui-message-stream/read-ui-message-stream.ts +87 -0
  297. package/src/ui-message-stream/ui-message-chunks.test-d.ts +18 -0
  298. package/src/ui-message-stream/ui-message-chunks.ts +344 -0
  299. package/src/ui-message-stream/ui-message-stream-headers.ts +7 -0
  300. package/src/ui-message-stream/ui-message-stream-on-finish-callback.ts +32 -0
  301. package/src/ui-message-stream/ui-message-stream-response-init.ts +5 -0
  302. package/src/ui-message-stream/ui-message-stream-writer.ts +24 -0
  303. package/src/util/as-array.ts +3 -0
  304. package/src/util/async-iterable-stream.test.ts +241 -0
  305. package/src/util/async-iterable-stream.ts +94 -0
  306. package/src/util/consume-stream.ts +29 -0
  307. package/src/util/cosine-similarity.test.ts +57 -0
  308. package/src/util/cosine-similarity.ts +47 -0
  309. package/src/util/create-resolvable-promise.ts +30 -0
  310. package/src/util/create-stitchable-stream.test.ts +239 -0
  311. package/src/util/create-stitchable-stream.ts +112 -0
  312. package/src/util/data-url.ts +17 -0
  313. package/src/util/deep-partial.ts +84 -0
  314. package/src/util/detect-media-type.test.ts +670 -0
  315. package/src/util/detect-media-type.ts +184 -0
  316. package/src/util/download/download-function.ts +45 -0
  317. package/src/util/download/download.test.ts +69 -0
  318. package/src/util/download/download.ts +46 -0
  319. package/src/util/error-handler.ts +1 -0
  320. package/src/util/fix-json.test.ts +279 -0
  321. package/src/util/fix-json.ts +401 -0
  322. package/src/util/get-potential-start-index.test.ts +34 -0
  323. package/src/util/get-potential-start-index.ts +30 -0
  324. package/src/util/index.ts +11 -0
  325. package/src/util/is-deep-equal-data.test.ts +119 -0
  326. package/src/util/is-deep-equal-data.ts +48 -0
  327. package/src/util/is-non-empty-object.ts +5 -0
  328. package/src/util/job.ts +1 -0
  329. package/src/util/log-v2-compatibility-warning.ts +21 -0
  330. package/src/util/merge-abort-signals.test.ts +155 -0
  331. package/src/util/merge-abort-signals.ts +43 -0
  332. package/src/util/merge-objects.test.ts +118 -0
  333. package/src/util/merge-objects.ts +79 -0
  334. package/src/util/now.ts +4 -0
  335. package/src/util/parse-partial-json.test.ts +80 -0
  336. package/src/util/parse-partial-json.ts +30 -0
  337. package/src/util/prepare-headers.test.ts +51 -0
  338. package/src/util/prepare-headers.ts +14 -0
  339. package/src/util/prepare-retries.test.ts +10 -0
  340. package/src/util/prepare-retries.ts +47 -0
  341. package/src/util/retry-error.ts +41 -0
  342. package/src/util/retry-with-exponential-backoff.test.ts +446 -0
  343. package/src/util/retry-with-exponential-backoff.ts +154 -0
  344. package/src/util/serial-job-executor.test.ts +162 -0
  345. package/src/util/serial-job-executor.ts +36 -0
  346. package/src/util/simulate-readable-stream.test.ts +98 -0
  347. package/src/util/simulate-readable-stream.ts +39 -0
  348. package/src/util/split-array.test.ts +60 -0
  349. package/src/util/split-array.ts +20 -0
  350. package/src/util/value-of.ts +65 -0
  351. package/src/util/write-to-server-response.test.ts +266 -0
  352. package/src/util/write-to-server-response.ts +49 -0
  353. package/src/version.ts +5 -0
@@ -0,0 +1,423 @@
1
+ import {
2
+ ImageModelV3CallOptions,
3
+ ImageModelV3Middleware,
4
+ } from '@ai-sdk/provider';
5
+ import { wrapImageModel } from '../middleware/wrap-image-model';
6
+ import { MockImageModelV3 } from '../test/mock-image-model-v3';
7
+ import { describe, it, expect, vi } from 'vitest';
8
+
9
+ describe('wrapImageModel', () => {
10
+ describe('model property', () => {
11
+ it('should pass through by default', () => {
12
+ const wrappedModel = wrapImageModel({
13
+ model: new MockImageModelV3({
14
+ modelId: 'test-model',
15
+ }),
16
+ middleware: {
17
+ specificationVersion: 'v3',
18
+ },
19
+ });
20
+
21
+ expect(wrappedModel.modelId).toBe('test-model');
22
+ });
23
+
24
+ it('should use middleware overrideModelId if provided', () => {
25
+ const wrappedModel = wrapImageModel({
26
+ model: new MockImageModelV3({
27
+ modelId: 'test-model',
28
+ }),
29
+ middleware: {
30
+ specificationVersion: 'v3',
31
+ overrideModelId: ({ model }) => 'override-model',
32
+ },
33
+ });
34
+
35
+ expect(wrappedModel.modelId).toBe('override-model');
36
+ });
37
+
38
+ it('should use modelId parameter if provided', () => {
39
+ const wrappedModel = wrapImageModel({
40
+ model: new MockImageModelV3({
41
+ modelId: 'test-model',
42
+ }),
43
+ middleware: {
44
+ specificationVersion: 'v3',
45
+ },
46
+ modelId: 'override-model',
47
+ });
48
+
49
+ expect(wrappedModel.modelId).toBe('override-model');
50
+ });
51
+ });
52
+
53
+ describe('provider property', () => {
54
+ it('should pass through by default', () => {
55
+ const wrappedModel = wrapImageModel({
56
+ model: new MockImageModelV3({
57
+ provider: 'test-provider',
58
+ }),
59
+ middleware: {
60
+ specificationVersion: 'v3',
61
+ },
62
+ });
63
+
64
+ expect(wrappedModel.provider).toBe('test-provider');
65
+ });
66
+
67
+ it('should use middleware overrideProvider if provided', () => {
68
+ const wrappedModel = wrapImageModel({
69
+ model: new MockImageModelV3({
70
+ provider: 'test-provider',
71
+ }),
72
+ middleware: {
73
+ specificationVersion: 'v3',
74
+ overrideProvider: ({ model }) => 'override-provider',
75
+ },
76
+ });
77
+
78
+ expect(wrappedModel.provider).toBe('override-provider');
79
+ });
80
+
81
+ it('should use providerId parameter if provided', () => {
82
+ const wrappedModel = wrapImageModel({
83
+ model: new MockImageModelV3({
84
+ provider: 'test-provider',
85
+ }),
86
+ middleware: {
87
+ specificationVersion: 'v3',
88
+ },
89
+ providerId: 'override-provider',
90
+ });
91
+
92
+ expect(wrappedModel.provider).toBe('override-provider');
93
+ });
94
+ });
95
+
96
+ describe('maxImagesPerCall property', () => {
97
+ it('should pass through by default', () => {
98
+ const wrappedModel = wrapImageModel({
99
+ model: new MockImageModelV3({ maxImagesPerCall: 2 }),
100
+ middleware: {
101
+ specificationVersion: 'v3',
102
+ },
103
+ });
104
+
105
+ expect(wrappedModel.maxImagesPerCall).toBe(2);
106
+ });
107
+
108
+ it('should use middleware overrideMaxImagesPerCall if provided', () => {
109
+ const wrappedModel = wrapImageModel({
110
+ model: new MockImageModelV3({ maxImagesPerCall: 2 }),
111
+ middleware: {
112
+ specificationVersion: 'v3',
113
+ overrideMaxImagesPerCall: () => 3,
114
+ },
115
+ });
116
+
117
+ expect(wrappedModel.maxImagesPerCall).toBe(3);
118
+ });
119
+ });
120
+
121
+ it('should call transformParams middleware for doGenerate', async () => {
122
+ let capturedArgs!: Parameters<MockImageModelV3['doGenerate']>[0];
123
+
124
+ const mockModel = new MockImageModelV3({
125
+ doGenerate: vi.fn().mockImplementation(async args => {
126
+ capturedArgs = args;
127
+ return {
128
+ images: [],
129
+ warnings: [],
130
+ response: {
131
+ timestamp: new Date(),
132
+ modelId: 'test-model-id',
133
+ headers: undefined,
134
+ },
135
+ };
136
+ }),
137
+ });
138
+
139
+ const transformParams = vi.fn().mockImplementation(({ params }) => ({
140
+ ...params,
141
+ prompt: 'transformed',
142
+ }));
143
+
144
+ const wrappedModel = wrapImageModel({
145
+ model: mockModel,
146
+ middleware: {
147
+ specificationVersion: 'v3',
148
+ transformParams,
149
+ },
150
+ });
151
+
152
+ const params: ImageModelV3CallOptions = {
153
+ prompt: 'original',
154
+ n: 1,
155
+ size: undefined,
156
+ aspectRatio: undefined,
157
+ seed: undefined,
158
+ files: undefined,
159
+ mask: undefined,
160
+ providerOptions: {},
161
+ };
162
+
163
+ await wrappedModel.doGenerate(params);
164
+
165
+ expect(transformParams).toHaveBeenCalledWith({
166
+ params,
167
+ model: expect.any(Object),
168
+ });
169
+
170
+ expect(capturedArgs).toStrictEqual({
171
+ ...params,
172
+ prompt: 'transformed',
173
+ });
174
+ });
175
+
176
+ it('should call wrapGenerate middleware', async () => {
177
+ const mockModel = new MockImageModelV3({
178
+ doGenerate: vi.fn().mockResolvedValue({
179
+ images: [],
180
+ warnings: [],
181
+ response: {
182
+ timestamp: new Date(),
183
+ modelId: 'test-model-id',
184
+ headers: undefined,
185
+ },
186
+ }),
187
+ });
188
+
189
+ const wrapGenerate = vi
190
+ .fn()
191
+ .mockImplementation(({ doGenerate }) => doGenerate());
192
+
193
+ const wrappedModel = wrapImageModel({
194
+ model: mockModel,
195
+ middleware: {
196
+ specificationVersion: 'v3',
197
+ wrapGenerate,
198
+ },
199
+ });
200
+
201
+ const params: ImageModelV3CallOptions = {
202
+ prompt: 'original',
203
+ n: 1,
204
+ size: undefined,
205
+ aspectRatio: undefined,
206
+ seed: undefined,
207
+ files: undefined,
208
+ mask: undefined,
209
+ providerOptions: {},
210
+ };
211
+
212
+ await wrappedModel.doGenerate(params);
213
+
214
+ expect(wrapGenerate).toHaveBeenCalledWith({
215
+ doGenerate: expect.any(Function),
216
+ params,
217
+ model: mockModel,
218
+ });
219
+ });
220
+
221
+ it('should support models that use \"this\" context in maxImagesPerCall', async () => {
222
+ let maxImagesPerCallThis: unknown = undefined;
223
+
224
+ class MockImageModelWithThisContext extends MockImageModelV3 {
225
+ readonly value = 42;
226
+
227
+ constructor() {
228
+ super({
229
+ maxImagesPerCall: function () {
230
+ maxImagesPerCallThis = this;
231
+ return (this as any).value;
232
+ },
233
+ });
234
+ }
235
+ }
236
+
237
+ const model = new MockImageModelWithThisContext();
238
+
239
+ const wrappedModel = wrapImageModel({
240
+ model,
241
+ middleware: { specificationVersion: 'v3' },
242
+ });
243
+
244
+ if (!(wrappedModel.maxImagesPerCall instanceof Function)) {
245
+ throw new Error('Expected maxImagesPerCall to be a function');
246
+ }
247
+
248
+ const result = await wrappedModel.maxImagesPerCall({
249
+ modelId: wrappedModel.modelId,
250
+ });
251
+
252
+ expect(result).toBe(42);
253
+ expect(maxImagesPerCallThis).toBe(model);
254
+ });
255
+
256
+ describe('multiple middlewares', () => {
257
+ it('should call multiple transformParams middlewares in sequence for doGenerate', async () => {
258
+ let capturedArgs!: Parameters<MockImageModelV3['doGenerate']>[0];
259
+
260
+ const mockModel = new MockImageModelV3({
261
+ doGenerate: async args => {
262
+ capturedArgs = args;
263
+ return {
264
+ images: [],
265
+ warnings: [],
266
+ response: {
267
+ timestamp: new Date(),
268
+ modelId: 'test-model-id',
269
+ headers: undefined,
270
+ },
271
+ };
272
+ },
273
+ });
274
+
275
+ const transformParams1 = vi.fn().mockImplementation(({ params }) => ({
276
+ ...params,
277
+ transformationStep1: true,
278
+ }));
279
+
280
+ const transformParams2 = vi.fn().mockImplementation(({ params }) => ({
281
+ ...params,
282
+ transformationStep2: true,
283
+ }));
284
+
285
+ const wrappedModel = wrapImageModel({
286
+ model: mockModel,
287
+ middleware: [
288
+ {
289
+ specificationVersion: 'v3',
290
+ transformParams: transformParams1,
291
+ },
292
+ {
293
+ specificationVersion: 'v3',
294
+ transformParams: transformParams2,
295
+ },
296
+ ],
297
+ });
298
+
299
+ const params: ImageModelV3CallOptions = {
300
+ prompt: 'original',
301
+ n: 1,
302
+ size: undefined,
303
+ aspectRatio: undefined,
304
+ seed: undefined,
305
+ files: undefined,
306
+ mask: undefined,
307
+ providerOptions: {},
308
+ };
309
+
310
+ await wrappedModel.doGenerate(params);
311
+
312
+ expect(transformParams1).toHaveBeenCalledWith({
313
+ params,
314
+ model: expect.any(Object),
315
+ });
316
+
317
+ expect(transformParams2).toHaveBeenCalledWith({
318
+ params: { ...params, transformationStep1: true },
319
+ model: expect.any(Object),
320
+ });
321
+
322
+ expect(capturedArgs).toStrictEqual(
323
+ expect.objectContaining({
324
+ transformationStep1: true,
325
+ transformationStep2: true,
326
+ }),
327
+ );
328
+ });
329
+
330
+ it('should chain multiple wrapGenerate middlewares in the correct order', async () => {
331
+ const mockModel = new MockImageModelV3({
332
+ doGenerate: vi.fn().mockResolvedValue({
333
+ images: [],
334
+ warnings: [],
335
+ response: {
336
+ timestamp: new Date(),
337
+ modelId: 'test-model-id',
338
+ headers: undefined,
339
+ },
340
+ }),
341
+ });
342
+
343
+ const wrapGenerate1 = vi
344
+ .fn()
345
+ .mockImplementation(async ({ doGenerate }) => {
346
+ const result = await doGenerate();
347
+ return {
348
+ ...result,
349
+ wrapped: `wrapGenerate1(${(result as any).wrapped ?? 'result'})`,
350
+ };
351
+ });
352
+
353
+ const wrapGenerate2 = vi
354
+ .fn()
355
+ .mockImplementation(async ({ doGenerate }) => {
356
+ const result = await doGenerate();
357
+ return {
358
+ ...result,
359
+ wrapped: `wrapGenerate2(${(result as any).wrapped ?? 'result'})`,
360
+ };
361
+ });
362
+
363
+ const wrappedModel = wrapImageModel({
364
+ model: mockModel,
365
+ middleware: [
366
+ {
367
+ specificationVersion: 'v3',
368
+ wrapGenerate: wrapGenerate1,
369
+ },
370
+ {
371
+ specificationVersion: 'v3',
372
+ wrapGenerate: wrapGenerate2,
373
+ },
374
+ ],
375
+ });
376
+
377
+ const params: ImageModelV3CallOptions = {
378
+ prompt: 'original',
379
+ n: 1,
380
+ size: undefined,
381
+ aspectRatio: undefined,
382
+ seed: undefined,
383
+ files: undefined,
384
+ mask: undefined,
385
+ providerOptions: {},
386
+ };
387
+
388
+ const result = await wrappedModel.doGenerate(params);
389
+
390
+ expect((result as any).wrapped).toBe(
391
+ 'wrapGenerate1(wrapGenerate2(result))',
392
+ );
393
+ expect(wrapGenerate1).toHaveBeenCalled();
394
+ expect(wrapGenerate2).toHaveBeenCalled();
395
+ });
396
+
397
+ it('should not mutate the middleware array argument', async () => {
398
+ const middleware1 = {
399
+ specificationVersion: 'v3',
400
+ wrapStream: vi.fn(),
401
+ };
402
+
403
+ const middleware2 = {
404
+ specificationVersion: 'v3',
405
+ wrapStream: vi.fn(),
406
+ };
407
+
408
+ const middlewares = [
409
+ middleware1,
410
+ middleware2,
411
+ ] as ImageModelV3Middleware[];
412
+
413
+ wrapImageModel({
414
+ model: new MockImageModelV3(),
415
+ middleware: middlewares,
416
+ });
417
+
418
+ expect(middlewares.length).toBe(2);
419
+ expect(middlewares[0]).toBe(middleware1);
420
+ expect(middlewares[1]).toBe(middleware2);
421
+ });
422
+ });
423
+ });
@@ -0,0 +1,85 @@
1
+ import { ImageModelV3, ImageModelV3CallOptions } from '@ai-sdk/provider';
2
+ import { ImageModelMiddleware } from '../types';
3
+ import { asArray } from '../util/as-array';
4
+
5
+ /**
6
+ * Wraps an ImageModelV3 instance with middleware functionality.
7
+ * This function allows you to apply middleware to transform parameters
8
+ * and wrap generate operations of an image model.
9
+ *
10
+ * @param options - Configuration options for wrapping the image model.
11
+ * @param options.model - The original ImageModelV3 instance to be wrapped.
12
+ * @param options.middleware - The middleware to be applied to the image model. When multiple middlewares are provided, the first middleware will transform the input first, and the last middleware will be wrapped directly around the model.
13
+ * @param options.modelId - Optional custom model ID to override the original model's ID.
14
+ * @param options.providerId - Optional custom provider ID to override the original model's provider ID.
15
+ * @returns A new ImageModelV3 instance with middleware applied.
16
+ */
17
+ export const wrapImageModel = ({
18
+ model,
19
+ middleware: middlewareArg,
20
+ modelId,
21
+ providerId,
22
+ }: {
23
+ model: ImageModelV3;
24
+ middleware: ImageModelMiddleware | ImageModelMiddleware[];
25
+ modelId?: string;
26
+ providerId?: string;
27
+ }): ImageModelV3 => {
28
+ return [...asArray(middlewareArg)]
29
+ .reverse()
30
+ .reduce((wrappedModel, middleware) => {
31
+ return doWrap({ model: wrappedModel, middleware, modelId, providerId });
32
+ }, model);
33
+ };
34
+
35
+ const doWrap = ({
36
+ model,
37
+ middleware: {
38
+ transformParams,
39
+ wrapGenerate,
40
+ overrideProvider,
41
+ overrideModelId,
42
+ overrideMaxImagesPerCall,
43
+ },
44
+ modelId,
45
+ providerId,
46
+ }: {
47
+ model: ImageModelV3;
48
+ middleware: ImageModelMiddleware;
49
+ modelId?: string;
50
+ providerId?: string;
51
+ }): ImageModelV3 => {
52
+ async function doTransform({ params }: { params: ImageModelV3CallOptions }) {
53
+ return transformParams ? await transformParams({ params, model }) : params;
54
+ }
55
+
56
+ const maxImagesPerCallRaw =
57
+ overrideMaxImagesPerCall?.({ model }) ?? model.maxImagesPerCall;
58
+
59
+ // Ensure provider implementations that rely on `this` inside `maxImagesPerCall`
60
+ // keep working after the value is copied onto the wrapper object.
61
+ const maxImagesPerCall =
62
+ maxImagesPerCallRaw instanceof Function
63
+ ? maxImagesPerCallRaw.bind(model)
64
+ : maxImagesPerCallRaw;
65
+
66
+ return {
67
+ specificationVersion: 'v3',
68
+ provider: providerId ?? overrideProvider?.({ model }) ?? model.provider,
69
+ modelId: modelId ?? overrideModelId?.({ model }) ?? model.modelId,
70
+ maxImagesPerCall,
71
+ async doGenerate(
72
+ params: ImageModelV3CallOptions,
73
+ ): Promise<Awaited<ReturnType<ImageModelV3['doGenerate']>>> {
74
+ const transformedParams = await doTransform({ params });
75
+ const doGenerate = async () => model.doGenerate(transformedParams);
76
+ return wrapGenerate
77
+ ? wrapGenerate({
78
+ doGenerate,
79
+ params: transformedParams,
80
+ model,
81
+ })
82
+ : doGenerate();
83
+ },
84
+ };
85
+ };