@tanstack/ai-grok 0.16.2 → 0.17.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.
@@ -1,5 +1,5 @@
1
1
  import { OpenAIBaseResponsesTextAdapter } from '@tanstack/openai-base';
2
- import { GROK_CHAT_MODELS, GrokChatModelToolCapabilitiesByName, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
2
+ import { GROK_CHAT_MODELS, GrokChatModelToolCapabilitiesByName, GrokTextAdapterModel, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
3
3
  import { Modality, TextOptions } from '@tanstack/ai';
4
4
  import { GrokMessageMetadataByModality } from '../message-types.js';
5
5
  import { GrokClientConfig } from '../utils/client.js';
@@ -27,7 +27,7 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
27
27
  * from `@tanstack/openai-base` and threads Grok-specific tool-capability
28
28
  * typing through the 5th generic of the base class.
29
29
  */
30
- export declare class GrokTextAdapter<TModel extends (typeof GROK_CHAT_MODELS)[number], TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends OpenAIBaseResponsesTextAdapter<TModel, TProviderOptions, TInputModalities, GrokMessageMetadataByModality, TToolCapabilities> {
30
+ export declare class GrokTextAdapter<TModel extends GrokTextAdapterModel, TProviderOptions extends Record<string, any> = ResolveProviderOptions<TModel>, TInputModalities extends ReadonlyArray<Modality> = ResolveInputModalities<TModel>, TToolCapabilities extends ReadonlyArray<string> = ResolveToolCapabilities<TModel>> extends OpenAIBaseResponsesTextAdapter<TModel, TProviderOptions, TInputModalities, GrokMessageMetadataByModality, TToolCapabilities> {
31
31
  readonly kind: "text";
32
32
  readonly name: "grok";
33
33
  constructor(config: GrokTextConfig, model: TModel);
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"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"],"mappings":";;;;;;;;;;;;;;;AA2CA,IAAa,kBAAb,cAWU,+BAMR;CACA,OAAyB;CACzB,OAAyB;CAEzB,YAAY,QAAwB,OAAe;EACjD,MAAM,OAAO,QAAQ,IAAI,OAAO,iBAAiB,MAAM,CAAC,CAAC;CAC3D;CAEA,oBACE,SACsC;EACtC,MAAM,EAAE,OAAO,YAAY,GAAG,YAAY,MAAM,oBAAoB;GAClE,GAAG;GACH,OAAO,KAAA;EACT,CAAC;EAGD,IAAI,KAAK,UAAU,oBAAoB,QAAQ,cAAc,KAAA,GAC3D,MAAM,IAAI,MACR,wFACF;EAGF,MAAM,QAAQ,QAAQ,QAClB,6BAA6B,QAAQ,KAAK,IAC1C,KAAA;EAEJ,OAAO;GACL,GAAG;GAGH,OAAO,QAAQ,SAAS;GACxB,SAAS,QAAQ,WAAW,CAAC,6BAA6B;GAC1D,GAAI,SACF,MAAM,SAAS,KAAK,EAAS,MAAuC;EACxE;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,eAGd,OACA,QACA,QACyB;CACzB,OAAO,IAAI,gBAAgB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,SACd,OACA,QACyB;CAEzB,OAAO,eAAe,OADP,qBACc,GAAQ,MAAM;AAC7C"}
1
+ {"version":3,"file":"text.js","names":[],"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 GrokTextAdapterModel,\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 GrokTextAdapterModel,\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"],"mappings":";;;;;;;;;;;;;;;AA4CA,IAAa,kBAAb,cAWU,+BAMR;CACA,OAAyB;CACzB,OAAyB;CAEzB,YAAY,QAAwB,OAAe;EACjD,MAAM,OAAO,QAAQ,IAAI,OAAO,iBAAiB,MAAM,CAAC,CAAC;CAC3D;CAEA,oBACE,SACsC;EACtC,MAAM,EAAE,OAAO,YAAY,GAAG,YAAY,MAAM,oBAAoB;GAClE,GAAG;GACH,OAAO,KAAA;EACT,CAAC;EAGD,IAAI,KAAK,UAAU,oBAAoB,QAAQ,cAAc,KAAA,GAC3D,MAAM,IAAI,MACR,wFACF;EAGF,MAAM,QAAQ,QAAQ,QAClB,6BAA6B,QAAQ,KAAK,IAC1C,KAAA;EAEJ,OAAO;GACL,GAAG;GAGH,OAAO,QAAQ,SAAS;GACxB,SAAS,QAAQ,WAAW,CAAC,6BAA6B;GAC1D,GAAI,SACF,MAAM,SAAS,KAAK,EAAS,MAAuC;EACxE;CACF;AACF;;;;;;;;;;;;;;;;AAiBA,SAAgB,eAGd,OACA,QACA,QACyB;CACzB,OAAO,IAAI,gBAAgB;EAAE;EAAQ,GAAG;CAAO,GAAG,KAAK;AACzD;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,SACd,OACA,QACyB;CAEzB,OAAO,eAAe,OADP,qBACc,GAAQ,MAAM;AAC7C"}
@@ -47,7 +47,6 @@ export declare class GrokVideoAdapter<TModel extends GrokVideoModel> extends Bas
47
47
  readonly name: "grok";
48
48
  private readonly clientConfig;
49
49
  constructor(config: GrokVideoConfig, model: TModel);
50
- private get fetch();
51
50
  private request;
52
51
  /**
53
52
  * Reads the error message out of an Imagine API error body
@@ -76,11 +76,8 @@ var GrokVideoAdapter = class extends BaseVideoAdapter {
76
76
  super({}, model);
77
77
  this.clientConfig = withGrokDefaults(config);
78
78
  }
79
- get fetch() {
80
- return this.clientConfig.fetch ?? fetch;
81
- }
82
79
  async request(path, init) {
83
- return await this.fetch(`${this.clientConfig.baseURL}${path}`, {
80
+ return await (this.clientConfig.fetch ?? globalThis.fetch.bind(globalThis))(`${this.clientConfig.baseURL}${path}`, {
84
81
  ...init,
85
82
  headers: {
86
83
  "Content-Type": "application/json",
@@ -1 +1 @@
1
- {"version":3,"file":"video.js","names":[],"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 GROK_VIDEO_MAX_REFERENCE_AUDIOS,\n GROK_VIDEO_MAX_REFERENCE_IMAGES,\n getGrokVideoDurationOptions,\n isGrokVideoReferenceModel,\n isGrokVideoSourceModel,\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 VideoPart,\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 GrokVideoRuntimeOptions,\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 the POST /v1/videos/{generations,edits,extensions} endpoints. */\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 image / video part to the URL string accepted by xAI's\n * Imagine video endpoints: public URLs pass through (fetched by xAI's\n * servers), data sources become base64 data URIs.\n */\nfunction mediaPartToUrl(\n part: ImagePart<MediaInputMetadata> | VideoPart<MediaInputMetadata>,\n): 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 && {\n billed: { quantity: seconds, unit: 'seconds' },\n unitsBilled: seconds,\n }),\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 * Both models support text-to-video and image-to-video;\n * `grok-imagine-video-1.5` is xAI's documented default and adds native\n * 1080p generation plus reference-to-video inputs. Source-video edit\n * and extend are `grok-imagine-video` only.\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 * - Reference-to-video via image prompt parts with\n * `metadata.role: 'reference'` or `'character'` (→ `reference_images`)\n * and preset voices via `modelOptions.reference_audios`\n * (grok-imagine-video-1.5 only)\n * - Video editing / extension on `grok-imagine-video` via a source\n * `video` prompt part and `modelOptions.mode: 'edit' | 'extend'`\n * (`/v1/videos/edits` / `/v1/videos/extensions`; in extend mode\n * `duration` is the added tail)\n * - Usage reporting: billed seconds (`usage.billed`) and exact cost\n */\nexport class GrokVideoAdapter<\n TModel extends GrokVideoModel,\n> extends BaseVideoAdapter<\n TModel,\n GrokVideoModelProviderOptionsByName[TModel],\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 GrokVideoModelProviderOptionsByName[TModel],\n GrokVideoModelSizeByName[TModel],\n GrokVideoModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult> {\n const { model, size, modelOptions, logger } = options\n\n // `mode` is a routing hint for this adapter, not an API field — strip it\n // before the remaining options are spread onto the request body. The\n // per-model map narrows what callers can pass, but modelOptions often\n // arrives as deserialized JSON, so the adapter handles the widest option\n // surface (the 1.5 shape) uniformly and gates by model at runtime.\n const { mode, ...wireOptions } = (modelOptions ??\n {}) as GrokVideoRuntimeOptions\n\n // `mode` is typed 'edit' | 'extend' but reaches us untrusted from JSON\n // callers. An unrecognised value must not fall through to the\n // generations endpoint with a source-video body — that would silently\n // run (and bill) a generation the caller never asked for.\n if (mode !== undefined && mode !== 'edit' && mode !== 'extend') {\n throw new Error(\n `${this.name}: unknown modelOptions.mode '${String(mode)}'. ` +\n `Expected 'edit' or 'extend'.`,\n )\n }\n\n // The interleaved prompt decomposes into verbatim text plus typed media\n // buckets. Reference audio is voice-id based (not an audio file), so\n // audio prompt parts have no request field to land in.\n const resolved = resolveMediaPrompt(options.prompt)\n if (resolved.audios.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support audio prompt parts (model: ${model}). ` +\n `To reference a preset voice, pass modelOptions.reference_audios ` +\n `(e.g. [{ voice_id: 'eve' }]).`,\n )\n }\n\n // A video prompt part is the source clip for edit / extension mode.\n // Those endpoints are grok-imagine-video only — 1.5 has no video input.\n if (\n !isGrokVideoSourceModel(model) &&\n (mode !== undefined || resolved.videos.length > 0)\n ) {\n throw new Error(\n `${this.name}: ${model} does not support video editing or extension. ` +\n `Use 'grok-imagine-video' for /v1/videos/edits and /v1/videos/extensions.`,\n )\n }\n\n // The mode must be chosen explicitly because the two endpoints have\n // different semantics (edit rewrites the clip, extend appends\n // `duration` seconds).\n if (resolved.videos.length > 1) {\n throw new Error(\n `${this.name}: ${model} accepts at most one source video; received ${resolved.videos.length}.`,\n )\n }\n const [sourceVideo] = resolved.videos\n if (sourceVideo && mode === undefined) {\n throw new Error(\n `${this.name}: a video prompt part needs modelOptions.mode set to ` +\n `'edit' (rewrite the clip) or 'extend' (append to it).`,\n )\n }\n if (!sourceVideo && mode !== undefined) {\n throw new Error(\n `${this.name}: modelOptions.mode '${mode}' requires a video prompt ` +\n `part carrying the source clip.`,\n )\n }\n\n if (mode !== undefined && sourceVideo) {\n return await this.createSourceVideoJob({\n model,\n mode,\n sourceVideo,\n resolved,\n wireOptions,\n size,\n genericDuration: options.duration,\n logger,\n })\n }\n\n validateVideoSize(model, size)\n\n // Pull the specially-handled keys out of the wire options: `duration`\n // is folded into the snapped value below, and the reference fields are\n // re-added explicitly so a JSON-serialized `null` or empty array reads\n // as \"unset\" instead of leaking onto the wire.\n const {\n duration: rawOptionDuration,\n reference_images: explicitReferenceImages,\n reference_audios: referenceAudios,\n ...generationOptions\n } = wireOptions\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 = rawOptionDuration ?? options.duration\n const duration =\n rawDuration != null ? this.snapDuration(rawDuration) : undefined\n\n // Image parts split by role: un-roled / 'start_frame' images become the\n // starting frame (image-to-video); 'reference' / 'character' images\n // become reference_images (reference-to-video). The Imagine API has no\n // mask / control / end-frame inputs. Unknown role strings (possible via\n // JSON callers) throw rather than silently dropping the part.\n const startFrames: Array<ImagePart<MediaInputMetadata>> = []\n const referenceImages: Array<{ url: string }> = []\n for (const part of resolved.images) {\n const role = part.metadata?.role\n switch (role) {\n case 'mask':\n case 'control':\n case 'end_frame':\n throw new Error(\n `${this.name}: the Imagine video API has no '${role}' image ` +\n `input on model ${model}. Use an un-roled / 'start_frame' ` +\n `image as the starting frame, or 'reference' images.`,\n )\n case 'reference':\n case 'character':\n referenceImages.push({ url: mediaPartToUrl(part) })\n break\n case 'start_frame':\n case undefined:\n startFrames.push(part)\n break\n default:\n throw new Error(\n `${this.name}: unknown image metadata.role '${String(role)}'. ` +\n `Expected 'start_frame', 'reference', or 'character'.`,\n )\n }\n }\n if (startFrames.length > 1) {\n throw new Error(\n `${this.name}: ${model} accepts at most one starting-frame image; received ${startFrames.length}. ` +\n `Use metadata.role: 'reference' for reference-to-video inputs.`,\n )\n }\n // Explicit modelOptions.reference_images replaces the part-derived list\n // (an explicit empty array means \"none\").\n const finalReferenceImages =\n explicitReferenceImages ??\n (referenceImages.length > 0 ? referenceImages : undefined)\n const referenceImageCount = finalReferenceImages?.length ?? 0\n const referenceAudioCount = referenceAudios?.length ?? 0\n const hasReference = referenceImageCount > 0 || referenceAudioCount > 0\n\n // Reference inputs are a grok-imagine-video-1.5 feature. The per-model\n // options map already hides the fields from other models at compile\n // time; this runtime gate covers prompt-part roles and untyped callers.\n if (!isGrokVideoReferenceModel(model) && hasReference) {\n throw new Error(\n `${this.name}: ${model} does not support reference-to-video inputs. ` +\n `Use 'grok-imagine-video-1.5' for reference_images / reference_audios.`,\n )\n }\n if (referenceAudioCount > GROK_VIDEO_MAX_REFERENCE_AUDIOS) {\n throw new Error(\n `${this.name}: ${model} accepts at most ${GROK_VIDEO_MAX_REFERENCE_AUDIOS} reference voices; received ${referenceAudioCount}.`,\n )\n }\n if (referenceImageCount > GROK_VIDEO_MAX_REFERENCE_IMAGES) {\n throw new Error(\n `${this.name}: ${model} accepts at most ${GROK_VIDEO_MAX_REFERENCE_IMAGES} reference images; received ${referenceImageCount}.`,\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] = startFrames\n\n // xAI rejects `image` + `reference_images` / `reference_audios` as a\n // 400: only one of image-to-video or reference-to-video can be active.\n if (startFrame && hasReference) {\n throw new Error(\n `${this.name}: image-to-video and reference-to-video cannot be combined. ` +\n `Use a starting-frame image, or reference images / voices, not both.`,\n )\n }\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 // (including `reference_images`, which replaces the part-derived list).\n const parsedSize = size !== undefined ? parseGrokVideoSize(size) : undefined\n const resolvedResolution =\n generationOptions.resolution ?? parsedSize?.resolution\n if (hasReference && resolvedResolution === '1080p') {\n throw new Error(\n `${this.name}: reference-to-video is capped at 720p on ${model}.`,\n )\n }\n const request = {\n model,\n prompt: resolved.text,\n ...(startFrame && { image: { url: mediaPartToUrl(startFrame) } }),\n ...(referenceImageCount > 0 && {\n reference_images: finalReferenceImages,\n }),\n ...(referenceAudioCount > 0 && {\n reference_audios: referenceAudios,\n }),\n ...(parsedSize && {\n aspect_ratio: parsedSize.aspectRatio,\n ...(parsedSize.resolution !== undefined && {\n resolution: parsedSize.resolution,\n }),\n }),\n // The remaining options spread after the size template so explicit\n // aspect_ratio / resolution win over it; duration and the reference\n // fields were destructured out above and re-added normalized.\n ...generationOptions,\n ...(duration !== undefined && { duration }),\n }\n\n return await this.postVideoJob('/videos/generations', request, {\n model,\n logger,\n logLine: `activity=video.create provider=${this.name} model=${model} mode=generate size=${size ?? 'default'} duration=${duration ?? 'default'}`,\n })\n }\n\n /**\n * Build and post an edit / extension request. Both endpoints take only\n * `model`, `prompt`, and the source `video` (plus `duration` — the length\n * of the added tail — for extensions): output geometry is inherited from\n * the source clip, capped at 720p, and edit outputs also inherit the\n * source length. Rather than sending fields the API documents as ignored,\n * the inapplicable options are rejected with actionable errors.\n */\n private async createSourceVideoJob(args: {\n model: string\n mode: 'edit' | 'extend'\n sourceVideo: VideoPart<MediaInputMetadata>\n resolved: ReturnType<typeof resolveMediaPrompt>\n wireOptions: Omit<GrokVideoRuntimeOptions, 'mode'>\n size: string | undefined\n genericDuration: number | undefined\n logger: VideoGenerationOptions<GrokVideoRuntimeOptions>['logger']\n }): Promise<VideoJobResult> {\n const { model, mode, sourceVideo, resolved, wireOptions, logger } = args\n const endpoint = mode === 'edit' ? '/videos/edits' : '/videos/extensions'\n\n if (resolved.images.length > 0) {\n throw new Error(\n `${this.name}: '${mode}' mode takes only the source video — image ` +\n `prompt parts are not supported by ${endpoint}.`,\n )\n }\n\n // Pull every generation-only key out of the wire options so nothing can\n // leak into the edit/extend body via the spread below. JSON-serialized\n // `null` values (a common \"unset\" encoding) are treated as absent;\n // actual values are rejected with actionable errors.\n const {\n aspect_ratio: aspectRatio,\n resolution,\n duration: modeDuration,\n reference_images: referenceImagesOption,\n reference_audios: referenceAudiosOption,\n ...passthrough\n } = wireOptions\n if (\n (referenceImagesOption?.length ?? 0) > 0 ||\n (referenceAudiosOption?.length ?? 0) > 0\n ) {\n throw new Error(\n `${this.name}: reference inputs are only supported by video ` +\n `generation, not '${mode}' mode.`,\n )\n }\n if (args.size !== undefined || aspectRatio != null || resolution != null) {\n throw new Error(\n `${this.name}: '${mode}' mode does not accept size / aspect_ratio / ` +\n `resolution — the output inherits the source clip's geometry ` +\n `(capped at 720p).`,\n )\n }\n const rawDuration = modeDuration ?? args.genericDuration\n if (mode === 'edit' && rawDuration != null) {\n throw new Error(\n `${this.name}: 'edit' mode does not accept a duration — the output ` +\n `inherits the source clip's length. Use mode 'extend' to append ` +\n `seconds to the clip.`,\n )\n }\n // Extend: the snapped duration is the added-tail length (1–15s).\n const duration =\n rawDuration != null ? this.snapDuration(rawDuration) : undefined\n\n const request = {\n model,\n prompt: resolved.text,\n video: { url: mediaPartToUrl(sourceVideo) },\n ...passthrough,\n ...(duration !== undefined && { duration }),\n }\n\n return await this.postVideoJob(endpoint, request, {\n model,\n logger,\n logLine: `activity=video.create provider=${this.name} model=${model} mode=${mode} duration=${duration ?? 'default'}`,\n })\n }\n\n /**\n * POST a create-job request body to one of the Imagine video endpoints\n * (`/videos/generations`, `/videos/edits`, `/videos/extensions`) and read\n * the `request_id` out of the shared response shape.\n */\n private async postVideoJob(\n endpoint: string,\n request: Record<string, unknown>,\n context: {\n model: string\n logger: VideoGenerationOptions<GrokVideoRuntimeOptions>['logger']\n logLine: string\n },\n ): Promise<VideoJobResult> {\n const { model, logger, logLine } = context\n try {\n logger.request(logLine, { provider: this.name, model })\n\n const response = await this.request(endpoint, {\n method: 'POST',\n body: JSON.stringify(request),\n })\n if (!response.ok) {\n throw new Error(\n `grok: ${endpoint} 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(`grok: ${endpoint} response contained no request_id`)\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-1.5')\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 * const adapter = createGrokVideo('grok-imagine-video-1.5', '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: an optional image prompt part is the starting frame.\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"],"mappings":"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"}
1
+ {"version":3,"file":"video.js","names":[],"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 GROK_VIDEO_MAX_REFERENCE_AUDIOS,\n GROK_VIDEO_MAX_REFERENCE_IMAGES,\n getGrokVideoDurationOptions,\n isGrokVideoReferenceModel,\n isGrokVideoSourceModel,\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 VideoPart,\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 GrokVideoRuntimeOptions,\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 the POST /v1/videos/{generations,edits,extensions} endpoints. */\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 image / video part to the URL string accepted by xAI's\n * Imagine video endpoints: public URLs pass through (fetched by xAI's\n * servers), data sources become base64 data URIs.\n */\nfunction mediaPartToUrl(\n part: ImagePart<MediaInputMetadata> | VideoPart<MediaInputMetadata>,\n): 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 && {\n billed: { quantity: seconds, unit: 'seconds' },\n unitsBilled: seconds,\n }),\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 * Both models support text-to-video and image-to-video;\n * `grok-imagine-video-1.5` is xAI's documented default and adds native\n * 1080p generation plus reference-to-video inputs. Source-video edit\n * and extend are `grok-imagine-video` only.\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 * - Reference-to-video via image prompt parts with\n * `metadata.role: 'reference'` or `'character'` (→ `reference_images`)\n * and preset voices via `modelOptions.reference_audios`\n * (grok-imagine-video-1.5 only)\n * - Video editing / extension on `grok-imagine-video` via a source\n * `video` prompt part and `modelOptions.mode: 'edit' | 'extend'`\n * (`/v1/videos/edits` / `/v1/videos/extensions`; in extend mode\n * `duration` is the added tail)\n * - Usage reporting: billed seconds (`usage.billed`) and exact cost\n */\nexport class GrokVideoAdapter<\n TModel extends GrokVideoModel,\n> extends BaseVideoAdapter<\n TModel,\n GrokVideoModelProviderOptionsByName[TModel],\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 async request(\n path: string,\n init?: Omit<RequestInit, 'headers'>,\n ): Promise<Response> {\n // workerd's fetch must be invoked with this === globalThis\n const fetchFn = this.clientConfig.fetch ?? globalThis.fetch.bind(globalThis)\n return await fetchFn(`${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 GrokVideoModelProviderOptionsByName[TModel],\n GrokVideoModelSizeByName[TModel],\n GrokVideoModelDurationByName[TModel]\n >,\n ): Promise<VideoJobResult> {\n const { model, size, modelOptions, logger } = options\n\n // `mode` is a routing hint for this adapter, not an API field — strip it\n // before the remaining options are spread onto the request body. The\n // per-model map narrows what callers can pass, but modelOptions often\n // arrives as deserialized JSON, so the adapter handles the widest option\n // surface (the 1.5 shape) uniformly and gates by model at runtime.\n const { mode, ...wireOptions } = (modelOptions ??\n {}) as GrokVideoRuntimeOptions\n\n // `mode` is typed 'edit' | 'extend' but reaches us untrusted from JSON\n // callers. An unrecognised value must not fall through to the\n // generations endpoint with a source-video body — that would silently\n // run (and bill) a generation the caller never asked for.\n if (mode !== undefined && mode !== 'edit' && mode !== 'extend') {\n throw new Error(\n `${this.name}: unknown modelOptions.mode '${String(mode)}'. ` +\n `Expected 'edit' or 'extend'.`,\n )\n }\n\n // The interleaved prompt decomposes into verbatim text plus typed media\n // buckets. Reference audio is voice-id based (not an audio file), so\n // audio prompt parts have no request field to land in.\n const resolved = resolveMediaPrompt(options.prompt)\n if (resolved.audios.length > 0) {\n throw new Error(\n `${this.name}.createVideoJob does not support audio prompt parts (model: ${model}). ` +\n `To reference a preset voice, pass modelOptions.reference_audios ` +\n `(e.g. [{ voice_id: 'eve' }]).`,\n )\n }\n\n // A video prompt part is the source clip for edit / extension mode.\n // Those endpoints are grok-imagine-video only — 1.5 has no video input.\n if (\n !isGrokVideoSourceModel(model) &&\n (mode !== undefined || resolved.videos.length > 0)\n ) {\n throw new Error(\n `${this.name}: ${model} does not support video editing or extension. ` +\n `Use 'grok-imagine-video' for /v1/videos/edits and /v1/videos/extensions.`,\n )\n }\n\n // The mode must be chosen explicitly because the two endpoints have\n // different semantics (edit rewrites the clip, extend appends\n // `duration` seconds).\n if (resolved.videos.length > 1) {\n throw new Error(\n `${this.name}: ${model} accepts at most one source video; received ${resolved.videos.length}.`,\n )\n }\n const [sourceVideo] = resolved.videos\n if (sourceVideo && mode === undefined) {\n throw new Error(\n `${this.name}: a video prompt part needs modelOptions.mode set to ` +\n `'edit' (rewrite the clip) or 'extend' (append to it).`,\n )\n }\n if (!sourceVideo && mode !== undefined) {\n throw new Error(\n `${this.name}: modelOptions.mode '${mode}' requires a video prompt ` +\n `part carrying the source clip.`,\n )\n }\n\n if (mode !== undefined && sourceVideo) {\n return await this.createSourceVideoJob({\n model,\n mode,\n sourceVideo,\n resolved,\n wireOptions,\n size,\n genericDuration: options.duration,\n logger,\n })\n }\n\n validateVideoSize(model, size)\n\n // Pull the specially-handled keys out of the wire options: `duration`\n // is folded into the snapped value below, and the reference fields are\n // re-added explicitly so a JSON-serialized `null` or empty array reads\n // as \"unset\" instead of leaking onto the wire.\n const {\n duration: rawOptionDuration,\n reference_images: explicitReferenceImages,\n reference_audios: referenceAudios,\n ...generationOptions\n } = wireOptions\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 = rawOptionDuration ?? options.duration\n const duration =\n rawDuration != null ? this.snapDuration(rawDuration) : undefined\n\n // Image parts split by role: un-roled / 'start_frame' images become the\n // starting frame (image-to-video); 'reference' / 'character' images\n // become reference_images (reference-to-video). The Imagine API has no\n // mask / control / end-frame inputs. Unknown role strings (possible via\n // JSON callers) throw rather than silently dropping the part.\n const startFrames: Array<ImagePart<MediaInputMetadata>> = []\n const referenceImages: Array<{ url: string }> = []\n for (const part of resolved.images) {\n const role = part.metadata?.role\n switch (role) {\n case 'mask':\n case 'control':\n case 'end_frame':\n throw new Error(\n `${this.name}: the Imagine video API has no '${role}' image ` +\n `input on model ${model}. Use an un-roled / 'start_frame' ` +\n `image as the starting frame, or 'reference' images.`,\n )\n case 'reference':\n case 'character':\n referenceImages.push({ url: mediaPartToUrl(part) })\n break\n case 'start_frame':\n case undefined:\n startFrames.push(part)\n break\n default:\n throw new Error(\n `${this.name}: unknown image metadata.role '${String(role)}'. ` +\n `Expected 'start_frame', 'reference', or 'character'.`,\n )\n }\n }\n if (startFrames.length > 1) {\n throw new Error(\n `${this.name}: ${model} accepts at most one starting-frame image; received ${startFrames.length}. ` +\n `Use metadata.role: 'reference' for reference-to-video inputs.`,\n )\n }\n // Explicit modelOptions.reference_images replaces the part-derived list\n // (an explicit empty array means \"none\").\n const finalReferenceImages =\n explicitReferenceImages ??\n (referenceImages.length > 0 ? referenceImages : undefined)\n const referenceImageCount = finalReferenceImages?.length ?? 0\n const referenceAudioCount = referenceAudios?.length ?? 0\n const hasReference = referenceImageCount > 0 || referenceAudioCount > 0\n\n // Reference inputs are a grok-imagine-video-1.5 feature. The per-model\n // options map already hides the fields from other models at compile\n // time; this runtime gate covers prompt-part roles and untyped callers.\n if (!isGrokVideoReferenceModel(model) && hasReference) {\n throw new Error(\n `${this.name}: ${model} does not support reference-to-video inputs. ` +\n `Use 'grok-imagine-video-1.5' for reference_images / reference_audios.`,\n )\n }\n if (referenceAudioCount > GROK_VIDEO_MAX_REFERENCE_AUDIOS) {\n throw new Error(\n `${this.name}: ${model} accepts at most ${GROK_VIDEO_MAX_REFERENCE_AUDIOS} reference voices; received ${referenceAudioCount}.`,\n )\n }\n if (referenceImageCount > GROK_VIDEO_MAX_REFERENCE_IMAGES) {\n throw new Error(\n `${this.name}: ${model} accepts at most ${GROK_VIDEO_MAX_REFERENCE_IMAGES} reference images; received ${referenceImageCount}.`,\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] = startFrames\n\n // xAI rejects `image` + `reference_images` / `reference_audios` as a\n // 400: only one of image-to-video or reference-to-video can be active.\n if (startFrame && hasReference) {\n throw new Error(\n `${this.name}: image-to-video and reference-to-video cannot be combined. ` +\n `Use a starting-frame image, or reference images / voices, not both.`,\n )\n }\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 // (including `reference_images`, which replaces the part-derived list).\n const parsedSize = size !== undefined ? parseGrokVideoSize(size) : undefined\n const resolvedResolution =\n generationOptions.resolution ?? parsedSize?.resolution\n if (hasReference && resolvedResolution === '1080p') {\n throw new Error(\n `${this.name}: reference-to-video is capped at 720p on ${model}.`,\n )\n }\n const request = {\n model,\n prompt: resolved.text,\n ...(startFrame && { image: { url: mediaPartToUrl(startFrame) } }),\n ...(referenceImageCount > 0 && {\n reference_images: finalReferenceImages,\n }),\n ...(referenceAudioCount > 0 && {\n reference_audios: referenceAudios,\n }),\n ...(parsedSize && {\n aspect_ratio: parsedSize.aspectRatio,\n ...(parsedSize.resolution !== undefined && {\n resolution: parsedSize.resolution,\n }),\n }),\n // The remaining options spread after the size template so explicit\n // aspect_ratio / resolution win over it; duration and the reference\n // fields were destructured out above and re-added normalized.\n ...generationOptions,\n ...(duration !== undefined && { duration }),\n }\n\n return await this.postVideoJob('/videos/generations', request, {\n model,\n logger,\n logLine: `activity=video.create provider=${this.name} model=${model} mode=generate size=${size ?? 'default'} duration=${duration ?? 'default'}`,\n })\n }\n\n /**\n * Build and post an edit / extension request. Both endpoints take only\n * `model`, `prompt`, and the source `video` (plus `duration` — the length\n * of the added tail — for extensions): output geometry is inherited from\n * the source clip, capped at 720p, and edit outputs also inherit the\n * source length. Rather than sending fields the API documents as ignored,\n * the inapplicable options are rejected with actionable errors.\n */\n private async createSourceVideoJob(args: {\n model: string\n mode: 'edit' | 'extend'\n sourceVideo: VideoPart<MediaInputMetadata>\n resolved: ReturnType<typeof resolveMediaPrompt>\n wireOptions: Omit<GrokVideoRuntimeOptions, 'mode'>\n size: string | undefined\n genericDuration: number | undefined\n logger: VideoGenerationOptions<GrokVideoRuntimeOptions>['logger']\n }): Promise<VideoJobResult> {\n const { model, mode, sourceVideo, resolved, wireOptions, logger } = args\n const endpoint = mode === 'edit' ? '/videos/edits' : '/videos/extensions'\n\n if (resolved.images.length > 0) {\n throw new Error(\n `${this.name}: '${mode}' mode takes only the source video — image ` +\n `prompt parts are not supported by ${endpoint}.`,\n )\n }\n\n // Pull every generation-only key out of the wire options so nothing can\n // leak into the edit/extend body via the spread below. JSON-serialized\n // `null` values (a common \"unset\" encoding) are treated as absent;\n // actual values are rejected with actionable errors.\n const {\n aspect_ratio: aspectRatio,\n resolution,\n duration: modeDuration,\n reference_images: referenceImagesOption,\n reference_audios: referenceAudiosOption,\n ...passthrough\n } = wireOptions\n if (\n (referenceImagesOption?.length ?? 0) > 0 ||\n (referenceAudiosOption?.length ?? 0) > 0\n ) {\n throw new Error(\n `${this.name}: reference inputs are only supported by video ` +\n `generation, not '${mode}' mode.`,\n )\n }\n if (args.size !== undefined || aspectRatio != null || resolution != null) {\n throw new Error(\n `${this.name}: '${mode}' mode does not accept size / aspect_ratio / ` +\n `resolution — the output inherits the source clip's geometry ` +\n `(capped at 720p).`,\n )\n }\n const rawDuration = modeDuration ?? args.genericDuration\n if (mode === 'edit' && rawDuration != null) {\n throw new Error(\n `${this.name}: 'edit' mode does not accept a duration — the output ` +\n `inherits the source clip's length. Use mode 'extend' to append ` +\n `seconds to the clip.`,\n )\n }\n // Extend: the snapped duration is the added-tail length (1–15s).\n const duration =\n rawDuration != null ? this.snapDuration(rawDuration) : undefined\n\n const request = {\n model,\n prompt: resolved.text,\n video: { url: mediaPartToUrl(sourceVideo) },\n ...passthrough,\n ...(duration !== undefined && { duration }),\n }\n\n return await this.postVideoJob(endpoint, request, {\n model,\n logger,\n logLine: `activity=video.create provider=${this.name} model=${model} mode=${mode} duration=${duration ?? 'default'}`,\n })\n }\n\n /**\n * POST a create-job request body to one of the Imagine video endpoints\n * (`/videos/generations`, `/videos/edits`, `/videos/extensions`) and read\n * the `request_id` out of the shared response shape.\n */\n private async postVideoJob(\n endpoint: string,\n request: Record<string, unknown>,\n context: {\n model: string\n logger: VideoGenerationOptions<GrokVideoRuntimeOptions>['logger']\n logLine: string\n },\n ): Promise<VideoJobResult> {\n const { model, logger, logLine } = context\n try {\n logger.request(logLine, { provider: this.name, model })\n\n const response = await this.request(endpoint, {\n method: 'POST',\n body: JSON.stringify(request),\n })\n if (!response.ok) {\n throw new Error(\n `grok: ${endpoint} 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(`grok: ${endpoint} response contained no request_id`)\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-1.5')\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 * const adapter = createGrokVideo('grok-imagine-video-1.5', '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: an optional image prompt part is the starting frame.\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"],"mappings":"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"}
@@ -9,8 +9,8 @@ export { GrokSpeechAdapter, createGrokSpeech, grokSpeech, type GrokSpeechConfig,
9
9
  export type { GrokTTSProviderOptions, GrokTTSVoice, GrokTTSCodec, } from './audio/tts-provider-options.js';
10
10
  export { GrokTranscriptionAdapter, createGrokTranscription, grokTranscription, type GrokTranscriptionConfig, } from './adapters/transcription.js';
11
11
  export type { GrokTranscriptionProviderOptions, GrokSTTAudioFormat, } from './audio/transcription-provider-options.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, GROK_DEFAULT_REALTIME_MODEL, } from './model-meta.js';
12
+ export type { GrokChatModelProviderOptionsByName, GrokChatModelToolCapabilitiesByName, GrokModelInputModalitiesByName, ResolveProviderOptions, ResolveInputModalities, GrokChatModel, GrokVertexChatModel, GrokImageModel, GrokVideoModel, GrokTTSModel, GrokTranscriptionModel, GrokRealtimeModel, } from './model-meta.js';
13
+ export { GROK_CHAT_MODELS, GROK_VERTEX_CHAT_MODELS, GROK_IMAGE_MODELS, GROK_VIDEO_MODELS, GROK_TTS_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_REALTIME_MODELS, GROK_DEFAULT_REALTIME_MODEL, } from './model-meta.js';
14
14
  export type { GrokTextMetadata, GrokImageMetadata, GrokAudioMetadata, GrokVideoMetadata, GrokDocumentMetadata, GrokMessageMetadataByModality, } from './message-types.js';
15
15
  export { grokRealtimeToken, grokRealtime } from './realtime/index.js';
16
16
  export type { GrokRealtimeVoice, GrokRealtimeTokenOptions, GrokRealtimeOptions, GrokTurnDetection, GrokSemanticVADConfig, GrokServerVADConfig, } from './realtime/index.js';
package/dist/esm/index.js CHANGED
@@ -5,8 +5,8 @@ import { GROK_VIDEO_DURATIONS, getGrokVideoDurationOptions } from "./video/video
5
5
  import { GrokVideoAdapter, createGrokVideo, grokVideo } from "./adapters/video.js";
6
6
  import { GrokSpeechAdapter, createGrokSpeech, grokSpeech } from "./adapters/tts.js";
7
7
  import { GrokTranscriptionAdapter, createGrokTranscription, grokTranscription } from "./adapters/transcription.js";
8
- import { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VIDEO_MODELS } from "./model-meta.js";
8
+ import { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VERTEX_CHAT_MODELS, GROK_VIDEO_MODELS } from "./model-meta.js";
9
9
  import { grokRealtimeToken } from "./realtime/token.js";
10
10
  import { grokRealtime } from "./realtime/adapter.js";
11
11
  import "./realtime/index.js";
12
- export { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VIDEO_DURATIONS, GROK_VIDEO_MODELS, GrokImageAdapter, GrokSpeechAdapter, GrokTextAdapter, GrokTranscriptionAdapter, GrokVideoAdapter, createGrokImage, createGrokSpeech, createGrokSummarize, createGrokText, createGrokTranscription, createGrokVideo, getGrokVideoDurationOptions, grokImage, grokRealtime, grokRealtimeToken, grokSpeech, grokSummarize, grokText, grokTranscription, grokVideo };
12
+ export { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VERTEX_CHAT_MODELS, GROK_VIDEO_DURATIONS, GROK_VIDEO_MODELS, GrokImageAdapter, GrokSpeechAdapter, GrokTextAdapter, GrokTranscriptionAdapter, GrokVideoAdapter, createGrokImage, createGrokSpeech, createGrokSummarize, createGrokText, createGrokTranscription, createGrokVideo, getGrokVideoDurationOptions, grokImage, grokRealtime, grokRealtimeToken, grokSpeech, grokSummarize, grokText, grokTranscription, grokVideo };
@@ -76,10 +76,55 @@ declare const GROK_BUILD_0_1: {
76
76
  };
77
77
  };
78
78
  };
79
+ declare const GROK_4_20_REASONING: {
80
+ readonly name: "grok-4.20-reasoning";
81
+ readonly context_window: 1000000;
82
+ readonly supports: {
83
+ readonly input: ["text", "image"];
84
+ readonly output: ["text"];
85
+ readonly capabilities: ["reasoning", "structured_outputs", "tool_calling"];
86
+ readonly tools: readonly [];
87
+ };
88
+ };
89
+ declare const GROK_4_20_NON_REASONING: {
90
+ readonly name: "grok-4.20-non-reasoning";
91
+ readonly context_window: 1000000;
92
+ readonly supports: {
93
+ readonly input: ["text", "image"];
94
+ readonly output: ["text"];
95
+ readonly capabilities: ["structured_outputs", "tool_calling"];
96
+ readonly tools: readonly [];
97
+ };
98
+ };
99
+ declare const GROK_4_1_FAST_REASONING: {
100
+ readonly name: "grok-4.1-fast-reasoning";
101
+ readonly context_window: 2000000;
102
+ readonly supports: {
103
+ readonly input: ["text", "image"];
104
+ readonly output: ["text"];
105
+ readonly capabilities: ["reasoning", "structured_outputs", "tool_calling"];
106
+ readonly tools: readonly [];
107
+ };
108
+ };
109
+ declare const GROK_4_1_FAST_NON_REASONING: {
110
+ readonly name: "grok-4.1-fast-non-reasoning";
111
+ readonly context_window: 2000000;
112
+ readonly supports: {
113
+ readonly input: ["text", "image"];
114
+ readonly output: ["text"];
115
+ readonly capabilities: ["structured_outputs", "tool_calling"];
116
+ readonly tools: readonly [];
117
+ };
118
+ };
79
119
  /**
80
- * Grok chat models supported by the Responses adapter.
120
+ * Grok chat models supported by the xAI Responses adapter.
81
121
  */
82
122
  export declare const GROK_CHAT_MODELS: readonly ["grok-4.5", "grok-4.6", "grok-build-0.1", "grok-4.3"];
123
+ /**
124
+ * Grok chat models on Vertex AI / Gemini Enterprise Agent Platform.
125
+ * This list is the Google partner catalog, not the xAI API catalog.
126
+ */
127
+ export declare const GROK_VERTEX_CHAT_MODELS: readonly ["grok-4.3", "grok-4.20-reasoning", "grok-4.20-non-reasoning", "grok-4.1-fast-reasoning", "grok-4.1-fast-non-reasoning"];
83
128
  /**
84
129
  * Grok Image Generation Models
85
130
  */
@@ -100,6 +145,8 @@ export declare const GROK_REALTIME_MODELS: readonly ["grok-voice-think-fast-2.0"
100
145
  */
101
146
  export declare const GROK_DEFAULT_REALTIME_MODEL: GrokRealtimeModel;
102
147
  export type GrokChatModel = (typeof GROK_CHAT_MODELS)[number];
148
+ export type GrokVertexChatModel = (typeof GROK_VERTEX_CHAT_MODELS)[number];
149
+ export type GrokTextAdapterModel = GrokChatModel | GrokVertexChatModel;
103
150
  export type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number];
104
151
  export type GrokVideoModel = (typeof GROK_VIDEO_MODELS)[number];
105
152
  export type GrokTTSModel = (typeof GROK_TTS_MODELS)[number];
@@ -114,6 +161,10 @@ export type GrokModelInputModalitiesByName = {
114
161
  [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.input;
115
162
  [GROK_4_5.name]: typeof GROK_4_5.supports.input;
116
163
  [GROK_4_6.name]: typeof GROK_4_6.supports.input;
164
+ [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.input;
165
+ [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.input;
166
+ [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.input;
167
+ [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.supports.input;
117
168
  };
118
169
  /**
119
170
  * Type-only map from Grok chat model name to its supported provider tools.
@@ -123,6 +174,10 @@ export type GrokModelInputModalitiesByName = {
123
174
  export type GrokChatModelToolCapabilitiesByName = {
124
175
  [GROK_4_3.name]: typeof GROK_4_3.supports.tools;
125
176
  [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.tools;
177
+ [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.tools;
178
+ [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.tools;
179
+ [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.tools;
180
+ [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.supports.tools;
126
181
  };
127
182
  export type GrokProviderOptions = GrokTextProviderOptions;
128
183
  /**
@@ -131,6 +186,10 @@ export type GrokProviderOptions = GrokTextProviderOptions;
131
186
  export type GrokChatModelProviderOptionsByName = {
132
187
  [GROK_4_3.name]: GrokProviderOptions;
133
188
  [GROK_BUILD_0_1.name]: GrokBuildProviderOptions;
189
+ [GROK_4_20_REASONING.name]: GrokProviderOptions;
190
+ [GROK_4_20_NON_REASONING.name]: GrokProviderOptions;
191
+ [GROK_4_1_FAST_REASONING.name]: GrokProviderOptions;
192
+ [GROK_4_1_FAST_NON_REASONING.name]: GrokProviderOptions;
134
193
  };
135
194
  /**
136
195
  * Resolve provider options for a specific model.
@@ -167,8 +167,56 @@ var GROK_BUILD_0_1 = {
167
167
  output: { normal: 2 }
168
168
  }
169
169
  };
170
+ var GROK_4_20_REASONING = {
171
+ name: "grok-4.20-reasoning",
172
+ context_window: 1e6,
173
+ supports: {
174
+ input: ["text", "image"],
175
+ output: ["text"],
176
+ capabilities: [
177
+ "reasoning",
178
+ "structured_outputs",
179
+ "tool_calling"
180
+ ],
181
+ tools: []
182
+ }
183
+ };
184
+ var GROK_4_20_NON_REASONING = {
185
+ name: "grok-4.20-non-reasoning",
186
+ context_window: 1e6,
187
+ supports: {
188
+ input: ["text", "image"],
189
+ output: ["text"],
190
+ capabilities: ["structured_outputs", "tool_calling"],
191
+ tools: []
192
+ }
193
+ };
194
+ var GROK_4_1_FAST_REASONING = {
195
+ name: "grok-4.1-fast-reasoning",
196
+ context_window: 2e6,
197
+ supports: {
198
+ input: ["text", "image"],
199
+ output: ["text"],
200
+ capabilities: [
201
+ "reasoning",
202
+ "structured_outputs",
203
+ "tool_calling"
204
+ ],
205
+ tools: []
206
+ }
207
+ };
208
+ var GROK_4_1_FAST_NON_REASONING = {
209
+ name: "grok-4.1-fast-non-reasoning",
210
+ context_window: 2e6,
211
+ supports: {
212
+ input: ["text", "image"],
213
+ output: ["text"],
214
+ capabilities: ["structured_outputs", "tool_calling"],
215
+ tools: []
216
+ }
217
+ };
170
218
  /**
171
- * Grok chat models supported by the Responses adapter.
219
+ * Grok chat models supported by the xAI Responses adapter.
172
220
  */
173
221
  var GROK_CHAT_MODELS = [
174
222
  GROK_4_5.name,
@@ -177,6 +225,17 @@ var GROK_CHAT_MODELS = [
177
225
  GROK_4_3.name
178
226
  ];
179
227
  /**
228
+ * Grok chat models on Vertex AI / Gemini Enterprise Agent Platform.
229
+ * This list is the Google partner catalog, not the xAI API catalog.
230
+ */
231
+ var GROK_VERTEX_CHAT_MODELS = [
232
+ GROK_4_3.name,
233
+ GROK_4_20_REASONING.name,
234
+ GROK_4_20_NON_REASONING.name,
235
+ GROK_4_1_FAST_REASONING.name,
236
+ GROK_4_1_FAST_NON_REASONING.name
237
+ ];
238
+ /**
180
239
  * Grok Image Generation Models
181
240
  */
182
241
  var GROK_IMAGE_MODELS = [
@@ -257,6 +316,6 @@ var GROK_REALTIME_MODELS = [
257
316
  */
258
317
  var GROK_DEFAULT_REALTIME_MODEL = "grok-voice-think-fast-2.0";
259
318
  //#endregion
260
- export { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VIDEO_MODELS };
319
+ export { GROK_CHAT_MODELS, GROK_DEFAULT_REALTIME_MODEL, GROK_IMAGE_MODELS, GROK_REALTIME_MODELS, GROK_TRANSCRIPTION_MODELS, GROK_TTS_MODELS, GROK_VERTEX_CHAT_MODELS, GROK_VIDEO_MODELS };
261
320
 
262
321
  //# sourceMappingURL=model-meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-meta.js","names":[],"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\nconst GROK_4_5 = {\n name: 'grok-4.5',\n context_window: 500_000,\n supports: {\n input: ['text', 'image', 'document'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [],\n },\n pricing: {\n input: {\n normal: 2,\n cached: 0.3,\n },\n output: {\n normal: 6,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_6 = {\n name: 'grok-4.6',\n context_window: 500_000,\n supports: {\n input: ['text', 'image', 'document'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [],\n },\n pricing: {\n input: {\n normal: 2,\n cached: 0.5,\n },\n output: {\n normal: 6,\n },\n },\n} as const satisfies ModelMeta\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// xAI's recommended Imagine image model. Supports the 2.0-only `quality`\n// provider option ('low' | 'medium', default 'medium').\nconst GROK_IMAGINE_IMAGE_2_0 = {\n name: 'grok-imagine-image-2.0',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.04,\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// Both models support text-to-video and image-to-video (a starting-frame\n// image is optional). grok-imagine-video-1.5 is the documented default: it\n// adds native 1080p for text-to-video / image-to-video plus\n// reference-to-video (`reference_images` / `reference_audios`; reference\n// output is capped at 720p). Source-video edit (`/v1/videos/edits`) and\n// extend (`/v1/videos/extensions`) are grok-imagine-video only — xAI's\n// 1.5 model page lists text+image input, not video.\nconst GROK_IMAGINE_VIDEO = {\n name: 'grok-imagine-video',\n supports: {\n input: ['text', 'image', 'video'],\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 = [\n GROK_4_5.name,\n GROK_4_6.name,\n GROK_BUILD_0_1.name,\n GROK_4_3.name,\n] 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_2_0.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\n/** @deprecated xAI has deprecated grok-voice-think-fast-1.0 — use grok-voice-think-fast-2.0. */\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\n// xAI's current recommended speech-to-speech model.\nconst GROK_VOICE_THINK_FAST_2 = {\n name: 'grok-voice-think-fast-2.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\n// Rolling alias used by xAI's realtime docs examples; always points at the\n// latest speech-to-speech model.\nconst GROK_VOICE_LATEST = {\n name: 'grok-voice-latest',\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_THINK_FAST_2.name,\n GROK_VOICE_LATEST.name,\n GROK_VOICE_FAST_1.name,\n GROK_VOICE_THINK_FAST_1.name,\n] as const\n\n/**\n * Default speech-to-speech model used by the realtime token issuer and the\n * realtime client adapter when no model is specified. Single source of truth\n * so a future default bump cannot leave the two sides disagreeing.\n */\nexport const GROK_DEFAULT_REALTIME_MODEL: GrokRealtimeModel =\n 'grok-voice-think-fast-2.0'\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 [GROK_4_5.name]: typeof GROK_4_5.supports.input\n [GROK_4_6.name]: typeof GROK_4_6.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"],"mappings":"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"}
1
+ {"version":3,"file":"model-meta.js","names":[],"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\nconst GROK_4_5 = {\n name: 'grok-4.5',\n context_window: 500_000,\n supports: {\n input: ['text', 'image', 'document'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [],\n },\n pricing: {\n input: {\n normal: 2,\n cached: 0.3,\n },\n output: {\n normal: 6,\n },\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_6 = {\n name: 'grok-4.6',\n context_window: 500_000,\n supports: {\n input: ['text', 'image', 'document'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [],\n },\n pricing: {\n input: {\n normal: 2,\n cached: 0.5,\n },\n output: {\n normal: 6,\n },\n },\n} as const satisfies ModelMeta\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// xAI's recommended Imagine image model. Supports the 2.0-only `quality`\n// provider option ('low' | 'medium', default 'medium').\nconst GROK_IMAGINE_IMAGE_2_0 = {\n name: 'grok-imagine-image-2.0',\n supports: {\n input: ['text', 'image'],\n output: ['image'],\n },\n pricing: {\n input: {\n normal: 0,\n },\n output: {\n normal: 0.04,\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// Both models support text-to-video and image-to-video (a starting-frame\n// image is optional). grok-imagine-video-1.5 is the documented default: it\n// adds native 1080p for text-to-video / image-to-video plus\n// reference-to-video (`reference_images` / `reference_audios`; reference\n// output is capped at 720p). Source-video edit (`/v1/videos/edits`) and\n// extend (`/v1/videos/extensions`) are grok-imagine-video only — xAI's\n// 1.5 model page lists text+image input, not video.\nconst GROK_IMAGINE_VIDEO = {\n name: 'grok-imagine-video',\n supports: {\n input: ['text', 'image', 'video'],\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// Vertex Model Garden IDs. These are not the xAI API catalog.\n// Source: https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/partner-models/grok\nconst GROK_4_20_REASONING = {\n name: 'grok-4.20-reasoning',\n context_window: 1_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_20_NON_REASONING = {\n name: 'grok-4.20-non-reasoning',\n context_window: 1_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['structured_outputs', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_1_FAST_REASONING = {\n name: 'grok-4.1-fast-reasoning',\n context_window: 2_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\nconst GROK_4_1_FAST_NON_REASONING = {\n name: 'grok-4.1-fast-non-reasoning',\n context_window: 2_000_000,\n supports: {\n input: ['text', 'image'],\n output: ['text'],\n capabilities: ['structured_outputs', 'tool_calling'],\n tools: [] as const,\n },\n} as const satisfies ModelMeta\n\n/**\n * Grok chat models supported by the xAI Responses adapter.\n */\nexport const GROK_CHAT_MODELS = [\n GROK_4_5.name,\n GROK_4_6.name,\n GROK_BUILD_0_1.name,\n GROK_4_3.name,\n] as const\n\n/**\n * Grok chat models on Vertex AI / Gemini Enterprise Agent Platform.\n * This list is the Google partner catalog, not the xAI API catalog.\n */\nexport const GROK_VERTEX_CHAT_MODELS = [\n GROK_4_3.name,\n GROK_4_20_REASONING.name,\n GROK_4_20_NON_REASONING.name,\n GROK_4_1_FAST_REASONING.name,\n GROK_4_1_FAST_NON_REASONING.name,\n] 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_2_0.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\n/** @deprecated xAI has deprecated grok-voice-think-fast-1.0 — use grok-voice-think-fast-2.0. */\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\n// xAI's current recommended speech-to-speech model.\nconst GROK_VOICE_THINK_FAST_2 = {\n name: 'grok-voice-think-fast-2.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\n// Rolling alias used by xAI's realtime docs examples; always points at the\n// latest speech-to-speech model.\nconst GROK_VOICE_LATEST = {\n name: 'grok-voice-latest',\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_THINK_FAST_2.name,\n GROK_VOICE_LATEST.name,\n GROK_VOICE_FAST_1.name,\n GROK_VOICE_THINK_FAST_1.name,\n] as const\n\n/**\n * Default speech-to-speech model used by the realtime token issuer and the\n * realtime client adapter when no model is specified. Single source of truth\n * so a future default bump cannot leave the two sides disagreeing.\n */\nexport const GROK_DEFAULT_REALTIME_MODEL: GrokRealtimeModel =\n 'grok-voice-think-fast-2.0'\n\nexport type GrokChatModel = (typeof GROK_CHAT_MODELS)[number]\nexport type GrokVertexChatModel = (typeof GROK_VERTEX_CHAT_MODELS)[number]\nexport type GrokTextAdapterModel = GrokChatModel | GrokVertexChatModel\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 [GROK_4_5.name]: typeof GROK_4_5.supports.input\n [GROK_4_6.name]: typeof GROK_4_6.supports.input\n [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.input\n [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.input\n [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.input\n [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.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 [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.tools\n [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.tools\n [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.tools\n [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.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 [GROK_4_20_REASONING.name]: GrokProviderOptions\n [GROK_4_20_NON_REASONING.name]: GrokProviderOptions\n [GROK_4_1_FAST_REASONING.name]: GrokProviderOptions\n [GROK_4_1_FAST_NON_REASONING.name]: GrokProviderOptions\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"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export declare class GrokVertexAuthError extends Error {
2
+ constructor(message: string, options?: ErrorOptions);
3
+ }
4
+ export type VertexAuthClient = {
5
+ getRequestHeaders: (url?: string | URL) => Promise<Headers>;
6
+ };
7
+ /**
8
+ * Public Vertex config for Grok. `project` and `location` match the Gemini
9
+ * Vertex factories so one auth object works for both.
10
+ *
11
+ * Default location is `global`. Grok on Vertex uses the OpenAI-compatible
12
+ * Responses endpoint under `/endpoints/openapi`.
13
+ */
14
+ export type GrokVertexConfig = {
15
+ project?: string;
16
+ location?: string;
17
+ /** Override the OpenAI-compatible Vertex base URL. Used by e2e. */
18
+ baseURL?: string;
19
+ getAccessToken?: () => Promise<string>;
20
+ authClient?: VertexAuthClient;
21
+ defaultHeaders?: Record<string, string>;
22
+ };
23
+ export declare function toVertexGrokModelId(model: string): string;
24
+ export declare function resolveGrokVertexProject(config: GrokVertexConfig): string | undefined;
25
+ export declare function resolveGrokVertexLocation(config: GrokVertexConfig): string;
26
+ export declare function resolveGrokVertexBaseURL(config: GrokVertexConfig): string;
27
+ export declare function resolveGrokVertexAccessToken(config: GrokVertexConfig): Promise<string>;
@@ -0,0 +1,61 @@
1
+ //#region src/vertex/auth.ts
2
+ var GrokVertexAuthError = class extends Error {
3
+ constructor(message, options) {
4
+ super(message, options);
5
+ this.name = "GrokVertexAuthError";
6
+ }
7
+ };
8
+ function isMissingGoogleAuthLibrary(error) {
9
+ if (!(error instanceof Error) || !("code" in error)) return false;
10
+ const code = error.code;
11
+ if (code !== "ERR_MODULE_NOT_FOUND" && code !== "MODULE_NOT_FOUND") return false;
12
+ return error.message.includes("google-auth-library");
13
+ }
14
+ function nonEmpty(value) {
15
+ if (value === void 0 || value.length === 0) return;
16
+ return value;
17
+ }
18
+ function readEnv(name) {
19
+ if (typeof process === "undefined" || process.env === void 0) return;
20
+ return nonEmpty(process.env[name]);
21
+ }
22
+ function toVertexGrokModelId(model) {
23
+ if (model.startsWith("xai/")) return model;
24
+ return `xai/${model}`;
25
+ }
26
+ function resolveGrokVertexProject(config) {
27
+ return nonEmpty(config.project) ?? readEnv("GOOGLE_CLOUD_PROJECT") ?? readEnv("GOOGLE_VERTEX_PROJECT");
28
+ }
29
+ function resolveGrokVertexLocation(config) {
30
+ return nonEmpty(config.location) ?? readEnv("GOOGLE_CLOUD_LOCATION") ?? readEnv("GOOGLE_VERTEX_LOCATION") ?? "global";
31
+ }
32
+ function resolveGrokVertexBaseURL(config) {
33
+ if (config.baseURL !== void 0 && config.baseURL.length > 0) return config.baseURL.replace(/\/+$/, "");
34
+ const project = resolveGrokVertexProject(config);
35
+ if (project === void 0) throw new GrokVertexAuthError("Grok Vertex needs a project, or a baseURL. Pass project on the factory, or set GOOGLE_CLOUD_PROJECT or GOOGLE_VERTEX_PROJECT.");
36
+ const location = resolveGrokVertexLocation(config);
37
+ if (location === "global") return `https://aiplatform.googleapis.com/v1/projects/${project}/locations/global/endpoints/openapi`;
38
+ return `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/endpoints/openapi`;
39
+ }
40
+ async function resolveGrokVertexAccessToken(config) {
41
+ if (config.getAccessToken !== void 0) return config.getAccessToken();
42
+ if (config.authClient !== void 0) {
43
+ const authorization = (await config.authClient.getRequestHeaders()).get("Authorization");
44
+ if (authorization === null || !authorization.startsWith("Bearer ")) throw new GrokVertexAuthError("Grok Vertex authClient.getRequestHeaders() must return an Authorization Bearer token.");
45
+ return authorization.slice(7);
46
+ }
47
+ try {
48
+ const { GoogleAuth } = await import("google-auth-library");
49
+ const token = await (await new GoogleAuth({ scopes: ["https://www.googleapis.com/auth/cloud-platform"] }).getClient()).getAccessToken();
50
+ if (token.token === null || token.token === void 0) throw new GrokVertexAuthError("Grok Vertex could not load a Google access token from Application Default Credentials.");
51
+ return token.token;
52
+ } catch (error) {
53
+ if (error instanceof GrokVertexAuthError) throw error;
54
+ if (isMissingGoogleAuthLibrary(error)) throw new GrokVertexAuthError("Grok Vertex needs google-auth-library, or pass authClient or getAccessToken. Install google-auth-library next to @tanstack/ai-grok.");
55
+ throw new GrokVertexAuthError("Grok Vertex could not load a Google access token from Application Default Credentials.", { cause: error });
56
+ }
57
+ }
58
+ //#endregion
59
+ export { GrokVertexAuthError, resolveGrokVertexAccessToken, resolveGrokVertexBaseURL, resolveGrokVertexLocation, resolveGrokVertexProject, toVertexGrokModelId };
60
+
61
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","names":[],"sources":["../../../src/vertex/auth.ts"],"sourcesContent":["export class GrokVertexAuthError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'GrokVertexAuthError'\n }\n}\n\nfunction isMissingGoogleAuthLibrary(error: unknown): boolean {\n if (!(error instanceof Error) || !('code' in error)) {\n return false\n }\n const code = error.code\n if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') {\n return false\n }\n return error.message.includes('google-auth-library')\n}\n\nexport type VertexAuthClient = {\n getRequestHeaders: (url?: string | URL) => Promise<Headers>\n}\n\n/**\n * Public Vertex config for Grok. `project` and `location` match the Gemini\n * Vertex factories so one auth object works for both.\n *\n * Default location is `global`. Grok on Vertex uses the OpenAI-compatible\n * Responses endpoint under `/endpoints/openapi`.\n */\nexport type GrokVertexConfig = {\n project?: string\n location?: string\n /** Override the OpenAI-compatible Vertex base URL. Used by e2e. */\n baseURL?: string\n getAccessToken?: () => Promise<string>\n authClient?: VertexAuthClient\n defaultHeaders?: Record<string, string>\n}\n\nfunction nonEmpty(value: string | undefined): string | undefined {\n if (value === undefined || value.length === 0) {\n return undefined\n }\n return value\n}\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === 'undefined' || process.env === undefined) {\n return undefined\n }\n return nonEmpty(process.env[name])\n}\n\nexport function toVertexGrokModelId(model: string): string {\n if (model.startsWith('xai/')) {\n return model\n }\n return `xai/${model}`\n}\n\nexport function resolveGrokVertexProject(\n config: GrokVertexConfig,\n): string | undefined {\n return (\n nonEmpty(config.project) ??\n readEnv('GOOGLE_CLOUD_PROJECT') ??\n readEnv('GOOGLE_VERTEX_PROJECT')\n )\n}\n\nexport function resolveGrokVertexLocation(config: GrokVertexConfig): string {\n return (\n nonEmpty(config.location) ??\n readEnv('GOOGLE_CLOUD_LOCATION') ??\n readEnv('GOOGLE_VERTEX_LOCATION') ??\n 'global'\n )\n}\n\nexport function resolveGrokVertexBaseURL(config: GrokVertexConfig): string {\n if (config.baseURL !== undefined && config.baseURL.length > 0) {\n return config.baseURL.replace(/\\/+$/, '')\n }\n\n const project = resolveGrokVertexProject(config)\n if (project === undefined) {\n throw new GrokVertexAuthError(\n 'Grok Vertex needs a project, or a baseURL. Pass project on the factory, or set GOOGLE_CLOUD_PROJECT or GOOGLE_VERTEX_PROJECT.',\n )\n }\n\n const location = resolveGrokVertexLocation(config)\n if (location === 'global') {\n return `https://aiplatform.googleapis.com/v1/projects/${project}/locations/global/endpoints/openapi`\n }\n return `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/endpoints/openapi`\n}\n\nexport async function resolveGrokVertexAccessToken(\n config: GrokVertexConfig,\n): Promise<string> {\n if (config.getAccessToken !== undefined) {\n return config.getAccessToken()\n }\n\n if (config.authClient !== undefined) {\n const headers = await config.authClient.getRequestHeaders()\n const authorization = headers.get('Authorization')\n if (authorization === null || !authorization.startsWith('Bearer ')) {\n throw new GrokVertexAuthError(\n 'Grok Vertex authClient.getRequestHeaders() must return an Authorization Bearer token.',\n )\n }\n return authorization.slice('Bearer '.length)\n }\n\n try {\n const { GoogleAuth } = await import('google-auth-library')\n const auth = new GoogleAuth({\n scopes: ['https://www.googleapis.com/auth/cloud-platform'],\n })\n const client = await auth.getClient()\n const token = await client.getAccessToken()\n if (token.token === null || token.token === undefined) {\n throw new GrokVertexAuthError(\n 'Grok Vertex could not load a Google access token from Application Default Credentials.',\n )\n }\n return token.token\n } catch (error) {\n if (error instanceof GrokVertexAuthError) {\n throw error\n }\n if (isMissingGoogleAuthLibrary(error)) {\n throw new GrokVertexAuthError(\n 'Grok Vertex needs google-auth-library, or pass authClient or getAccessToken. Install google-auth-library next to @tanstack/ai-grok.',\n )\n }\n throw new GrokVertexAuthError(\n 'Grok Vertex could not load a Google access token from Application Default Credentials.',\n { cause: error },\n )\n }\n}\n"],"mappings":";AAAA,IAAa,sBAAb,cAAyC,MAAM;CAC7C,YAAY,SAAiB,SAAwB;EACnD,MAAM,SAAS,OAAO;EACtB,KAAK,OAAO;CACd;AACF;AAEA,SAAS,2BAA2B,OAAyB;CAC3D,IAAI,EAAE,iBAAiB,UAAU,EAAE,UAAU,QAC3C,OAAO;CAET,MAAM,OAAO,MAAM;CACnB,IAAI,SAAS,0BAA0B,SAAS,oBAC9C,OAAO;CAET,OAAO,MAAM,QAAQ,SAAS,qBAAqB;AACrD;AAuBA,SAAS,SAAS,OAA+C;CAC/D,IAAI,UAAU,KAAA,KAAa,MAAM,WAAW,GAC1C;CAEF,OAAO;AACT;AAEA,SAAS,QAAQ,MAAkC;CACjD,IAAI,OAAO,YAAY,eAAe,QAAQ,QAAQ,KAAA,GACpD;CAEF,OAAO,SAAS,QAAQ,IAAI,KAAK;AACnC;AAEA,SAAgB,oBAAoB,OAAuB;CACzD,IAAI,MAAM,WAAW,MAAM,GACzB,OAAO;CAET,OAAO,OAAO;AAChB;AAEA,SAAgB,yBACd,QACoB;CACpB,OACE,SAAS,OAAO,OAAO,KACvB,QAAQ,sBAAsB,KAC9B,QAAQ,uBAAuB;AAEnC;AAEA,SAAgB,0BAA0B,QAAkC;CAC1E,OACE,SAAS,OAAO,QAAQ,KACxB,QAAQ,uBAAuB,KAC/B,QAAQ,wBAAwB,KAChC;AAEJ;AAEA,SAAgB,yBAAyB,QAAkC;CACzE,IAAI,OAAO,YAAY,KAAA,KAAa,OAAO,QAAQ,SAAS,GAC1D,OAAO,OAAO,QAAQ,QAAQ,QAAQ,EAAE;CAG1C,MAAM,UAAU,yBAAyB,MAAM;CAC/C,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,oBACR,+HACF;CAGF,MAAM,WAAW,0BAA0B,MAAM;CACjD,IAAI,aAAa,UACf,OAAO,iDAAiD,QAAQ;CAElE,OAAO,WAAW,SAAS,yCAAyC,QAAQ,aAAa,SAAS;AACpG;AAEA,eAAsB,6BACpB,QACiB;CACjB,IAAI,OAAO,mBAAmB,KAAA,GAC5B,OAAO,OAAO,eAAe;CAG/B,IAAI,OAAO,eAAe,KAAA,GAAW;EAEnC,MAAM,iBAAgB,MADA,OAAO,WAAW,kBAAkB,EAAA,CAC5B,IAAI,eAAe;EACjD,IAAI,kBAAkB,QAAQ,CAAC,cAAc,WAAW,SAAS,GAC/D,MAAM,IAAI,oBACR,uFACF;EAEF,OAAO,cAAc,MAAM,CAAgB;CAC7C;CAEA,IAAI;EACF,MAAM,EAAE,eAAe,MAAM,OAAO;EAKpC,MAAM,QAAQ,OAAM,MADC,IAHJ,WAAW,EAC1B,QAAQ,CAAC,gDAAgD,EAC3D,CACqB,CAAA,CAAK,UAAU,EAAA,CACT,eAAe;EAC1C,IAAI,MAAM,UAAU,QAAQ,MAAM,UAAU,KAAA,GAC1C,MAAM,IAAI,oBACR,wFACF;EAEF,OAAO,MAAM;CACf,SAAS,OAAO;EACd,IAAI,iBAAiB,qBACnB,MAAM;EAER,IAAI,2BAA2B,KAAK,GAClC,MAAM,IAAI,oBACR,qIACF;EAEF,MAAM,IAAI,oBACR,0FACA,EAAE,OAAO,MAAM,CACjB;CACF;AACF"}
@@ -0,0 +1,17 @@
1
+ import { ChatStreamSummarizeAdapter, InferTextProviderOptions } from '@tanstack/ai/adapters';
2
+ import { GrokTextAdapter } from '../adapters/text.js';
3
+ import { GrokVertexChatModel, ResolveInputModalities, ResolveProviderOptions } from '../model-meta.js';
4
+ import { GrokVertexConfig } from './auth.js';
5
+ export { GrokVertexAuthError, resolveGrokVertexAccessToken, resolveGrokVertexBaseURL, resolveGrokVertexLocation, resolveGrokVertexProject, toVertexGrokModelId, type GrokVertexConfig, type VertexAuthClient, } from './auth.js';
6
+ export { GROK_VERTEX_CHAT_MODELS, type GrokVertexChatModel, } from '../model-meta.js';
7
+ /**
8
+ * Creates a Grok chat adapter that talks to xAI Grok on Vertex AI.
9
+ *
10
+ * Install `google-auth-library` next to `@tanstack/ai-grok` for Application
11
+ * Default Credentials. Or pass `authClient` or `getAccessToken`.
12
+ */
13
+ export declare function grokVertexText<TModel extends GrokVertexChatModel>(model: TModel, config?: GrokVertexConfig): GrokTextAdapter<TModel, ResolveProviderOptions<TModel>, ResolveInputModalities<TModel>, readonly []>;
14
+ /**
15
+ * Creates a Grok summarize adapter that talks to xAI Grok on Vertex AI.
16
+ */
17
+ export declare function grokVertexSummarize<TModel extends GrokVertexChatModel>(model: TModel, config?: GrokVertexConfig): ChatStreamSummarizeAdapter<TModel, InferTextProviderOptions<GrokTextAdapter<TModel>>>;
@@ -0,0 +1,58 @@
1
+ import { GrokTextAdapter } from "../adapters/text.js";
2
+ import { GROK_VERTEX_CHAT_MODELS } from "../model-meta.js";
3
+ import { GrokVertexAuthError, resolveGrokVertexAccessToken, resolveGrokVertexBaseURL, resolveGrokVertexLocation, resolveGrokVertexProject, toVertexGrokModelId } from "./auth.js";
4
+ import { ChatStreamSummarizeAdapter } from "@tanstack/ai/adapters";
5
+ //#region src/vertex/index.ts
6
+ var VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS = /* @__PURE__ */ new Set([
7
+ "web_search",
8
+ "x_search",
9
+ "file_search",
10
+ "mcp"
11
+ ]);
12
+ var GrokVertexTextAdapter = class extends GrokTextAdapter {
13
+ mapOptionsToRequest(options) {
14
+ const request = super.mapOptionsToRequest(options);
15
+ const tools = request.tools;
16
+ if (tools !== void 0) for (const tool of tools) {
17
+ if (tool === null || typeof tool !== "object" || !("type" in tool)) continue;
18
+ if (VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS.has(String(tool.type))) throw new Error("Grok Vertex does not support xAI server tools (web_search, x_search, file_search, mcp). Use a function tool.");
19
+ }
20
+ return {
21
+ ...request,
22
+ model: toVertexGrokModelId(this.model)
23
+ };
24
+ }
25
+ };
26
+ /**
27
+ * Creates a Grok chat adapter that talks to xAI Grok on Vertex AI.
28
+ *
29
+ * Install `google-auth-library` next to `@tanstack/ai-grok` for Application
30
+ * Default Credentials. Or pass `authClient` or `getAccessToken`.
31
+ */
32
+ function grokVertexText(model, config = {}) {
33
+ return new GrokVertexTextAdapter({
34
+ apiKey: "vertex",
35
+ baseURL: resolveGrokVertexBaseURL(config),
36
+ defaultHeaders: config.defaultHeaders,
37
+ fetch: async (input, init) => {
38
+ const token = await resolveGrokVertexAccessToken(config);
39
+ const headers = new Headers(init?.headers);
40
+ headers.set("Authorization", `Bearer ${token}`);
41
+ if (config.defaultHeaders) for (const [key, value] of Object.entries(config.defaultHeaders)) headers.set(key, value);
42
+ return fetch(input, {
43
+ ...init,
44
+ headers
45
+ });
46
+ }
47
+ }, model);
48
+ }
49
+ /**
50
+ * Creates a Grok summarize adapter that talks to xAI Grok on Vertex AI.
51
+ */
52
+ function grokVertexSummarize(model, config = {}) {
53
+ return new ChatStreamSummarizeAdapter(grokVertexText(model, config), model, "grok");
54
+ }
55
+ //#endregion
56
+ export { GROK_VERTEX_CHAT_MODELS, GrokVertexAuthError, grokVertexSummarize, grokVertexText, resolveGrokVertexAccessToken, resolveGrokVertexBaseURL, resolveGrokVertexLocation, resolveGrokVertexProject, toVertexGrokModelId };
57
+
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/vertex/index.ts"],"sourcesContent":["import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'\nimport { GrokTextAdapter } from '../adapters/text'\nimport {\n resolveGrokVertexAccessToken,\n resolveGrokVertexBaseURL,\n toVertexGrokModelId,\n} from './auth'\nimport type { TextOptions } from '@tanstack/ai'\nimport type { InferTextProviderOptions } from '@tanstack/ai/adapters'\nimport type { ResponseCreateParams } from 'openai/resources/responses/responses'\nimport type {\n GrokVertexChatModel,\n ResolveInputModalities,\n ResolveProviderOptions,\n} from '../model-meta'\nimport type { GrokVertexConfig } from './auth'\n\nexport {\n GrokVertexAuthError,\n resolveGrokVertexAccessToken,\n resolveGrokVertexBaseURL,\n resolveGrokVertexLocation,\n resolveGrokVertexProject,\n toVertexGrokModelId,\n type GrokVertexConfig,\n type VertexAuthClient,\n} from './auth'\nexport {\n GROK_VERTEX_CHAT_MODELS,\n type GrokVertexChatModel,\n} from '../model-meta'\n\nconst VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS = new Set([\n 'web_search',\n 'x_search',\n 'file_search',\n 'mcp',\n])\n\nclass GrokVertexTextAdapter<\n TModel extends GrokVertexChatModel,\n> extends GrokTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>,\n readonly []\n> {\n protected override mapOptionsToRequest(\n options: TextOptions<ResolveProviderOptions<TModel>>,\n ): Omit<ResponseCreateParams, 'stream'> {\n const request = super.mapOptionsToRequest(options)\n const tools = request.tools\n if (tools !== undefined) {\n for (const tool of tools) {\n if (tool === null || typeof tool !== 'object' || !('type' in tool)) {\n continue\n }\n if (VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS.has(String(tool.type))) {\n throw new Error(\n 'Grok Vertex does not support xAI server tools (web_search, x_search, file_search, mcp). Use a function tool.',\n )\n }\n }\n }\n return {\n ...request,\n model: toVertexGrokModelId(this.model),\n }\n }\n}\n\n/**\n * Creates a Grok chat adapter that talks to xAI Grok on Vertex AI.\n *\n * Install `google-auth-library` next to `@tanstack/ai-grok` for Application\n * Default Credentials. Or pass `authClient` or `getAccessToken`.\n */\nexport function grokVertexText<TModel extends GrokVertexChatModel>(\n model: TModel,\n config: GrokVertexConfig = {},\n): GrokTextAdapter<\n TModel,\n ResolveProviderOptions<TModel>,\n ResolveInputModalities<TModel>,\n readonly []\n> {\n const baseURL = resolveGrokVertexBaseURL(config)\n\n return new GrokVertexTextAdapter(\n {\n apiKey: 'vertex',\n baseURL,\n defaultHeaders: config.defaultHeaders,\n fetch: async (input, init) => {\n const token = await resolveGrokVertexAccessToken(config)\n const headers = new Headers(init?.headers)\n headers.set('Authorization', `Bearer ${token}`)\n if (config.defaultHeaders) {\n for (const [key, value] of Object.entries(config.defaultHeaders)) {\n headers.set(key, value)\n }\n }\n return fetch(input, { ...init, headers })\n },\n },\n model,\n )\n}\n\n/**\n * Creates a Grok summarize adapter that talks to xAI Grok on Vertex AI.\n */\nexport function grokVertexSummarize<TModel extends GrokVertexChatModel>(\n model: TModel,\n config: GrokVertexConfig = {},\n): ChatStreamSummarizeAdapter<\n TModel,\n InferTextProviderOptions<GrokTextAdapter<TModel>>\n> {\n return new ChatStreamSummarizeAdapter(\n grokVertexText(model, config),\n model,\n 'grok',\n )\n}\n"],"mappings":";;;;;AAgCA,IAAM,uDAAuC,IAAI,IAAI;CACnD;CACA;CACA;CACA;AACF,CAAC;AAED,IAAM,wBAAN,cAEU,gBAKR;CACA,oBACE,SACsC;EACtC,MAAM,UAAU,MAAM,oBAAoB,OAAO;EACjD,MAAM,QAAQ,QAAQ;EACtB,IAAI,UAAU,KAAA,GACZ,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAC3D;GAEF,IAAI,qCAAqC,IAAI,OAAO,KAAK,IAAI,CAAC,GAC5D,MAAM,IAAI,MACR,8GACF;EAEJ;EAEF,OAAO;GACL,GAAG;GACH,OAAO,oBAAoB,KAAK,KAAK;EACvC;CACF;AACF;;;;;;;AAQA,SAAgB,eACd,OACA,SAA2B,CAAC,GAM5B;CAGA,OAAO,IAAI,sBACT;EACE,QAAQ;EACR,SALY,yBAAyB,MAKrC;EACA,gBAAgB,OAAO;EACvB,OAAO,OAAO,OAAO,SAAS;GAC5B,MAAM,QAAQ,MAAM,6BAA6B,MAAM;GACvD,MAAM,UAAU,IAAI,QAAQ,MAAM,OAAO;GACzC,QAAQ,IAAI,iBAAiB,UAAU,OAAO;GAC9C,IAAI,OAAO,gBACT,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,cAAc,GAC7D,QAAQ,IAAI,KAAK,KAAK;GAG1B,OAAO,MAAM,OAAO;IAAE,GAAG;IAAM;GAAQ,CAAC;EAC1C;CACF,GACA,KACF;AACF;;;;AAKA,SAAgB,oBACd,OACA,SAA2B,CAAC,GAI5B;CACA,OAAO,IAAI,2BACT,eAAe,OAAO,MAAM,GAC5B,OACA,MACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/ai-grok",
3
- "version": "0.16.2",
3
+ "version": "0.17.1",
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",
@@ -28,6 +28,10 @@
28
28
  "./tools": {
29
29
  "types": "./dist/esm/tools/index.d.ts",
30
30
  "import": "./dist/esm/tools/index.js"
31
+ },
32
+ "./vertex": {
33
+ "types": "./dist/esm/vertex/index.d.ts",
34
+ "import": "./dist/esm/vertex/index.js"
31
35
  }
32
36
  },
33
37
  "files": [
@@ -51,16 +55,23 @@
51
55
  "dependencies": {
52
56
  "openai": "^6.41.0",
53
57
  "@tanstack/ai-utils": "^0.4.0",
54
- "@tanstack/openai-base": "^0.10.0"
58
+ "@tanstack/openai-base": "^0.10.3"
55
59
  },
56
60
  "devDependencies": {
57
61
  "@vitest/coverage-v8": "4.1.10",
62
+ "google-auth-library": "^10.5.0",
58
63
  "vite": "^8.2.1",
59
- "@tanstack/ai": "0.47.1"
64
+ "@tanstack/ai": "0.48.0"
60
65
  },
61
66
  "peerDependencies": {
67
+ "google-auth-library": "^10.5.0",
62
68
  "zod": "^4.0.0",
63
- "@tanstack/ai": "^0.47.1"
69
+ "@tanstack/ai": "^0.48.0"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "google-auth-library": {
73
+ "optional": true
74
+ }
64
75
  },
65
76
  "scripts": {
66
77
  "build": "vite build",
@@ -5,6 +5,7 @@ import { convertToolsToProviderFormat } from '../tools'
5
5
  import type {
6
6
  GROK_CHAT_MODELS,
7
7
  GrokChatModelToolCapabilitiesByName,
8
+ GrokTextAdapterModel,
8
9
  ResolveInputModalities,
9
10
  ResolveProviderOptions,
10
11
  } from '../model-meta'
@@ -42,7 +43,7 @@ export type { ExternalTextProviderOptions as GrokTextProviderOptions } from '../
42
43
  * typing through the 5th generic of the base class.
43
44
  */
44
45
  export class GrokTextAdapter<
45
- TModel extends (typeof GROK_CHAT_MODELS)[number],
46
+ TModel extends GrokTextAdapterModel,
46
47
  // Use `Record<string, any>` (not `unknown`) to match the OpenAI text
47
48
  // adapter: the resolved Grok provider options are a type-alias intersection
48
49
  // with no explicit index signature, which is assignable to
@@ -147,18 +147,13 @@ export class GrokVideoAdapter<
147
147
  this.clientConfig = withGrokDefaults(config)
148
148
  }
149
149
 
150
- private get fetch(): (
151
- input: string,
152
- init?: RequestInit,
153
- ) => Promise<Response> {
154
- return this.clientConfig.fetch ?? fetch
155
- }
156
-
157
150
  private async request(
158
151
  path: string,
159
152
  init?: Omit<RequestInit, 'headers'>,
160
153
  ): Promise<Response> {
161
- return await this.fetch(`${this.clientConfig.baseURL}${path}`, {
154
+ // workerd's fetch must be invoked with this === globalThis
155
+ const fetchFn = this.clientConfig.fetch ?? globalThis.fetch.bind(globalThis)
156
+ return await fetchFn(`${this.clientConfig.baseURL}${path}`, {
162
157
  ...init,
163
158
  headers: {
164
159
  'Content-Type': 'application/json',
package/src/index.ts CHANGED
@@ -94,6 +94,7 @@ export type {
94
94
  ResolveProviderOptions,
95
95
  ResolveInputModalities,
96
96
  GrokChatModel,
97
+ GrokVertexChatModel,
97
98
  GrokImageModel,
98
99
  GrokVideoModel,
99
100
  GrokTTSModel,
@@ -102,6 +103,7 @@ export type {
102
103
  } from './model-meta'
103
104
  export {
104
105
  GROK_CHAT_MODELS,
106
+ GROK_VERTEX_CHAT_MODELS,
105
107
  GROK_IMAGE_MODELS,
106
108
  GROK_VIDEO_MODELS,
107
109
  GROK_TTS_MODELS,
package/src/model-meta.ts CHANGED
@@ -233,8 +233,54 @@ const GROK_BUILD_0_1 = {
233
233
  },
234
234
  } as const satisfies ModelMeta
235
235
 
236
+ // Vertex Model Garden IDs. These are not the xAI API catalog.
237
+ // Source: https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/partner-models/grok
238
+ const GROK_4_20_REASONING = {
239
+ name: 'grok-4.20-reasoning',
240
+ context_window: 1_000_000,
241
+ supports: {
242
+ input: ['text', 'image'],
243
+ output: ['text'],
244
+ capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],
245
+ tools: [] as const,
246
+ },
247
+ } as const satisfies ModelMeta
248
+
249
+ const GROK_4_20_NON_REASONING = {
250
+ name: 'grok-4.20-non-reasoning',
251
+ context_window: 1_000_000,
252
+ supports: {
253
+ input: ['text', 'image'],
254
+ output: ['text'],
255
+ capabilities: ['structured_outputs', 'tool_calling'],
256
+ tools: [] as const,
257
+ },
258
+ } as const satisfies ModelMeta
259
+
260
+ const GROK_4_1_FAST_REASONING = {
261
+ name: 'grok-4.1-fast-reasoning',
262
+ context_window: 2_000_000,
263
+ supports: {
264
+ input: ['text', 'image'],
265
+ output: ['text'],
266
+ capabilities: ['reasoning', 'structured_outputs', 'tool_calling'],
267
+ tools: [] as const,
268
+ },
269
+ } as const satisfies ModelMeta
270
+
271
+ const GROK_4_1_FAST_NON_REASONING = {
272
+ name: 'grok-4.1-fast-non-reasoning',
273
+ context_window: 2_000_000,
274
+ supports: {
275
+ input: ['text', 'image'],
276
+ output: ['text'],
277
+ capabilities: ['structured_outputs', 'tool_calling'],
278
+ tools: [] as const,
279
+ },
280
+ } as const satisfies ModelMeta
281
+
236
282
  /**
237
- * Grok chat models supported by the Responses adapter.
283
+ * Grok chat models supported by the xAI Responses adapter.
238
284
  */
239
285
  export const GROK_CHAT_MODELS = [
240
286
  GROK_4_5.name,
@@ -243,6 +289,18 @@ export const GROK_CHAT_MODELS = [
243
289
  GROK_4_3.name,
244
290
  ] as const
245
291
 
292
+ /**
293
+ * Grok chat models on Vertex AI / Gemini Enterprise Agent Platform.
294
+ * This list is the Google partner catalog, not the xAI API catalog.
295
+ */
296
+ export const GROK_VERTEX_CHAT_MODELS = [
297
+ GROK_4_3.name,
298
+ GROK_4_20_REASONING.name,
299
+ GROK_4_20_NON_REASONING.name,
300
+ GROK_4_1_FAST_REASONING.name,
301
+ GROK_4_1_FAST_NON_REASONING.name,
302
+ ] as const
303
+
246
304
  /**
247
305
  * Grok Image Generation Models
248
306
  */
@@ -349,6 +407,8 @@ export const GROK_DEFAULT_REALTIME_MODEL: GrokRealtimeModel =
349
407
  'grok-voice-think-fast-2.0'
350
408
 
351
409
  export type GrokChatModel = (typeof GROK_CHAT_MODELS)[number]
410
+ export type GrokVertexChatModel = (typeof GROK_VERTEX_CHAT_MODELS)[number]
411
+ export type GrokTextAdapterModel = GrokChatModel | GrokVertexChatModel
352
412
  export type GrokImageModel = (typeof GROK_IMAGE_MODELS)[number]
353
413
  export type GrokVideoModel = (typeof GROK_VIDEO_MODELS)[number]
354
414
  export type GrokTTSModel = (typeof GROK_TTS_MODELS)[number]
@@ -364,6 +424,10 @@ export type GrokModelInputModalitiesByName = {
364
424
  [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.input
365
425
  [GROK_4_5.name]: typeof GROK_4_5.supports.input
366
426
  [GROK_4_6.name]: typeof GROK_4_6.supports.input
427
+ [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.input
428
+ [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.input
429
+ [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.input
430
+ [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.supports.input
367
431
  }
368
432
 
369
433
  /**
@@ -374,6 +438,10 @@ export type GrokModelInputModalitiesByName = {
374
438
  export type GrokChatModelToolCapabilitiesByName = {
375
439
  [GROK_4_3.name]: typeof GROK_4_3.supports.tools
376
440
  [GROK_BUILD_0_1.name]: typeof GROK_BUILD_0_1.supports.tools
441
+ [GROK_4_20_REASONING.name]: typeof GROK_4_20_REASONING.supports.tools
442
+ [GROK_4_20_NON_REASONING.name]: typeof GROK_4_20_NON_REASONING.supports.tools
443
+ [GROK_4_1_FAST_REASONING.name]: typeof GROK_4_1_FAST_REASONING.supports.tools
444
+ [GROK_4_1_FAST_NON_REASONING.name]: typeof GROK_4_1_FAST_NON_REASONING.supports.tools
377
445
  }
378
446
 
379
447
  export type GrokProviderOptions = GrokTextProviderOptions
@@ -384,6 +452,10 @@ export type GrokProviderOptions = GrokTextProviderOptions
384
452
  export type GrokChatModelProviderOptionsByName = {
385
453
  [GROK_4_3.name]: GrokProviderOptions
386
454
  [GROK_BUILD_0_1.name]: GrokBuildProviderOptions
455
+ [GROK_4_20_REASONING.name]: GrokProviderOptions
456
+ [GROK_4_20_NON_REASONING.name]: GrokProviderOptions
457
+ [GROK_4_1_FAST_REASONING.name]: GrokProviderOptions
458
+ [GROK_4_1_FAST_NON_REASONING.name]: GrokProviderOptions
387
459
  }
388
460
 
389
461
  // ===========================
@@ -0,0 +1,144 @@
1
+ export class GrokVertexAuthError extends Error {
2
+ constructor(message: string, options?: ErrorOptions) {
3
+ super(message, options)
4
+ this.name = 'GrokVertexAuthError'
5
+ }
6
+ }
7
+
8
+ function isMissingGoogleAuthLibrary(error: unknown): boolean {
9
+ if (!(error instanceof Error) || !('code' in error)) {
10
+ return false
11
+ }
12
+ const code = error.code
13
+ if (code !== 'ERR_MODULE_NOT_FOUND' && code !== 'MODULE_NOT_FOUND') {
14
+ return false
15
+ }
16
+ return error.message.includes('google-auth-library')
17
+ }
18
+
19
+ export type VertexAuthClient = {
20
+ getRequestHeaders: (url?: string | URL) => Promise<Headers>
21
+ }
22
+
23
+ /**
24
+ * Public Vertex config for Grok. `project` and `location` match the Gemini
25
+ * Vertex factories so one auth object works for both.
26
+ *
27
+ * Default location is `global`. Grok on Vertex uses the OpenAI-compatible
28
+ * Responses endpoint under `/endpoints/openapi`.
29
+ */
30
+ export type GrokVertexConfig = {
31
+ project?: string
32
+ location?: string
33
+ /** Override the OpenAI-compatible Vertex base URL. Used by e2e. */
34
+ baseURL?: string
35
+ getAccessToken?: () => Promise<string>
36
+ authClient?: VertexAuthClient
37
+ defaultHeaders?: Record<string, string>
38
+ }
39
+
40
+ function nonEmpty(value: string | undefined): string | undefined {
41
+ if (value === undefined || value.length === 0) {
42
+ return undefined
43
+ }
44
+ return value
45
+ }
46
+
47
+ function readEnv(name: string): string | undefined {
48
+ if (typeof process === 'undefined' || process.env === undefined) {
49
+ return undefined
50
+ }
51
+ return nonEmpty(process.env[name])
52
+ }
53
+
54
+ export function toVertexGrokModelId(model: string): string {
55
+ if (model.startsWith('xai/')) {
56
+ return model
57
+ }
58
+ return `xai/${model}`
59
+ }
60
+
61
+ export function resolveGrokVertexProject(
62
+ config: GrokVertexConfig,
63
+ ): string | undefined {
64
+ return (
65
+ nonEmpty(config.project) ??
66
+ readEnv('GOOGLE_CLOUD_PROJECT') ??
67
+ readEnv('GOOGLE_VERTEX_PROJECT')
68
+ )
69
+ }
70
+
71
+ export function resolveGrokVertexLocation(config: GrokVertexConfig): string {
72
+ return (
73
+ nonEmpty(config.location) ??
74
+ readEnv('GOOGLE_CLOUD_LOCATION') ??
75
+ readEnv('GOOGLE_VERTEX_LOCATION') ??
76
+ 'global'
77
+ )
78
+ }
79
+
80
+ export function resolveGrokVertexBaseURL(config: GrokVertexConfig): string {
81
+ if (config.baseURL !== undefined && config.baseURL.length > 0) {
82
+ return config.baseURL.replace(/\/+$/, '')
83
+ }
84
+
85
+ const project = resolveGrokVertexProject(config)
86
+ if (project === undefined) {
87
+ throw new GrokVertexAuthError(
88
+ 'Grok Vertex needs a project, or a baseURL. Pass project on the factory, or set GOOGLE_CLOUD_PROJECT or GOOGLE_VERTEX_PROJECT.',
89
+ )
90
+ }
91
+
92
+ const location = resolveGrokVertexLocation(config)
93
+ if (location === 'global') {
94
+ return `https://aiplatform.googleapis.com/v1/projects/${project}/locations/global/endpoints/openapi`
95
+ }
96
+ return `https://${location}-aiplatform.googleapis.com/v1/projects/${project}/locations/${location}/endpoints/openapi`
97
+ }
98
+
99
+ export async function resolveGrokVertexAccessToken(
100
+ config: GrokVertexConfig,
101
+ ): Promise<string> {
102
+ if (config.getAccessToken !== undefined) {
103
+ return config.getAccessToken()
104
+ }
105
+
106
+ if (config.authClient !== undefined) {
107
+ const headers = await config.authClient.getRequestHeaders()
108
+ const authorization = headers.get('Authorization')
109
+ if (authorization === null || !authorization.startsWith('Bearer ')) {
110
+ throw new GrokVertexAuthError(
111
+ 'Grok Vertex authClient.getRequestHeaders() must return an Authorization Bearer token.',
112
+ )
113
+ }
114
+ return authorization.slice('Bearer '.length)
115
+ }
116
+
117
+ try {
118
+ const { GoogleAuth } = await import('google-auth-library')
119
+ const auth = new GoogleAuth({
120
+ scopes: ['https://www.googleapis.com/auth/cloud-platform'],
121
+ })
122
+ const client = await auth.getClient()
123
+ const token = await client.getAccessToken()
124
+ if (token.token === null || token.token === undefined) {
125
+ throw new GrokVertexAuthError(
126
+ 'Grok Vertex could not load a Google access token from Application Default Credentials.',
127
+ )
128
+ }
129
+ return token.token
130
+ } catch (error) {
131
+ if (error instanceof GrokVertexAuthError) {
132
+ throw error
133
+ }
134
+ if (isMissingGoogleAuthLibrary(error)) {
135
+ throw new GrokVertexAuthError(
136
+ 'Grok Vertex needs google-auth-library, or pass authClient or getAccessToken. Install google-auth-library next to @tanstack/ai-grok.',
137
+ )
138
+ }
139
+ throw new GrokVertexAuthError(
140
+ 'Grok Vertex could not load a Google access token from Application Default Credentials.',
141
+ { cause: error },
142
+ )
143
+ }
144
+ }
@@ -0,0 +1,125 @@
1
+ import { ChatStreamSummarizeAdapter } from '@tanstack/ai/adapters'
2
+ import { GrokTextAdapter } from '../adapters/text'
3
+ import {
4
+ resolveGrokVertexAccessToken,
5
+ resolveGrokVertexBaseURL,
6
+ toVertexGrokModelId,
7
+ } from './auth'
8
+ import type { TextOptions } from '@tanstack/ai'
9
+ import type { InferTextProviderOptions } from '@tanstack/ai/adapters'
10
+ import type { ResponseCreateParams } from 'openai/resources/responses/responses'
11
+ import type {
12
+ GrokVertexChatModel,
13
+ ResolveInputModalities,
14
+ ResolveProviderOptions,
15
+ } from '../model-meta'
16
+ import type { GrokVertexConfig } from './auth'
17
+
18
+ export {
19
+ GrokVertexAuthError,
20
+ resolveGrokVertexAccessToken,
21
+ resolveGrokVertexBaseURL,
22
+ resolveGrokVertexLocation,
23
+ resolveGrokVertexProject,
24
+ toVertexGrokModelId,
25
+ type GrokVertexConfig,
26
+ type VertexAuthClient,
27
+ } from './auth'
28
+ export {
29
+ GROK_VERTEX_CHAT_MODELS,
30
+ type GrokVertexChatModel,
31
+ } from '../model-meta'
32
+
33
+ const VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS = new Set([
34
+ 'web_search',
35
+ 'x_search',
36
+ 'file_search',
37
+ 'mcp',
38
+ ])
39
+
40
+ class GrokVertexTextAdapter<
41
+ TModel extends GrokVertexChatModel,
42
+ > extends GrokTextAdapter<
43
+ TModel,
44
+ ResolveProviderOptions<TModel>,
45
+ ResolveInputModalities<TModel>,
46
+ readonly []
47
+ > {
48
+ protected override mapOptionsToRequest(
49
+ options: TextOptions<ResolveProviderOptions<TModel>>,
50
+ ): Omit<ResponseCreateParams, 'stream'> {
51
+ const request = super.mapOptionsToRequest(options)
52
+ const tools = request.tools
53
+ if (tools !== undefined) {
54
+ for (const tool of tools) {
55
+ if (tool === null || typeof tool !== 'object' || !('type' in tool)) {
56
+ continue
57
+ }
58
+ if (VERTEX_UNSUPPORTED_GROK_SERVER_TOOLS.has(String(tool.type))) {
59
+ throw new Error(
60
+ 'Grok Vertex does not support xAI server tools (web_search, x_search, file_search, mcp). Use a function tool.',
61
+ )
62
+ }
63
+ }
64
+ }
65
+ return {
66
+ ...request,
67
+ model: toVertexGrokModelId(this.model),
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Creates a Grok chat adapter that talks to xAI Grok on Vertex AI.
74
+ *
75
+ * Install `google-auth-library` next to `@tanstack/ai-grok` for Application
76
+ * Default Credentials. Or pass `authClient` or `getAccessToken`.
77
+ */
78
+ export function grokVertexText<TModel extends GrokVertexChatModel>(
79
+ model: TModel,
80
+ config: GrokVertexConfig = {},
81
+ ): GrokTextAdapter<
82
+ TModel,
83
+ ResolveProviderOptions<TModel>,
84
+ ResolveInputModalities<TModel>,
85
+ readonly []
86
+ > {
87
+ const baseURL = resolveGrokVertexBaseURL(config)
88
+
89
+ return new GrokVertexTextAdapter(
90
+ {
91
+ apiKey: 'vertex',
92
+ baseURL,
93
+ defaultHeaders: config.defaultHeaders,
94
+ fetch: async (input, init) => {
95
+ const token = await resolveGrokVertexAccessToken(config)
96
+ const headers = new Headers(init?.headers)
97
+ headers.set('Authorization', `Bearer ${token}`)
98
+ if (config.defaultHeaders) {
99
+ for (const [key, value] of Object.entries(config.defaultHeaders)) {
100
+ headers.set(key, value)
101
+ }
102
+ }
103
+ return fetch(input, { ...init, headers })
104
+ },
105
+ },
106
+ model,
107
+ )
108
+ }
109
+
110
+ /**
111
+ * Creates a Grok summarize adapter that talks to xAI Grok on Vertex AI.
112
+ */
113
+ export function grokVertexSummarize<TModel extends GrokVertexChatModel>(
114
+ model: TModel,
115
+ config: GrokVertexConfig = {},
116
+ ): ChatStreamSummarizeAdapter<
117
+ TModel,
118
+ InferTextProviderOptions<GrokTextAdapter<TModel>>
119
+ > {
120
+ return new ChatStreamSummarizeAdapter(
121
+ grokVertexText(model, config),
122
+ model,
123
+ 'grok',
124
+ )
125
+ }