@tanstack/ai-grok 0.14.7 → 0.14.9
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/dist/esm/adapters/image.d.ts +1 -1
- package/dist/esm/adapters/image.js.map +1 -1
- package/dist/esm/adapters/summarize.d.ts +1 -1
- package/dist/esm/adapters/summarize.js +0 -2
- package/dist/esm/adapters/summarize.js.map +1 -1
- package/dist/esm/adapters/text.d.ts +1 -1
- package/dist/esm/adapters/text.js.map +1 -1
- package/dist/esm/adapters/video.d.ts +1 -1
- package/dist/esm/adapters/video.js.map +1 -1
- package/package.json +4 -4
- package/src/adapters/image.ts +1 -1
- package/src/adapters/summarize.ts +2 -2
- package/src/adapters/text.ts +1 -1
- package/src/adapters/video.ts +1 -1
|
@@ -3,7 +3,7 @@ import { BaseImageAdapter } from '@tanstack/ai/adapters';
|
|
|
3
3
|
import { ImageGenerationOptions, ImageGenerationResult } from '@tanstack/ai';
|
|
4
4
|
import { GrokImageModel } from '../model-meta.js';
|
|
5
5
|
import { GrokImageModelInputModalitiesByName, GrokImageModelProviderOptionsByName, GrokImageModelSizeByName, GrokImageProviderOptions } from '../image/image-provider-options.js';
|
|
6
|
-
import { GrokClientConfig } from '../utils.js';
|
|
6
|
+
import { GrokClientConfig } from '../utils/client.js';
|
|
7
7
|
/**
|
|
8
8
|
* Configuration for Grok image adapter
|
|
9
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { buildImagesUsage } from '@tanstack/openai-base'\nimport { generateId } from '@tanstack/ai-utils'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n isGrokImagineImageModel,\n parseGrokImagineSize,\n validateImageSize,\n validateNumberOfImages,\n validatePrompt,\n} from '../image/image-provider-options'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImagePart,\n MediaInputMetadata,\n ResolvedMediaPrompt,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { GrokImageModel } from '../model-meta'\nimport type {\n GrokImageModelInputModalitiesByName,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageProviderOptions,\n} from '../image/image-provider-options'\nimport type { GrokClientConfig } from '../utils'\n\n/**\n * Configuration for Grok image adapter\n */\nexport interface GrokImageConfig extends GrokClientConfig {}\n\n/** Maximum source images accepted by xAI's image edit endpoint. */\nconst MAX_EDIT_IMAGES = 3\n\n/**\n * Maps the generic `size` option onto Imagine API parameters: the\n * \"aspectRatio_resolution\" template (\"16:9_2k\") splits into `aspect_ratio`\n * and optional `resolution` request fields.\n */\nfunction imagineSizeParams(size: string | undefined): {\n aspect_ratio?: string\n resolution?: string\n} {\n if (!size) return {}\n const parsed = parseGrokImagineSize(size)\n if (!parsed) return {}\n return {\n aspect_ratio: parsed.aspectRatio,\n ...(parsed.resolution !== undefined && { resolution: parsed.resolution }),\n }\n}\n\n/**\n * Convert a TanStack ImagePart to the URL string accepted by xAI's edit\n * 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\n/** Response shape of xAI's `/v1/images/edits` endpoint. */\ninterface GrokImageEditResponse {\n data?: Array<{\n url?: string | null\n b64_json?: string | null\n mime_type?: string\n }>\n}\n\n/**\n * Grok Image Generation Adapter\n *\n * Tree-shakeable adapter for Grok image generation functionality.\n * Supports the legacy grok-2-image-1212 model (text-to-image via the\n * OpenAI-compat endpoint) and the grok-imagine image models, which also\n * accept image prompt parts for image-conditioned generation via xAI's\n * `/v1/images/edits` endpoint (up to 3 source images).\n *\n * Features:\n * - Model-specific type-safe provider options\n * - Size / aspect-ratio validation per model\n * - Number of images validation\n */\nexport class GrokImageAdapter<\n TModel extends GrokImageModel,\n> extends BaseImageAdapter<\n TModel,\n GrokImageProviderOptions,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageModelInputModalitiesByName\n> {\n override readonly kind = 'image' as const\n readonly name = 'grok' as const\n\n protected client: OpenAI\n private readonly clientConfig: GrokImageConfig\n\n constructor(config: GrokImageConfig, model: TModel) {\n super(model, {})\n this.clientConfig = withGrokDefaults(config)\n this.client = new OpenAI(this.clientConfig)\n }\n\n async generateImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions } = options\n\n const resolved = resolveMediaPrompt(options.prompt)\n const prompt = resolved.text\n\n if (resolved.videos.length > 0 || resolved.audios.length > 0) {\n throw new Error(\n `grok.generateImages does not support video / audio prompt parts on model ${model}.`,\n )\n }\n\n if (resolved.images.length > 0) {\n if (!isGrokImagineImageModel(model)) {\n throw new Error(\n `grok: model \"${model}\" does not support image prompt parts. ` +\n `Image-conditioned generation requires an Imagine API model ` +\n `('grok-imagine-image' or 'grok-imagine-image-quality').`,\n )\n }\n return await this.editImages(options, resolved)\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n // grok-imagine models are aspect-ratio sized: the generic `size` option\n // carries an \"aspectRatio_resolution\" template (e.g. '16:9_2k', like\n // Gemini native image models) and maps to the Imagine API's\n // `aspect_ratio` / `resolution` parameters instead of OpenAI-style `size`.\n const isImagine = isGrokImagineImageModel(model)\n const request = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n ...(isImagine\n ? imagineSizeParams(size)\n : size !== undefined && {\n size: size,\n }),\n stream: false,\n ...modelOptions,\n } as OpenAI_SDK.Images.ImageGenerateParamsNonStreaming\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate(request)\n\n const images: Array<GeneratedImage> = (response.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPrompt = item.revised_prompt\n if (item.b64_json) {\n return [\n {\n b64Json: item.b64_json,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n if (item.url) {\n return [\n {\n url: item.url,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n return []\n },\n )\n\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n /**\n * Image-conditioned generation via xAI's Imagine API.\n *\n * The `/v1/images/edits` endpoint takes `application/json` (the OpenAI\n * SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),\n * so this path issues the request directly. One input is sent as\n * `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,\n * addressed by xAI in the order they are sent. The prompt text is sent\n * verbatim — no referencing markers are injected.\n */\n private async editImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n resolved: ResolvedMediaPrompt,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions, logger } = options\n const prompt = resolved.text\n const imageInputs = resolved.images\n\n const unsupportedRole = imageInputs.find(\n (part) =>\n part.metadata?.role === 'mask' || part.metadata?.role === 'control',\n )\n if (unsupportedRole) {\n throw new Error(\n `grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; ` +\n `only source/reference images are supported.`,\n )\n }\n if (imageInputs.length > MAX_EDIT_IMAGES) {\n throw new Error(\n `grok: model \"${model}\" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`,\n )\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n const urls = imageInputs.map((part) => imagePartToUrl(part))\n const request: Record<string, unknown> = {\n model,\n prompt,\n ...(urls.length === 1\n ? { image: { url: urls[0] } }\n : { images: urls.map((url) => ({ url })) }),\n ...(numberOfImages !== undefined && { n: numberOfImages }),\n ...imagineSizeParams(size),\n ...modelOptions,\n }\n\n try {\n logger.request(\n `activity=image provider=${this.name} model=${model} edit images=${urls.length}`,\n { provider: this.name, model },\n )\n\n const response = await fetch(\n `${this.clientConfig.baseURL}/images/edits`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.clientConfig.apiKey}`,\n },\n body: JSON.stringify(request),\n },\n )\n if (!response.ok) {\n const body = await response.text()\n throw new Error(\n `grok: image edit request failed (${response.status} ${response.statusText}): ${body}`,\n )\n }\n\n const result = (await response.json()) as GrokImageEditResponse\n const images: Array<GeneratedImage> = (result.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n if (item.b64_json) return [{ b64Json: item.b64_json }]\n if (item.url) return [{ url: item.url }]\n return []\n },\n )\n if (images.length === 0) {\n throw new Error('grok: image edit response contained no images')\n }\n\n return {\n id: generateId(this.name),\n model,\n images,\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n}\n\n/**\n * Creates a Grok image adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok image adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokImage('grok-2-image-1212', \"xai-...\");\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A cute baby sea otter'\n * });\n * ```\n */\nexport function createGrokImage<TModel extends GrokImageModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n return new GrokImageAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok image 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 * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok image 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 = grokImage('grok-2-image-1212');\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A beautiful sunset over mountains'\n * });\n * ```\n */\nexport function grokImage<TModel extends GrokImageModel>(\n model: TModel,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokImage(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"image.js","sources":["../../../src/adapters/image.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { resolveMediaPrompt } from '@tanstack/ai'\nimport { BaseImageAdapter } from '@tanstack/ai/adapters'\nimport { toRunErrorPayload } from '@tanstack/ai/adapter-internals'\nimport { buildImagesUsage } from '@tanstack/openai-base'\nimport { generateId } from '@tanstack/ai-utils'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport {\n isGrokImagineImageModel,\n parseGrokImagineSize,\n validateImageSize,\n validateNumberOfImages,\n validatePrompt,\n} from '../image/image-provider-options'\nimport type {\n GeneratedImage,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImagePart,\n MediaInputMetadata,\n ResolvedMediaPrompt,\n} from '@tanstack/ai'\nimport type OpenAI_SDK from 'openai'\nimport type { GrokImageModel } from '../model-meta'\nimport type {\n GrokImageModelInputModalitiesByName,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageProviderOptions,\n} from '../image/image-provider-options'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok image adapter\n */\nexport interface GrokImageConfig extends GrokClientConfig {}\n\n/** Maximum source images accepted by xAI's image edit endpoint. */\nconst MAX_EDIT_IMAGES = 3\n\n/**\n * Maps the generic `size` option onto Imagine API parameters: the\n * \"aspectRatio_resolution\" template (\"16:9_2k\") splits into `aspect_ratio`\n * and optional `resolution` request fields.\n */\nfunction imagineSizeParams(size: string | undefined): {\n aspect_ratio?: string\n resolution?: string\n} {\n if (!size) return {}\n const parsed = parseGrokImagineSize(size)\n if (!parsed) return {}\n return {\n aspect_ratio: parsed.aspectRatio,\n ...(parsed.resolution !== undefined && { resolution: parsed.resolution }),\n }\n}\n\n/**\n * Convert a TanStack ImagePart to the URL string accepted by xAI's edit\n * 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\n/** Response shape of xAI's `/v1/images/edits` endpoint. */\ninterface GrokImageEditResponse {\n data?: Array<{\n url?: string | null\n b64_json?: string | null\n mime_type?: string\n }>\n}\n\n/**\n * Grok Image Generation Adapter\n *\n * Tree-shakeable adapter for Grok image generation functionality.\n * Supports the legacy grok-2-image-1212 model (text-to-image via the\n * OpenAI-compat endpoint) and the grok-imagine image models, which also\n * accept image prompt parts for image-conditioned generation via xAI's\n * `/v1/images/edits` endpoint (up to 3 source images).\n *\n * Features:\n * - Model-specific type-safe provider options\n * - Size / aspect-ratio validation per model\n * - Number of images validation\n */\nexport class GrokImageAdapter<\n TModel extends GrokImageModel,\n> extends BaseImageAdapter<\n TModel,\n GrokImageProviderOptions,\n GrokImageModelProviderOptionsByName,\n GrokImageModelSizeByName,\n GrokImageModelInputModalitiesByName\n> {\n override readonly kind = 'image' as const\n readonly name = 'grok' as const\n\n protected client: OpenAI\n private readonly clientConfig: GrokImageConfig\n\n constructor(config: GrokImageConfig, model: TModel) {\n super(model, {})\n this.clientConfig = withGrokDefaults(config)\n this.client = new OpenAI(this.clientConfig)\n }\n\n async generateImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions } = options\n\n const resolved = resolveMediaPrompt(options.prompt)\n const prompt = resolved.text\n\n if (resolved.videos.length > 0 || resolved.audios.length > 0) {\n throw new Error(\n `grok.generateImages does not support video / audio prompt parts on model ${model}.`,\n )\n }\n\n if (resolved.images.length > 0) {\n if (!isGrokImagineImageModel(model)) {\n throw new Error(\n `grok: model \"${model}\" does not support image prompt parts. ` +\n `Image-conditioned generation requires an Imagine API model ` +\n `('grok-imagine-image' or 'grok-imagine-image-quality').`,\n )\n }\n return await this.editImages(options, resolved)\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n // grok-imagine models are aspect-ratio sized: the generic `size` option\n // carries an \"aspectRatio_resolution\" template (e.g. '16:9_2k', like\n // Gemini native image models) and maps to the Imagine API's\n // `aspect_ratio` / `resolution` parameters instead of OpenAI-style `size`.\n const isImagine = isGrokImagineImageModel(model)\n const request = {\n model,\n prompt,\n n: numberOfImages ?? 1,\n ...(isImagine\n ? imagineSizeParams(size)\n : size !== undefined && {\n size: size,\n }),\n stream: false,\n ...modelOptions,\n } as OpenAI_SDK.Images.ImageGenerateParamsNonStreaming\n\n try {\n options.logger.request(\n `activity=image provider=${this.name} model=${model} n=${request.n ?? 1} size=${request.size ?? 'default'}`,\n { provider: this.name, model },\n )\n const response = await this.client.images.generate(request)\n\n const images: Array<GeneratedImage> = (response.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n const revisedPrompt = item.revised_prompt\n if (item.b64_json) {\n return [\n {\n b64Json: item.b64_json,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n if (item.url) {\n return [\n {\n url: item.url,\n ...(revisedPrompt !== undefined && { revisedPrompt }),\n },\n ]\n }\n return []\n },\n )\n\n const usage = buildImagesUsage(response.usage)\n\n return {\n id: generateId(this.name),\n model,\n images,\n ...(usage ? { usage } : {}),\n }\n } catch (error: unknown) {\n options.logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n\n /**\n * Image-conditioned generation via xAI's Imagine API.\n *\n * The `/v1/images/edits` endpoint takes `application/json` (the OpenAI\n * SDK's `images.edit()` sends `multipart/form-data`, which xAI rejects),\n * so this path issues the request directly. One input is sent as\n * `image: { url }`; multiple inputs (up to 3) as `images: [{ url }, ...]`,\n * addressed by xAI in the order they are sent. The prompt text is sent\n * verbatim — no referencing markers are injected.\n */\n private async editImages(\n options: ImageGenerationOptions<GrokImageProviderOptions>,\n resolved: ResolvedMediaPrompt,\n ): Promise<ImageGenerationResult> {\n const { model, numberOfImages, size, modelOptions, logger } = options\n const prompt = resolved.text\n const imageInputs = resolved.images\n\n const unsupportedRole = imageInputs.find(\n (part) =>\n part.metadata?.role === 'mask' || part.metadata?.role === 'control',\n )\n if (unsupportedRole) {\n throw new Error(\n `grok: the Imagine API has no ${unsupportedRole.metadata?.role} input; ` +\n `only source/reference images are supported.`,\n )\n }\n if (imageInputs.length > MAX_EDIT_IMAGES) {\n throw new Error(\n `grok: model \"${model}\" accepts at most ${MAX_EDIT_IMAGES} source images; received ${imageInputs.length}.`,\n )\n }\n\n validatePrompt({ prompt, model })\n validateImageSize(model, size)\n validateNumberOfImages(model, numberOfImages)\n\n const urls = imageInputs.map((part) => imagePartToUrl(part))\n const request: Record<string, unknown> = {\n model,\n prompt,\n ...(urls.length === 1\n ? { image: { url: urls[0] } }\n : { images: urls.map((url) => ({ url })) }),\n ...(numberOfImages !== undefined && { n: numberOfImages }),\n ...imagineSizeParams(size),\n ...modelOptions,\n }\n\n try {\n logger.request(\n `activity=image provider=${this.name} model=${model} edit images=${urls.length}`,\n { provider: this.name, model },\n )\n\n const response = await fetch(\n `${this.clientConfig.baseURL}/images/edits`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.clientConfig.apiKey}`,\n },\n body: JSON.stringify(request),\n },\n )\n if (!response.ok) {\n const body = await response.text()\n throw new Error(\n `grok: image edit request failed (${response.status} ${response.statusText}): ${body}`,\n )\n }\n\n const result = (await response.json()) as GrokImageEditResponse\n const images: Array<GeneratedImage> = (result.data ?? []).flatMap(\n (item): Array<GeneratedImage> => {\n if (item.b64_json) return [{ b64Json: item.b64_json }]\n if (item.url) return [{ url: item.url }]\n return []\n },\n )\n if (images.length === 0) {\n throw new Error('grok: image edit response contained no images')\n }\n\n return {\n id: generateId(this.name),\n model,\n images,\n }\n } catch (error: unknown) {\n logger.errors(`${this.name}.generateImages fatal`, {\n error: toRunErrorPayload(error, `${this.name}.generateImages failed`),\n source: `${this.name}.generateImages`,\n })\n throw error\n }\n }\n}\n\n/**\n * Creates a Grok image adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok image adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokImage('grok-2-image-1212', \"xai-...\");\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A cute baby sea otter'\n * });\n * ```\n */\nexport function createGrokImage<TModel extends GrokImageModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n return new GrokImageAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok image 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 * @param model - The model name (e.g., 'grok-2-image-1212')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok image 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 = grokImage('grok-2-image-1212');\n *\n * const result = await generateImage({\n * adapter,\n * prompt: 'A beautiful sunset over mountains'\n * });\n * ```\n */\nexport function grokImage<TModel extends GrokImageModel>(\n model: TModel,\n config?: Omit<GrokImageConfig, 'apiKey'>,\n): GrokImageAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokImage(model, apiKey, config)\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ChatStreamSummarizeAdapter, InferTextProviderOptions } from '@tanstack/ai/adapters';
|
|
2
2
|
import { GrokTextAdapter } from './text.js';
|
|
3
3
|
import { GROK_CHAT_MODELS } from '../model-meta.js';
|
|
4
|
-
import { GrokClientConfig } from '../utils.js';
|
|
4
|
+
import { GrokClientConfig } from '../utils/client.js';
|
|
5
5
|
/**
|
|
6
6
|
* Configuration for Grok summarize adapter
|
|
7
7
|
*/
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
|
|
2
|
-
import "@tanstack/ai-utils";
|
|
3
2
|
import { getGrokApiKeyFromEnv } from "../utils/client.js";
|
|
4
|
-
import "@tanstack/openai-base";
|
|
5
3
|
import { GrokTextAdapter } from "./text.js";
|
|
6
4
|
function createGrokSummarize(model, apiKey, config) {
|
|
7
5
|
return new ChatStreamSummarizeAdapter(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getGrokApiKeyFromEnv } from '../utils'\nimport { GrokTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { GROK_CHAT_MODELS } from '../model-meta'\nimport type { GrokClientConfig } from '../utils'\n\n/**\n * Configuration for Grok summarize adapter\n */\nexport interface GrokSummarizeConfig extends GrokClientConfig {}\n\n/** Model type for Grok summarization */\nexport type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]\n\n/**\n * Creates a Grok summarize adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok summarize adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokSummarize('grok-build-0.1', \"xai-...\");\n * ```\n */\nexport function createGrokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n new GrokTextAdapter({ apiKey, ...config }, model),\n model,\n 'grok',\n )\n}\n\n/**\n * Creates a Grok summarize 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 * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok summarize 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 = grokSummarize('grok-build-0.1');\n *\n * await summarize({\n * adapter,\n * text: \"Long article text...\"\n * });\n * ```\n */\nexport function grokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return createGrokSummarize(model, getGrokApiKeyFromEnv(), config)\n}\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"summarize.js","sources":["../../../src/adapters/summarize.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { getGrokApiKeyFromEnv } from '../utils/client'\nimport { GrokTextAdapter } from './text'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { GROK_CHAT_MODELS } from '../model-meta'\nimport type { GrokClientConfig } from '../utils/client'\n\n/**\n * Configuration for Grok summarize adapter\n */\nexport interface GrokSummarizeConfig extends GrokClientConfig {}\n\n/** Model type for Grok summarization */\nexport type GrokSummarizeModel = (typeof GROK_CHAT_MODELS)[number]\n\n/**\n * Creates a Grok summarize adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok summarize adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokSummarize('grok-build-0.1', \"xai-...\");\n * ```\n */\nexport function createGrokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n new GrokTextAdapter({ apiKey, ...config }, model),\n model,\n 'grok',\n )\n}\n\n/**\n * Creates a Grok summarize 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 * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok summarize 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 = grokSummarize('grok-build-0.1');\n *\n * await summarize({\n * adapter,\n * text: \"Long article text...\"\n * });\n * ```\n */\nexport function grokSummarize<TModel extends GrokSummarizeModel>(\n model: TModel,\n config?: Omit<GrokSummarizeConfig, 'apiKey'>,\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return createGrokSummarize(model, getGrokApiKeyFromEnv(), config)\n}\n"],"names":[],"mappings":";;;AA6BO,SAAS,oBACd,OACA,QACA,QAIA;AACA,SAAO,IAAI;AAAA,IACT,IAAI,gBAAgB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AAAA,IAChD;AAAA,IACA;AAAA,EAAA;AAEJ;AA0BO,SAAS,cACd,OACA,QAIA;AACA,SAAO,oBAAoB,OAAO,qBAAA,GAAwB,MAAM;AAClE;"}
|
|
@@ -2,7 +2,7 @@ import { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base';
|
|
|
2
2
|
import { GROK_CHAT_MODELS, GrokChatModelToolCapabilitiesByName, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
|
|
3
3
|
import { Modality, TextOptions } from '@tanstack/ai';
|
|
4
4
|
import { GrokMessageMetadataByModality } from '../message-types.js';
|
|
5
|
-
import { GrokClientConfig } from '../utils.js';
|
|
5
|
+
import { GrokClientConfig } from '../utils/client.js';
|
|
6
6
|
import { ResponseCreateParams } from 'openai/resources/responses/responses';
|
|
7
7
|
/**
|
|
8
8
|
* Resolve tool capabilities for a specific Grok model.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport { convertToolsToProviderFormat } from '../tools'\nimport type {\n GROK_CHAT_MODELS,\n GrokChatModelToolCapabilitiesByName,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { Modality, TextOptions } from '@tanstack/ai'\nimport type { GrokMessageMetadataByModality } from '../message-types'\nimport type { GrokClientConfig } from '../utils'\nimport type { ResponseCreateParams } from 'openai/resources/responses/responses'\n\n/**\n * Resolve tool capabilities for a specific Grok model.\n */\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof GrokChatModelToolCapabilitiesByName\n ? NonNullable<GrokChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n/**\n * Configuration for Grok text adapter\n */\nexport interface GrokTextConfig extends GrokClientConfig {}\n\n/**\n * Alias for TextProviderOptions for external use\n */\nexport type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Grok Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Grok chat/text completion functionality.\n * Uses xAI's OpenAI-compatible Responses API.\n *\n * Delegates implementation to {@link OpenAIBaseResponsesTextAdapter}\n * from `@tanstack/openai-base` and threads Grok-specific tool-capability\n * typing through the 5th generic of the base class.\n */\nexport class GrokTextAdapter<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n // Use `Record<string, any>` (not `unknown`) to match the OpenAI text\n // adapter: the resolved Grok provider options are a type-alias intersection\n // with no explicit index signature, which is assignable to\n // `Record<string, any>` but not `Record<string, unknown>`. See issue #821.\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends OpenAIBaseResponsesTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n GrokMessageMetadataByModality,\n TToolCapabilities\n> {\n override readonly kind = 'text' as const\n override readonly name = 'grok' as const\n\n constructor(config: GrokTextConfig, model: TModel) {\n super(model, 'grok', new OpenAI(withGrokDefaults(config)))\n }\n\n protected override mapOptionsToRequest(\n options: TextOptions<TProviderOptions>,\n ): Omit<ResponseCreateParams, 'stream'> {\n const { tools: _baseTools, ...request } = super.mapOptionsToRequest({\n ...options,\n tools: undefined,\n })\n void _baseTools\n\n if (this.model === 'grok-build-0.1' && request.reasoning !== undefined) {\n throw new Error(\n 'grok-build-0.1 does not support reasoning modelOptions; omit reasoning for this model.',\n )\n }\n\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n return {\n ...request,\n // xAI recommends encrypted reasoning for reasoning-capable Responses\n // requests; callers can still override either field in modelOptions.\n store: request.store ?? false,\n include: request.include ?? ['reasoning.encrypted_content'],\n ...(tools &&\n tools.length > 0 && { tools: tools as ResponseCreateParams['tools'] }),\n }\n }\n}\n\n/**\n * Creates a Grok text adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok text adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokText('grok-build-0.1', \"xai-...\");\n * // adapter has type-safe providerOptions for grok-build-0.1\n * ```\n */\nexport function createGrokText<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n return new GrokTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok text 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 * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok text 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 = grokText('grok-build-0.1');\n *\n * const stream = chat({\n * adapter,\n * messages: [{ role: \"user\", content: \"Hello!\" }]\n * });\n * ```\n */\nexport function grokText<TModel extends (typeof GROK_CHAT_MODELS)[number]>(\n model: TModel,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokText(model, apiKey, config)\n}\n"],"names":[],"mappings":";;;;AA2CO,MAAM,wBAWH,+BAMR;AAAA,EACkB,OAAO;AAAA,EACP,OAAO;AAAA,EAEzB,YAAY,QAAwB,OAAe;AACjD,UAAM,OAAO,QAAQ,IAAI,OAAO,iBAAiB,MAAM,CAAC,CAAC;AAAA,EAC3D;AAAA,EAEmB,oBACjB,SACsC;AACtC,UAAM,EAAE,OAAO,YAAY,GAAG,QAAA,IAAY,MAAM,oBAAoB;AAAA,MAClE,GAAG;AAAA,MACH,OAAO;AAAA,IAAA,CACR;AAGD,QAAI,KAAK,UAAU,oBAAoB,QAAQ,cAAc,QAAW;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,QAAQ,QAAQ,QAClB,6BAA6B,QAAQ,KAAK,IAC1C;AAEJ,WAAO;AAAA,MACL,GAAG;AAAA;AAAA;AAAA,MAGH,OAAO,QAAQ,SAAS;AAAA,MACxB,SAAS,QAAQ,WAAW,CAAC,6BAA6B;AAAA,MAC1D,GAAI,SACF,MAAM,SAAS,KAAK,EAAE,MAAA;AAAA,IAA8C;AAAA,EAE1E;AACF;AAiBO,SAAS,eAGd,OACA,QACA,QACyB;AACzB,SAAO,IAAI,gBAAgB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AACzD;AA0BO,SAAS,SACd,OACA,QACyB;AACzB,QAAM,SAAS,qBAAA;AACf,SAAO,eAAe,OAAO,QAAQ,MAAM;AAC7C;"}
|
|
1
|
+
{"version":3,"file":"text.js","sources":["../../../src/adapters/text.ts"],"sourcesContent":["import OpenAI from 'openai'\nimport { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base'\nimport { getGrokApiKeyFromEnv, withGrokDefaults } from '../utils/client'\nimport { convertToolsToProviderFormat } from '../tools'\nimport type {\n GROK_CHAT_MODELS,\n GrokChatModelToolCapabilitiesByName,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { Modality, TextOptions } from '@tanstack/ai'\nimport type { GrokMessageMetadataByModality } from '../message-types'\nimport type { GrokClientConfig } from '../utils/client'\nimport type { ResponseCreateParams } from 'openai/resources/responses/responses'\n\n/**\n * Resolve tool capabilities for a specific Grok model.\n */\ntype ResolveToolCapabilities<TModel extends string> =\n TModel extends keyof GrokChatModelToolCapabilitiesByName\n ? NonNullable<GrokChatModelToolCapabilitiesByName[TModel]>\n : readonly []\n\n/**\n * Configuration for Grok text adapter\n */\nexport interface GrokTextConfig extends GrokClientConfig {}\n\n/**\n * Alias for TextProviderOptions for external use\n */\nexport type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../text/text-provider-options'\n\n/**\n * Grok Text (Chat) Adapter\n *\n * Tree-shakeable adapter for Grok chat/text completion functionality.\n * Uses xAI's OpenAI-compatible Responses API.\n *\n * Delegates implementation to {@link OpenAIBaseResponsesTextAdapter}\n * from `@tanstack/openai-base` and threads Grok-specific tool-capability\n * typing through the 5th generic of the base class.\n */\nexport class GrokTextAdapter<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n // Use `Record<string, any>` (not `unknown`) to match the OpenAI text\n // adapter: the resolved Grok provider options are a type-alias intersection\n // with no explicit index signature, which is assignable to\n // `Record<string, any>` but not `Record<string, unknown>`. See issue #821.\n TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>,\n TInputModalities extends ReadonlyArray<Modality> =\n ResolveInputModalities<TModel>,\n TToolCapabilities extends ReadonlyArray<string> =\n ResolveToolCapabilities<TModel>,\n> extends OpenAIBaseResponsesTextAdapter<\n TModel,\n TProviderOptions,\n TInputModalities,\n GrokMessageMetadataByModality,\n TToolCapabilities\n> {\n override readonly kind = 'text' as const\n override readonly name = 'grok' as const\n\n constructor(config: GrokTextConfig, model: TModel) {\n super(model, 'grok', new OpenAI(withGrokDefaults(config)))\n }\n\n protected override mapOptionsToRequest(\n options: TextOptions<TProviderOptions>,\n ): Omit<ResponseCreateParams, 'stream'> {\n const { tools: _baseTools, ...request } = super.mapOptionsToRequest({\n ...options,\n tools: undefined,\n })\n void _baseTools\n\n if (this.model === 'grok-build-0.1' && request.reasoning !== undefined) {\n throw new Error(\n 'grok-build-0.1 does not support reasoning modelOptions; omit reasoning for this model.',\n )\n }\n\n const tools = options.tools\n ? convertToolsToProviderFormat(options.tools)\n : undefined\n\n return {\n ...request,\n // xAI recommends encrypted reasoning for reasoning-capable Responses\n // requests; callers can still override either field in modelOptions.\n store: request.store ?? false,\n include: request.include ?? ['reasoning.encrypted_content'],\n ...(tools &&\n tools.length > 0 && { tools: tools as ResponseCreateParams['tools'] }),\n }\n }\n}\n\n/**\n * Creates a Grok text adapter with explicit API key.\n * Type resolution happens here at the call site.\n *\n * @param model - The model name (e.g., 'grok-build-0.1')\n * @param apiKey - Your xAI API key\n * @param config - Optional additional configuration\n * @returns Configured Grok text adapter instance with resolved types\n *\n * @example\n * ```typescript\n * const adapter = createGrokText('grok-build-0.1', \"xai-...\");\n * // adapter has type-safe providerOptions for grok-build-0.1\n * ```\n */\nexport function createGrokText<\n TModel extends (typeof GROK_CHAT_MODELS)[number],\n>(\n model: TModel,\n apiKey: string,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n return new GrokTextAdapter({ apiKey, ...config }, model)\n}\n\n/**\n * Creates a Grok text 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 * @param model - The model name (e.g., 'grok-build-0.1')\n * @param config - Optional configuration (excluding apiKey which is auto-detected)\n * @returns Configured Grok text 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 = grokText('grok-build-0.1');\n *\n * const stream = chat({\n * adapter,\n * messages: [{ role: \"user\", content: \"Hello!\" }]\n * });\n * ```\n */\nexport function grokText<TModel extends (typeof GROK_CHAT_MODELS)[number]>(\n model: TModel,\n config?: Omit<GrokTextConfig, 'apiKey'>,\n): GrokTextAdapter<TModel> {\n const apiKey = getGrokApiKeyFromEnv()\n return createGrokText(model, apiKey, config)\n}\n"],"names":[],"mappings":";;;;AA2CO,MAAM,wBAWH,+BAMR;AAAA,EACkB,OAAO;AAAA,EACP,OAAO;AAAA,EAEzB,YAAY,QAAwB,OAAe;AACjD,UAAM,OAAO,QAAQ,IAAI,OAAO,iBAAiB,MAAM,CAAC,CAAC;AAAA,EAC3D;AAAA,EAEmB,oBACjB,SACsC;AACtC,UAAM,EAAE,OAAO,YAAY,GAAG,QAAA,IAAY,MAAM,oBAAoB;AAAA,MAClE,GAAG;AAAA,MACH,OAAO;AAAA,IAAA,CACR;AAGD,QAAI,KAAK,UAAU,oBAAoB,QAAQ,cAAc,QAAW;AACtE,YAAM,IAAI;AAAA,QACR;AAAA,MAAA;AAAA,IAEJ;AAEA,UAAM,QAAQ,QAAQ,QAClB,6BAA6B,QAAQ,KAAK,IAC1C;AAEJ,WAAO;AAAA,MACL,GAAG;AAAA;AAAA;AAAA,MAGH,OAAO,QAAQ,SAAS;AAAA,MACxB,SAAS,QAAQ,WAAW,CAAC,6BAA6B;AAAA,MAC1D,GAAI,SACF,MAAM,SAAS,KAAK,EAAE,MAAA;AAAA,IAA8C;AAAA,EAE1E;AACF;AAiBO,SAAS,eAGd,OACA,QACA,QACyB;AACzB,SAAO,IAAI,gBAAgB,EAAE,QAAQ,GAAG,OAAA,GAAU,KAAK;AACzD;AA0BO,SAAS,SACd,OACA,QACyB;AACzB,QAAM,SAAS,qBAAA;AACf,SAAO,eAAe,OAAO,QAAQ,MAAM;AAC7C;"}
|
|
@@ -2,7 +2,7 @@ import { BaseVideoAdapter, DurationOptions } from '@tanstack/ai/adapters';
|
|
|
2
2
|
import { VideoGenerationOptions, VideoJobResult, VideoStatusResult, VideoUrlResult } from '@tanstack/ai';
|
|
3
3
|
import { GrokVideoModel } from '../model-meta.js';
|
|
4
4
|
import { GrokVideoModelDurationByName, GrokVideoModelInputModalitiesByName, GrokVideoModelProviderOptionsByName, GrokVideoModelSizeByName, GrokVideoProviderOptions } from '../video/video-provider-options.js';
|
|
5
|
-
import { GrokClientConfig } from '../utils.js';
|
|
5
|
+
import { GrokClientConfig } from '../utils/client.js';
|
|
6
6
|
/**
|
|
7
7
|
* Configuration for Grok video adapter.
|
|
8
8
|
*
|
|
@@ -1 +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":"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"}
|
|
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/client'\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":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/ai-grok",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.9",
|
|
4
4
|
"description": "xAI Grok adapter for TanStack AI chat, image generation, realtime, and structured outputs.",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -51,16 +51,16 @@
|
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"openai": "^6.41.0",
|
|
53
53
|
"@tanstack/ai-utils": "0.3.1",
|
|
54
|
-
"@tanstack/openai-base": "0.9.
|
|
54
|
+
"@tanstack/openai-base": "0.9.9"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@vitest/coverage-v8": "4.0.14",
|
|
58
58
|
"vite": "^7.3.3",
|
|
59
|
-
"@tanstack/ai": "0.
|
|
59
|
+
"@tanstack/ai": "0.42.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"zod": "^4.0.0",
|
|
63
|
-
"@tanstack/ai": "^0.
|
|
63
|
+
"@tanstack/ai": "^0.42.0"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "vite build",
|
package/src/adapters/image.ts
CHANGED
|
@@ -28,7 +28,7 @@ import type {
|
|
|
28
28
|
GrokImageModelSizeByName,
|
|
29
29
|
GrokImageProviderOptions,
|
|
30
30
|
} from '../image/image-provider-options'
|
|
31
|
-
import type { GrokClientConfig } from '../utils'
|
|
31
|
+
import type { GrokClientConfig } from '../utils/client'
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Configuration for Grok image adapter
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'
|
|
2
|
-
import { getGrokApiKeyFromEnv } from '../utils'
|
|
2
|
+
import { getGrokApiKeyFromEnv } from '../utils/client'
|
|
3
3
|
import { GrokTextAdapter } from './text'
|
|
4
4
|
import type { InferTextProviderOptions } from '@tanstack/ai/adapters'
|
|
5
5
|
import type { GROK_CHAT_MODELS } from '../model-meta'
|
|
6
|
-
import type { GrokClientConfig } from '../utils'
|
|
6
|
+
import type { GrokClientConfig } from '../utils/client'
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Configuration for Grok summarize adapter
|
package/src/adapters/text.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type {
|
|
|
10
10
|
} from '../model-meta'
|
|
11
11
|
import type { Modality, TextOptions } from '@tanstack/ai'
|
|
12
12
|
import type { GrokMessageMetadataByModality } from '../message-types'
|
|
13
|
-
import type { GrokClientConfig } from '../utils'
|
|
13
|
+
import type { GrokClientConfig } from '../utils/client'
|
|
14
14
|
import type { ResponseCreateParams } from 'openai/resources/responses/responses'
|
|
15
15
|
|
|
16
16
|
/**
|
package/src/adapters/video.ts
CHANGED
|
@@ -26,7 +26,7 @@ import type {
|
|
|
26
26
|
GrokVideoModelSizeByName,
|
|
27
27
|
GrokVideoProviderOptions,
|
|
28
28
|
} from '../video/video-provider-options'
|
|
29
|
-
import type { GrokClientConfig } from '../utils'
|
|
29
|
+
import type { GrokClientConfig } from '../utils/client'
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Configuration for Grok video adapter.
|