@ai-sdk/xai 4.0.53 → 4.0.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/01-xai.mdx CHANGED
@@ -641,27 +641,37 @@ import { xai } from '@ai-sdk/xai';
641
641
  import {
642
642
  experimental_getBatchResults as getBatchResults,
643
643
  experimental_getBatchStatus as getBatchStatus,
644
- experimental_startTextBatch as startTextBatch,
644
+ experimental_startBatch as startBatch,
645
645
  } from 'ai';
646
646
  import { setTimeout } from 'node:timers/promises';
647
647
 
648
- const model = xai('grok-4.3');
648
+ const model = 'grok-4.3';
649
649
 
650
- const batch = await startTextBatch({
651
- model,
650
+ const batch = await startBatch({
651
+ provider: xai,
652
652
  requests: [
653
- { id: 'capital-france', prompt: 'What is the capital of France?' },
654
- { id: 'capital-germany', prompt: 'What is the capital of Germany?' },
653
+ {
654
+ id: 'capital-france',
655
+ type: 'text',
656
+ model,
657
+ prompt: 'What is the capital of France?',
658
+ },
659
+ {
660
+ id: 'capital-germany',
661
+ type: 'text',
662
+ model: 'grok-4.20-non-reasoning',
663
+ prompt: 'What is the capital of Germany?',
664
+ },
655
665
  ],
656
666
  });
657
667
 
658
668
  let status = batch.status;
659
669
  while (status === 'pending') {
660
670
  await setTimeout(60_000);
661
- ({ status } = await getBatchStatus({ model, batch }));
671
+ ({ status } = await getBatchStatus({ provider: xai, batch }));
662
672
  }
663
673
 
664
- for await (const item of getBatchResults({ model, batch })) {
674
+ for await (const item of getBatchResults({ provider: xai, batch })) {
665
675
  if (item.status === 'succeeded') {
666
676
  console.log(item.id, item.text);
667
677
  } else {
@@ -670,14 +680,13 @@ for await (const item of getBatchResults({ model, batch })) {
670
680
  }
671
681
  ```
672
682
 
673
- `startTextBatch` returns a serializable batch reference. Persist this reference
683
+ `startBatch` returns a serializable batch reference. Persist this reference
674
684
  to check the batch status or retrieve its results from another process. Results
675
685
  can arrive in a different order from the input requests, so match each result by
676
686
  its `id`.
677
687
 
678
- Text batches are available through `xai(modelId)` and
679
- `xai.responses(modelId)`. The legacy `xai.chat(modelId)` models do not expose
680
- the batch APIs.
688
+ Each request specifies its `type` and `model`. xAI supports using different
689
+ text models within the same batch.
681
690
 
682
691
  <Note>
683
692
  The xAI Batch API does not support per-batch webhooks. When you provide a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/xai",
3
- "version": "4.0.53",
3
+ "version": "4.0.55",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -29,8 +29,8 @@
29
29
  }
30
30
  },
31
31
  "dependencies": {
32
- "@ai-sdk/provider": "4.0.10",
33
- "@ai-sdk/provider-utils": "5.0.36"
32
+ "@ai-sdk/provider": "4.0.11",
33
+ "@ai-sdk/provider-utils": "5.0.37"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@ai-sdk/test-server": "2.0.1",
@@ -139,6 +139,15 @@ function isRetryableStatusCode(statusCode: number): boolean {
139
139
  );
140
140
  }
141
141
 
142
+ export const xaiResponsesSupportedUrls: Record<string, RegExp[]> = {
143
+ 'image/*': [/^https?:\/\/.*$/],
144
+ // xAI's Responses API accepts non-image documents (PDF, plain text, CSV, etc.) as
145
+ // `{ type: 'input_file', file_url }`. Keeping these URLs intact here lets them pass
146
+ // through to the converter instead of being downloaded to bytes by the SDK.
147
+ 'application/pdf': [/^https?:\/\/.*$/],
148
+ 'text/*': [/^https?:\/\/.*$/],
149
+ };
150
+
142
151
  export class XaiResponsesLanguageModel implements LanguageModelV4 {
143
152
  readonly specificationVersion = 'v4';
144
153
 
@@ -169,31 +178,30 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
169
178
  return this.config.provider;
170
179
  }
171
180
 
172
- readonly supportedUrls: Record<string, RegExp[]> = {
173
- 'image/*': [/^https?:\/\/.*$/],
174
- // xAI's Responses API accepts non-image documents (PDF, plain text, CSV, etc.) as
175
- // `{ type: 'input_file', file_url }`. Keeping these URLs intact here lets them pass
176
- // through to the converter instead of being downloaded to bytes by the SDK.
177
- 'application/pdf': [/^https?:\/\/.*$/],
178
- 'text/*': [/^https?:\/\/.*$/],
179
- };
180
-
181
- protected async getArgs({
182
- prompt,
183
- maxOutputTokens,
184
- temperature,
185
- topP,
186
- topK,
187
- frequencyPenalty,
188
- presencePenalty,
189
- stopSequences,
190
- seed,
191
- responseFormat,
192
- providerOptions,
193
- tools,
194
- toolChoice,
195
- reasoning,
196
- }: LanguageModelV4CallOptions) {
181
+ readonly supportedUrls = xaiResponsesSupportedUrls;
182
+
183
+ static async prepareRequest({
184
+ modelId,
185
+ options: {
186
+ prompt,
187
+ maxOutputTokens,
188
+ temperature,
189
+ topP,
190
+ topK,
191
+ frequencyPenalty,
192
+ presencePenalty,
193
+ stopSequences,
194
+ seed,
195
+ responseFormat,
196
+ providerOptions,
197
+ tools,
198
+ toolChoice,
199
+ reasoning,
200
+ },
201
+ }: {
202
+ modelId: XaiResponsesModelId;
203
+ options: LanguageModelV4CallOptions;
204
+ }) {
197
205
  const warnings: SharedV4Warning[] = [];
198
206
 
199
207
  const options =
@@ -276,7 +284,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
276
284
 
277
285
  let resolvedReasoningEffort = options.reasoningEffort;
278
286
  if (resolvedReasoningEffort == null && isCustomReasoning(reasoning)) {
279
- if (!supportsReasoningEffort(this.modelId)) {
287
+ if (!supportsReasoningEffort(modelId)) {
280
288
  warnings.push({
281
289
  type: 'unsupported',
282
290
  feature: 'reasoning',
@@ -292,7 +300,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
292
300
  low: 'low',
293
301
  medium: 'medium',
294
302
  high: 'high',
295
- xhigh: this.modelId === 'grok-4.6' ? 'xhigh' : 'high',
303
+ xhigh: modelId === 'grok-4.6' ? 'xhigh' : 'high',
296
304
  },
297
305
  warnings,
298
306
  });
@@ -300,7 +308,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
300
308
  }
301
309
 
302
310
  const baseArgs: Record<string, unknown> = {
303
- model: this.modelId,
311
+ model: modelId,
304
312
  input,
305
313
  logprobs:
306
314
  options.logprobs === true || options.topLogprobs != null
@@ -370,6 +378,13 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
370
378
  };
371
379
  }
372
380
 
381
+ private getArgs(options: LanguageModelV4CallOptions) {
382
+ return XaiResponsesLanguageModel.prepareRequest({
383
+ modelId: this.modelId,
384
+ options,
385
+ });
386
+ }
387
+
373
388
  async doGenerate(
374
389
  options: LanguageModelV4CallOptions,
375
390
  ): Promise<LanguageModelV4GenerateResult> {
@@ -1,12 +1,14 @@
1
1
  import {
2
2
  InvalidArgumentError,
3
- type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
3
+ type Experimental_BatchV4 as BatchV4,
4
4
  type Experimental_BatchV4Error as BatchV4Error,
5
5
  type Experimental_BatchV4ItemResult as BatchV4ItemResult,
6
6
  type Experimental_BatchV4OperationOptions as BatchV4OperationOptions,
7
- type Experimental_BatchV4StartOptions as BatchV4StartOptions,
8
7
  type Experimental_BatchV4StartResult as BatchV4StartResult,
9
8
  type Experimental_BatchV4Status as BatchV4Status,
9
+ type Experimental_TextBatchV4Request as TextBatchV4Request,
10
+ type Experimental_TextBatchV4ItemResult as TextBatchV4ItemResult,
11
+ type Experimental_BatchV4StartOptions as BatchV4StartOptions,
10
12
  type LanguageModelV4Content,
11
13
  type LanguageModelV4GenerateResult,
12
14
  type SharedV4ProviderMetadata,
@@ -20,37 +22,54 @@ import {
20
22
  getFromApi,
21
23
  lazySchema,
22
24
  normalizeBatchRequestCounts,
25
+ parseProviderOptions,
23
26
  postFormDataToApi,
24
27
  postJsonToApi,
25
28
  safeValidateTypes,
26
- WORKFLOW_DESERIALIZE,
27
- WORKFLOW_SERIALIZE,
28
29
  zodSchema,
29
30
  type InferSchema,
30
31
  } from '@ai-sdk/provider-utils';
31
32
  import { z } from 'zod/v4';
32
- import { convertXaiChatUsage } from '../convert-xai-chat-usage';
33
- import { getResponseMetadata } from '../get-response-metadata';
34
- import { mapXaiFinishReason } from '../map-xai-finish-reason';
33
+ import { convertXaiChatUsage } from './convert-xai-chat-usage';
34
+ import { getResponseMetadata } from './get-response-metadata';
35
+ import { mapXaiFinishReason } from './map-xai-finish-reason';
35
36
  import {
36
37
  xaiChatResponseSchema,
37
38
  type XaiChatResponse,
38
- } from '../xai-chat-language-model';
39
- import { xaiFailedResponseHandler } from '../xai-error';
40
- import { xaiFilesResponseSchema } from '../files/xai-files-api';
39
+ } from './xai-chat-language-model';
40
+ import { xaiFailedResponseHandler } from './xai-error';
41
+ import { xaiFilesResponseSchema } from './files/xai-files-api';
41
42
  import {
42
43
  XaiResponsesLanguageModel,
44
+ xaiResponsesSupportedUrls,
43
45
  type XaiResponsesConfig,
44
- } from './xai-responses-language-model';
45
- import type { XaiResponsesModelId } from './xai-responses-language-model-options';
46
+ } from './responses/xai-responses-language-model';
47
+ import type { XaiResponsesModelId } from './responses/xai-responses-language-model-options';
46
48
 
47
49
  const xaiBatchEndpoint = '/v1/responses';
48
50
  const xaiBatchName = 'ai-sdk-text-batch';
49
51
  const xaiBatchResultsPageSize = 1000;
50
52
 
51
- type XaiBatchRequest = Parameters<
52
- BatchLanguageModelV4['experimental_doStartBatch']
53
- >[0]['requests'][number];
53
+ const xaiBatchProviderOptionsSchema = lazySchema(() =>
54
+ zodSchema(
55
+ z.object({
56
+ /**
57
+ * TTL in seconds for the uploaded batch input file, measured from
58
+ * upload time. xAI accepts integers between 3600 (1 hour) and
59
+ * 2592000 (30 days) inclusive. Without it the file has no expiry.
60
+ */
61
+ inputFileExpiresAfter: z
62
+ .number()
63
+ .int()
64
+ .min(3600)
65
+ .max(2_592_000)
66
+ .optional(),
67
+ }),
68
+ ),
69
+ );
70
+
71
+ type XaiBatchModelIds = { readonly text: XaiResponsesModelId };
72
+ type XaiBatchRequest = TextBatchV4Request<XaiResponsesModelId>;
54
73
 
55
74
  type XaiBatchPreparedRequest = {
56
75
  body: unknown;
@@ -116,18 +135,22 @@ const xaiBatchResultsPageSchema = lazySchema(() =>
116
135
  ),
117
136
  );
118
137
 
119
- class XaiResponsesBatch {
138
+ export class XaiBatch implements BatchV4<XaiBatchModelIds> {
139
+ readonly specificationVersion = 'v4' as const;
140
+ readonly provider: string;
141
+ readonly supportedUrls = xaiResponsesSupportedUrls;
142
+
120
143
  constructor(
121
144
  private readonly options: {
145
+ provider: string;
122
146
  config: XaiResponsesConfig;
123
- prepareRequest: (
124
- request: XaiBatchRequest,
125
- ) => PromiseLike<XaiBatchPreparedRequest>;
126
147
  },
127
- ) {}
148
+ ) {
149
+ this.provider = options.provider;
150
+ }
128
151
 
129
- async startBatch(
130
- options: BatchV4StartOptions<XaiBatchRequest>,
152
+ async doStartBatch(
153
+ options: BatchV4StartOptions<XaiBatchModelIds>,
131
154
  ): Promise<BatchV4StartResult> {
132
155
  const fileParts: string[] = [];
133
156
  const warnings: BatchV4StartResult['warnings'] =
@@ -144,8 +167,14 @@ class XaiResponsesBatch {
144
167
  },
145
168
  ];
146
169
 
170
+ const batchOptions = await parseProviderOptions({
171
+ provider: 'xai',
172
+ providerOptions: options.providerOptions,
173
+ schema: xaiBatchProviderOptionsSchema,
174
+ });
175
+
147
176
  for (const request of options.requests) {
148
- const preparedRequest = await this.options.prepareRequest(request);
177
+ const preparedRequest = await this.prepareRequest(request);
149
178
 
150
179
  fileParts.push(
151
180
  JSON.stringify({
@@ -166,6 +195,14 @@ class XaiResponsesBatch {
166
195
  const file = new Blob(fileParts, { type: 'application/jsonl' });
167
196
  fileParts.length = 0;
168
197
  const formData = new FormData();
198
+ // xAI rejects uploads where expires_after arrives after the file part,
199
+ // so all fields precede the file.
200
+ if (batchOptions?.inputFileExpiresAfter != null) {
201
+ formData.append(
202
+ 'expires_after',
203
+ String(batchOptions.inputFileExpiresAfter),
204
+ );
205
+ }
169
206
  formData.append('file', file, filename);
170
207
 
171
208
  const headers = combineHeaders(
@@ -203,19 +240,31 @@ class XaiResponsesBatch {
203
240
  return {
204
241
  batchId: batch.batch_id,
205
242
  ...convertXaiBatchStatus(batch),
243
+ providerMetadata: {
244
+ xai: {
245
+ inputFileId: uploadedFile.id,
246
+ ...(uploadedFile.expires_at != null
247
+ ? {
248
+ inputFileExpiresAt: new Date(
249
+ uploadedFile.expires_at * 1000,
250
+ ).toISOString(),
251
+ }
252
+ : {}),
253
+ },
254
+ },
206
255
  warnings,
207
256
  };
208
257
  }
209
258
 
210
- async getBatchStatus(
259
+ async doGetBatchStatus(
211
260
  options: BatchV4OperationOptions,
212
261
  ): Promise<BatchV4Status> {
213
262
  return convertXaiBatchStatus(await this.retrieveBatch(options));
214
263
  }
215
264
 
216
- async getBatchResults(
265
+ async doGetBatchResults(
217
266
  options: BatchV4OperationOptions,
218
- ): Promise<ReadableStream<BatchV4ItemResult<LanguageModelV4GenerateResult>>> {
267
+ ): Promise<ReadableStream<BatchV4ItemResult>> {
219
268
  const batch = await this.retrieveBatch(options);
220
269
  if (convertXaiBatchStatus(batch).status === 'pending') {
221
270
  throw new InvalidArgumentError({
@@ -249,7 +298,7 @@ class XaiResponsesBatch {
249
298
 
250
299
  private async *iterateBatchResults(
251
300
  options: BatchV4OperationOptions,
252
- ): AsyncGenerator<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
301
+ ): AsyncGenerator<BatchV4ItemResult> {
253
302
  let paginationToken: string | undefined;
254
303
 
255
304
  do {
@@ -287,7 +336,7 @@ class XaiResponsesBatch {
287
336
 
288
337
  private async convertBatchResult(
289
338
  result: XaiBatchResult,
290
- ): Promise<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
339
+ ): Promise<TextBatchV4ItemResult> {
291
340
  const error = result.batch_result?.error;
292
341
  if (
293
342
  (result.error_message?.length ?? 0) > 0 ||
@@ -296,6 +345,7 @@ class XaiResponsesBatch {
296
345
  ) {
297
346
  const convertedError = convertXaiBatchError(result);
298
347
  return {
348
+ type: 'text',
299
349
  id: result.batch_request_id,
300
350
  status: isXaiCancellationError(error?.code) ? 'cancelled' : 'failed',
301
351
  error: convertedError,
@@ -317,11 +367,13 @@ class XaiResponsesBatch {
317
367
  const conversion = convertXaiChatBatchResponse(validation.value);
318
368
  return conversion.success
319
369
  ? {
370
+ type: 'text',
320
371
  id: result.batch_request_id,
321
372
  status: 'succeeded',
322
373
  result: conversion.result,
323
374
  }
324
375
  : {
376
+ type: 'text',
325
377
  id: result.batch_request_id,
326
378
  status: 'failed',
327
379
  error: conversion.error,
@@ -331,51 +383,19 @@ class XaiResponsesBatch {
331
383
  return invalidXaiBatchResult(result.batch_request_id);
332
384
  }
333
385
 
334
- private getUrl(path: string) {
335
- return `${this.options.config.baseURL ?? 'https://api.x.ai/v1'}${path}`;
336
- }
337
- }
338
-
339
- export class XaiResponsesBatchLanguageModel
340
- extends XaiResponsesLanguageModel
341
- implements BatchLanguageModelV4
342
- {
343
- private readonly batch: XaiResponsesBatch;
344
-
345
- static [WORKFLOW_SERIALIZE](model: XaiResponsesLanguageModel) {
346
- return XaiResponsesLanguageModel[WORKFLOW_SERIALIZE](model);
347
- }
348
-
349
- static [WORKFLOW_DESERIALIZE](options: {
350
- modelId: XaiResponsesModelId;
351
- config: XaiResponsesConfig;
352
- }) {
353
- return new XaiResponsesBatchLanguageModel(options.modelId, options.config);
354
- }
355
-
356
- constructor(modelId: XaiResponsesModelId, config: XaiResponsesConfig) {
357
- super(modelId, config);
358
- this.batch = new XaiResponsesBatch({
359
- config,
360
- prepareRequest: async request => {
361
- const { args: body, warnings } = await this.getArgs(request.options);
362
- return { body, warnings };
363
- },
364
- });
365
- }
366
-
367
- experimental_doStartBatch(
368
- options: Parameters<BatchLanguageModelV4['experimental_doStartBatch']>[0],
369
- ) {
370
- return this.batch.startBatch(options);
371
- }
372
-
373
- experimental_doGetBatchStatus(options: BatchV4OperationOptions) {
374
- return this.batch.getBatchStatus(options);
386
+ private async prepareRequest(
387
+ request: XaiBatchRequest,
388
+ ): Promise<XaiBatchPreparedRequest> {
389
+ const { args: body, warnings } =
390
+ await XaiResponsesLanguageModel.prepareRequest({
391
+ modelId: request.modelId,
392
+ options: request.options,
393
+ });
394
+ return { body, warnings };
375
395
  }
376
396
 
377
- experimental_doGetBatchResults(options: BatchV4OperationOptions) {
378
- return this.batch.getBatchResults(options);
397
+ private getUrl(path: string) {
398
+ return `${this.options.config.baseURL ?? 'https://api.x.ai/v1'}${path}`;
379
399
  }
380
400
  }
381
401
 
@@ -455,10 +475,9 @@ function isXaiCancellationError(code: string | number | null | undefined) {
455
475
  );
456
476
  }
457
477
 
458
- function invalidXaiBatchResult(
459
- id: string,
460
- ): BatchV4ItemResult<LanguageModelV4GenerateResult> {
478
+ function invalidXaiBatchResult(id: string): TextBatchV4ItemResult {
461
479
  return {
480
+ type: 'text',
462
481
  id,
463
482
  status: 'failed',
464
483
  error: {
@@ -2,7 +2,7 @@ import {
2
2
  type Experimental_RealtimeFactoryV4 as RealtimeFactoryV4,
3
3
  type Experimental_RealtimeFactoryV4GetTokenOptions as RealtimeFactoryV4GetTokenOptions,
4
4
  type Experimental_VideoModelV4,
5
- type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
5
+ type Experimental_BatchV4 as BatchV4,
6
6
  type FilesV4,
7
7
  type ImageModelV4,
8
8
  type LanguageModelV4,
@@ -23,7 +23,8 @@ import { XaiChatLanguageModel } from './xai-chat-language-model';
23
23
  import type { XaiChatModelId } from './xai-chat-language-model-options';
24
24
  import { XaiImageModel } from './xai-image-model';
25
25
  import type { XaiImageModelId } from './xai-image-settings';
26
- import { XaiResponsesBatchLanguageModel } from './responses/xai-responses-batch';
26
+ import { XaiBatch } from './xai-batch';
27
+ import { XaiResponsesLanguageModel } from './responses/xai-responses-language-model';
27
28
  import type { XaiResponsesModelId } from './responses/xai-responses-language-model-options';
28
29
  import { XaiRealtimeModel } from './realtime/xai-realtime-model';
29
30
  import { xaiTools } from './tool';
@@ -35,12 +36,12 @@ import { XaiSpeechModel } from './xai-speech-model';
35
36
  import { XaiTranscriptionModel } from './xai-transcription-model';
36
37
 
37
38
  export interface XaiProvider extends ProviderV4 {
38
- (modelId: XaiResponsesModelId): BatchLanguageModelV4;
39
+ (modelId: XaiResponsesModelId): LanguageModelV4;
39
40
 
40
41
  /**
41
42
  * Creates an Xai language model for text generation.
42
43
  */
43
- languageModel(modelId: XaiResponsesModelId): BatchLanguageModelV4;
44
+ languageModel(modelId: XaiResponsesModelId): LanguageModelV4;
44
45
 
45
46
  /**
46
47
  * Creates an Xai chat model for text generation.
@@ -50,7 +51,12 @@ export interface XaiProvider extends ProviderV4 {
50
51
  /**
51
52
  * Creates an Xai responses model for text generation.
52
53
  */
53
- responses: (modelId: XaiResponsesModelId) => BatchLanguageModelV4;
54
+ responses: (modelId: XaiResponsesModelId) => LanguageModelV4;
55
+
56
+ /**
57
+ * Returns a BatchV4 interface for processing batches with xAI.
58
+ */
59
+ experimental_batch(): BatchV4<{ text: XaiResponsesModelId }>;
54
60
 
55
61
  /**
56
62
  * Creates an Xai image model for image generation.
@@ -167,7 +173,7 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider {
167
173
  };
168
174
 
169
175
  const createResponsesLanguageModel = (modelId: XaiResponsesModelId) => {
170
- return new XaiResponsesBatchLanguageModel(modelId, {
176
+ return new XaiResponsesLanguageModel(modelId, {
171
177
  provider: 'xai.responses',
172
178
  baseURL,
173
179
  headers: getHeaders,
@@ -249,6 +255,18 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider {
249
255
  fetch: options.fetch,
250
256
  });
251
257
 
258
+ const createBatch = () =>
259
+ new XaiBatch({
260
+ provider: 'xai.batch',
261
+ config: {
262
+ provider: 'xai.responses',
263
+ baseURL,
264
+ headers: getHeaders,
265
+ generateId,
266
+ fetch: options.fetch,
267
+ },
268
+ });
269
+
252
270
  const provider = (modelId: XaiResponsesModelId) =>
253
271
  createResponsesLanguageModel(modelId);
254
272
 
@@ -270,6 +288,7 @@ export function createXai(options: XaiProviderSettings = {}): XaiProvider {
270
288
  provider.transcriptionModel = createTranscriptionModel;
271
289
  provider.transcription = createTranscriptionModel;
272
290
  provider.files = createFiles;
291
+ provider.experimental_batch = createBatch;
273
292
  provider.tools = xaiTools;
274
293
 
275
294
  return provider;