@tanstack/ai-grok 0.13.0 → 0.14.1

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.
@@ -0,0 +1,128 @@
1
+ import { BaseVideoAdapter, DurationOptions } from '@tanstack/ai/adapters';
2
+ import { VideoGenerationOptions, VideoJobResult, VideoStatusResult, VideoUrlResult } from '@tanstack/ai';
3
+ import { GrokVideoModel } from '../model-meta.js';
4
+ import { GrokVideoModelDurationByName, GrokVideoModelInputModalitiesByName, GrokVideoModelProviderOptionsByName, GrokVideoModelSizeByName, GrokVideoProviderOptions } from '../video/video-provider-options.js';
5
+ import { GrokClientConfig } from '../utils.js';
6
+ /**
7
+ * Configuration for Grok video adapter.
8
+ *
9
+ * @experimental Video generation is an experimental feature and may change.
10
+ */
11
+ export interface GrokVideoConfig extends GrokClientConfig {
12
+ }
13
+ /**
14
+ * Grok Video Generation Adapter (xAI Imagine API)
15
+ *
16
+ * Tree-shakeable adapter for the grok-imagine video models using the
17
+ * async jobs/polling architecture: create a generation request, poll it,
18
+ * then read the completed video URL.
19
+ *
20
+ * `grok-imagine-video` (v1.0) supports text-to-video and image-to-video.
21
+ * `grok-imagine-video-1.5` is image-to-video only — every request needs an
22
+ * image prompt part as the starting frame, and the adapter rejects a
23
+ * text-only prompt with a clear error rather than a raw API 400.
24
+ *
25
+ * The Imagine video endpoints are not part of the OpenAI SDK surface (and
26
+ * xAI rejects the SDK's multipart paths), so requests are plain JSON calls
27
+ * issued with the configured `fetch` (or the global one).
28
+ *
29
+ * @experimental Video generation is an experimental feature and may change.
30
+ *
31
+ * Features:
32
+ * - Async job-based video generation (1–15 second clips with audio)
33
+ * - Aspect-ratio sizing via the "aspectRatio_resolution" size template
34
+ * (e.g. '16:9_720p'), consistent with the grok-imagine image models
35
+ * - Image-to-video via an `image` prompt part (starting frame URL or data URI)
36
+ * - Usage reporting: billed seconds (`unitsBilled`) and exact cost
37
+ */
38
+ export declare class GrokVideoAdapter<TModel extends GrokVideoModel> extends BaseVideoAdapter<TModel, GrokVideoProviderOptions, GrokVideoModelProviderOptionsByName, GrokVideoModelSizeByName, GrokVideoModelInputModalitiesByName, GrokVideoModelDurationByName> {
39
+ readonly name: "grok";
40
+ private readonly clientConfig;
41
+ constructor(config: GrokVideoConfig, model: TModel);
42
+ private get fetch();
43
+ private request;
44
+ /**
45
+ * Reads the error message out of an Imagine API error body
46
+ * (`{"code": "...", "error": "..."}`), falling back to the raw text.
47
+ */
48
+ private errorMessage;
49
+ createVideoJob(options: VideoGenerationOptions<GrokVideoProviderOptions, GrokVideoModelSizeByName[TModel], GrokVideoModelDurationByName[TModel]>): Promise<VideoJobResult>;
50
+ private retrieveJob;
51
+ getVideoStatus(jobId: string): Promise<VideoStatusResult>;
52
+ getVideoUrl(jobId: string): Promise<VideoUrlResult>;
53
+ /**
54
+ * Maps Imagine API job statuses onto the generic video status set. The
55
+ * API reports 'pending' while queued/generating (with a numeric
56
+ * `progress`), then a terminal 'done' / 'failed' / 'expired'.
57
+ */
58
+ protected mapStatus(apiStatus: string | undefined): 'pending' | 'processing' | 'completed' | 'failed';
59
+ /**
60
+ * Both grok-imagine video models accept a continuous 1–15 integer-second
61
+ * range. Consumers can use this to render UI without provider knowledge.
62
+ */
63
+ availableDurations(): DurationOptions<GrokVideoModelDurationByName[TModel]>;
64
+ /**
65
+ * Coerce a raw seconds value to the closest valid duration (clamped to
66
+ * [1, 15] and rounded to whole seconds).
67
+ */
68
+ snapDuration(seconds: number): GrokVideoModelDurationByName[TModel] | undefined;
69
+ }
70
+ /**
71
+ * Creates a Grok video adapter with an explicit API key.
72
+ * Type resolution happens here at the call site.
73
+ *
74
+ * @experimental Video generation is an experimental feature and may change.
75
+ *
76
+ * @param model - The model name (e.g., 'grok-imagine-video')
77
+ * @param apiKey - Your xAI API key
78
+ * @param config - Optional additional configuration
79
+ * @returns Configured Grok video adapter instance with resolved types
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * // grok-imagine-video (v1.0) supports text-to-video.
84
+ * const adapter = createGrokVideo('grok-imagine-video', 'xai-...');
85
+ *
86
+ * const { jobId } = await generateVideo({
87
+ * adapter,
88
+ * prompt: 'A beautiful sunset over the ocean',
89
+ * size: '16:9_720p',
90
+ * duration: 5
91
+ * });
92
+ * ```
93
+ */
94
+ export declare function createGrokVideo<TModel extends GrokVideoModel>(model: TModel, apiKey: string, config?: Omit<GrokVideoConfig, 'apiKey'>): GrokVideoAdapter<TModel>;
95
+ /**
96
+ * Creates a Grok video adapter with automatic API key detection from environment variables.
97
+ * Type resolution happens here at the call site.
98
+ *
99
+ * Looks for `XAI_API_KEY` in:
100
+ * - `process.env` (Node.js)
101
+ * - `window.env` (Browser with injected env)
102
+ *
103
+ * @experimental Video generation is an experimental feature and may change.
104
+ *
105
+ * @param model - The model name (e.g., 'grok-imagine-video-1.5')
106
+ * @param config - Optional configuration (excluding apiKey which is auto-detected)
107
+ * @returns Configured Grok video adapter instance with resolved types
108
+ * @throws Error if XAI_API_KEY is not found in environment
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * // Automatically uses XAI_API_KEY from environment
113
+ * const adapter = grokVideo('grok-imagine-video-1.5');
114
+ *
115
+ * // Image-to-video only: the prompt must carry a starting-frame image part.
116
+ * const { jobId } = await generateVideo({
117
+ * adapter,
118
+ * prompt: [
119
+ * { type: 'text', content: 'Make the cat start playing the piano' },
120
+ * { type: 'image', source: { type: 'url', value: 'https://example.com/cat.png' } },
121
+ * ],
122
+ * });
123
+ *
124
+ * // Poll for status
125
+ * const status = await getVideoJobStatus({ adapter, jobId });
126
+ * ```
127
+ */
128
+ export declare function grokVideo<TModel extends GrokVideoModel>(model: TModel, config?: Omit<GrokVideoConfig, 'apiKey'>): GrokVideoAdapter<TModel>;
@@ -0,0 +1,237 @@
1
+ import { resolveMediaPrompt } from "@tanstack/ai";
2
+ import { BaseVideoAdapter, snapToDurationOption } from "@tanstack/ai/adapters";
3
+ import { toRunErrorPayload } from "@tanstack/ai/adapter-internals";
4
+ import { withGrokDefaults, getGrokApiKeyFromEnv } from "../utils/client.js";
5
+ import { validateVideoSize, isImageToVideoOnlyModel, parseGrokVideoSize, getGrokVideoDurationOptions } from "../video/video-provider-options.js";
6
+ const USD_TICKS_PER_DOLLAR = 1e10;
7
+ function imagePartToUrl(part) {
8
+ if (part.source.type === "url") return part.source.value;
9
+ return `data:${part.source.mimeType};base64,${part.source.value}`;
10
+ }
11
+ function buildGrokVideoUsage(response) {
12
+ const seconds = response.video?.duration;
13
+ const ticks = response.usage?.cost_in_usd_ticks;
14
+ if (seconds === void 0 && ticks === void 0) return void 0;
15
+ return {
16
+ promptTokens: 0,
17
+ completionTokens: 0,
18
+ totalTokens: 0,
19
+ ...seconds !== void 0 && { unitsBilled: seconds },
20
+ ...ticks !== void 0 && { cost: ticks / USD_TICKS_PER_DOLLAR }
21
+ };
22
+ }
23
+ class GrokVideoAdapter extends BaseVideoAdapter {
24
+ name = "grok";
25
+ clientConfig;
26
+ constructor(config, model) {
27
+ super({}, model);
28
+ this.clientConfig = withGrokDefaults(config);
29
+ }
30
+ get fetch() {
31
+ return this.clientConfig.fetch ?? fetch;
32
+ }
33
+ async request(path, init) {
34
+ return await this.fetch(`${this.clientConfig.baseURL}${path}`, {
35
+ ...init,
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ Authorization: `Bearer ${this.clientConfig.apiKey}`
39
+ }
40
+ });
41
+ }
42
+ /**
43
+ * Reads the error message out of an Imagine API error body
44
+ * (`{"code": "...", "error": "..."}`), falling back to the raw text.
45
+ */
46
+ async errorMessage(response) {
47
+ const body = await response.text();
48
+ try {
49
+ const parsed = JSON.parse(body);
50
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed && typeof parsed.error === "string") {
51
+ return parsed.error;
52
+ }
53
+ } catch {
54
+ }
55
+ return body;
56
+ }
57
+ async createVideoJob(options) {
58
+ const { model, size, modelOptions, logger } = options;
59
+ validateVideoSize(model, size);
60
+ const rawDuration = modelOptions?.duration ?? options.duration;
61
+ const duration = rawDuration !== void 0 ? this.snapDuration(rawDuration) : void 0;
62
+ const resolved = resolveMediaPrompt(options.prompt);
63
+ if (resolved.videos.length > 0) {
64
+ throw new Error(
65
+ `${this.name}.createVideoJob does not support video prompt parts (model: ${model}).`
66
+ );
67
+ }
68
+ if (resolved.audios.length > 0) {
69
+ throw new Error(
70
+ `${this.name}.createVideoJob does not support audio prompt parts (model: ${model}).`
71
+ );
72
+ }
73
+ if (resolved.images.length === 0 && isImageToVideoOnlyModel(model)) {
74
+ throw new Error(
75
+ `${this.name}: ${model} does not support text-to-video — it is image-to-video only. Include an image prompt part as the starting frame, or use 'grok-imagine-video' for text-to-video.`
76
+ );
77
+ }
78
+ if (resolved.images.length > 1) {
79
+ throw new Error(
80
+ `${this.name}: ${model} accepts at most one starting-frame image; received ${resolved.images.length}.`
81
+ );
82
+ }
83
+ const [startFrame] = resolved.images;
84
+ const parsedSize = size !== void 0 ? parseGrokVideoSize(size) : void 0;
85
+ const request = {
86
+ model,
87
+ prompt: resolved.text,
88
+ ...startFrame && { image: { url: imagePartToUrl(startFrame) } },
89
+ ...parsedSize && {
90
+ aspect_ratio: parsedSize.aspectRatio,
91
+ ...parsedSize.resolution !== void 0 && {
92
+ resolution: parsedSize.resolution
93
+ }
94
+ },
95
+ ...modelOptions,
96
+ // Spread after modelOptions so the snapped duration is authoritative
97
+ // (modelOptions.duration is folded into `duration` via snapDuration above).
98
+ ...duration !== void 0 && { duration }
99
+ };
100
+ try {
101
+ logger.request(
102
+ `activity=video.create provider=${this.name} model=${model} size=${size ?? "default"} duration=${duration ?? "default"}`,
103
+ { provider: this.name, model }
104
+ );
105
+ const response = await this.request("/videos/generations", {
106
+ method: "POST",
107
+ body: JSON.stringify(request)
108
+ });
109
+ if (!response.ok) {
110
+ throw new Error(
111
+ `grok: video generation request failed (${response.status} ${response.statusText}): ${await this.errorMessage(response)}`
112
+ );
113
+ }
114
+ const result = await response.json();
115
+ if (!result.request_id) {
116
+ throw new Error(
117
+ "grok: video generation response contained no request_id"
118
+ );
119
+ }
120
+ return { jobId: result.request_id, model };
121
+ } catch (error) {
122
+ logger.errors(`${this.name}.createVideoJob fatal`, {
123
+ error: toRunErrorPayload(error, `${this.name}.createVideoJob failed`),
124
+ source: `${this.name}.createVideoJob`
125
+ });
126
+ throw error;
127
+ }
128
+ }
129
+ async retrieveJob(jobId) {
130
+ const response = await this.request(`/videos/${jobId}`);
131
+ if (!response.ok) {
132
+ const error = new Error(
133
+ `grok: video status request failed (${response.status} ${response.statusText}): ${await this.errorMessage(response)}`
134
+ );
135
+ error.status = response.status;
136
+ throw error;
137
+ }
138
+ return await response.json();
139
+ }
140
+ async getVideoStatus(jobId) {
141
+ let response;
142
+ try {
143
+ response = await this.retrieveJob(jobId);
144
+ } catch (error) {
145
+ if (error.status === 404) {
146
+ return { jobId, status: "failed", error: "Job not found" };
147
+ }
148
+ throw error;
149
+ }
150
+ return {
151
+ jobId,
152
+ status: this.mapStatus(response.status),
153
+ ...response.progress !== void 0 && { progress: response.progress },
154
+ ...response.error !== void 0 && { error: response.error }
155
+ };
156
+ }
157
+ async getVideoUrl(jobId) {
158
+ let response;
159
+ try {
160
+ response = await this.retrieveJob(jobId);
161
+ } catch (error) {
162
+ if (error.status === 404) {
163
+ throw new Error(`Video job not found: ${jobId}`);
164
+ }
165
+ throw error;
166
+ }
167
+ const status = this.mapStatus(response.status);
168
+ if (status === "failed") {
169
+ throw new Error(
170
+ `Video generation failed${response.error ? `: ${response.error}` : ""}. Job ID: ${jobId}`
171
+ );
172
+ }
173
+ const url = response.video?.url;
174
+ if (!url) {
175
+ throw new Error(
176
+ `Video is not ready for download. Check status first. Job ID: ${jobId}`
177
+ );
178
+ }
179
+ const usage = buildGrokVideoUsage(response);
180
+ return {
181
+ jobId,
182
+ url,
183
+ ...usage && { usage }
184
+ };
185
+ }
186
+ /**
187
+ * Maps Imagine API job statuses onto the generic video status set. The
188
+ * API reports 'pending' while queued/generating (with a numeric
189
+ * `progress`), then a terminal 'done' / 'failed' / 'expired'.
190
+ */
191
+ mapStatus(apiStatus) {
192
+ switch (apiStatus) {
193
+ case "pending":
194
+ case "queued":
195
+ return "pending";
196
+ case "done":
197
+ case "completed":
198
+ case "succeeded":
199
+ return "completed";
200
+ case "failed":
201
+ case "expired":
202
+ case "error":
203
+ case "cancelled":
204
+ return "failed";
205
+ case void 0:
206
+ default:
207
+ return "processing";
208
+ }
209
+ }
210
+ /**
211
+ * Both grok-imagine video models accept a continuous 1–15 integer-second
212
+ * range. Consumers can use this to render UI without provider knowledge.
213
+ */
214
+ availableDurations() {
215
+ return getGrokVideoDurationOptions(this.model);
216
+ }
217
+ /**
218
+ * Coerce a raw seconds value to the closest valid duration (clamped to
219
+ * [1, 15] and rounded to whole seconds).
220
+ */
221
+ snapDuration(seconds) {
222
+ return snapToDurationOption(seconds, this.availableDurations());
223
+ }
224
+ }
225
+ function createGrokVideo(model, apiKey, config) {
226
+ return new GrokVideoAdapter({ apiKey, ...config }, model);
227
+ }
228
+ function grokVideo(model, config) {
229
+ const apiKey = getGrokApiKeyFromEnv();
230
+ return createGrokVideo(model, apiKey, config);
231
+ }
232
+ export {
233
+ GrokVideoAdapter,
234
+ createGrokVideo,
235
+ grokVideo
236
+ };
237
+ //# sourceMappingURL=video.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"video.js","sources":["../../../src/adapters/video.ts"],"sourcesContent":["import { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseVideoAdapter, snapToDurationOption } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n getGrokVideoDurationOptions,\n isImageToVideoOnlyModel,\n parseGrokVideoSize,\n validateVideoSize,\n} from '../video/video-provider-options'\nimport type { DurationOptions } from '@tanstack/ai/adapters'\nimport type {\n ImagePart,\n MediaInputMetadata,\n TokenUsage,\n VideoGenerationOptions,\n VideoJobResult,\n VideoStatusResult,\n VideoUrlResult,\n} from '@tanstack/ai'\nimport type { GrokVideoModel } from '../model-meta'\nimport type {\n GrokVideoModelDurationByName,\n GrokVideoModelInputModalitiesByName,\n GrokVideoModelProviderOptionsByName,\n GrokVideoModelSizeByName,\n GrokVideoProviderOptions,\n} from '../video/video-provider-options'\nimport type { GrokClientConfig } from '../utils'\n\n/**\n * Configuration for Grok video adapter.\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport interface GrokVideoConfig extends GrokClientConfig {}\n\n/**\n * xAI bills video generation in \"USD ticks\": 10^10 ticks per US dollar\n * (e.g. one grok-imagine-video-1.5 second costs $0.08 = 800_000_000 ticks).\n */\nconst USD_TICKS_PER_DOLLAR = 10_000_000_000\n\n/** Response of POST /v1/videos/generations. */\ninterface GrokVideoCreateResponse {\n request_id?: string\n}\n\n/** Response of GET /v1/videos/{request_id}. */\ninterface GrokVideoStatusResponse {\n status?: string\n progress?: number\n model?: string\n video?: {\n url?: string\n duration?: number\n }\n usage?: {\n cost_in_usd_ticks?: number\n }\n error?: string\n}\n\n/**\n * Convert a TanStack ImagePart to the URL string accepted by xAI's Imagine\n * video endpoint: public URLs pass through (fetched by xAI's servers), data\n * sources become base64 data URIs.\n */\nfunction imagePartToUrl(part: ImagePart<MediaInputMetadata>): string {\n if (part.source.type === 'url') return part.source.value\n return `data:${part.source.mimeType};base64,${part.source.value}`\n}\n\nfunction buildGrokVideoUsage(\n response: GrokVideoStatusResponse,\n): TokenUsage | undefined {\n const seconds = response.video?.duration\n const ticks = response.usage?.cost_in_usd_ticks\n if (seconds === undefined && ticks === undefined) return undefined\n return {\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n ...(seconds !== undefined && { unitsBilled: seconds }),\n ...(ticks !== undefined && { cost: ticks / USD_TICKS_PER_DOLLAR }),\n }\n}\n\n/**\n * Grok Video Generation Adapter (xAI Imagine API)\n *\n * Tree-shakeable adapter for the grok-imagine video models using the\n * async jobs/polling architecture: create a generation request, poll it,\n * then read the completed video URL.\n *\n * `grok-imagine-video` (v1.0) supports text-to-video and image-to-video.\n * `grok-imagine-video-1.5` is image-to-video only — every request needs an\n * image prompt part as the starting frame, and the adapter rejects a\n * text-only prompt with a clear error rather than a raw API 400.\n *\n * The Imagine video endpoints are not part of the OpenAI SDK surface (and\n * xAI rejects the SDK's multipart paths), so requests are plain JSON calls\n * issued with the configured `fetch` (or the global one).\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * Features:\n * - Async job-based video generation (1–15 second clips with audio)\n * - Aspect-ratio sizing via the \"aspectRatio_resolution\" size template\n * (e.g. '16:9_720p'), consistent with the grok-imagine image models\n * - Image-to-video via an `image` prompt part (starting frame URL or data URI)\n * - Usage reporting: billed seconds (`unitsBilled`) and exact cost\n */\nexport class GrokVideoAdapter<\n TModel extends GrokVideoModel,\n> extends BaseVideoAdapter<\n TModel,\n GrokVideoProviderOptions,\n GrokVideoModelProviderOptionsByName,\n GrokVideoModelSizeByName,\n GrokVideoModelInputModalitiesByName,\n GrokVideoModelDurationByName\n> {\n readonly name = 'grok' as const\n\n private readonly clientConfig: GrokVideoConfig\n\n constructor(config: GrokVideoConfig, model: TModel) {\n super({}, model)\n this.clientConfig = withGrokDefaults(config)\n }\n\n private get fetch(): (\n input: string,\n init?: RequestInit,\n ) => Promise<Response> {\n return this.clientConfig.fetch ?? fetch\n }\n\n private async request(\n path: string,\n init?: Omit<RequestInit, 'headers'>,\n ): Promise<Response> {\n return await this.fetch(`${this.clientConfig.baseURL}${path}`, {\n ...init,\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.clientConfig.apiKey}`,\n },\n })\n }\n\n /**\n * Reads the error message out of an Imagine API error body\n * (`{\"code\": \"...\", \"error\": \"...\"}`), falling back to the raw text.\n */\n private async errorMessage(response: Response): Promise<string> {\n const body = await response.text()\n try {\n const parsed: unknown = JSON.parse(body)\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n 'error' in parsed &&\n typeof parsed.error === 'string'\n ) {\n return parsed.error\n }\n } catch {\n // not JSON — fall through to the raw body\n }\n return body\n }\n\n async createVideoJob(\n options: VideoGenerationOptions<\n GrokVideoProviderOptions,\n GrokVideoModelSizeByName[TModel],\n GrokVideoModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult> {\n const { model, size, modelOptions, logger } = options\n\n validateVideoSize(model, size)\n\n // Coerce the requested duration into the model's valid range (1–15s,\n // integer) instead of rejecting it — `snapDuration` clamps and rounds.\n // modelOptions wins over the generic `duration`, mirroring the size\n // precedence below.\n const rawDuration = modelOptions?.duration ?? options.duration\n const duration =\n rawDuration !== undefined ? this.snapDuration(rawDuration) : undefined\n\n // The interleaved prompt decomposes into verbatim text plus typed media\n // buckets. The Imagine video endpoint takes a text prompt and an optional\n // starting frame; reject the modalities it can't consume.\n const resolved = resolveMediaPrompt(options.prompt)\n if (resolved.videos.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support video prompt parts (model: ${model}).`,\n )\n }\n if (resolved.audios.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support audio prompt parts (model: ${model}).`,\n )\n }\n // grok-imagine-video-1.5 is image-to-video only — text-to-video is\n // rejected by the API, so fail fast with a clear, actionable message\n // pointing at the model that does support text-to-video.\n if (resolved.images.length === 0 && isImageToVideoOnlyModel(model)) {\n throw new Error(\n `${this.name}: ${model} does not support text-to-video — it is image-to-video only. ` +\n `Include an image prompt part as the starting frame, or use 'grok-imagine-video' for text-to-video.`,\n )\n }\n if (resolved.images.length > 1) {\n throw new Error(\n `${this.name}: ${model} accepts at most one starting-frame image; received ${resolved.images.length}.`,\n )\n }\n\n // Image-to-video: the single image prompt part becomes the starting frame\n // and the prompt text describes the desired motion. URL sources are\n // fetched by xAI's servers; data sources are sent as base64 data URIs.\n const [startFrame] = resolved.images\n\n // The generic `size` option carries an \"aspectRatio_resolution\" template\n // (e.g. '16:9_720p') and maps to the Imagine API's `aspect_ratio` /\n // `resolution` parameters; explicit modelOptions win over the template.\n const parsedSize = size !== undefined ? parseGrokVideoSize(size) : undefined\n const request = {\n model,\n prompt: resolved.text,\n ...(startFrame && { image: { url: imagePartToUrl(startFrame) } }),\n ...(parsedSize && {\n aspect_ratio: parsedSize.aspectRatio,\n ...(parsedSize.resolution !== undefined && {\n resolution: parsedSize.resolution,\n }),\n }),\n ...modelOptions,\n // Spread after modelOptions so the snapped duration is authoritative\n // (modelOptions.duration is folded into `duration` via snapDuration above).\n ...(duration !== undefined && { duration }),\n }\n\n try {\n logger.request(\n `activity=video.create provider=${this.name} model=${model} size=${size ?? 'default'} duration=${duration ?? 'default'}`,\n { provider: this.name, model },\n )\n\n const response = await this.request('/videos/generations', {\n method: 'POST',\n body: JSON.stringify(request),\n })\n if (!response.ok) {\n throw new Error(\n `grok: video generation request failed (${response.status} ${response.statusText}): ${await this.errorMessage(response)}`,\n )\n }\n\n const result = (await response.json()) as GrokVideoCreateResponse\n if (!result.request_id) {\n throw new Error(\n 'grok: video generation response contained no request_id',\n )\n }\n return { jobId: result.request_id, model }\n } catch (error: unknown) {\n logger.errors(`${this.name}.createVideoJob fatal`, {\n error: toRunErrorPayload(error, `${this.name}.createVideoJob failed`),\n source: `${this.name}.createVideoJob`,\n })\n throw error\n }\n }\n\n private async retrieveJob(jobId: string): Promise<GrokVideoStatusResponse> {\n const response = await this.request(`/videos/${jobId}`)\n if (!response.ok) {\n const error = new Error(\n `grok: video status request failed (${response.status} ${response.statusText}): ${await this.errorMessage(response)}`,\n )\n ;(error as { status?: number }).status = response.status\n throw error\n }\n return (await response.json()) as GrokVideoStatusResponse\n }\n\n async getVideoStatus(jobId: string): Promise<VideoStatusResult> {\n let response: GrokVideoStatusResponse\n try {\n response = await this.retrieveJob(jobId)\n } catch (error) {\n if ((error as { status?: number }).status === 404) {\n return { jobId, status: 'failed', error: 'Job not found' }\n }\n throw error\n }\n\n return {\n jobId,\n status: this.mapStatus(response.status),\n ...(response.progress !== undefined && { progress: response.progress }),\n ...(response.error !== undefined && { error: response.error }),\n }\n }\n\n async getVideoUrl(jobId: string): Promise<VideoUrlResult> {\n let response: GrokVideoStatusResponse\n try {\n response = await this.retrieveJob(jobId)\n } catch (error) {\n if ((error as { status?: number }).status === 404) {\n throw new Error(`Video job not found: ${jobId}`)\n }\n throw error\n }\n\n const status = this.mapStatus(response.status)\n if (status === 'failed') {\n throw new Error(\n `Video generation failed${response.error ? `: ${response.error}` : ''}. Job ID: ${jobId}`,\n )\n }\n const url = response.video?.url\n if (!url) {\n throw new Error(\n `Video is not ready for download. Check status first. Job ID: ${jobId}`,\n )\n }\n\n const usage = buildGrokVideoUsage(response)\n return {\n jobId,\n url,\n ...(usage && { usage }),\n }\n }\n\n /**\n * Maps Imagine API job statuses onto the generic video status set. The\n * API reports 'pending' while queued/generating (with a numeric\n * `progress`), then a terminal 'done' / 'failed' / 'expired'.\n */\n protected mapStatus(\n apiStatus: string | undefined,\n ): 'pending' | 'processing' | 'completed' | 'failed' {\n switch (apiStatus) {\n case 'pending':\n case 'queued':\n return 'pending'\n case 'done':\n case 'completed':\n case 'succeeded':\n return 'completed'\n case 'failed':\n case 'expired':\n case 'error':\n case 'cancelled':\n return 'failed'\n case undefined:\n default:\n return 'processing'\n }\n }\n\n /**\n * Both grok-imagine video models accept a continuous 1–15 integer-second\n * range. Consumers can use this to render UI without provider knowledge.\n */\n override availableDurations(): DurationOptions<\n GrokVideoModelDurationByName[TModel]\n > {\n return getGrokVideoDurationOptions(this.model)\n }\n\n /**\n * Coerce a raw seconds value to the closest valid duration (clamped to\n * [1, 15] and rounded to whole seconds).\n */\n override snapDuration(\n seconds: number,\n ): GrokVideoModelDurationByName[TModel] | undefined {\n return snapToDurationOption(seconds, this.availableDurations())\n }\n}\n\n/**\n * Creates a Grok video adapter with an explicit API key.\n * Type resolution happens here at the call site.\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @param model - The model name (e.g., 'grok-imagine-video')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok video adapter instance with resolved types\n *\n * @example\n * ```typescript\n * // grok-imagine-video (v1.0) supports text-to-video.\n * const adapter = createGrokVideo('grok-imagine-video', 'xai-...');\n *\n * const { jobId } = await generateVideo({\n * adapter,\n * prompt: 'A beautiful sunset over the ocean',\n * size: '16:9_720p',\n * duration: 5\n * });\n * ```\n */\nexport function createGrokVideo<TModel extends GrokVideoModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokVideoConfig, 'apiKey'>,\n): GrokVideoAdapter<TModel> {\n return new GrokVideoAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok video adapter with automatic API key detection from environment variables.\n * Type resolution happens here at the call site.\n *\n * Looks for `XAI_API_KEY` in:\n * - `process.env` (Node.js)\n * - `window.env` (Browser with injected env)\n *\n * @experimental Video generation is an experimental feature and may change.\n *\n * @param model - The model name (e.g., 'grok-imagine-video-1.5')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok video adapter instance with resolved types\n * @throws Error if XAI_API_KEY is not found in environment\n *\n * @example\n * ```typescript\n * // Automatically uses XAI_API_KEY from environment\n * const adapter = grokVideo('grok-imagine-video-1.5');\n *\n * // Image-to-video only: the prompt must carry a starting-frame image part.\n * const { jobId } = await generateVideo({\n * adapter,\n * prompt: [\n * { type: 'text', content: 'Make the cat start playing the piano' },\n * { type: 'image', source: { type: 'url', value: 'https://example.com/cat.png' } },\n * ],\n * });\n *\n * // Poll for status\n * const status = await getVideoJobStatus({ adapter, jobId });\n * ```\n */\nexport function grokVideo<TModel extends GrokVideoModel>(\n model: TModel,\n config?: Omit<GrokVideoConfig, 'apiKey'>,\n): GrokVideoAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokVideo(model, apiKey, config)\n}\n"],"names":[],"mappings":";;;;;AAyCA,MAAM,uBAAuB;AA2B7B,SAAS,eAAe,MAA6C;AACnE,MAAI,KAAK,OAAO,SAAS,MAAO,QAAO,KAAK,OAAO;AACnD,SAAO,QAAQ,KAAK,OAAO,QAAQ,WAAW,KAAK,OAAO,KAAK;AACjE;AAEA,SAAS,oBACP,UACwB;AACxB,QAAM,UAAU,SAAS,OAAO;AAChC,QAAM,QAAQ,SAAS,OAAO;AAC9B,MAAI,YAAY,UAAa,UAAU,OAAW,QAAO;AACzD,SAAO;AAAA,IACL,cAAc;AAAA,IACd,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,GAAI,YAAY,UAAa,EAAE,aAAa,QAAA;AAAA,IAC5C,GAAI,UAAU,UAAa,EAAE,MAAM,QAAQ,qBAAA;AAAA,EAAqB;AAEpE;AA2BO,MAAM,yBAEH,iBAOR;AAAA,EACS,OAAO;AAAA,EAEC;AAAA,EAEjB,YAAY,QAAyB,OAAe;AAClD,UAAM,CAAA,GAAI,KAAK;AACf,SAAK,eAAe,iBAAiB,MAAM;AAAA,EAC7C;AAAA,EAEA,IAAY,QAGW;AACrB,WAAO,KAAK,aAAa,SAAS;AAAA,EACpC;AAAA,EAEA,MAAc,QACZ,MACA,MACmB;AACnB,WAAO,MAAM,KAAK,MAAM,GAAG,KAAK,aAAa,OAAO,GAAG,IAAI,IAAI;AAAA,MAC7D,GAAG;AAAA,MACH,SAAS;AAAA,QACP,gBAAgB;AAAA,QAChB,eAAe,UAAU,KAAK,aAAa,MAAM;AAAA,MAAA;AAAA,IACnD,CACD;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,aAAa,UAAqC;AAC9D,UAAM,OAAO,MAAM,SAAS,KAAA;AAC5B,QAAI;AACF,YAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,UACE,OAAO,WAAW,YAClB,WAAW,QACX,WAAW,UACX,OAAO,OAAO,UAAU,UACxB;AACA,eAAO,OAAO;AAAA,MAChB;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,eACJ,SAKyB;AACzB,UAAM,EAAE,OAAO,MAAM,cAAc,WAAW;AAE9C,sBAAkB,OAAO,IAAI;AAM7B,UAAM,cAAc,cAAc,YAAY,QAAQ;AACtD,UAAM,WACJ,gBAAgB,SAAY,KAAK,aAAa,WAAW,IAAI;AAK/D,UAAM,WAAW,mBAAmB,QAAQ,MAAM;AAClD,QAAI,SAAS,OAAO,SAAS,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,+DAA+D,KAAK;AAAA,MAAA;AAAA,IAEpF;AACA,QAAI,SAAS,OAAO,SAAS,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,+DAA+D,KAAK;AAAA,MAAA;AAAA,IAEpF;AAIA,QAAI,SAAS,OAAO,WAAW,KAAK,wBAAwB,KAAK,GAAG;AAClE,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,KAAK,KAAK;AAAA,MAAA;AAAA,IAG1B;AACA,QAAI,SAAS,OAAO,SAAS,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR,GAAG,KAAK,IAAI,KAAK,KAAK,uDAAuD,SAAS,OAAO,MAAM;AAAA,MAAA;AAAA,IAEvG;AAKA,UAAM,CAAC,UAAU,IAAI,SAAS;AAK9B,UAAM,aAAa,SAAS,SAAY,mBAAmB,IAAI,IAAI;AACnE,UAAM,UAAU;AAAA,MACd;AAAA,MACA,QAAQ,SAAS;AAAA,MACjB,GAAI,cAAc,EAAE,OAAO,EAAE,KAAK,eAAe,UAAU,IAAE;AAAA,MAC7D,GAAI,cAAc;AAAA,QAChB,cAAc,WAAW;AAAA,QACzB,GAAI,WAAW,eAAe,UAAa;AAAA,UACzC,YAAY,WAAW;AAAA,QAAA;AAAA,MACzB;AAAA,MAEF,GAAG;AAAA;AAAA;AAAA,MAGH,GAAI,aAAa,UAAa,EAAE,SAAA;AAAA,IAAS;AAG3C,QAAI;AACF,aAAO;AAAA,QACL,kCAAkC,KAAK,IAAI,UAAU,KAAK,SAAS,QAAQ,SAAS,aAAa,YAAY,SAAS;AAAA,QACtH,EAAE,UAAU,KAAK,MAAM,MAAA;AAAA,MAAM;AAG/B,YAAM,WAAW,MAAM,KAAK,QAAQ,uBAAuB;AAAA,QACzD,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU,OAAO;AAAA,MAAA,CAC7B;AACD,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI;AAAA,UACR,0CAA0C,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,MAAM,KAAK,aAAa,QAAQ,CAAC;AAAA,QAAA;AAAA,MAE3H;AAEA,YAAM,SAAU,MAAM,SAAS,KAAA;AAC/B,UAAI,CAAC,OAAO,YAAY;AACtB,cAAM,IAAI;AAAA,UACR;AAAA,QAAA;AAAA,MAEJ;AACA,aAAO,EAAE,OAAO,OAAO,YAAY,MAAA;AAAA,IACrC,SAAS,OAAgB;AACvB,aAAO,OAAO,GAAG,KAAK,IAAI,yBAAyB;AAAA,QACjD,OAAO,kBAAkB,OAAO,GAAG,KAAK,IAAI,wBAAwB;AAAA,QACpE,QAAQ,GAAG,KAAK,IAAI;AAAA,MAAA,CACrB;AACD,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,OAAiD;AACzE,UAAM,WAAW,MAAM,KAAK,QAAQ,WAAW,KAAK,EAAE;AACtD,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,IAAI;AAAA,QAChB,sCAAsC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,MAAM,KAAK,aAAa,QAAQ,CAAC;AAAA,MAAA;AAEnH,YAA8B,SAAS,SAAS;AAClD,YAAM;AAAA,IACR;AACA,WAAQ,MAAM,SAAS,KAAA;AAAA,EACzB;AAAA,EAEA,MAAM,eAAe,OAA2C;AAC9D,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,YAAY,KAAK;AAAA,IACzC,SAAS,OAAO;AACd,UAAK,MAA8B,WAAW,KAAK;AACjD,eAAO,EAAE,OAAO,QAAQ,UAAU,OAAO,gBAAA;AAAA,MAC3C;AACA,YAAM;AAAA,IACR;AAEA,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,KAAK,UAAU,SAAS,MAAM;AAAA,MACtC,GAAI,SAAS,aAAa,UAAa,EAAE,UAAU,SAAS,SAAA;AAAA,MAC5D,GAAI,SAAS,UAAU,UAAa,EAAE,OAAO,SAAS,MAAA;AAAA,IAAM;AAAA,EAEhE;AAAA,EAEA,MAAM,YAAY,OAAwC;AACxD,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,KAAK,YAAY,KAAK;AAAA,IACzC,SAAS,OAAO;AACd,UAAK,MAA8B,WAAW,KAAK;AACjD,cAAM,IAAI,MAAM,wBAAwB,KAAK,EAAE;AAAA,MACjD;AACA,YAAM;AAAA,IACR;AAEA,UAAM,SAAS,KAAK,UAAU,SAAS,MAAM;AAC7C,QAAI,WAAW,UAAU;AACvB,YAAM,IAAI;AAAA,QACR,0BAA0B,SAAS,QAAQ,KAAK,SAAS,KAAK,KAAK,EAAE,aAAa,KAAK;AAAA,MAAA;AAAA,IAE3F;AACA,UAAM,MAAM,SAAS,OAAO;AAC5B,QAAI,CAAC,KAAK;AACR,YAAM,IAAI;AAAA,QACR,gEAAgE,KAAK;AAAA,MAAA;AAAA,IAEzE;AAEA,UAAM,QAAQ,oBAAoB,QAAQ;AAC1C,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,GAAI,SAAS,EAAE,MAAA;AAAA,IAAM;AAAA,EAEzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,UACR,WACmD;AACnD,YAAQ,WAAA;AAAA,MACN,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,qBAEP;AACA,WAAO,4BAA4B,KAAK,KAAK;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA,EAMS,aACP,SACkD;AAClD,WAAO,qBAAqB,SAAS,KAAK,mBAAA,CAAoB;AAAA,EAChE;AACF;AA0BO,SAAS,gBACd,OACA,QACA,QAC0B;AAC1B,SAAO,IAAI,iBAAiB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AAC1D;AAmCO,SAAS,UACd,OACA,QAC0B;AAC1B,QAAM,SAAS,qBAAA;AACf,SAAO,gBAAgB,OAAO,QAAQ,MAAM;AAC9C;"}
@@ -2,12 +2,15 @@ export { GrokTextAdapter, createGrokText, grokText, type GrokTextConfig, type Gr
2
2
  export { createGrokSummarize, grokSummarize, type GrokSummarizeConfig, type GrokSummarizeModel, } from './adapters/summarize.js';
3
3
  export { GrokImageAdapter, createGrokImage, grokImage, type GrokImageConfig, } from './adapters/image.js';
4
4
  export type { GrokImageProviderOptions, GrokImageModelProviderOptionsByName, } from './image/image-provider-options.js';
5
+ export { GrokVideoAdapter, createGrokVideo, grokVideo, type GrokVideoConfig, } from './adapters/video.js';
6
+ export { GROK_VIDEO_DURATIONS, getGrokVideoDurationOptions, } from './video/video-provider-options.js';
7
+ export type { GrokVideoProviderOptions, GrokVideoModelProviderOptionsByName, GrokVideoModelSizeByName, GrokVideoModelDurationByName, GrokVideoAspectRatio, GrokVideoResolution, GrokVideoSize, } from './video/video-provider-options.js';
5
8
  export { GrokSpeechAdapter, createGrokSpeech, grokSpeech, type GrokSpeechConfig, } from './adapters/tts.js';
6
9
  export type { GrokTTSProviderOptions, GrokTTSVoice, GrokTTSCodec, } from './audio/tts-provider-options.js';
7
10
  export { GrokTranscriptionAdapter, createGrokTranscription, grokTranscription, type GrokTranscriptionConfig, } from './adapters/transcription.js';
8
11
  export type { GrokTranscriptionProviderOptions, GrokSTTAudioFormat, } from './audio/transcription-provider-options.js';
9
- export type { GrokChatModelProviderOptionsByName, GrokChatModelToolCapabilitiesByName, GrokModelInputModalitiesByName, ResolveProviderOptions, ResolveInputModalities, GrokChatModel, GrokImageModel, GrokTTSModel, GrokTranscriptionModel, GrokRealtimeModel, } from './model-meta.js';
10
- export { GROK_CHAT_MODELS, GROK_IMAGE_MODELS, GROK_TTS_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_REALTIME_MODELS, } from './model-meta.js';
12
+ export type { GrokChatModelProviderOptionsByName, GrokChatModelToolCapabilitiesByName, GrokModelInputModalitiesByName, ResolveProviderOptions, ResolveInputModalities, GrokChatModel, GrokImageModel, GrokVideoModel, GrokTTSModel, GrokTranscriptionModel, GrokRealtimeModel, } from './model-meta.js';
13
+ export { GROK_CHAT_MODELS, GROK_IMAGE_MODELS, GROK_VIDEO_MODELS, GROK_TTS_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_REALTIME_MODELS, } from './model-meta.js';
11
14
  export type { GrokTextMetadata, GrokImageMetadata, GrokAudioMetadata, GrokVideoMetadata, GrokDocumentMetadata, GrokMessageMetadataByModality, } from './message-types.js';
12
15
  export { grokRealtimeToken, grokRealtime } from './realtime/index.js';
13
16
  export type { GrokRealtimeVoice, GrokRealtimeTokenOptions, GrokRealtimeOptions, GrokTurnDetection, GrokSemanticVADConfig, GrokServerVADConfig, } from './realtime/index.js';
package/dist/esm/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { GrokTextAdapter, createGrokText, grokText } from "./adapters/text.js";
2
2
  import { createGrokSummarize, grokSummarize } from "./adapters/summarize.js";
3
3
  import { GrokImageAdapter, createGrokImage, grokImage } from "./adapters/image.js";
4
+ import { GrokVideoAdapter, createGrokVideo, grokVideo } from "./adapters/video.js";
5
+ import { GROK_VIDEO_DURATIONS, getGrokVideoDurationOptions } from "./video/video-provider-options.js";
4
6
  import { GrokSpeechAdapter, createGrokSpeech, grokSpeech } from "./adapters/tts.js";
5
7
  import { GrokTranscriptionAdapter, createGrokTranscription, grokTranscription } from "./adapters/transcription.js";
6
- import { GROK_CHAT_MODELS, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS } from "./model-meta.js";
8
+ import { GROK_CHAT_MODELS, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VIDEO_MODELS } from "./model-meta.js";
7
9
  import { grokRealtimeToken } from "./realtime/token.js";
8
10
  import { grokRealtime } from "./realtime/adapter.js";
9
11
  export {
@@ -12,21 +14,27 @@ export {
12
14
  GROK_REALTIME_MODELS,
13
15
  GROK_TRANSCRIPTION_MODELS,
14
16
  GROK_TTS_MODELS,
17
+ GROK_VIDEO_DURATIONS,
18
+ GROK_VIDEO_MODELS,
15
19
  GrokImageAdapter,
16
20
  GrokSpeechAdapter,
17
21
  GrokTextAdapter,
18
22
  GrokTranscriptionAdapter,
23
+ GrokVideoAdapter,
19
24
  createGrokImage,
20
25
  createGrokSpeech,
21
26
  createGrokSummarize,
22
27
  createGrokText,
23
28
  createGrokTranscription,
29
+ createGrokVideo,
30
+ getGrokVideoDurationOptions,
24
31
  grokImage,
25
32
  grokRealtime,
26
33
  grokRealtimeToken,
27
34
  grokSpeech,
28
35
  grokSummarize,
29
36
  grokText,
30
- grokTranscription
37
+ grokTranscription,
38
+ grokVideo
31
39
  };
32
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
@@ -46,11 +46,18 @@ export declare const GROK_CHAT_MODELS: readonly ["grok-build-0.1", "grok-4.3"];
46
46
  * Grok Image Generation Models
47
47
  */
48
48
  export declare const GROK_IMAGE_MODELS: readonly ["grok-2-image-1212", "grok-imagine-image", "grok-imagine-image-quality"];
49
+ /**
50
+ * Grok Video Generation Models (xAI Imagine API)
51
+ *
52
+ * @experimental Video generation is an experimental feature and may change.
53
+ */
54
+ export declare const GROK_VIDEO_MODELS: readonly ["grok-imagine-video", "grok-imagine-video-1.5"];
49
55
  export declare const GROK_TTS_MODELS: readonly ["grok-tts"];
50
56
  export declare const GROK_TRANSCRIPTION_MODELS: readonly ["grok-stt"];
51
57
  export declare const GROK_REALTIME_MODELS: readonly ["grok-voice-fast-1.0", "grok-voice-think-fast-1.0"];
52
58
  export type GrokChatModel = (typeof GROK_CHAT_MODELS)[number];
53
59
  export type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number];
60
+ export type GrokVideoModel = (typeof GROK_VIDEO_MODELS)[number];
54
61
  export type GrokTTSModel = (typeof GROK_TTS_MODELS)[number];
55
62
  export type GrokTranscriptionModel = (typeof GROK_TRANSCRIPTION_MODELS)[number];
56
63
  export type GrokRealtimeModel = (typeof GROK_REALTIME_MODELS)[number];
@@ -7,6 +7,12 @@ const GROK_IMAGINE_IMAGE = {
7
7
  const GROK_IMAGINE_IMAGE_QUALITY = {
8
8
  name: "grok-imagine-image-quality"
9
9
  };
10
+ const GROK_IMAGINE_VIDEO = {
11
+ name: "grok-imagine-video"
12
+ };
13
+ const GROK_IMAGINE_VIDEO_1_5 = {
14
+ name: "grok-imagine-video-1.5"
15
+ };
10
16
  const GROK_4_3 = {
11
17
  name: "grok-4.3"
12
18
  };
@@ -19,6 +25,10 @@ const GROK_IMAGE_MODELS = [
19
25
  GROK_IMAGINE_IMAGE.name,
20
26
  GROK_IMAGINE_IMAGE_QUALITY.name
21
27
  ];
28
+ const GROK_VIDEO_MODELS = [
29
+ GROK_IMAGINE_VIDEO.name,
30
+ GROK_IMAGINE_VIDEO_1_5.name
31
+ ];
22
32
  const GROK_TTS = {
23
33
  name: "grok-tts"
24
34
  };
@@ -42,6 +52,7 @@ export {
42
52
  GROK_IMAGE_MODELS,
43
53
  GROK_REALTIME_MODELS,
44
54
  GROK_TRANSCRIPTION_MODELS,
45
- GROK_TTS_MODELS
55
+ GROK_TTS_MODELS,
56
+ GROK_VIDEO_MODELS
46
57
  };
47
58
  //# sourceMappingURL=model-meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["/**\n * Model metadata interface for documentation and type inference\n */\nimport type {\n GrokBuildProviderOptions,\n GrokTextProviderOptions,\n} from './text/text-provider-options'\n\ninterface ModelMeta {\n name: string\n supports: {\n input: Array<'text' | 'image' | 'audio' | 'video' | 'document'>\n output: Array<'text' | 'image' | 'audio' | 'video'>\n capabilities?: Array<'reasoning' | 'tool_calling' | 'structured_outputs'>\n tools?: ReadonlyArray<GrokProviderToolKind>\n }\n max_input_tokens?: number\n max_output_tokens?: number\n context_window?: number\n knowledge_cutoff?: string\n pricing?: {\n input: {\n normal: number\n cached?: number\n }\n output: {\n normal: number\n }\n }\n}\n\nexport type GrokProviderToolKind =\n | 'web_search'\n | 'x_search'\n | 'file_search'\n | 'mcp'\n\nconst GROK_RESPONSES_TOOLS = [\n 'web_search',\n 'x_search',\n 'file_search',\n 'mcp',\n] as const satisfies ReadonlyArray<GrokProviderToolKind>\n\nconst GROK_2_IMAGE = {\n name: 'grok-2-image-1212',\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0.07,\n },\n output: {\n normal: 0.07,\n },\n },\n} as const satisfies ModelMeta\n\n// Imagine API image models. Pricing is per generated image (output only).\nconst GROK_IMAGINE_IMAGE = {\n name: 'grok-imagine-image',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.02,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_IMAGINE_IMAGE_QUALITY = {\n name: 'grok-imagine-image-quality',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.05,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_3 = {\n name: 'grok-4.3',\n context_window: 1_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: GROK_RESPONSES_TOOLS,\n },\n pricing: {\n input: {\n normal: 1.25,\n cached: 0.2,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_BUILD_0_1 = {\n name: 'grok-build-0.1',\n context_window: 256_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: GROK_RESPONSES_TOOLS,\n },\n pricing: {\n input: {\n normal: 1,\n cached: 0.2,\n },\n output: {\n normal: 2,\n },\n },\n} as const satisfies ModelMeta\n\n/**\n * Grok chat models supported by the Responses adapter.\n */\nexport const GROK_CHAT_MODELS = [GROK_BUILD_0_1.name, GROK_4_3.name] as const\n\n/**\n * Grok Image Generation Models\n */\nexport const GROK_IMAGE_MODELS = [\n GROK_2_IMAGE.name,\n GROK_IMAGINE_IMAGE.name,\n GROK_IMAGINE_IMAGE_QUALITY.name,\n] as const\n\n// xAI's `/v1/tts` endpoint is endpoint-addressed and does not take a `model`\n// parameter. This synthetic identifier satisfies the SDK's `TTSOptions.model`\n// contract and provides a stable value for logging and fixture matching.\nconst GROK_TTS = {\n name: 'grok-tts',\n supports: {\n input: ['text'],\n output: ['audio'],\n },\n} as const satisfies ModelMeta\n\n// xAI's `/v1/stt` endpoint is endpoint-addressed and does not take a `model`\n// parameter. This synthetic identifier satisfies the SDK's\n// `TranscriptionOptions.model` contract.\nconst GROK_STT = {\n name: 'grok-stt',\n supports: {\n input: ['audio'],\n output: ['text'],\n },\n} as const satisfies ModelMeta\n\nconst GROK_VOICE_FAST_1 = {\n name: 'grok-voice-fast-1.0',\n supports: {\n input: ['audio', 'text'],\n output: ['audio', 'text'],\n capabilities: ['tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nconst GROK_VOICE_THINK_FAST_1 = {\n name: 'grok-voice-think-fast-1.0',\n supports: {\n input: ['audio', 'text'],\n output: ['audio', 'text'],\n capabilities: ['reasoning', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nexport const GROK_TTS_MODELS = [GROK_TTS.name] as const\n\nexport const GROK_TRANSCRIPTION_MODELS = [GROK_STT.name] as const\n\nexport const GROK_REALTIME_MODELS = [\n GROK_VOICE_FAST_1.name,\n GROK_VOICE_THINK_FAST_1.name,\n] as const\n\nexport type GrokChatModel = (typeof GROK_CHAT_MODELS)[number]\nexport type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number]\nexport type GrokTTSModel = (typeof GROK_TTS_MODELS)[number]\nexport type GrokTranscriptionModel = (typeof GROK_TRANSCRIPTION_MODELS)[number]\nexport type GrokRealtimeModel = (typeof GROK_REALTIME_MODELS)[number]\n\n/**\n * Type-only map from Grok chat model name to its supported input modalities.\n * Used for type inference when constructing multimodal messages.\n */\nexport type GrokModelInputModalitiesByName = {\n [GROK_4_3.name]: typeof GROK_4_3.supports.input\n [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.input\n}\n\n/**\n * Type-only map from Grok chat model name to its supported provider tools.\n * Keeps Grok provider-tool factories type-checked against the models that\n * advertise xAI Responses server-side tools.\n */\nexport type GrokChatModelToolCapabilitiesByName = {\n [GROK_4_3.name]: typeof GROK_4_3.supports.tools\n [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.tools\n}\n\nexport type GrokProviderOptions = GrokTextProviderOptions\n\n/**\n * Type-only map from Grok chat model name to its provider options type.\n */\nexport type GrokChatModelProviderOptionsByName = {\n [GROK_4_3.name]: GrokProviderOptions\n [GROK_BUILD_0_1.name]: GrokBuildProviderOptions\n}\n\n// ===========================\n// Type Resolution Helpers\n// ===========================\n\n/**\n * Resolve provider options for a specific model.\n * If the model has explicit options in the map, use those; otherwise use base options.\n */\nexport type ResolveProviderOptions<TModel extends string> =\n TModel extends keyof GrokChatModelProviderOptionsByName\n ? GrokChatModelProviderOptionsByName[TModel]\n : GrokProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use text only.\n */\nexport type ResolveInputModalities<TModel extends string> =\n TModel extends keyof GrokModelInputModalitiesByName\n ? GrokModelInputModalitiesByName[TModel]\n : readonly ['text']\n"],"names":[],"mappings":"AA4CA,MAAM,eAAe;AAAA,EACnB,MAAM;AAaR;AAGA,MAAM,qBAAqB;AAAA,EACzB,MAAM;AAaR;AAEA,MAAM,6BAA6B;AAAA,EACjC,MAAM;AAaR;AAEA,MAAM,WAAW;AAAA,EACf,MAAM;AAiBR;AAEA,MAAM,iBAAiB;AAAA,EACrB,MAAM;AAiBR;AAKO,MAAM,mBAAmB,CAAC,eAAe,MAAM,SAAS,IAAI;AAK5D,MAAM,oBAAoB;AAAA,EAC/B,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,2BAA2B;AAC7B;AAKA,MAAM,WAAW;AAAA,EACf,MAAM;AAKR;AAKA,MAAM,WAAW;AAAA,EACf,MAAM;AAKR;AAEA,MAAM,oBAAoB;AAAA,EACxB,MAAM;AAOR;AAEA,MAAM,0BAA0B;AAAA,EAC9B,MAAM;AAOR;AAEO,MAAM,kBAAkB,CAAC,SAAS,IAAI;AAEtC,MAAM,4BAA4B,CAAC,SAAS,IAAI;AAEhD,MAAM,uBAAuB;AAAA,EAClC,kBAAkB;AAAA,EAClB,wBAAwB;AAC1B;"}
1
+ {"version":3,"file":"model-meta.js","sources":["../../src/model-meta.ts"],"sourcesContent":["/**\n * Model metadata interface for documentation and type inference\n */\nimport type {\n GrokBuildProviderOptions,\n GrokTextProviderOptions,\n} from './text/text-provider-options'\n\ninterface ModelMeta {\n name: string\n supports: {\n input: Array<'text' | 'image' | 'audio' | 'video' | 'document'>\n output: Array<'text' | 'image' | 'audio' | 'video'>\n capabilities?: Array<'reasoning' | 'tool_calling' | 'structured_outputs'>\n tools?: ReadonlyArray<GrokProviderToolKind>\n }\n max_input_tokens?: number\n max_output_tokens?: number\n context_window?: number\n knowledge_cutoff?: string\n pricing?: {\n input: {\n normal: number\n cached?: number\n }\n output: {\n normal: number\n }\n }\n}\n\nexport type GrokProviderToolKind =\n | 'web_search'\n | 'x_search'\n | 'file_search'\n | 'mcp'\n\nconst GROK_RESPONSES_TOOLS = [\n 'web_search',\n 'x_search',\n 'file_search',\n 'mcp',\n] as const satisfies ReadonlyArray<GrokProviderToolKind>\n\nconst GROK_2_IMAGE = {\n name: 'grok-2-image-1212',\n supports: {\n input: ['text'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0.07,\n },\n output: {\n normal: 0.07,\n },\n },\n} as const satisfies ModelMeta\n\n// Imagine API image models. Pricing is per generated image (output only).\nconst GROK_IMAGINE_IMAGE = {\n name: 'grok-imagine-image',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.02,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_IMAGINE_IMAGE_QUALITY = {\n name: 'grok-imagine-image-quality',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.05,\n },\n },\n} as const satisfies ModelMeta\n\n// Imagine API video models. Pricing is per second of generated video\n// (output only); generated videos carry an audio track.\n//\n// grok-imagine-video (v1.0) supports both text-to-video (a starting image is\n// optional) and image-to-video. grok-imagine-video-1.5 is image-to-video\n// only: a starting-frame image is required (the text prompt describes the\n// desired motion) — its text-to-video is rejected by the API.\nconst GROK_IMAGINE_VIDEO = {\n name: 'grok-imagine-video',\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n // per second of video\n normal: 0.05,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_IMAGINE_VIDEO_1_5 = {\n name: 'grok-imagine-video-1.5',\n supports: {\n input: ['text', 'image'],\n output: ['video', 'audio'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n // per second of video\n normal: 0.08,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_3 = {\n name: 'grok-4.3',\n context_window: 1_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: GROK_RESPONSES_TOOLS,\n },\n pricing: {\n input: {\n normal: 1.25,\n cached: 0.2,\n },\n output: {\n normal: 2.5,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_BUILD_0_1 = {\n name: 'grok-build-0.1',\n context_window: 256_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: GROK_RESPONSES_TOOLS,\n },\n pricing: {\n input: {\n normal: 1,\n cached: 0.2,\n },\n output: {\n normal: 2,\n },\n },\n} as const satisfies ModelMeta\n\n/**\n * Grok chat models supported by the Responses adapter.\n */\nexport const GROK_CHAT_MODELS = [GROK_BUILD_0_1.name, GROK_4_3.name] as const\n\n/**\n * Grok Image Generation Models\n */\nexport const GROK_IMAGE_MODELS = [\n GROK_2_IMAGE.name,\n GROK_IMAGINE_IMAGE.name,\n GROK_IMAGINE_IMAGE_QUALITY.name,\n] as const\n\n/**\n * Grok Video Generation Models (xAI Imagine API)\n *\n * @experimental Video generation is an experimental feature and may change.\n */\nexport const GROK_VIDEO_MODELS = [\n GROK_IMAGINE_VIDEO.name,\n GROK_IMAGINE_VIDEO_1_5.name,\n] as const\n\n// xAI's `/v1/tts` endpoint is endpoint-addressed and does not take a `model`\n// parameter. This synthetic identifier satisfies the SDK's `TTSOptions.model`\n// contract and provides a stable value for logging and fixture matching.\nconst GROK_TTS = {\n name: 'grok-tts',\n supports: {\n input: ['text'],\n output: ['audio'],\n },\n} as const satisfies ModelMeta\n\n// xAI's `/v1/stt` endpoint is endpoint-addressed and does not take a `model`\n// parameter. This synthetic identifier satisfies the SDK's\n// `TranscriptionOptions.model` contract.\nconst GROK_STT = {\n name: 'grok-stt',\n supports: {\n input: ['audio'],\n output: ['text'],\n },\n} as const satisfies ModelMeta\n\nconst GROK_VOICE_FAST_1 = {\n name: 'grok-voice-fast-1.0',\n supports: {\n input: ['audio', 'text'],\n output: ['audio', 'text'],\n capabilities: ['tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nconst GROK_VOICE_THINK_FAST_1 = {\n name: 'grok-voice-think-fast-1.0',\n supports: {\n input: ['audio', 'text'],\n output: ['audio', 'text'],\n capabilities: ['reasoning', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nexport const GROK_TTS_MODELS = [GROK_TTS.name] as const\n\nexport const GROK_TRANSCRIPTION_MODELS = [GROK_STT.name] as const\n\nexport const GROK_REALTIME_MODELS = [\n GROK_VOICE_FAST_1.name,\n GROK_VOICE_THINK_FAST_1.name,\n] as const\n\nexport type GrokChatModel = (typeof GROK_CHAT_MODELS)[number]\nexport type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number]\nexport type GrokVideoModel = (typeof GROK_VIDEO_MODELS)[number]\nexport type GrokTTSModel = (typeof GROK_TTS_MODELS)[number]\nexport type GrokTranscriptionModel = (typeof GROK_TRANSCRIPTION_MODELS)[number]\nexport type GrokRealtimeModel = (typeof GROK_REALTIME_MODELS)[number]\n\n/**\n * Type-only map from Grok chat model name to its supported input modalities.\n * Used for type inference when constructing multimodal messages.\n */\nexport type GrokModelInputModalitiesByName = {\n [GROK_4_3.name]: typeof GROK_4_3.supports.input\n [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.input\n}\n\n/**\n * Type-only map from Grok chat model name to its supported provider tools.\n * Keeps Grok provider-tool factories type-checked against the models that\n * advertise xAI Responses server-side tools.\n */\nexport type GrokChatModelToolCapabilitiesByName = {\n [GROK_4_3.name]: typeof GROK_4_3.supports.tools\n [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.tools\n}\n\nexport type GrokProviderOptions = GrokTextProviderOptions\n\n/**\n * Type-only map from Grok chat model name to its provider options type.\n */\nexport type GrokChatModelProviderOptionsByName = {\n [GROK_4_3.name]: GrokProviderOptions\n [GROK_BUILD_0_1.name]: GrokBuildProviderOptions\n}\n\n// ===========================\n// Type Resolution Helpers\n// ===========================\n\n/**\n * Resolve provider options for a specific model.\n * If the model has explicit options in the map, use those; otherwise use base options.\n */\nexport type ResolveProviderOptions<TModel extends string> =\n TModel extends keyof GrokChatModelProviderOptionsByName\n ? GrokChatModelProviderOptionsByName[TModel]\n : GrokProviderOptions\n\n/**\n * Resolve input modalities for a specific model.\n * If the model has explicit modalities in the map, use those; otherwise use text only.\n */\nexport type ResolveInputModalities<TModel extends string> =\n TModel extends keyof GrokModelInputModalitiesByName\n ? GrokModelInputModalitiesByName[TModel]\n : readonly ['text']\n"],"names":[],"mappings":"AA4CA,MAAM,eAAe;AAAA,EACnB,MAAM;AAaR;AAGA,MAAM,qBAAqB;AAAA,EACzB,MAAM;AAaR;AAEA,MAAM,6BAA6B;AAAA,EACjC,MAAM;AAaR;AASA,MAAM,qBAAqB;AAAA,EACzB,MAAM;AAcR;AAEA,MAAM,yBAAyB;AAAA,EAC7B,MAAM;AAcR;AAEA,MAAM,WAAW;AAAA,EACf,MAAM;AAiBR;AAEA,MAAM,iBAAiB;AAAA,EACrB,MAAM;AAiBR;AAKO,MAAM,mBAAmB,CAAC,eAAe,MAAM,SAAS,IAAI;AAK5D,MAAM,oBAAoB;AAAA,EAC/B,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,2BAA2B;AAC7B;AAOO,MAAM,oBAAoB;AAAA,EAC/B,mBAAmB;AAAA,EACnB,uBAAuB;AACzB;AAKA,MAAM,WAAW;AAAA,EACf,MAAM;AAKR;AAKA,MAAM,WAAW;AAAA,EACf,MAAM;AAKR;AAEA,MAAM,oBAAoB;AAAA,EACxB,MAAM;AAOR;AAEA,MAAM,0BAA0B;AAAA,EAC9B,MAAM;AAOR;AAEO,MAAM,kBAAkB,CAAC,SAAS,IAAI;AAEtC,MAAM,4BAA4B,CAAC,SAAS,IAAI;AAEhD,MAAM,uBAAuB;AAAA,EAClC,kBAAkB;AAAA,EAClB,wBAAwB;AAC1B;"}
@@ -1,4 +1,4 @@
1
- import { RealtimeAdapter } from './realtime-contract.js';
1
+ import { RealtimeAdapter } from '@tanstack/ai';
2
2
  import { GrokRealtimeOptions } from './types.js';
3
3
  /**
4
4
  * Creates a Grok realtime adapter for client-side use.