ai 6.0.216 → 6.0.217

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.
@@ -152,7 +152,7 @@ function detectMediaType({
152
152
  var import_provider_utils2 = require("@ai-sdk/provider-utils");
153
153
 
154
154
  // src/version.ts
155
- var VERSION = true ? "6.0.216" : "0.0.0-test";
155
+ var VERSION = true ? "6.0.217" : "0.0.0-test";
156
156
 
157
157
  // src/util/download/download.ts
158
158
  var download = async ({
@@ -132,7 +132,7 @@ import {
132
132
  } from "@ai-sdk/provider-utils";
133
133
 
134
134
  // src/version.ts
135
- var VERSION = true ? "6.0.216" : "0.0.0-test";
135
+ var VERSION = true ? "6.0.217" : "0.0.0-test";
136
136
 
137
137
  // src/util/download/download.ts
138
138
  var download = async ({
@@ -133,6 +133,7 @@ Here are the capabilities of popular models:
133
133
  | [OpenAI](/providers/ai-sdk-providers/openai) | `gpt-5.1` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
134
134
  | [OpenAI](/providers/ai-sdk-providers/openai) | `gpt-5-codex` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
135
135
  | [OpenAI](/providers/ai-sdk-providers/openai) | `gpt-5-chat-latest` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
136
+ | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-sonnet-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
136
137
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-fable-5` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
137
138
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-opus-4-8` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
138
139
  | [Anthropic](/providers/ai-sdk-providers/anthropic) | `claude-opus-4-7` | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> | <Check size={18} /> |
@@ -171,6 +171,46 @@ const { video } = await generateVideo({
171
171
  });
172
172
  ```
173
173
 
174
+ ### First and Last Frame
175
+
176
+ Some video models support first-last-frame generation, where you provide the
177
+ starting and/or ending frames of the video. Use the `frameImages` option to pass
178
+ role-tagged images in a provider-agnostic way:
179
+
180
+ ```tsx highlight={"5-16"}
181
+ const { video } = await generateVideo({
182
+ model: __VIDEO_MODEL__,
183
+ prompt: 'The cat walks across the scene and transforms into a dog by the end',
184
+ frameImages: [
185
+ {
186
+ image: 'https://example.com/first-frame.png',
187
+ frameType: 'first_frame',
188
+ },
189
+ {
190
+ image: 'https://example.com/last-frame.png',
191
+ frameType: 'last_frame',
192
+ },
193
+ ],
194
+ });
195
+ ```
196
+
197
+ ### Reference Images
198
+
199
+ Some video models support reference-to-video generation, where you provide one or
200
+ more reference images that the model incorporates into the generated video. Use the `inputReferences` option to pass
201
+ these images in a provider-agnostic way:
202
+
203
+ ```tsx highlight={"5-8"}
204
+ const { video } = await generateVideo({
205
+ model: __VIDEO_MODEL__,
206
+ prompt: 'The two characters meet in a bustling market',
207
+ inputReferences: [
208
+ 'https://example.com/character-1.png',
209
+ 'https://example.com/character-2.png',
210
+ ],
211
+ });
212
+ ```
213
+
174
214
  ### Providing a Seed
175
215
 
176
216
  You can provide a seed to the `experimental_generateVideo` function to control the output of the video generation process.
@@ -271,15 +271,15 @@ Find more examples at this [link](https://github.com/minpeter/ai-sdk-tool-call-m
271
271
  <Note>
272
272
  Implementing language model middleware is advanced functionality and requires
273
273
  a solid understanding of the [language model
274
- specification](https://github.com/vercel/ai/blob/v5/packages/provider/src/language-model/v2/language-model-v2.ts).
274
+ specification](https://github.com/vercel/ai/blob/release-v6.0/packages/provider/src/language-model/v3/language-model-v3.ts).
275
275
  </Note>
276
276
 
277
277
  You can implement any of the following three function to modify the behavior of the language model:
278
278
 
279
279
  1. `transformParams`: Transforms the parameters before they are passed to the language model, for both `doGenerate` and `doStream`.
280
- 2. `wrapGenerate`: Wraps the `doGenerate` method of the [language model](https://github.com/vercel/ai/blob/v5/packages/provider/src/language-model/v2/language-model-v2.ts).
280
+ 2. `wrapGenerate`: Wraps the `doGenerate` method of the [language model](https://github.com/vercel/ai/blob/release-v6.0/packages/provider/src/language-model/v3/language-model-v3.ts).
281
281
  You can modify the parameters, call the language model, and modify the result.
282
- 3. `wrapStream`: Wraps the `doStream` method of the [language model](https://github.com/vercel/ai/blob/v5/packages/provider/src/language-model/v2/language-model-v2.ts).
282
+ 3. `wrapStream`: Wraps the `doStream` method of the [language model](https://github.com/vercel/ai/blob/release-v6.0/packages/provider/src/language-model/v3/language-model-v3.ts).
283
283
  You can modify the parameters, call the language model, and modify the result.
284
284
 
285
285
  Here are some examples of how to implement language model middleware:
@@ -110,6 +110,18 @@ console.log(videos);
110
110
  isOptional: true,
111
111
  description: 'Seed for the video generation.',
112
112
  },
113
+ {
114
+ name: 'frameImages',
115
+ type: 'Array<{ image: DataContent; frameType: "first_frame" | "last_frame" }>',
116
+ isOptional: true,
117
+ description: 'Role-tagged image inputs for first-last-frame generation.',
118
+ },
119
+ {
120
+ name: 'inputReferences',
121
+ type: 'Array<DataContent>',
122
+ isOptional: true,
123
+ description: 'Reference image inputs for reference-to-video generation.',
124
+ },
113
125
  {
114
126
  name: 'generateAudio',
115
127
  type: 'boolean',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "6.0.216",
3
+ "version": "6.0.217",
4
4
  "description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -45,9 +45,9 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@opentelemetry/api": "^1.9.0",
48
- "@ai-sdk/gateway": "3.0.140",
49
- "@ai-sdk/provider": "3.0.12",
50
- "@ai-sdk/provider-utils": "4.0.33"
48
+ "@ai-sdk/gateway": "3.0.141",
49
+ "@ai-sdk/provider": "3.0.13",
50
+ "@ai-sdk/provider-utils": "4.0.34"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@edge-runtime/vm": "^5.0.0",
@@ -2,6 +2,8 @@ import type {
2
2
  Experimental_VideoModelV3,
3
3
  Experimental_VideoModelV3CallOptions,
4
4
  Experimental_VideoModelV3File,
5
+ Experimental_VideoModelV3FrameImage,
6
+ Experimental_VideoModelV3FrameType,
5
7
  SharedV3ProviderMetadata,
6
8
  } from '@ai-sdk/provider';
7
9
  import {
@@ -30,6 +32,7 @@ import { prepareRetries } from '../util/prepare-retries';
30
32
  import { VERSION } from '../version';
31
33
  import type { GenerateVideoResult } from './generate-video-result';
32
34
  import { splitDataUrl } from '../prompt/split-data-url';
35
+ import { convertDataContentToUint8Array } from '../prompt/data-content';
33
36
 
34
37
  export type GenerateVideoPrompt =
35
38
  | string
@@ -49,6 +52,8 @@ export type GenerateVideoPrompt =
49
52
  * @param duration - Duration of the video in seconds.
50
53
  * @param fps - Frames per second for the video.
51
54
  * @param seed - Seed for the video generation.
55
+ * @param frameImages - Role-tagged image inputs for image-to-video and first-last-frame generation.
56
+ * @param inputReferences - Reference image inputs for reference-to-video generation.
52
57
  * @param generateAudio - Whether the model should generate audio alongside the video.
53
58
  * @param providerOptions - Additional provider-specific options that are passed through to the provider
54
59
  * as body parameters.
@@ -70,6 +75,8 @@ export async function experimental_generateVideo({
70
75
  duration,
71
76
  fps,
72
77
  seed,
78
+ frameImages,
79
+ inputReferences,
73
80
  generateAudio,
74
81
  providerOptions,
75
82
  maxRetries: maxRetriesArg,
@@ -122,6 +129,26 @@ export async function experimental_generateVideo({
122
129
  */
123
130
  seed?: number;
124
131
 
132
+ /**
133
+ * Role-tagged image inputs for image-to-video and first-last-frame generation.
134
+ */
135
+ frameImages?: Array<{
136
+ /**
137
+ * The image for this frame.
138
+ */
139
+ image: DataContent;
140
+
141
+ /**
142
+ * Which frame this image represents.
143
+ */
144
+ frameType: Experimental_VideoModelV3FrameType;
145
+ }>;
146
+
147
+ /**
148
+ * Reference image inputs for reference-to-video generation.
149
+ */
150
+ inputReferences?: Array<DataContent>;
151
+
125
152
  /**
126
153
  * Whether the model should generate audio alongside the video.
127
154
  */
@@ -176,6 +203,55 @@ export async function experimental_generateVideo({
176
203
 
177
204
  const { prompt, image } = normalizePrompt(promptArg);
178
205
 
206
+ const normalizedFrameImages:
207
+ | Array<Experimental_VideoModelV3FrameImage>
208
+ | undefined = frameImages?.map(frame => ({
209
+ image: normalizeImageData(frame.image),
210
+ frameType: frame.frameType,
211
+ }));
212
+
213
+ const normalizedInputReferences:
214
+ | Array<Experimental_VideoModelV3File>
215
+ | undefined = inputReferences?.map(reference =>
216
+ normalizeImageData(reference),
217
+ );
218
+
219
+ const effectiveInputReferences =
220
+ normalizedFrameImages != null && normalizedFrameImages.length > 0
221
+ ? undefined
222
+ : normalizedInputReferences;
223
+
224
+ const warnings: Array<Warning> = [];
225
+
226
+ if (
227
+ normalizedFrameImages != null &&
228
+ normalizedFrameImages.length > 0 &&
229
+ normalizedInputReferences != null &&
230
+ normalizedInputReferences.length > 0
231
+ ) {
232
+ warnings.push({
233
+ type: 'other',
234
+ message:
235
+ 'inputReferences were ignored because frameImages were provided; ' +
236
+ 'frameImages and inputReferences cannot be combined.',
237
+ });
238
+ }
239
+
240
+ const firstFrameImage = normalizedFrameImages?.find(
241
+ frame => frame.frameType === 'first_frame',
242
+ )?.image;
243
+
244
+ if (image != null && firstFrameImage != null) {
245
+ warnings.push({
246
+ type: 'other',
247
+ message:
248
+ 'prompt.image was ignored because a first_frame frameImage was provided; ' +
249
+ 'the first_frame frameImage takes precedence as the start image.',
250
+ });
251
+ }
252
+
253
+ const resolvedImage = firstFrameImage ?? image;
254
+
179
255
  const maxVideosPerCallWithDefault =
180
256
  maxVideosPerCall ?? (await invokeModelMaxVideosPerCall(model)) ?? 1;
181
257
 
@@ -187,29 +263,31 @@ export async function experimental_generateVideo({
187
263
  });
188
264
 
189
265
  const results = await Promise.all(
190
- callVideoCounts.map(async callVideoCount =>
191
- retry(() =>
192
- model.doGenerate({
193
- prompt,
194
- n: callVideoCount,
195
- aspectRatio,
196
- resolution,
197
- duration,
198
- fps,
199
- seed,
200
- generateAudio,
201
- image,
202
- providerOptions: providerOptions ?? {},
203
- headers: headersWithUserAgent,
204
- abortSignal,
205
- } satisfies Experimental_VideoModelV3CallOptions),
206
- ),
266
+ callVideoCounts.map(
267
+ async callVideoCount =>
268
+ await retry(() =>
269
+ model.doGenerate({
270
+ prompt,
271
+ n: callVideoCount,
272
+ aspectRatio,
273
+ resolution,
274
+ duration,
275
+ fps,
276
+ seed,
277
+ image: resolvedImage,
278
+ frameImages: normalizedFrameImages,
279
+ inputReferences: effectiveInputReferences,
280
+ generateAudio,
281
+ providerOptions: providerOptions ?? {},
282
+ headers: headersWithUserAgent,
283
+ abortSignal,
284
+ } satisfies Experimental_VideoModelV3CallOptions),
285
+ ),
207
286
  ),
208
287
  );
209
288
 
210
289
  // collect result videos, warnings, and response metadata
211
290
  const videos: Array<GeneratedFile> = [];
212
- const warnings: Array<Warning> = [];
213
291
  const responses: Array<VideoModelResponseMetadata> = [];
214
292
  const providerMetadata: SharedV3ProviderMetadata = {};
215
293
 
@@ -345,59 +423,59 @@ function normalizePrompt(promptArg: GenerateVideoPrompt): {
345
423
  };
346
424
  }
347
425
 
348
- let image: Experimental_VideoModelV3File | undefined;
349
-
350
- if (promptArg.image != null) {
351
- const dataContent = promptArg.image;
352
-
353
- if (typeof dataContent === 'string') {
354
- if (
355
- dataContent.startsWith('http://') ||
356
- dataContent.startsWith('https://')
357
- ) {
358
- image = {
359
- type: 'url',
360
- url: dataContent,
361
- };
362
- } else if (dataContent.startsWith('data:')) {
363
- const { mediaType, base64Content } = splitDataUrl(dataContent);
364
- image = {
365
- type: 'file',
366
- mediaType: mediaType ?? 'image/png',
367
- data: convertBase64ToUint8Array(base64Content ?? ''),
368
- };
369
- } else {
370
- const bytes = convertBase64ToUint8Array(dataContent);
371
- const mediaType =
372
- detectMediaType({
373
- data: bytes,
374
- signatures: imageMediaTypeSignatures,
375
- }) ?? 'image/png';
376
-
377
- image = {
378
- type: 'file',
379
- mediaType,
380
- data: bytes,
381
- };
382
- }
383
- } else if (dataContent instanceof Uint8Array) {
384
- const mediaType =
385
- detectMediaType({
386
- data: dataContent,
387
- signatures: imageMediaTypeSignatures,
388
- }) ?? 'image/png';
426
+ return {
427
+ prompt: promptArg.text,
428
+ image:
429
+ promptArg.image != null ? normalizeImageData(promptArg.image) : undefined,
430
+ };
431
+ }
432
+
433
+ /**
434
+ * Normalizes a {@link DataContent} image into a {@link Experimental_VideoModelV3File}.
435
+ * Accepts a URL string, a data URL, a base64 string, or binary image data.
436
+ */
437
+ function normalizeImageData(
438
+ dataContent: DataContent,
439
+ ): Experimental_VideoModelV3File {
440
+ if (typeof dataContent === 'string') {
441
+ if (
442
+ dataContent.startsWith('http://') ||
443
+ dataContent.startsWith('https://')
444
+ ) {
445
+ return {
446
+ type: 'url',
447
+ url: dataContent,
448
+ };
449
+ }
389
450
 
390
- image = {
451
+ if (dataContent.startsWith('data:')) {
452
+ const { mediaType, base64Content } = splitDataUrl(dataContent);
453
+ return {
391
454
  type: 'file',
392
- mediaType,
393
- data: dataContent,
455
+ mediaType: mediaType ?? 'image/png',
456
+ data: convertBase64ToUint8Array(base64Content ?? ''),
394
457
  };
395
458
  }
459
+
460
+ const bytes = convertBase64ToUint8Array(dataContent);
461
+ return {
462
+ type: 'file',
463
+ mediaType:
464
+ detectMediaType({
465
+ data: bytes,
466
+ signatures: imageMediaTypeSignatures,
467
+ }) ?? 'image/png',
468
+ data: bytes,
469
+ };
396
470
  }
397
471
 
472
+ const bytes = convertDataContentToUint8Array(dataContent);
398
473
  return {
399
- prompt: promptArg.text,
400
- image,
474
+ type: 'file',
475
+ mediaType:
476
+ detectMediaType({ data: bytes, signatures: imageMediaTypeSignatures }) ??
477
+ 'image/png',
478
+ data: bytes,
401
479
  };
402
480
  }
403
481