Skip to content

Commit bacdae4

Browse files
vercel-ai-sdk[bot]Jaaneekfelixarntz
authored
Backport: feat(provider/xai): add video extension and reference-to-video (R2V) support (#14079)
This is an automated backport of #13887 to the release-v6.0 branch. FYI @Jaaneek ~~This backport has conflicts that need to be resolved manually.~~ Conflicts resolved. ### `git cherry-pick` output ``` Auto-merging content/providers/01-ai-sdk-providers/01-xai.mdx Auto-merging packages/xai/src/xai-video-model.test.ts Auto-merging packages/xai/src/xai-video-model.ts CONFLICT (content): Merge conflict in packages/xai/src/xai-video-model.ts error: could not apply f51c95e... feat(provider/xai): add video extension and reference-to-video (R2V) support (#13887) hint: After resolving the conflicts, mark them with hint: "git add/rm <pathspec>", then run hint: "git cherry-pick --continue". hint: You can instead skip this commit with "git cherry-pick --skip". hint: To abort and get back to the state before "git cherry-pick", hint: run "git cherry-pick --abort". hint: Disable this message with "git config set advice.mergeConflict false" ``` --------- Co-authored-by: Jaaneek <25470423+Jaaneek@users.noreply.github.com> Co-authored-by: Felix Arntz <felix.arntz@vercel.com>
1 parent 8aefbbb commit bacdae4

16 files changed

Lines changed: 1288 additions & 87 deletions

File tree

.changeset/tidy-pumpkins-rest.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ai-sdk/xai": patch
3+
---
4+
5+
feat(provider/xai): add video extension and reference-to-video (R2V) support

content/docs/03-ai-sdk-core/38-video-generation.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,6 @@ try {
361361
| [Kling AI](/providers/ai-sdk-providers/klingai#video-models) | `kling-v2.6-i2v` | Image-to-video |
362362
| [Kling AI](/providers/ai-sdk-providers/klingai#video-models) | `kling-v2.6-motion-control` | Motion control |
363363
| [Replicate](/providers/ai-sdk-providers/replicate#video-models) | `minimax/video-01` | Text-to-video |
364-
| [xAI](/providers/ai-sdk-providers/xai#video-models) | `grok-imagine-video` | Text-to-video, image-to-video, editing |
364+
| [xAI](/providers/ai-sdk-providers/xai#video-models) | `grok-imagine-video` | Text-to-video, image-to-video, editing, extension, R2V |
365365

366366
Above are a small subset of the video models supported by the AI SDK providers. For more, see the respective provider documentation.

content/providers/01-ai-sdk-providers/01-xai.mdx

Lines changed: 166 additions & 47 deletions
Large diffs are not rendered by default.

examples/ai-functions/src/generate-video/xai/basic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { run } from '../../lib/run';
55
import { withSpinner } from '../../lib/spinner';
66

77
run(async () => {
8-
const { videos } = await withSpinner(
8+
const { video } = await withSpinner(
99
'Generating xAI video with grok-imagine-video...',
1010
() =>
1111
generateVideo({
@@ -21,5 +21,5 @@ run(async () => {
2121
}),
2222
);
2323

24-
await presentVideos(videos);
24+
await presentVideos([video]);
2525
});

examples/ai-functions/src/generate-video/xai/edit-concurrent.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ run(async () => {
1212
prompt: 'Make the cat look like a princess with a small tiara',
1313
providerOptions: {
1414
xai: {
15+
mode: 'edit-video',
1516
videoUrl:
1617
'https://raw.githubusercontent.com/vercel/ai/refs/heads/main/examples/ai-functions/data/prudence.mp4',
1718
pollTimeoutMs: 600000,
@@ -24,7 +25,12 @@ run(async () => {
2425
await presentVideos(step1.videos);
2526

2627
// Use the xAI-hosted URL from step 1 as input for the next two edits
27-
const step1VideoUrl = step1.providerMetadata?.xai?.videoUrl as string;
28+
const step1VideoUrl = step1.providerMetadata?.xai?.videoUrl as
29+
| string
30+
| undefined;
31+
if (step1VideoUrl == null) {
32+
throw new Error('xAI provider metadata did not include a step-1 videoUrl.');
33+
}
2834

2935
// Step 2: Apply two more edits concurrently, building on step 1
3036
const edits = [
@@ -42,6 +48,7 @@ run(async () => {
4248
prompt,
4349
providerOptions: {
4450
xai: {
51+
mode: 'edit-video',
4552
videoUrl: step1VideoUrl,
4653
pollTimeoutMs: 600000,
4754
} satisfies XaiVideoModelOptions,

examples/ai-functions/src/generate-video/xai/edit.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ import { run } from '../../lib/run';
55
import { withSpinner } from '../../lib/spinner';
66

77
run(async () => {
8-
const { videos } = await withSpinner(
8+
const { video } = await withSpinner(
99
'Editing video with xAI grok-imagine-video...',
1010
() =>
1111
generateVideo({
1212
model: xai.video('grok-imagine-video'),
1313
prompt: 'Render this cat as a dog in the style of 90s anime.',
1414
providerOptions: {
1515
xai: {
16+
mode: 'edit-video',
1617
videoUrl:
1718
'https://raw.githubusercontent.com/vercel/ai/refs/heads/main/examples/ai-functions/data/prudence.mp4',
1819
pollTimeoutMs: 600000, // 10 minutes
@@ -21,5 +22,5 @@ run(async () => {
2122
}),
2223
);
2324

24-
await presentVideos(videos);
25+
await presentVideos([video]);
2526
});
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { type XaiVideoModelOptions, xai } from '@ai-sdk/xai';
2+
import { experimental_generateVideo as generateVideo } from 'ai';
3+
import { run } from '../../lib/run';
4+
5+
// Demonstrates that aspectRatio and resolution are silently ignored
6+
// (with a warning) when using extension mode.
7+
run(async () => {
8+
console.log('Step 1: generating a source video...');
9+
const source = await generateVideo({
10+
model: xai.video('grok-imagine-video'),
11+
prompt: 'A cat sitting on a windowsill.',
12+
duration: 3,
13+
providerOptions: {
14+
xai: { pollTimeoutMs: 600000 } satisfies XaiVideoModelOptions,
15+
},
16+
});
17+
18+
const sourceUrl = source.providerMetadata?.xai?.videoUrl as
19+
| string
20+
| undefined;
21+
if (sourceUrl == null) {
22+
throw new Error('xAI provider metadata did not include a source videoUrl.');
23+
}
24+
25+
console.log('Source video URL:', sourceUrl);
26+
27+
console.log('\nStep 2: extending with unsupported params...');
28+
const result = await generateVideo({
29+
model: xai.video('grok-imagine-video'),
30+
prompt: 'The cat stretches and jumps off the windowsill.',
31+
duration: 5,
32+
aspectRatio: '16:9',
33+
resolution: '1280x720',
34+
providerOptions: {
35+
xai: {
36+
mode: 'extend-video',
37+
videoUrl: sourceUrl,
38+
pollTimeoutMs: 600000,
39+
} satisfies XaiVideoModelOptions,
40+
},
41+
});
42+
43+
console.log('\nWarnings (aspectRatio and resolution are unsupported):');
44+
console.log(JSON.stringify(result.warnings, null, 2));
45+
});
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { type XaiVideoModelOptions, xai } from '@ai-sdk/xai';
2+
import { experimental_generateVideo as generateVideo } from 'ai';
3+
import { presentVideos } from '../../lib/present-video';
4+
import { run } from '../../lib/run';
5+
import { withSpinner } from '../../lib/spinner';
6+
7+
// Video extension: continue an existing video from its last frame.
8+
// The `duration` controls the length of the *extension* only, not the total.
9+
// `aspectRatio` and `resolution` are not supported in extension mode — the
10+
// output inherits those from the input video.
11+
run(async () => {
12+
// Step 1: Generate a short source video.
13+
const source = await withSpinner('Step 1: Generating source video...', () =>
14+
generateVideo({
15+
model: xai.video('grok-imagine-video'),
16+
prompt: 'A cat sitting on a sunlit windowsill, tail gently swishing.',
17+
duration: 5,
18+
aspectRatio: '16:9',
19+
providerOptions: {
20+
xai: { pollTimeoutMs: 600000 } satisfies XaiVideoModelOptions,
21+
},
22+
}),
23+
);
24+
25+
const sourceUrl = source.providerMetadata?.xai?.videoUrl as
26+
| string
27+
| undefined;
28+
if (sourceUrl == null) {
29+
throw new Error('xAI provider metadata did not include a source videoUrl.');
30+
}
31+
32+
console.log('Source video URL:', sourceUrl);
33+
await presentVideos(source.videos);
34+
35+
// Step 2: Extend the video with a new scene.
36+
const extended = await withSpinner(
37+
'Step 2: Extending video with a new scene...',
38+
() =>
39+
generateVideo({
40+
model: xai.video('grok-imagine-video'),
41+
prompt:
42+
'The cat slowly turns its head, notices a butterfly, and leaps off the windowsill.',
43+
duration: 6,
44+
providerOptions: {
45+
xai: {
46+
mode: 'extend-video',
47+
videoUrl: sourceUrl,
48+
pollTimeoutMs: 600000,
49+
} satisfies XaiVideoModelOptions,
50+
},
51+
}),
52+
);
53+
54+
console.log('\nExtended video (original 5s + 6s extension = 11s total):');
55+
console.log(
56+
'Provider metadata:',
57+
JSON.stringify(extended.providerMetadata, null, 2),
58+
);
59+
await presentVideos(extended.videos);
60+
});

examples/ai-functions/src/generate-video/xai/i2v-base64.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { run } from '../../lib/run';
66
import { withSpinner } from '../../lib/spinner';
77

88
run(async () => {
9-
const { videos } = await withSpinner(
9+
const { video } = await withSpinner(
1010
'Generating xAI image-to-video from base64...',
1111
() =>
1212
generateVideo({
@@ -24,5 +24,5 @@ run(async () => {
2424
}),
2525
);
2626

27-
await presentVideos(videos);
27+
await presentVideos([video]);
2828
});

examples/ai-functions/src/generate-video/xai/i2v-url.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { run } from '../../lib/run';
55
import { withSpinner } from '../../lib/spinner';
66

77
run(async () => {
8-
const { videos } = await withSpinner(
8+
const { video } = await withSpinner(
99
'Generating xAI image-to-video with grok-imagine-video...',
1010
() =>
1111
generateVideo({
@@ -24,5 +24,5 @@ run(async () => {
2424
}),
2525
);
2626

27-
await presentVideos(videos);
27+
await presentVideos([video]);
2828
});

0 commit comments

Comments
 (0)