@ai-sdk/xai 4.0.33 → 4.0.35

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
@@ -369,6 +369,47 @@ const { text } = await generateText({
369
369
  });
370
370
  ```
371
371
 
372
+ ### Image Generation Tool
373
+
374
+ The image generation tool lets the model create and edit images with Grok Imagine as part of a conversation. The model decides when to call the tool, writes the image prompt, and returns the finished image alongside its text response:
375
+
376
+ ```ts
377
+ import { xai } from '@ai-sdk/xai';
378
+ import { generateText } from 'ai';
379
+
380
+ const result = await generateText({
381
+ model: xai.responses('grok-4.5'),
382
+ prompt:
383
+ 'Generate an image of a corgi surfing a big wave, in the style of a Japanese woodblock print',
384
+ tools: {
385
+ image_generation: xai.tools.imageGeneration(),
386
+ },
387
+ });
388
+
389
+ for (const toolResult of result.staticToolResults) {
390
+ if (toolResult.toolName === 'image_generation') {
391
+ const base64Image = toolResult.output.result;
392
+ }
393
+ }
394
+ ```
395
+
396
+ The tool result also contains the prompt that the model wrote for the image model, which is useful for understanding and debugging what was generated.
397
+
398
+ #### Image Generation Parameters
399
+
400
+ - **action** _'auto' | 'generate' | 'edit'_
401
+
402
+ Restricts what the tool can do. Defaults to `'auto'`.
403
+ - `'auto'`: the model can generate and edit images.
404
+ - `'generate'`: text-to-image generation only.
405
+ - `'edit'`: image editing only (edits images already in the conversation, including images the model generated earlier).
406
+
407
+ <Note>
408
+ The tool takes no size or format parameters; the model picks an aspect ratio
409
+ for each call. To control it, ask in your prompt (e.g. "in a 9:16 vertical
410
+ aspect ratio").
411
+ </Note>
412
+
372
413
  ### MCP Server Tool
373
414
 
374
415
  The MCP server tool enables the model to connect to remote [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers and use their tools:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/xai",
3
- "version": "4.0.33",
3
+ "version": "4.0.35",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@ai-sdk/provider": "4.0.7",
33
- "@ai-sdk/provider-utils": "5.0.25"
33
+ "@ai-sdk/provider-utils": "5.0.27"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "22.19.19",
package/src/index.ts CHANGED
@@ -30,6 +30,7 @@ export { XaiRealtimeModel as Experimental_XaiRealtimeModel } from './realtime/xa
30
30
  export type { XaiRealtimeModelConfig as Experimental_XaiRealtimeModelConfig } from './realtime/xai-realtime-model';
31
31
  export {
32
32
  codeExecution,
33
+ imageGeneration,
33
34
  mcpServer,
34
35
  viewImage,
35
36
  viewXVideo,
@@ -109,6 +109,10 @@ export type XaiResponsesTool =
109
109
  | { type: 'code_interpreter' }
110
110
  | { type: 'view_image' }
111
111
  | { type: 'view_x_video' }
112
+ | {
113
+ type: 'image_generation';
114
+ action?: 'auto' | 'generate' | 'edit';
115
+ }
112
116
  | {
113
117
  type: 'file_search';
114
118
  vector_store_ids?: string[];
@@ -215,6 +219,13 @@ const outputItemSchema = z.discriminatedUnion('type', [
215
219
  )
216
220
  .nullish(),
217
221
  }),
222
+ z.object({
223
+ type: z.literal('image_generation_call'),
224
+ id: z.string(),
225
+ status: z.string(),
226
+ prompt: z.string().nullish(),
227
+ result: z.string().nullish(),
228
+ }),
218
229
  z.object({
219
230
  type: z.literal('custom_tool_call'),
220
231
  ...toolCallSchema.shape,
@@ -423,6 +434,21 @@ export const xaiResponsesChunkSchema = z.union([
423
434
  item_id: z.string(),
424
435
  output_index: z.number(),
425
436
  }),
437
+ z.object({
438
+ type: z.literal('response.image_generation_call.in_progress'),
439
+ item_id: z.string(),
440
+ output_index: z.number(),
441
+ }),
442
+ z.object({
443
+ type: z.literal('response.image_generation_call.generating'),
444
+ item_id: z.string(),
445
+ output_index: z.number(),
446
+ }),
447
+ z.object({
448
+ type: z.literal('response.image_generation_call.completed'),
449
+ item_id: z.string(),
450
+ output_index: z.number(),
451
+ }),
426
452
  z.object({
427
453
  type: z.literal('response.code_execution_call.in_progress'),
428
454
  item_id: z.string(),
@@ -149,6 +149,10 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
149
149
  tool => tool.type === 'provider' && tool.id === 'xai.file_search',
150
150
  )?.name;
151
151
 
152
+ const imageGenerationToolName = tools?.find(
153
+ tool => tool.type === 'provider' && tool.id === 'xai.image_generation',
154
+ )?.name;
155
+
152
156
  const { input, inputWarnings } = await convertToXaiResponsesInput({
153
157
  prompt,
154
158
  store: options.store ?? true,
@@ -269,6 +273,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
269
273
  codeExecutionToolName,
270
274
  mcpToolName,
271
275
  fileSearchToolName,
276
+ imageGenerationToolName,
272
277
  };
273
278
  }
274
279
 
@@ -283,6 +288,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
283
288
  codeExecutionToolName,
284
289
  mcpToolName,
285
290
  fileSearchToolName,
291
+ imageGenerationToolName,
286
292
  } = await this.getArgs(options);
287
293
 
288
294
  const {
@@ -347,6 +353,40 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
347
353
  continue;
348
354
  }
349
355
 
356
+ if (part.type === 'image_generation_call') {
357
+ const toolName = imageGenerationToolName ?? 'image_generation';
358
+
359
+ content.push({
360
+ type: 'tool-call',
361
+ toolCallId: part.id,
362
+ toolName,
363
+ input: '{}',
364
+ providerExecuted: true,
365
+ });
366
+
367
+ if (part.result != null) {
368
+ content.push({
369
+ type: 'tool-result',
370
+ toolCallId: part.id,
371
+ toolName,
372
+ result: {
373
+ result: part.result,
374
+ ...(part.prompt != null && { prompt: part.prompt }),
375
+ },
376
+ });
377
+ } else {
378
+ content.push({
379
+ type: 'tool-result',
380
+ toolCallId: part.id,
381
+ toolName,
382
+ isError: true,
383
+ result: `Image generation failed (status: ${part.status}).`,
384
+ });
385
+ }
386
+
387
+ continue;
388
+ }
389
+
350
390
  if (
351
391
  part.type === 'web_search_call' ||
352
392
  part.type === 'x_search_call' ||
@@ -514,6 +554,7 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
514
554
  codeExecutionToolName,
515
555
  mcpToolName,
516
556
  fileSearchToolName,
557
+ imageGenerationToolName,
517
558
  } = await this.getArgs(options);
518
559
  const body = {
519
560
  ...args,
@@ -801,6 +842,45 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
801
842
  return;
802
843
  }
803
844
 
845
+ if (
846
+ event.type === 'response.image_generation_call.in_progress' ||
847
+ event.type === 'response.image_generation_call.generating' ||
848
+ event.type === 'response.image_generation_call.completed'
849
+ ) {
850
+ if (!seenToolCalls.has(event.item_id)) {
851
+ seenToolCalls.add(event.item_id);
852
+
853
+ const toolName = imageGenerationToolName ?? 'image_generation';
854
+
855
+ controller.enqueue({
856
+ type: 'tool-input-start',
857
+ id: event.item_id,
858
+ toolName,
859
+ });
860
+
861
+ controller.enqueue({
862
+ type: 'tool-input-delta',
863
+ id: event.item_id,
864
+ delta: '{}',
865
+ });
866
+
867
+ controller.enqueue({
868
+ type: 'tool-input-end',
869
+ id: event.item_id,
870
+ });
871
+
872
+ controller.enqueue({
873
+ type: 'tool-call',
874
+ toolCallId: event.item_id,
875
+ toolName,
876
+ input: '{}',
877
+ providerExecuted: true,
878
+ });
879
+ }
880
+
881
+ return;
882
+ }
883
+
804
884
  if (
805
885
  event.type === 'response.output_item.added' ||
806
886
  event.type === 'response.output_item.done'
@@ -895,6 +975,63 @@ export class XaiResponsesLanguageModel implements LanguageModelV4 {
895
975
  return;
896
976
  }
897
977
 
978
+ if (part.type === 'image_generation_call') {
979
+ const toolName = imageGenerationToolName ?? 'image_generation';
980
+
981
+ if (!seenToolCalls.has(part.id)) {
982
+ seenToolCalls.add(part.id);
983
+
984
+ controller.enqueue({
985
+ type: 'tool-input-start',
986
+ id: part.id,
987
+ toolName,
988
+ });
989
+
990
+ controller.enqueue({
991
+ type: 'tool-input-delta',
992
+ id: part.id,
993
+ delta: '{}',
994
+ });
995
+
996
+ controller.enqueue({
997
+ type: 'tool-input-end',
998
+ id: part.id,
999
+ });
1000
+
1001
+ controller.enqueue({
1002
+ type: 'tool-call',
1003
+ toolCallId: part.id,
1004
+ toolName,
1005
+ input: '{}',
1006
+ providerExecuted: true,
1007
+ });
1008
+ }
1009
+
1010
+ if (event.type === 'response.output_item.done') {
1011
+ if (part.result != null) {
1012
+ controller.enqueue({
1013
+ type: 'tool-result',
1014
+ toolCallId: part.id,
1015
+ toolName,
1016
+ result: {
1017
+ result: part.result,
1018
+ ...(part.prompt != null && { prompt: part.prompt }),
1019
+ },
1020
+ });
1021
+ } else {
1022
+ controller.enqueue({
1023
+ type: 'tool-result',
1024
+ toolCallId: part.id,
1025
+ toolName,
1026
+ isError: true,
1027
+ result: `Image generation failed (status: ${part.status}).`,
1028
+ });
1029
+ }
1030
+ }
1031
+
1032
+ return;
1033
+ }
1034
+
898
1035
  if (
899
1036
  part.type === 'web_search_call' ||
900
1037
  part.type === 'x_search_call' ||
@@ -6,6 +6,7 @@ import {
6
6
  import { validateTypes } from '@ai-sdk/provider-utils';
7
7
  import { removeAdditionalPropertiesFalse } from '../remove-additional-properties';
8
8
  import { fileSearchArgsSchema } from '../tool/file-search';
9
+ import { imageGenerationArgsSchema } from '../tool/image-generation';
9
10
  import { mcpServerArgsSchema } from '../tool/mcp-server';
10
11
  import { webSearchArgsSchema } from '../tool/web-search';
11
12
  import { xSearchArgsSchema } from '../tool/x-search';
@@ -99,6 +100,19 @@ export async function prepareResponsesTools({
99
100
  break;
100
101
  }
101
102
 
103
+ case 'xai.image_generation': {
104
+ const args = await validateTypes({
105
+ value: tool.args,
106
+ schema: imageGenerationArgsSchema,
107
+ });
108
+
109
+ xaiTools.push({
110
+ type: 'image_generation',
111
+ action: args.action,
112
+ });
113
+ break;
114
+ }
115
+
102
116
  case 'xai.file_search': {
103
117
  const args = await validateTypes({
104
118
  value: tool.args,
@@ -0,0 +1,62 @@
1
+ import {
2
+ createProviderExecutedToolFactory,
3
+ lazySchema,
4
+ zodSchema,
5
+ } from '@ai-sdk/provider-utils';
6
+ import { z } from 'zod/v4';
7
+
8
+ /**
9
+ * Schema for image generation tool arguments.
10
+ * @see https://docs.x.ai/developers/tools/overview
11
+ */
12
+ export const imageGenerationArgsSchema = lazySchema(() =>
13
+ zodSchema(
14
+ z.object({
15
+ action: z.enum(['auto', 'generate', 'edit']).optional(),
16
+ }),
17
+ ),
18
+ );
19
+
20
+ const imageGenerationInputSchema = lazySchema(() => zodSchema(z.object({})));
21
+
22
+ const imageGenerationOutputSchema = lazySchema(() =>
23
+ zodSchema(
24
+ z.object({
25
+ result: z.string(),
26
+ prompt: z.string().optional(),
27
+ }),
28
+ ),
29
+ );
30
+
31
+ const imageGenerationToolFactory = createProviderExecutedToolFactory<
32
+ {},
33
+ {
34
+ /**
35
+ * The generated image encoded in base64.
36
+ */
37
+ result: string;
38
+
39
+ /**
40
+ * The prompt that the model wrote for the image model.
41
+ */
42
+ prompt?: string;
43
+ },
44
+ {
45
+ /**
46
+ * Restricts what the tool can do. Defaults to 'auto'.
47
+ *
48
+ * - 'auto': the model can generate and edit images.
49
+ * - 'generate': text-to-image generation only.
50
+ * - 'edit': image editing only.
51
+ */
52
+ action?: 'auto' | 'generate' | 'edit';
53
+ }
54
+ >({
55
+ id: 'xai.image_generation',
56
+ inputSchema: imageGenerationInputSchema,
57
+ outputSchema: imageGenerationOutputSchema,
58
+ });
59
+
60
+ export const imageGeneration = (
61
+ args: Parameters<typeof imageGenerationToolFactory>[0] = {},
62
+ ) => imageGenerationToolFactory(args);
package/src/tool/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { codeExecution } from './code-execution';
2
2
  import { fileSearch } from './file-search';
3
+ import { imageGeneration } from './image-generation';
3
4
  import { mcpServer } from './mcp-server';
4
5
  import { viewImage } from './view-image';
5
6
  import { viewXVideo } from './view-x-video';
@@ -9,6 +10,7 @@ import { xSearch } from './x-search';
9
10
  export {
10
11
  codeExecution,
11
12
  fileSearch,
13
+ imageGeneration,
12
14
  mcpServer,
13
15
  viewImage,
14
16
  viewXVideo,
@@ -19,6 +21,7 @@ export {
19
21
  export const xaiTools = {
20
22
  codeExecution,
21
23
  fileSearch,
24
+ imageGeneration,
22
25
  mcpServer,
23
26
  viewImage,
24
27
  viewXVideo,