@ai-sdk/xai 4.0.35 → 4.0.37
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.
- package/CHANGELOG.md +13 -0
- package/dist/index.d.ts +14 -3
- package/dist/index.js +66 -64
- package/dist/index.js.map +1 -1
- package/docs/01-xai.mdx +92 -14
- package/package.json +3 -3
- package/src/responses/xai-responses-language-model-options.ts +6 -2
- package/src/responses/xai-responses-language-model.ts +1 -1
- package/src/xai-chat-language-model-options.ts +5 -1
- package/src/xai-chat-language-model.ts +1 -1
- package/src/xai-video-model-options.ts +10 -43
- package/src/xai-video-model.ts +109 -30
- package/src/xai-video-settings.ts +4 -1
package/docs/01-xai.mdx
CHANGED
|
@@ -121,16 +121,20 @@ The AI SDK option accepts these values, but each xAI model supports a subset:
|
|
|
121
121
|
- `'high'` — More reasoning tokens for deeper thinking. Suited for very
|
|
122
122
|
challenging problems, complex math, multi-step logic, and competition-level
|
|
123
123
|
tasks.
|
|
124
|
+
- `'xhigh'` — Uses the most reasoning tokens for the most challenging tasks.
|
|
125
|
+
This level is only supported by `grok-4.6`.
|
|
124
126
|
|
|
125
127
|
<Note>
|
|
126
128
|
Support and defaults are model-specific. `grok-4.3` supports `'none'`,
|
|
127
129
|
`'low'`, `'medium'`, and `'high'`. `grok-4.5` supports `'low'`, `'medium'`,
|
|
128
|
-
and `'high'`, defaults to `'high'`, and cannot disable reasoning.
|
|
129
|
-
`
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
and `'high'`, defaults to `'high'`, and cannot disable reasoning. `grok-4.6`
|
|
131
|
+
supports `'low'`, `'medium'`, `'high'`, and `'xhigh'`, and defaults to
|
|
132
|
+
`'high'`. The `grok-4.20-reasoning` and `grok-4.20-non-reasoning` variants do
|
|
133
|
+
not accept this option. For `grok-4.20-multi-agent`, `'low'`, `'medium'`, and
|
|
134
|
+
`'high'` control the number of agents instead of reasoning depth. See xAI's
|
|
135
|
+
[reasoning
|
|
132
136
|
docs](https://docs.x.ai/developers/model-capabilities/text/reasoning) and
|
|
133
|
-
[Grok 4.
|
|
137
|
+
[Grok 4.6 model page](https://docs.x.ai/developers/models/grok-4.6) for
|
|
134
138
|
current details.
|
|
135
139
|
</Note>
|
|
136
140
|
|
|
@@ -590,6 +594,7 @@ The following provider options are available:
|
|
|
590
594
|
|
|
591
595
|
| Model | Image Input | Object Generation | Tool Usage | Tool Streaming | Reasoning |
|
|
592
596
|
| ----------------------------- | ----------- | ----------------- | ---------- | -------------- | --------- |
|
|
597
|
+
| `grok-4.6` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
593
598
|
| `grok-4.5` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
594
599
|
| `grok-4.20-reasoning` | <Check /> | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
595
600
|
| `grok-4.20-non-reasoning` | <Check /> | <Check /> | <Check /> | <Check /> | <Cross /> |
|
|
@@ -1223,12 +1228,64 @@ const { video } = await generateVideo({
|
|
|
1223
1228
|
});
|
|
1224
1229
|
```
|
|
1225
1230
|
|
|
1231
|
+
`inputReferences` accepts image references only. A reference with a non-image
|
|
1232
|
+
media type (for example a video or audio clip) is ignored with a warning, and a
|
|
1233
|
+
reference with no media type is treated as an image. If no image reference
|
|
1234
|
+
remains, reference-to-video is not selected and no reference images are sent.
|
|
1235
|
+
|
|
1236
|
+
#### Reference Audio
|
|
1237
|
+
|
|
1238
|
+
Reference-to-video can also give the subject a voice. `referenceVoiceIds` takes
|
|
1239
|
+
up to 3 xAI **preset** voice ids — you cannot upload your own audio clips.
|
|
1240
|
+
Reference the voices from the prompt with `<AUDIO_0>`, `<AUDIO_1>`, and
|
|
1241
|
+
`<AUDIO_2>`, in the order the voices are passed.
|
|
1242
|
+
|
|
1243
|
+
```ts
|
|
1244
|
+
import { xai, type XaiVideoModelOptions } from '@ai-sdk/xai';
|
|
1245
|
+
import { experimental_generateVideo as generateVideo } from 'ai';
|
|
1246
|
+
|
|
1247
|
+
const { video } = await generateVideo({
|
|
1248
|
+
model: xai.video('grok-imagine-video-1.5'),
|
|
1249
|
+
prompt:
|
|
1250
|
+
'The person from <IMAGE_0> stands in the room from <IMAGE_1> and speaks ' +
|
|
1251
|
+
'to the camera with the voice from <AUDIO_0>.',
|
|
1252
|
+
aspectRatio: '9:16',
|
|
1253
|
+
duration: 10,
|
|
1254
|
+
providerOptions: {
|
|
1255
|
+
xai: {
|
|
1256
|
+
mode: 'reference-to-video',
|
|
1257
|
+
referenceImageUrls: [
|
|
1258
|
+
'https://example.com/person.png',
|
|
1259
|
+
'https://example.com/room.png',
|
|
1260
|
+
],
|
|
1261
|
+
referenceVoiceIds: ['eve'],
|
|
1262
|
+
resolution: '720p',
|
|
1263
|
+
pollTimeoutMs: 600000,
|
|
1264
|
+
} satisfies XaiVideoModelOptions,
|
|
1265
|
+
},
|
|
1266
|
+
});
|
|
1267
|
+
```
|
|
1268
|
+
|
|
1269
|
+
Valid voice ids come from the xAI
|
|
1270
|
+
[text-to-speech voice roster](https://docs.x.ai/developers/model-capabilities/audio/text-to-speech#voices).
|
|
1271
|
+
Ids are case-insensitive, and an unknown id returns a `400` response listing the
|
|
1272
|
+
available voices. `referenceVoiceIds` is ignored with a warning when the
|
|
1273
|
+
resolved operation is not reference-to-video.
|
|
1274
|
+
|
|
1275
|
+
<Note>
|
|
1276
|
+
xAI documents reference audio as available in the United States only, for
|
|
1277
|
+
trusted partners. Requests from accounts without access are rejected by the
|
|
1278
|
+
xAI API.
|
|
1279
|
+
</Note>
|
|
1280
|
+
|
|
1226
1281
|
<Note>
|
|
1227
1282
|
Reference-to-video supports `duration`, `aspectRatio`, and `resolution`. Use
|
|
1228
1283
|
`mode` to select the operation — each mode is mutually exclusive. When both
|
|
1229
1284
|
are provided, `frameImages` takes precedence over `inputReferences`, and
|
|
1230
1285
|
`inputReferences` takes precedence over the legacy `referenceImageUrls`
|
|
1231
|
-
provider option. Reference-to-video
|
|
1286
|
+
provider option. Reference-to-video is supported by the `grok-imagine-video`
|
|
1287
|
+
and `grok-imagine-video-1.5` models; native 1080p requires
|
|
1288
|
+
`grok-imagine-video-1.5`.
|
|
1232
1289
|
</Note>
|
|
1233
1290
|
|
|
1234
1291
|
### Video Provider Options
|
|
@@ -1244,11 +1301,14 @@ You can validate the provider options using the `XaiVideoModelOptions` type.
|
|
|
1244
1301
|
|
|
1245
1302
|
Maximum wait time in milliseconds for video generation. Defaults to 600000 (10 minutes).
|
|
1246
1303
|
|
|
1247
|
-
- **resolution** _'480p' | '720p'_
|
|
1304
|
+
- **resolution** _'480p' | '720p' | '1080p'_
|
|
1248
1305
|
|
|
1249
1306
|
Video resolution. When using the SDK's standard `resolution` parameter,
|
|
1250
|
-
`1280x720` maps to `720p
|
|
1251
|
-
Use this provider option to pass the native format directly.
|
|
1307
|
+
`1920x1080` maps to `1080p`, `1280x720` maps to `720p`, and `854x480` maps
|
|
1308
|
+
to `480p`. Use this provider option to pass the native format directly.
|
|
1309
|
+
`1080p` requires the `grok-imagine-video-1.5` model and is available for
|
|
1310
|
+
text-to-video and image-to-video; reference-to-video is capped at `720p`
|
|
1311
|
+
(a `1080p` request is downgraded with a warning).
|
|
1252
1312
|
|
|
1253
1313
|
- **user** _string_
|
|
1254
1314
|
|
|
@@ -1280,6 +1340,17 @@ You can validate the provider options using the `XaiVideoModelOptions` type.
|
|
|
1280
1340
|
`<IMAGE_1>`, `<IMAGE_2>`, etc. in the prompt to reference specific
|
|
1281
1341
|
images. Used with `mode: 'reference-to-video'`.
|
|
1282
1342
|
|
|
1343
|
+
- **referenceVoiceIds** _string[]_
|
|
1344
|
+
|
|
1345
|
+
Up to 3 xAI preset voice ids that give the subject a voice in
|
|
1346
|
+
reference-to-video (R2V) generation. Preset voices only — audio clips
|
|
1347
|
+
cannot be uploaded. Ids are case-insensitive and come from the
|
|
1348
|
+
[text-to-speech voice roster](https://docs.x.ai/developers/model-capabilities/audio/text-to-speech#voices);
|
|
1349
|
+
an unknown id returns a `400` listing the available voices. Use `<AUDIO_0>`,
|
|
1350
|
+
`<AUDIO_1>`, and `<AUDIO_2>` tags in the prompt to reference the voices.
|
|
1351
|
+
Ignored with a warning outside reference-to-video. Reference audio is
|
|
1352
|
+
documented as US-only and limited to trusted partners.
|
|
1353
|
+
|
|
1283
1354
|
<Note>
|
|
1284
1355
|
Video generation is an asynchronous process that can take several minutes.
|
|
1285
1356
|
Consider setting `pollTimeoutMs` to at least 10 minutes (600000ms) for
|
|
@@ -1290,7 +1361,9 @@ You can validate the provider options using the `XaiVideoModelOptions` type.
|
|
|
1290
1361
|
### Aspect Ratio and Resolution
|
|
1291
1362
|
|
|
1292
1363
|
For **text-to-video**, you can specify both `aspectRatio` and `resolution`.
|
|
1293
|
-
The default aspect ratio is `16:9` and the default resolution is `480p`.
|
|
1364
|
+
The default aspect ratio is `16:9` and the default resolution is `480p`. The
|
|
1365
|
+
`grok-imagine-video-1.5` model additionally supports native `1080p` for
|
|
1366
|
+
text-to-video and image-to-video.
|
|
1294
1367
|
|
|
1295
1368
|
For **image-to-video**, the output defaults to the input image's aspect ratio.
|
|
1296
1369
|
If you specify `aspectRatio`, it will override this and stretch the image to the
|
|
@@ -1306,13 +1379,18 @@ from the source video. `duration` is supported and controls only the
|
|
|
1306
1379
|
extension length.
|
|
1307
1380
|
|
|
1308
1381
|
For **reference-to-video (R2V)**, you can specify `duration`, `aspectRatio`,
|
|
1309
|
-
and `resolution
|
|
1382
|
+
and `resolution`. Unlike text-to-video, R2V is capped at `720p` — a `1080p`
|
|
1383
|
+
request is downgraded to `720p` with a warning.
|
|
1310
1384
|
|
|
1311
1385
|
### Video Model Capabilities
|
|
1312
1386
|
|
|
1313
|
-
| Model
|
|
1314
|
-
|
|
|
1315
|
-
| `grok-imagine-video`
|
|
1387
|
+
| Model | Duration | Aspect Ratios | Resolution | Image-to-Video | Editing | Extension | R2V |
|
|
1388
|
+
| ------------------------ | -------- | ------------------------------------------------- | ------------------------- | -------------- | --------- | --------- | --------- |
|
|
1389
|
+
| `grok-imagine-video` | 1–15s | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `480p`, `720p` | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
1390
|
+
| `grok-imagine-video-1.5` | 1–15s | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `480p`, `720p`, `1080p`\* | <Check /> | <Check /> | <Check /> | <Check /> |
|
|
1391
|
+
|
|
1392
|
+
\* Native `1080p` applies to text-to-video and image-to-video. Reference-to-video
|
|
1393
|
+
is capped at `720p` — a `1080p` request is downgraded with a warning.
|
|
1316
1394
|
|
|
1317
1395
|
<Note>
|
|
1318
1396
|
You can also pass any available provider model ID as a string if needed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/xai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.37",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"tsup": "^8.5.1",
|
|
38
38
|
"typescript": "5.8.3",
|
|
39
39
|
"zod": "3.25.76",
|
|
40
|
-
"@ai-
|
|
41
|
-
"@
|
|
40
|
+
"@vercel/ai-tsconfig": "0.0.0",
|
|
41
|
+
"@ai-sdk/test-server": "2.0.1"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"zod": "^3.25.76 || ^4.1.8"
|
|
@@ -5,6 +5,7 @@ export type XaiResponsesModelId =
|
|
|
5
5
|
| 'grok-4.20-reasoning'
|
|
6
6
|
| 'grok-4.3'
|
|
7
7
|
| 'grok-4.5'
|
|
8
|
+
| 'grok-4.6'
|
|
8
9
|
| 'grok-latest'
|
|
9
10
|
| (string & {});
|
|
10
11
|
|
|
@@ -16,11 +17,14 @@ export const xaiLanguageModelResponsesOptions = z.object({
|
|
|
16
17
|
* Constrains how hard a reasoning model thinks before responding.
|
|
17
18
|
* Possible values are `none` (disables reasoning entirely; supported by
|
|
18
19
|
* `grok-4.3` and newer reasoning models), `low` (uses fewer reasoning
|
|
19
|
-
* tokens), `medium`,
|
|
20
|
+
* tokens), `medium`, `high` (uses more reasoning tokens), and `xhigh`
|
|
21
|
+
* (supported by `grok-4.6`).
|
|
20
22
|
*
|
|
21
23
|
* @see https://docs.x.ai/docs/guides/reasoning
|
|
22
24
|
*/
|
|
23
|
-
reasoningEffort: z
|
|
25
|
+
reasoningEffort: z
|
|
26
|
+
.enum(['none', 'low', 'medium', 'high', 'xhigh'])
|
|
27
|
+
.optional(),
|
|
24
28
|
reasoningSummary: z.enum(['auto', 'concise', 'detailed']).optional(),
|
|
25
29
|
logprobs: z.boolean().optional(),
|
|
26
30
|
topLogprobs: z.number().int().min(0).max(8).optional(),
|
|
@@ -6,6 +6,7 @@ export type XaiChatModelId =
|
|
|
6
6
|
| 'grok-4.20-reasoning'
|
|
7
7
|
| 'grok-4.3'
|
|
8
8
|
| 'grok-4.5'
|
|
9
|
+
| 'grok-4.6'
|
|
9
10
|
| 'grok-latest'
|
|
10
11
|
| (string & {});
|
|
11
12
|
|
|
@@ -59,13 +60,16 @@ export const xaiLanguageModelChatOptions = z.object({
|
|
|
59
60
|
* - `low` (default): Uses some reasoning tokens, but still fast.
|
|
60
61
|
* - `medium`: More thinking for less-latency-sensitive applications.
|
|
61
62
|
* - `high`: Uses more reasoning tokens for deeper thinking.
|
|
63
|
+
* - `xhigh`: Uses the most reasoning tokens (supported by `grok-4.6`).
|
|
62
64
|
*
|
|
63
65
|
* Note: Not every Grok model accepts every value. Refer to xAI's docs for
|
|
64
66
|
* the values supported by your selected model.
|
|
65
67
|
*
|
|
66
68
|
* @see https://docs.x.ai/docs/guides/reasoning
|
|
67
69
|
*/
|
|
68
|
-
reasoningEffort: z
|
|
70
|
+
reasoningEffort: z
|
|
71
|
+
.enum(['none', 'low', 'medium', 'high', 'xhigh'])
|
|
72
|
+
.optional(),
|
|
69
73
|
logprobs: z.boolean().optional(),
|
|
70
74
|
topLogprobs: z.number().int().min(0).max(8).optional(),
|
|
71
75
|
|
|
@@ -2,7 +2,7 @@ import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
|
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
|
|
4
4
|
const nonEmptyStringSchema = z.string().min(1);
|
|
5
|
-
const resolutionSchema = z.enum(['480p', '720p']);
|
|
5
|
+
const resolutionSchema = z.enum(['480p', '720p', '1080p']);
|
|
6
6
|
const modeSchema = z.enum(['edit-video', 'extend-video', 'reference-to-video']);
|
|
7
7
|
|
|
8
8
|
export type XaiVideoMode = z.infer<typeof modeSchema>;
|
|
@@ -48,6 +48,10 @@ interface XaiVideoReferenceToVideoOptions
|
|
|
48
48
|
mode: 'reference-to-video';
|
|
49
49
|
/** Reference image URLs (1-7) for R2V generation. */
|
|
50
50
|
referenceImageUrls: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Preset voice ids (up to 3) that give the subject a voice.
|
|
53
|
+
*/
|
|
54
|
+
referenceVoiceIds?: string[];
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
interface XaiVideoGenerationOptions
|
|
@@ -75,6 +79,10 @@ interface XaiLegacyReferenceToVideoOptions
|
|
|
75
79
|
*/
|
|
76
80
|
mode?: undefined;
|
|
77
81
|
referenceImageUrls: string[];
|
|
82
|
+
/**
|
|
83
|
+
* Preset voice ids (up to 3) that give the subject a voice.
|
|
84
|
+
*/
|
|
85
|
+
referenceVoiceIds?: string[];
|
|
78
86
|
}
|
|
79
87
|
|
|
80
88
|
/**
|
|
@@ -106,52 +114,11 @@ const baseFields = {
|
|
|
106
114
|
resolution: resolutionSchema.nullish(),
|
|
107
115
|
};
|
|
108
116
|
|
|
109
|
-
const userField = {
|
|
110
|
-
user: z.string().optional(),
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
const editVideoSchema = z.object({
|
|
114
|
-
...baseFields,
|
|
115
|
-
...userField,
|
|
116
|
-
mode: z.literal('edit-video'),
|
|
117
|
-
videoUrl: nonEmptyStringSchema,
|
|
118
|
-
referenceImageUrls: z.undefined().optional(),
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
const extendVideoSchema = z.object({
|
|
122
|
-
...baseFields,
|
|
123
|
-
mode: z.literal('extend-video'),
|
|
124
|
-
videoUrl: nonEmptyStringSchema,
|
|
125
|
-
referenceImageUrls: z.undefined().optional(),
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const referenceToVideoSchema = z.object({
|
|
129
|
-
...baseFields,
|
|
130
|
-
...userField,
|
|
131
|
-
mode: z.literal('reference-to-video'),
|
|
132
|
-
referenceImageUrls: z.array(nonEmptyStringSchema).min(1).max(7),
|
|
133
|
-
videoUrl: z.undefined().optional(),
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
const autoDetectSchema = z.object({
|
|
137
|
-
...baseFields,
|
|
138
|
-
...userField,
|
|
139
|
-
mode: z.undefined().optional(),
|
|
140
|
-
videoUrl: nonEmptyStringSchema.optional(),
|
|
141
|
-
referenceImageUrls: z.array(nonEmptyStringSchema).min(1).max(7).optional(),
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
export const xaiVideoModelOptions = z.union([
|
|
145
|
-
editVideoSchema,
|
|
146
|
-
extendVideoSchema,
|
|
147
|
-
referenceToVideoSchema,
|
|
148
|
-
autoDetectSchema,
|
|
149
|
-
]);
|
|
150
|
-
|
|
151
117
|
const runtimeSchema = z.looseObject({
|
|
152
118
|
mode: modeSchema.optional(),
|
|
153
119
|
videoUrl: nonEmptyStringSchema.optional(),
|
|
154
120
|
referenceImageUrls: z.array(nonEmptyStringSchema).min(1).max(7).optional(),
|
|
121
|
+
referenceVoiceIds: z.array(nonEmptyStringSchema).max(3).optional(),
|
|
155
122
|
user: z.string().optional(),
|
|
156
123
|
...baseFields,
|
|
157
124
|
});
|
package/src/xai-video-model.ts
CHANGED
|
@@ -40,6 +40,7 @@ interface XaiVideoModelConfig {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
const RESOLUTION_MAP: Record<string, string> = {
|
|
43
|
+
'1920x1080': '1080p',
|
|
43
44
|
'1280x720': '720p',
|
|
44
45
|
'854x480': '480p',
|
|
45
46
|
'640x480': '480p',
|
|
@@ -70,7 +71,12 @@ function resolveStartImage(
|
|
|
70
71
|
const isVideoFile = (file: VideoModelV4File): boolean =>
|
|
71
72
|
file.mediaType != null && getTopLevelMediaType(file.mediaType) === 'video';
|
|
72
73
|
|
|
73
|
-
|
|
74
|
+
// References without a media type (only possible for URLs) are treated as
|
|
75
|
+
// images, matching the legacy `referenceImageUrls` behavior.
|
|
76
|
+
const isImageReference = (file: VideoModelV4File): boolean =>
|
|
77
|
+
file.mediaType == null || getTopLevelMediaType(file.mediaType) === 'image';
|
|
78
|
+
|
|
79
|
+
function fileToXaiUrl(file: VideoModelV4File): string {
|
|
74
80
|
if (file.type === 'url') {
|
|
75
81
|
return file.url;
|
|
76
82
|
}
|
|
@@ -84,32 +90,37 @@ function fileToXaiImageUrl(file: VideoModelV4File): string {
|
|
|
84
90
|
|
|
85
91
|
// Resolves the reference images for R2V generation. First-class
|
|
86
92
|
// `inputReferences` win over the legacy `referenceImageUrls` provider option.
|
|
87
|
-
//
|
|
88
|
-
// with a warning.
|
|
89
|
-
function
|
|
93
|
+
// Non-image references (video or audio) are not supported for
|
|
94
|
+
// reference-to-video and are skipped with a warning.
|
|
95
|
+
function resolveReferences(
|
|
90
96
|
options: XaiVideoCallOptions,
|
|
91
97
|
xaiOptions: XaiParsedVideoModelOptions | undefined,
|
|
92
98
|
warnings: SharedV4Warning[],
|
|
93
99
|
): Array<{ url: string }> | undefined {
|
|
94
100
|
if (options.inputReferences != null && options.inputReferences.length > 0) {
|
|
95
|
-
const
|
|
96
|
-
|
|
101
|
+
const imageFiles: VideoModelV4File[] = [];
|
|
102
|
+
|
|
103
|
+
for (const reference of options.inputReferences) {
|
|
104
|
+
if (!isImageReference(reference)) {
|
|
97
105
|
warnings.push({
|
|
98
106
|
type: 'unsupported',
|
|
99
107
|
feature: 'inputReferences',
|
|
100
|
-
details:
|
|
101
|
-
'xAI reference-to-video accepts image references only. The
|
|
102
|
-
|
|
103
|
-
|
|
108
|
+
details: isVideoFile(reference)
|
|
109
|
+
? 'xAI reference-to-video accepts image references only. The ' +
|
|
110
|
+
'video reference was ignored. Use providerOptions.xai.mode ' +
|
|
111
|
+
'"extend-video" to continue from a video.'
|
|
112
|
+
: 'xAI reference-to-video accepts image references only. The ' +
|
|
113
|
+
'non-image reference was ignored.',
|
|
104
114
|
});
|
|
105
|
-
|
|
115
|
+
continue;
|
|
106
116
|
}
|
|
107
|
-
return true;
|
|
108
|
-
});
|
|
109
117
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
imageFiles.push(reference);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return imageFiles.length > 0
|
|
122
|
+
? imageFiles.map(reference => ({ url: fileToXaiUrl(reference) }))
|
|
123
|
+
: undefined;
|
|
113
124
|
}
|
|
114
125
|
|
|
115
126
|
if (
|
|
@@ -122,6 +133,11 @@ function resolveReferenceImages(
|
|
|
122
133
|
return undefined;
|
|
123
134
|
}
|
|
124
135
|
|
|
136
|
+
// True when at least one reference would survive as an image.
|
|
137
|
+
function hasImageInputReference(options: XaiVideoCallOptions): boolean {
|
|
138
|
+
return options.inputReferences?.some(isImageReference) ?? false;
|
|
139
|
+
}
|
|
140
|
+
|
|
125
141
|
function resolveVideoMode(
|
|
126
142
|
options: XaiVideoCallOptions,
|
|
127
143
|
xaiOptions: XaiParsedVideoModelOptions | undefined,
|
|
@@ -138,13 +154,17 @@ function resolveVideoMode(
|
|
|
138
154
|
// only auto-select reference-to-video when no frame images are provided.
|
|
139
155
|
const hasFrameImages =
|
|
140
156
|
options.frameImages != null && options.frameImages.length > 0;
|
|
141
|
-
const hasInputReferences =
|
|
142
|
-
options.inputReferences != null && options.inputReferences.length > 0;
|
|
143
157
|
const hasLegacyReferenceUrls =
|
|
144
158
|
xaiOptions?.referenceImageUrls != null &&
|
|
145
159
|
xaiOptions.referenceImageUrls.length > 0;
|
|
146
160
|
|
|
147
|
-
|
|
161
|
+
// Reference-to-video needs at least one image reference. An audio-only (or
|
|
162
|
+
// video-only) `inputReferences` array must not flip a text- or
|
|
163
|
+
// image-to-video request into R2V.
|
|
164
|
+
if (
|
|
165
|
+
!hasFrameImages &&
|
|
166
|
+
(hasImageInputReference(options) || hasLegacyReferenceUrls)
|
|
167
|
+
) {
|
|
148
168
|
return 'reference-to-video';
|
|
149
169
|
}
|
|
150
170
|
|
|
@@ -290,7 +310,8 @@ export class XaiVideoModel implements VideoModelV4 {
|
|
|
290
310
|
feature: 'resolution',
|
|
291
311
|
details:
|
|
292
312
|
`Unrecognized resolution "${options.resolution}". ` +
|
|
293
|
-
'Use providerOptions.xai.resolution with "480p"
|
|
313
|
+
'Use providerOptions.xai.resolution with "480p", "720p", or ' +
|
|
314
|
+
'"1080p" instead.',
|
|
294
315
|
});
|
|
295
316
|
}
|
|
296
317
|
}
|
|
@@ -320,7 +341,7 @@ export class XaiVideoModel implements VideoModelV4 {
|
|
|
320
341
|
'continue from a video instead.',
|
|
321
342
|
});
|
|
322
343
|
} else {
|
|
323
|
-
body.image = { url:
|
|
344
|
+
body.image = { url: fileToXaiUrl(startImage) };
|
|
324
345
|
}
|
|
325
346
|
}
|
|
326
347
|
|
|
@@ -342,18 +363,58 @@ export class XaiVideoModel implements VideoModelV4 {
|
|
|
342
363
|
|
|
343
364
|
// Reference images for R2V (reference-to-video) generation
|
|
344
365
|
if (hasReferenceImages) {
|
|
345
|
-
const referenceImages =
|
|
346
|
-
|
|
347
|
-
xaiOptions,
|
|
348
|
-
warnings,
|
|
349
|
-
);
|
|
366
|
+
const referenceImages = resolveReferences(options, xaiOptions, warnings);
|
|
367
|
+
|
|
350
368
|
if (referenceImages != null) {
|
|
351
369
|
body.reference_images = referenceImages;
|
|
370
|
+
} else {
|
|
371
|
+
// Explicit R2V with no usable image references would silently send
|
|
372
|
+
// a plain generations request; tell the user it is no longer R2V.
|
|
373
|
+
warnings.push({
|
|
374
|
+
type: 'unsupported',
|
|
375
|
+
feature: 'referenceImages',
|
|
376
|
+
details:
|
|
377
|
+
'xAI reference-to-video requires at least one image reference. ' +
|
|
378
|
+
'The video will be generated without reference images.',
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const referenceVoiceIds = xaiOptions?.referenceVoiceIds;
|
|
383
|
+
if (referenceVoiceIds != null && referenceVoiceIds.length > 0) {
|
|
384
|
+
body.reference_audios = referenceVoiceIds.map(voiceId => ({
|
|
385
|
+
voice_id: voiceId,
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Reference-to-video is capped at 720p; downgrade a 1080p request.
|
|
390
|
+
if (body.resolution === '1080p') {
|
|
391
|
+
warnings.push({
|
|
392
|
+
type: 'unsupported',
|
|
393
|
+
feature: 'resolution',
|
|
394
|
+
details:
|
|
395
|
+
'xAI reference-to-video is limited to 720p. The request was ' +
|
|
396
|
+
'downgraded from 1080p to 720p.',
|
|
397
|
+
});
|
|
398
|
+
body.resolution = '720p';
|
|
352
399
|
}
|
|
353
400
|
}
|
|
354
401
|
|
|
355
|
-
//
|
|
356
|
-
//
|
|
402
|
+
// 1080p requires grok-imagine-video-1.5; the original grok-imagine-video
|
|
403
|
+
// rejects it. Warn, but send the request as the user asked.
|
|
404
|
+
if (body.resolution === '1080p' && this.modelId === 'grok-imagine-video') {
|
|
405
|
+
warnings.push({
|
|
406
|
+
type: 'unsupported',
|
|
407
|
+
feature: 'resolution',
|
|
408
|
+
details:
|
|
409
|
+
'xAI model "grok-imagine-video" does not support 1080p. Use ' +
|
|
410
|
+
'"grok-imagine-video-1.5" for 1080p, or a lower resolution. The ' +
|
|
411
|
+
'request was sent with 1080p.',
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Warn when references were provided but cannot be used in the resolved
|
|
416
|
+
// mode (e.g. alongside frameImages, in edit/extend modes, or when the
|
|
417
|
+
// references carried no usable image to drive reference-to-video).
|
|
357
418
|
if (
|
|
358
419
|
options.inputReferences != null &&
|
|
359
420
|
options.inputReferences.length > 0 &&
|
|
@@ -362,9 +423,26 @@ export class XaiVideoModel implements VideoModelV4 {
|
|
|
362
423
|
warnings.push({
|
|
363
424
|
type: 'unsupported',
|
|
364
425
|
feature: 'inputReferences',
|
|
426
|
+
details: hasImageInputReference(options)
|
|
427
|
+
? 'xAI only supports inputReferences for reference-to-video ' +
|
|
428
|
+
'generation. The reference images were ignored.'
|
|
429
|
+
: 'xAI reference-to-video requires at least one image reference. ' +
|
|
430
|
+
'The references were ignored.',
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Preset reference voices only apply to reference-to-video generation.
|
|
435
|
+
if (
|
|
436
|
+
xaiOptions?.referenceVoiceIds != null &&
|
|
437
|
+
xaiOptions.referenceVoiceIds.length > 0 &&
|
|
438
|
+
!hasReferenceImages
|
|
439
|
+
) {
|
|
440
|
+
warnings.push({
|
|
441
|
+
type: 'unsupported',
|
|
442
|
+
feature: 'referenceVoiceIds',
|
|
365
443
|
details:
|
|
366
|
-
'xAI only supports
|
|
367
|
-
'generation. The reference
|
|
444
|
+
'xAI only supports reference voices for reference-to-video ' +
|
|
445
|
+
'generation. The reference voices were ignored.',
|
|
368
446
|
});
|
|
369
447
|
}
|
|
370
448
|
|
|
@@ -382,6 +460,7 @@ export class XaiVideoModel implements VideoModelV4 {
|
|
|
382
460
|
'resolution',
|
|
383
461
|
'videoUrl',
|
|
384
462
|
'referenceImageUrls',
|
|
463
|
+
'referenceVoiceIds',
|
|
385
464
|
'user',
|
|
386
465
|
].includes(key)
|
|
387
466
|
) {
|