@ai-sdk/xai 4.0.37 → 4.0.39

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
@@ -59,10 +59,10 @@ You can use the following optional settings to customize the xAI provider instan
59
59
  ## Language Models
60
60
 
61
61
  You can create [xAI models](https://console.x.ai) using a provider instance. The
62
- first argument is the model id, e.g. `grok-4.20-non-reasoning`.
62
+ first argument is the model id, e.g. `grok-4.6`.
63
63
 
64
64
  ```ts
65
- const model = xai('grok-4.20-non-reasoning');
65
+ const model = xai('grok-4.6');
66
66
  ```
67
67
 
68
68
  <Note>
@@ -81,7 +81,7 @@ import { xai } from '@ai-sdk/xai';
81
81
  import { generateText } from 'ai';
82
82
 
83
83
  const { text } = await generateText({
84
- model: xai('grok-4.20-non-reasoning'),
84
+ model: xai('grok-4.6'),
85
85
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
86
86
  });
87
87
  ```
@@ -138,6 +138,37 @@ The AI SDK option accepts these values, but each xAI model supports a subset:
138
138
  current details.
139
139
  </Note>
140
140
 
141
+ ### Priority Processing
142
+
143
+ `providerOptions.xai.serviceTier` requests higher scheduling priority, which
144
+ typically lowers time-to-first-token and speeds up inter-token latency. This
145
+ works for both the Responses API (default) and the Chat Completions API
146
+ (`xai.chat()`).
147
+
148
+ ```ts
149
+ import { xai } from '@ai-sdk/xai';
150
+ import { generateText } from 'ai';
151
+
152
+ const { providerMetadata } = await generateText({
153
+ model: xai('grok-4.6'),
154
+ prompt: 'Explain quantum entanglement.',
155
+ providerOptions: {
156
+ xai: { serviceTier: 'priority' },
157
+ },
158
+ });
159
+
160
+ // 'priority' when the request was served at the priority tier,
161
+ // 'default' when priority capacity was unavailable.
162
+ console.log(providerMetadata?.xai?.serviceTier);
163
+ ```
164
+
165
+ Priority requests are billed at a premium per-token rate, and xAI only charges
166
+ that rate when the response confirms the priority tier — so read the applied
167
+ tier back from `providerMetadata.xai.serviceTier` rather than assuming the
168
+ request you sent is the tier you got. Omitting the option is equivalent to
169
+ `'default'`. See xAI's [priority processing
170
+ docs](https://docs.x.ai/developers/advanced-api-usage/priority-processing).
171
+
141
172
  ## Realtime Models
142
173
 
143
174
  <Note type="warning">Realtime is an experimental feature.</Note>
@@ -168,7 +199,7 @@ calling pattern.
168
199
  The xAI Responses API is the default when using `xai(modelId)` (since AI SDK 7). You can also use `xai.responses(modelId)` explicitly. This enables the model to autonomously orchestrate tool calls and research on xAI's servers.
169
200
 
170
201
  ```ts
171
- const model = xai.responses('grok-4.20-non-reasoning');
202
+ const model = xai.responses('grok-4.6');
172
203
  ```
173
204
 
174
205
  The Responses API provides server-side tools that the model can autonomously execute during its reasoning process:
@@ -190,7 +221,7 @@ import { xai } from '@ai-sdk/xai';
190
221
  import { generateText } from 'ai';
191
222
 
192
223
  const { text } = await generateText({
193
- model: xai.responses('grok-3'),
224
+ model: xai.responses('grok-4.6'),
194
225
  messages: [
195
226
  {
196
227
  role: 'user',
@@ -215,7 +246,7 @@ import { xai } from '@ai-sdk/xai';
215
246
  import { generateText } from 'ai';
216
247
 
217
248
  const { text } = await generateText({
218
- model: xai('grok-4.3'),
249
+ model: xai('grok-4.6'),
219
250
  messages: [
220
251
  {
221
252
  role: 'user',
@@ -252,7 +283,7 @@ import { xai } from '@ai-sdk/xai';
252
283
  import { generateText } from 'ai';
253
284
 
254
285
  const { text, sources } = await generateText({
255
- model: xai.responses('grok-4.20-non-reasoning'),
286
+ model: xai.responses('grok-4.6'),
256
287
  prompt: 'What are the latest developments in AI?',
257
288
  tools: {
258
289
  web_search: xai.tools.webSearch({
@@ -290,7 +321,7 @@ The X search tool enables searching X (Twitter) for posts, with filtering by han
290
321
 
291
322
  ```ts
292
323
  const { text, sources } = await generateText({
293
- model: xai.responses('grok-4.20-non-reasoning'),
324
+ model: xai.responses('grok-4.6'),
294
325
  prompt: 'What are people saying about AI on X this week?',
295
326
  tools: {
296
327
  x_search: xai.tools.xSearch({
@@ -336,7 +367,7 @@ The code execution tool enables the model to write and execute Python code for c
336
367
 
337
368
  ```ts
338
369
  const { text } = await generateText({
339
- model: xai.responses('grok-4.20-non-reasoning'),
370
+ model: xai.responses('grok-4.6'),
340
371
  prompt:
341
372
  'Calculate the compound interest for $10,000 at 5% annually for 10 years',
342
373
  tools: {
@@ -351,7 +382,7 @@ The view image tool enables the model to view and analyze images:
351
382
 
352
383
  ```ts
353
384
  const { text } = await generateText({
354
- model: xai.responses('grok-4.20-non-reasoning'),
385
+ model: xai.responses('grok-4.6'),
355
386
  prompt: 'Describe what you see in the image',
356
387
  tools: {
357
388
  view_image: xai.tools.viewImage(),
@@ -365,7 +396,7 @@ The view X video tool enables the model to view and analyze videos from X (Twitt
365
396
 
366
397
  ```ts
367
398
  const { text } = await generateText({
368
- model: xai.responses('grok-4.20-non-reasoning'),
399
+ model: xai.responses('grok-4.6'),
369
400
  prompt: 'Summarize the content of this X video',
370
401
  tools: {
371
402
  view_x_video: xai.tools.viewXVideo(),
@@ -382,7 +413,7 @@ import { xai } from '@ai-sdk/xai';
382
413
  import { generateText } from 'ai';
383
414
 
384
415
  const result = await generateText({
385
- model: xai.responses('grok-4.5'),
416
+ model: xai.responses('grok-4.6'),
386
417
  prompt:
387
418
  'Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print',
388
419
  tools: {
@@ -420,7 +451,7 @@ The MCP server tool enables the model to connect to remote [Model Context Protoc
420
451
 
421
452
  ```ts
422
453
  const { text } = await generateText({
423
- model: xai.responses('grok-4.20-non-reasoning'),
454
+ model: xai.responses('grok-4.6'),
424
455
  prompt: 'Use the weather tool to check conditions in San Francisco',
425
456
  tools: {
426
457
  weather_server: xai.tools.mcpServer({
@@ -468,7 +499,7 @@ import { xai, type XaiLanguageModelResponsesOptions } from '@ai-sdk/xai';
468
499
  import { streamText } from 'ai';
469
500
 
470
501
  const result = streamText({
471
- model: xai.responses('grok-4.20-reasoning'),
502
+ model: xai.responses('grok-4.6'),
472
503
  prompt: 'What documents do you have access to?',
473
504
  tools: {
474
505
  file_search: xai.tools.fileSearch({
@@ -515,7 +546,7 @@ import { xai } from '@ai-sdk/xai';
515
546
  import { streamText } from 'ai';
516
547
 
517
548
  const { stream } = streamText({
518
- model: xai.responses('grok-4.20-non-reasoning'),
549
+ model: xai.responses('grok-4.6'),
519
550
  prompt: 'Research AI safety developments and calculate risk metrics',
520
551
  tools: {
521
552
  web_search: xai.tools.webSearch(),
@@ -549,7 +580,7 @@ import { xai, type XaiLanguageModelResponsesOptions } from '@ai-sdk/xai';
549
580
  import { generateText } from 'ai';
550
581
 
551
582
  const result = await generateText({
552
- model: xai.responses('grok-4.5'),
583
+ model: xai.responses('grok-4.6'),
553
584
  providerOptions: {
554
585
  xai: {
555
586
  reasoningEffort: 'high',
@@ -585,6 +616,10 @@ The following provider options are available:
585
616
 
586
617
  The ID of the previous response from the model. You can use it to continue a conversation.
587
618
 
619
+ - **serviceTier** _'default' | 'priority'_
620
+
621
+ Scheduling priority for the request. `'priority'` buys lower time-to-first-token and faster inter-token latency at a premium per-token price. The tier xAI actually applied comes back on `providerMetadata.xai.serviceTier`, and is `'default'` when priority capacity was unavailable. See [Priority Processing](https://docs.x.ai/developers/advanced-api-usage/priority-processing).
622
+
588
623
  <Note>
589
624
  The Responses API only supports server-side tools. You cannot mix server-side
590
625
  tools with client-side function tools in the same request.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/xai",
3
- "version": "4.0.37",
3
+ "version": "4.0.39",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -37,8 +37,8 @@
37
37
  "tsup": "^8.5.1",
38
38
  "typescript": "5.8.3",
39
39
  "zod": "3.25.76",
40
- "@vercel/ai-tsconfig": "0.0.0",
41
- "@ai-sdk/test-server": "2.0.1"
40
+ "@ai-sdk/test-server": "2.0.1",
41
+ "@vercel/ai-tsconfig": "0.0.0"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "zod": "^3.25.76 || ^4.1.8"
@@ -287,6 +287,7 @@ export const xaiResponsesResponseSchema = z.object({
287
287
  output: z.array(outputItemSchema),
288
288
  usage: xaiResponsesUsageSchema.nullish(),
289
289
  status: z.string(),
290
+ service_tier: z.string().nullish(),
290
291
  });
291
292
 
292
293
  export const xaiResponsesChunkSchema = z.union([
@@ -571,6 +572,7 @@ export const xaiResponsesChunkSchema = z.union([
571
572
  response: z.object({
572
573
  incomplete_details: z.object({ reason: z.string() }).nullish(),
573
574
  usage: xaiResponsesUsageSchema.nullish(),
575
+ service_tier: z.string().nullish(),
574
576
  }),
575
577
  }),
576
578
  z.object({
@@ -28,6 +28,7 @@ export const xaiLanguageModelResponsesOptions = z.object({
28
28
  reasoningSummary: z.enum(['auto', 'concise', 'detailed']).optional(),
29
29
  logprobs: z.boolean().optional(),
30
30
  topLogprobs: z.number().int().min(0).max(8).optional(),
31
+ serviceTier: z.enum(['default', 'priority']).optional(),
31
32
  /**
32
33
  * Whether to store the input message(s) and model response for later retrieval.
33
34
  * Must be set to `false` for teams with Zero Data Retention (ZDR) enabled,
@@ -255,6 +255,9 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
255
255
  ...(options.previousResponseId != null && {
256
256
  previous_response_id: options.previousResponseId,
257
257
  }),
258
+ ...(options.serviceTier != null && {
259
+ service_tier: options.serviceTier,
260
+ }),
258
261
  };
259
262
 
260
263
  if (xaiTools && xaiTools.length > 0) {
@@ -526,10 +529,16 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
526
529
  inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
527
530
  outputTokens: { total: 0, text: 0, reasoning: 0 },
528
531
  },
529
- ...(response.usage?.cost_in_usd_ticks != null && {
532
+ ...((response.usage?.cost_in_usd_ticks != null ||
533
+ response.service_tier != null) && {
530
534
  providerMetadata: {
531
535
  xai: {
532
- costInUsdTicks: response.usage.cost_in_usd_ticks,
536
+ ...(response.usage?.cost_in_usd_ticks != null && {
537
+ costInUsdTicks: response.usage.cost_in_usd_ticks,
538
+ }),
539
+ ...(response.service_tier != null && {
540
+ serviceTier: response.service_tier,
541
+ }),
533
542
  },
534
543
  },
535
544
  }),
@@ -580,6 +589,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
580
589
  let hasFunctionCall = false;
581
590
  let usage: LanguageModelV4Usage | undefined = undefined;
582
591
  let costInUsdTicks: number | undefined = undefined;
592
+ let serviceTier: string | undefined = undefined;
583
593
  let isFirstChunk = true;
584
594
  const contentBlocks: Record<string, { type: 'text' }> = {};
585
595
  const seenToolCalls = new Set<string>();
@@ -774,6 +784,8 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
774
784
  costInUsdTicks = response.usage.cost_in_usd_ticks ?? undefined;
775
785
  }
776
786
 
787
+ serviceTier = response.service_tier ?? undefined;
788
+
777
789
  if (event.type === 'response.incomplete') {
778
790
  const reason =
779
791
  'incomplete_details' in response
@@ -1222,10 +1234,11 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
1222
1234
  },
1223
1235
  outputTokens: { total: 0, text: 0, reasoning: 0 },
1224
1236
  },
1225
- ...(costInUsdTicks != null && {
1237
+ ...((costInUsdTicks != null || serviceTier != null) && {
1226
1238
  providerMetadata: {
1227
1239
  xai: {
1228
- costInUsdTicks,
1240
+ ...(costInUsdTicks != null && { costInUsdTicks }),
1241
+ ...(serviceTier != null && { serviceTier }),
1229
1242
  },
1230
1243
  },
1231
1244
  }),
@@ -73,6 +73,8 @@ export const xaiLanguageModelChatOptions = z.object({
73
73
  logprobs: z.boolean().optional(),
74
74
  topLogprobs: z.number().int().min(0).max(8).optional(),
75
75
 
76
+ serviceTier: z.enum(['default', 'priority']).optional(),
77
+
76
78
  /**
77
79
  * Whether to enable parallel function calling during tool use.
78
80
  * When true, the model can call multiple functions in parallel.
@@ -181,6 +181,9 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
181
181
  seed,
182
182
  reasoning_effort: reasoningEffort,
183
183
 
184
+ // scheduling priority
185
+ service_tier: options.serviceTier,
186
+
184
187
  // parallel function calling
185
188
  parallel_function_calling: options.parallel_function_calling,
186
189
 
@@ -347,6 +350,11 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
347
350
  inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
348
351
  outputTokens: { total: 0, text: 0, reasoning: 0 },
349
352
  },
353
+ ...(response.service_tier != null && {
354
+ providerMetadata: {
355
+ xai: { serviceTier: response.service_tier },
356
+ },
357
+ }),
350
358
  request: { body },
351
359
  response: {
352
360
  ...getResponseMetadata(response),
@@ -426,6 +434,7 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
426
434
  raw: undefined,
427
435
  };
428
436
  let usage: LanguageModelV4Usage | undefined = undefined;
437
+ let serviceTier: string | undefined = undefined;
429
438
  let isFirstChunk = true;
430
439
  const contentBlocks: Record<
431
440
  string,
@@ -485,6 +494,11 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
485
494
  usage = convertXaiChatUsage(value.usage);
486
495
  }
487
496
 
497
+ // the applied tier is repeated on every chunk; keep the latest
498
+ if (value.service_tier != null) {
499
+ serviceTier = value.service_tier;
500
+ }
501
+
488
502
  const choice = value.choices[0];
489
503
 
490
504
  // update finish reason if present
@@ -644,6 +658,9 @@ export class XaiChatLanguageModel implements LanguageModelV4 {
644
658
  },
645
659
  outputTokens: { total: 0, text: 0, reasoning: 0 },
646
660
  },
661
+ ...(serviceTier != null && {
662
+ providerMetadata: { xai: { serviceTier } },
663
+ }),
647
664
  });
648
665
  },
649
666
  }),
@@ -711,6 +728,7 @@ const xaiChatResponseSchema = z.object({
711
728
  object: z.literal('chat.completion').nullish(),
712
729
  usage: xaiUsageSchema.nullish(),
713
730
  citations: z.array(z.string().url()).nullish(),
731
+ service_tier: z.string().nullish(),
714
732
  code: z.string().nullish(),
715
733
  error: z.string().nullish(),
716
734
  });
@@ -744,6 +762,7 @@ const xaiChatChunkSchema = z.object({
744
762
  ),
745
763
  usage: xaiUsageSchema.nullish(),
746
764
  citations: z.array(z.string().url()).nullish(),
765
+ service_tier: z.string().nullish(),
747
766
  });
748
767
 
749
768
  const xaiStreamErrorSchema = z.object({
@@ -581,19 +581,30 @@ export class XaiVideoModel implements VideoModelV4 {
581
581
  statusResponse.status === 'done' ||
582
582
  (statusResponse.status == null && statusResponse.video?.url)
583
583
  ) {
584
+ // Terminal outcomes, so they are reported the same way as an upstream `failed`
584
585
  if (statusResponse.video?.respect_moderation === false) {
585
- throw new AISDKError({
586
- name: 'XAI_VIDEO_MODERATION_ERROR',
587
- message:
586
+ return {
587
+ status: 'error' as const,
588
+ error:
588
589
  'Video generation was blocked due to a content policy violation.',
589
- });
590
+ response: {
591
+ timestamp: currentDate,
592
+ modelId: this.modelId,
593
+ headers: responseHeaders,
594
+ },
595
+ };
590
596
  }
591
597
 
592
598
  if (!statusResponse.video?.url) {
593
- throw new AISDKError({
594
- name: 'XAI_VIDEO_GENERATION_ERROR',
595
- message: 'Video generation completed but no video URL was returned.',
596
- });
599
+ return {
600
+ status: 'error' as const,
601
+ error: 'Video generation completed but no video URL was returned.',
602
+ response: {
603
+ timestamp: currentDate,
604
+ modelId: this.modelId,
605
+ headers: responseHeaders,
606
+ },
607
+ };
597
608
  }
598
609
 
599
610
  return {