@ai-sdk/xai 3.0.56 → 3.0.58

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/docs/01-xai.mdx CHANGED
@@ -95,7 +95,8 @@ const { text } = await generateText({
95
95
  });
96
96
  ```
97
97
 
98
- xAI language models can also be used in the `streamText`, `generateObject`, and `streamObject` functions
98
+ xAI language models can also be used in the `streamText` function
99
+ and support structured data generation with [`Output`](/docs/reference/ai-sdk-core/output)
99
100
  (see [AI SDK Core](/docs/ai-sdk-core)).
100
101
 
101
102
  ### Provider Options
@@ -876,3 +877,181 @@ const { images } = await generateImage({
876
877
  | -------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------- |
877
878
  | `grok-2-image` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `2:1`, `1:2`, `19.5:9`, `9:19.5`, `20:9`, `9:20`, `auto` | <Check size={18} /> |
878
879
  | `grok-imagine-image` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `2:1`, `1:2`, `19.5:9`, `9:19.5`, `20:9`, `9:20`, `auto` | <Check size={18} /> |
880
+
881
+ ## Video Models
882
+
883
+ You can create xAI video models using the `.video()` factory method.
884
+ For more on video generation with the AI SDK see [generateVideo()](/docs/reference/ai-sdk-core/generate-video).
885
+
886
+ This provider supports three video generation modes: text-to-video, image-to-video, and video editing.
887
+
888
+ ### Text-to-Video
889
+
890
+ Generate videos from text prompts:
891
+
892
+ ```ts
893
+ import { xai, type XaiVideoModelOptions } from '@ai-sdk/xai';
894
+ import { experimental_generateVideo as generateVideo } from 'ai';
895
+
896
+ const { videos } = await generateVideo({
897
+ model: xai.video('grok-imagine-video'),
898
+ prompt: 'A chicken flying into the sunset in the style of 90s anime.',
899
+ aspectRatio: '16:9',
900
+ duration: 5,
901
+ providerOptions: {
902
+ xai: {
903
+ pollTimeoutMs: 600000, // 10 minutes
904
+ } satisfies XaiVideoModelOptions,
905
+ },
906
+ });
907
+ ```
908
+
909
+ ### Image-to-Video
910
+
911
+ Generate videos using an image as the starting frame with an optional text prompt:
912
+
913
+ ```ts
914
+ import { xai, type XaiVideoModelOptions } from '@ai-sdk/xai';
915
+ import { experimental_generateVideo as generateVideo } from 'ai';
916
+
917
+ const { videos } = await generateVideo({
918
+ model: xai.video('grok-imagine-video'),
919
+ prompt: {
920
+ image: 'https://example.com/start-frame.png',
921
+ text: 'The cat slowly turns its head and blinks',
922
+ },
923
+ duration: 5,
924
+ providerOptions: {
925
+ xai: {
926
+ pollTimeoutMs: 600000, // 10 minutes
927
+ } satisfies XaiVideoModelOptions,
928
+ },
929
+ });
930
+ ```
931
+
932
+ ### Video Editing
933
+
934
+ Edit an existing video using a text prompt by providing a source video URL via provider options:
935
+
936
+ ```ts
937
+ import { xai, type XaiVideoModelOptions } from '@ai-sdk/xai';
938
+ import { experimental_generateVideo as generateVideo } from 'ai';
939
+
940
+ const { videos } = await generateVideo({
941
+ model: xai.video('grok-imagine-video'),
942
+ prompt: 'Give the person sunglasses and a hat',
943
+ providerOptions: {
944
+ xai: {
945
+ videoUrl: 'https://example.com/source-video.mp4',
946
+ pollTimeoutMs: 600000, // 10 minutes
947
+ } satisfies XaiVideoModelOptions,
948
+ },
949
+ });
950
+ ```
951
+
952
+ <Note>
953
+ Video editing accepts input videos up to 8.7 seconds long. The `duration`,
954
+ `aspectRatio`, and `resolution` parameters are not supported for editing - the
955
+ output matches the input video's properties (capped at 720p).
956
+ </Note>
957
+
958
+ ### Chaining and Concurrent Edits
959
+
960
+ The xAI-hosted video URL is available in `providerMetadata.xai.videoUrl`.
961
+ You can use it to chain sequential edits or branch into concurrent edits
962
+ using `Promise.all`:
963
+
964
+ ```ts
965
+ import { xai, type XaiVideoModelOptions } from '@ai-sdk/xai';
966
+ import { experimental_generateVideo as generateVideo } from 'ai';
967
+
968
+ const providerOptions = {
969
+ xai: {
970
+ videoUrl: 'https://example.com/source-video.mp4',
971
+ pollTimeoutMs: 600000,
972
+ } satisfies XaiVideoModelOptions,
973
+ };
974
+
975
+ // Step 1: Apply an initial edit
976
+ const step1 = await generateVideo({
977
+ model: xai.video('grok-imagine-video'),
978
+ prompt: 'Add a party hat to the person',
979
+ providerOptions,
980
+ });
981
+
982
+ // Get the xAI-hosted URL from provider metadata
983
+ const step1VideoUrl = step1.providerMetadata?.xai?.videoUrl as string;
984
+
985
+ // Step 2: Apply two more edits concurrently, building on step 1
986
+ const [withSunglasses, withScarf] = await Promise.all([
987
+ generateVideo({
988
+ model: xai.video('grok-imagine-video'),
989
+ prompt: 'Add sunglasses',
990
+ providerOptions: {
991
+ xai: { videoUrl: step1VideoUrl, pollTimeoutMs: 600000 },
992
+ },
993
+ }),
994
+ generateVideo({
995
+ model: xai.video('grok-imagine-video'),
996
+ prompt: 'Add a scarf',
997
+ providerOptions: {
998
+ xai: { videoUrl: step1VideoUrl, pollTimeoutMs: 600000 },
999
+ },
1000
+ }),
1001
+ ]);
1002
+ ```
1003
+
1004
+ ### Video Provider Options
1005
+
1006
+ The following provider options are available via `providerOptions.xai`.
1007
+ You can validate the provider options using the `XaiVideoModelOptions` type.
1008
+
1009
+ - **pollIntervalMs** _number_
1010
+
1011
+ Polling interval in milliseconds for checking task status. Defaults to 5000.
1012
+
1013
+ - **pollTimeoutMs** _number_
1014
+
1015
+ Maximum wait time in milliseconds for video generation. Defaults to 600000 (10 minutes).
1016
+
1017
+ - **resolution** _'480p' | '720p'_
1018
+
1019
+ Video resolution. When using the SDK's standard `resolution` parameter,
1020
+ `1280x720` maps to `720p` and `854x480` maps to `480p`.
1021
+ Use this provider option to pass the native format directly.
1022
+
1023
+ - **videoUrl** _string_
1024
+
1025
+ URL of a source video for video editing. When provided, the prompt is used
1026
+ to describe the desired edits to the video.
1027
+
1028
+ <Note>
1029
+ Video generation is an asynchronous process that can take several minutes.
1030
+ Consider setting `pollTimeoutMs` to at least 10 minutes (600000ms) for
1031
+ reliable operation. Generated video URLs are ephemeral and should be
1032
+ downloaded promptly.
1033
+ </Note>
1034
+
1035
+ ### Aspect Ratio and Resolution
1036
+
1037
+ For **text-to-video**, you can specify both `aspectRatio` and `resolution`.
1038
+ The default aspect ratio is `16:9` and the default resolution is `480p`.
1039
+
1040
+ For **image-to-video**, the output defaults to the input image's aspect ratio.
1041
+ If you specify `aspectRatio`, it will override this and stretch the image to the
1042
+ desired ratio.
1043
+
1044
+ For **video editing**, the output matches the input video's aspect ratio and
1045
+ resolution. Custom `duration`, `aspectRatio`, and `resolution` are not
1046
+ supported - the output resolution is capped at 720p (e.g., a 1080p input
1047
+ will be downsized to 720p).
1048
+
1049
+ ### Video Model Capabilities
1050
+
1051
+ | Model | Duration | Aspect Ratios | Resolution | Image-to-Video | Video Editing |
1052
+ | -------------------- | -------- | ------------------------------------------------- | -------------- | ------------------- | ------------------- |
1053
+ | `grok-imagine-video` | 1–15s | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `480p`, `720p` | <Check size={18} /> | <Check size={18} /> |
1054
+
1055
+ <Note>
1056
+ You can also pass any available provider model ID as a string if needed.
1057
+ </Note>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/xai",
3
- "version": "3.0.56",
3
+ "version": "3.0.58",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -30,16 +30,16 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@ai-sdk/openai-compatible": "2.0.30",
33
- "@ai-sdk/provider-utils": "4.0.15",
34
- "@ai-sdk/provider": "3.0.8"
33
+ "@ai-sdk/provider": "3.0.8",
34
+ "@ai-sdk/provider-utils": "4.0.15"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "20.17.24",
38
38
  "tsup": "^8",
39
39
  "typescript": "5.8.3",
40
40
  "zod": "3.25.76",
41
- "@ai-sdk/test-server": "1.0.3",
42
- "@vercel/ai-tsconfig": "0.0.0"
41
+ "@vercel/ai-tsconfig": "0.0.0",
42
+ "@ai-sdk/test-server": "1.0.3"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "zod": "^3.25.76 || ^4.1.8"
package/src/index.ts CHANGED
@@ -14,6 +14,12 @@ export type {
14
14
  /** @deprecated Use `XaiImageModelOptions` instead. */
15
15
  XaiImageModelOptions as XaiImageProviderOptions,
16
16
  } from './xai-image-options';
17
+ export type { XaiVideoModelId } from './xai-video-settings';
18
+ export type {
19
+ XaiVideoModelOptions,
20
+ /** @deprecated Use `XaiVideoModelOptions` instead. */
21
+ XaiVideoModelOptions as XaiVideoProviderOptions,
22
+ } from './xai-video-options';
17
23
  export { createXai, xai } from './xai-provider';
18
24
  export type { XaiProvider, XaiProviderSettings } from './xai-provider';
19
25
  export {
@@ -1,4 +1,6 @@
1
1
  export type XaiImageModelId =
2
2
  | 'grok-2-image'
3
+ | 'grok-2-image-1212'
3
4
  | 'grok-imagine-image'
5
+ | 'grok-imagine-image-pro'
4
6
  | (string & {});
@@ -1,4 +1,5 @@
1
1
  import {
2
+ type Experimental_VideoModelV3,
2
3
  ImageModelV3,
3
4
  LanguageModelV3,
4
5
  NoSuchModelError,
@@ -19,6 +20,8 @@ import { XaiResponsesLanguageModel } from './responses/xai-responses-language-mo
19
20
  import { XaiResponsesModelId } from './responses/xai-responses-options';
20
21
  import { xaiTools } from './tool';
21
22
  import { VERSION } from './version';
23
+ import { XaiVideoModel } from './xai-video-model';
24
+ import { XaiVideoModelId } from './xai-video-settings';
22
25
 
23
26
  export interface XaiProvider extends ProviderV3 {
24
27
  /**
@@ -51,6 +54,16 @@ export interface XaiProvider extends ProviderV3 {
51
54
  */
52
55
  imageModel(modelId: XaiImageModelId): ImageModelV3;
53
56
 
57
+ /**
58
+ * Creates an Xai video model for video generation.
59
+ */
60
+ video(modelId: XaiVideoModelId): Experimental_VideoModelV3;
61
+
62
+ /**
63
+ * Creates an Xai video model for video generation.
64
+ */
65
+ videoModel(modelId: XaiVideoModelId): Experimental_VideoModelV3;
66
+
54
67
  /**
55
68
  * Server-side agentic tools for use with the responses API.
56
69
  */
@@ -131,6 +144,15 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider {
131
144
  });
132
145
  };
133
146
 
147
+ const createVideoModel = (modelId: XaiVideoModelId) => {
148
+ return new XaiVideoModel(modelId, {
149
+ provider: 'xai.video',
150
+ baseURL,
151
+ headers: getHeaders,
152
+ fetch: options.fetch,
153
+ });
154
+ };
155
+
134
156
  const provider = (modelId: XaiChatModelId) =>
135
157
  createChatLanguageModel(modelId);
136
158
 
@@ -144,6 +166,8 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider {
144
166
  provider.textEmbeddingModel = provider.embeddingModel;
145
167
  provider.imageModel = createImageModel;
146
168
  provider.image = createImageModel;
169
+ provider.videoModel = createVideoModel;
170
+ provider.video = createVideoModel;
147
171
  provider.tools = xaiTools;
148
172
 
149
173
  return provider;
@@ -0,0 +1,302 @@
1
+ import {
2
+ AISDKError,
3
+ type Experimental_VideoModelV3,
4
+ type SharedV3Warning,
5
+ } from '@ai-sdk/provider';
6
+ import {
7
+ combineHeaders,
8
+ convertUint8ArrayToBase64,
9
+ createJsonResponseHandler,
10
+ delay,
11
+ type FetchFunction,
12
+ getFromApi,
13
+ parseProviderOptions,
14
+ postJsonToApi,
15
+ } from '@ai-sdk/provider-utils';
16
+ import { z } from 'zod/v4';
17
+ import { xaiFailedResponseHandler } from './xai-error';
18
+ import {
19
+ type XaiVideoModelOptions,
20
+ xaiVideoModelOptionsSchema,
21
+ } from './xai-video-options';
22
+ import type { XaiVideoModelId } from './xai-video-settings';
23
+
24
+ interface XaiVideoModelConfig {
25
+ provider: string;
26
+ baseURL: string | undefined;
27
+ headers: () => Record<string, string | undefined>;
28
+ fetch?: FetchFunction;
29
+ _internal?: {
30
+ currentDate?: () => Date;
31
+ };
32
+ }
33
+
34
+ const RESOLUTION_MAP: Record<string, string> = {
35
+ '1280x720': '720p',
36
+ '854x480': '480p',
37
+ '640x480': '480p',
38
+ };
39
+
40
+ export class XaiVideoModel implements Experimental_VideoModelV3 {
41
+ readonly specificationVersion = 'v3';
42
+ readonly maxVideosPerCall = 1;
43
+
44
+ get provider(): string {
45
+ return this.config.provider;
46
+ }
47
+
48
+ constructor(
49
+ readonly modelId: XaiVideoModelId,
50
+ private config: XaiVideoModelConfig,
51
+ ) {}
52
+
53
+ async doGenerate(
54
+ options: Parameters<Experimental_VideoModelV3['doGenerate']>[0],
55
+ ): Promise<Awaited<ReturnType<Experimental_VideoModelV3['doGenerate']>>> {
56
+ const currentDate = this.config._internal?.currentDate?.() ?? new Date();
57
+ const warnings: SharedV3Warning[] = [];
58
+
59
+ const xaiOptions = (await parseProviderOptions({
60
+ provider: 'xai',
61
+ providerOptions: options.providerOptions,
62
+ schema: xaiVideoModelOptionsSchema,
63
+ })) as XaiVideoModelOptions | undefined;
64
+
65
+ const isEdit = xaiOptions?.videoUrl != null;
66
+
67
+ if (options.fps != null) {
68
+ warnings.push({
69
+ type: 'unsupported',
70
+ feature: 'fps',
71
+ details: 'xAI video models do not support custom FPS.',
72
+ });
73
+ }
74
+
75
+ if (options.seed != null) {
76
+ warnings.push({
77
+ type: 'unsupported',
78
+ feature: 'seed',
79
+ details: 'xAI video models do not support seed.',
80
+ });
81
+ }
82
+
83
+ if (options.n != null && options.n > 1) {
84
+ warnings.push({
85
+ type: 'unsupported',
86
+ feature: 'n',
87
+ details:
88
+ 'xAI video models do not support generating multiple videos per call. ' +
89
+ 'Only 1 video will be generated.',
90
+ });
91
+ }
92
+
93
+ if (isEdit && options.duration != null) {
94
+ warnings.push({
95
+ type: 'unsupported',
96
+ feature: 'duration',
97
+ details: 'xAI video editing does not support custom duration.',
98
+ });
99
+ }
100
+
101
+ if (isEdit && options.aspectRatio != null) {
102
+ warnings.push({
103
+ type: 'unsupported',
104
+ feature: 'aspectRatio',
105
+ details: 'xAI video editing does not support custom aspect ratio.',
106
+ });
107
+ }
108
+
109
+ if (
110
+ isEdit &&
111
+ (xaiOptions?.resolution != null || options.resolution != null)
112
+ ) {
113
+ warnings.push({
114
+ type: 'unsupported',
115
+ feature: 'resolution',
116
+ details: 'xAI video editing does not support custom resolution.',
117
+ });
118
+ }
119
+
120
+ const body: Record<string, unknown> = {
121
+ model: this.modelId,
122
+ prompt: options.prompt,
123
+ };
124
+
125
+ if (!isEdit && options.duration != null) {
126
+ body.duration = options.duration;
127
+ }
128
+
129
+ if (!isEdit && options.aspectRatio != null) {
130
+ body.aspect_ratio = options.aspectRatio;
131
+ }
132
+
133
+ if (!isEdit && xaiOptions?.resolution != null) {
134
+ body.resolution = xaiOptions.resolution;
135
+ } else if (!isEdit && options.resolution != null) {
136
+ const mapped = RESOLUTION_MAP[options.resolution];
137
+ if (mapped != null) {
138
+ body.resolution = mapped;
139
+ } else {
140
+ warnings.push({
141
+ type: 'unsupported',
142
+ feature: 'resolution',
143
+ details:
144
+ `Unrecognized resolution "${options.resolution}". ` +
145
+ 'Use providerOptions.xai.resolution with "480p" or "720p" instead.',
146
+ });
147
+ }
148
+ }
149
+
150
+ // Video editing: pass source video URL (nested object like image)
151
+ if (xaiOptions?.videoUrl != null) {
152
+ body.video = { url: xaiOptions.videoUrl };
153
+ }
154
+
155
+ // Image-to-video: convert SDK image to nested image object
156
+ if (options.image != null) {
157
+ if (options.image.type === 'url') {
158
+ body.image = { url: options.image.url };
159
+ } else {
160
+ const base64Data =
161
+ typeof options.image.data === 'string'
162
+ ? options.image.data
163
+ : convertUint8ArrayToBase64(options.image.data);
164
+ body.image = {
165
+ url: `data:${options.image.mediaType};base64,${base64Data}`,
166
+ };
167
+ }
168
+ }
169
+
170
+ if (xaiOptions != null) {
171
+ for (const [key, value] of Object.entries(xaiOptions)) {
172
+ if (
173
+ ![
174
+ 'pollIntervalMs',
175
+ 'pollTimeoutMs',
176
+ 'resolution',
177
+ 'videoUrl',
178
+ ].includes(key)
179
+ ) {
180
+ body[key] = value;
181
+ }
182
+ }
183
+ }
184
+
185
+ const baseURL = this.config.baseURL ?? 'https://api.x.ai/v1';
186
+
187
+ // Step 1: Create video generation/edit request
188
+ const { value: createResponse } = await postJsonToApi({
189
+ url: `${baseURL}/videos/${isEdit ? 'edits' : 'generations'}`,
190
+ headers: combineHeaders(this.config.headers(), options.headers),
191
+ body,
192
+ failedResponseHandler: xaiFailedResponseHandler,
193
+ successfulResponseHandler: createJsonResponseHandler(
194
+ xaiCreateVideoResponseSchema,
195
+ ),
196
+ abortSignal: options.abortSignal,
197
+ fetch: this.config.fetch,
198
+ });
199
+
200
+ const requestId = createResponse.request_id;
201
+ if (!requestId) {
202
+ throw new AISDKError({
203
+ name: 'XAI_VIDEO_GENERATION_ERROR',
204
+ message: `No request_id returned from xAI API. Response: ${JSON.stringify(createResponse)}`,
205
+ });
206
+ }
207
+
208
+ // Step 2: Poll for completion
209
+ const pollIntervalMs = xaiOptions?.pollIntervalMs ?? 5000;
210
+ const pollTimeoutMs = xaiOptions?.pollTimeoutMs ?? 600000;
211
+ const startTime = Date.now();
212
+ let responseHeaders: Record<string, string> | undefined;
213
+
214
+ while (true) {
215
+ await delay(pollIntervalMs, { abortSignal: options.abortSignal });
216
+
217
+ if (Date.now() - startTime > pollTimeoutMs) {
218
+ throw new AISDKError({
219
+ name: 'XAI_VIDEO_GENERATION_TIMEOUT',
220
+ message: `Video generation timed out after ${pollTimeoutMs}ms`,
221
+ });
222
+ }
223
+
224
+ const { value: statusResponse, responseHeaders: pollHeaders } =
225
+ await getFromApi({
226
+ url: `${baseURL}/videos/${requestId}`,
227
+ headers: combineHeaders(this.config.headers(), options.headers),
228
+ successfulResponseHandler: createJsonResponseHandler(
229
+ xaiVideoStatusResponseSchema,
230
+ ),
231
+ failedResponseHandler: xaiFailedResponseHandler,
232
+ abortSignal: options.abortSignal,
233
+ fetch: this.config.fetch,
234
+ });
235
+
236
+ responseHeaders = pollHeaders;
237
+
238
+ if (
239
+ statusResponse.status === 'done' ||
240
+ (statusResponse.status == null && statusResponse.video?.url)
241
+ ) {
242
+ if (!statusResponse.video?.url) {
243
+ throw new AISDKError({
244
+ name: 'XAI_VIDEO_GENERATION_ERROR',
245
+ message:
246
+ 'Video generation completed but no video URL was returned.',
247
+ });
248
+ }
249
+
250
+ return {
251
+ videos: [
252
+ {
253
+ type: 'url' as const,
254
+ url: statusResponse.video.url,
255
+ mediaType: 'video/mp4',
256
+ },
257
+ ],
258
+ warnings,
259
+ response: {
260
+ timestamp: currentDate,
261
+ modelId: this.modelId,
262
+ headers: responseHeaders,
263
+ },
264
+ providerMetadata: {
265
+ xai: {
266
+ requestId,
267
+ videoUrl: statusResponse.video.url,
268
+ ...(statusResponse.video.duration != null
269
+ ? { duration: statusResponse.video.duration }
270
+ : {}),
271
+ },
272
+ },
273
+ };
274
+ }
275
+
276
+ if (statusResponse.status === 'expired') {
277
+ throw new AISDKError({
278
+ name: 'XAI_VIDEO_GENERATION_EXPIRED',
279
+ message: 'Video generation request expired.',
280
+ });
281
+ }
282
+
283
+ // 'pending' → continue polling
284
+ }
285
+ }
286
+ }
287
+
288
+ const xaiCreateVideoResponseSchema = z.object({
289
+ request_id: z.string().nullish(),
290
+ });
291
+
292
+ const xaiVideoStatusResponseSchema = z.object({
293
+ status: z.string().nullish(),
294
+ video: z
295
+ .object({
296
+ url: z.string(),
297
+ duration: z.number().nullish(),
298
+ respect_moderation: z.boolean().nullish(),
299
+ })
300
+ .nullish(),
301
+ model: z.string().nullish(),
302
+ });
@@ -0,0 +1,23 @@
1
+ import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
2
+ import { z } from 'zod/v4';
3
+
4
+ export type XaiVideoModelOptions = {
5
+ pollIntervalMs?: number | null;
6
+ pollTimeoutMs?: number | null;
7
+ resolution?: '480p' | '720p' | null;
8
+ videoUrl?: string | null;
9
+ [key: string]: unknown;
10
+ };
11
+
12
+ export const xaiVideoModelOptionsSchema = lazySchema(() =>
13
+ zodSchema(
14
+ z
15
+ .object({
16
+ pollIntervalMs: z.number().positive().nullish(),
17
+ pollTimeoutMs: z.number().positive().nullish(),
18
+ resolution: z.enum(['480p', '720p']).nullish(),
19
+ videoUrl: z.string().nullish(),
20
+ })
21
+ .passthrough(),
22
+ ),
23
+ );
@@ -0,0 +1 @@
1
+ export type XaiVideoModelId = 'grok-imagine-video' | (string & {});