@ai-sdk/openai 3.0.109 → 3.0.111

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.
@@ -548,6 +548,55 @@ metadata on tool-call parts. The SDK uses `providerMetadata.openai.namespace` or
548
548
  `providerOptions.openai.namespace` to round-trip the namespace back to OpenAI on
549
549
  subsequent requests.
550
550
 
551
+ #### Async Tool Calling
552
+
553
+ GPT-6 Astra and later Responses models support
554
+ [async tool calling](https://developers.openai.com/api/docs/guides/async-tool-calling).
555
+ An async tool lets the model continue generating independent output after issuing
556
+ the call instead of waiting for its result. Your application still executes the
557
+ tool and sends its result in a later request using the original tool call ID.
558
+
559
+ Enable async calling on a function tool with `providerOptions.openai.async`:
560
+
561
+ ```ts
562
+ import { openai, type OpenAIToolOptions } from '@ai-sdk/openai';
563
+ import { generateText, tool } from 'ai';
564
+ import { z } from 'zod';
565
+
566
+ const result = await generateText({
567
+ model: openai.responses('gpt-6-astra'),
568
+ tools: {
569
+ getWeather: tool({
570
+ description: 'Get the weather for a city.',
571
+ inputSchema: z.object({ city: z.string() }),
572
+ outputSchema: z.object({
573
+ city: z.string(),
574
+ temperatureC: z.number(),
575
+ }),
576
+ providerOptions: {
577
+ openai: { async: true } satisfies OpenAIToolOptions,
578
+ },
579
+ }),
580
+ },
581
+ prompt:
582
+ 'Start the weather lookup for Paris, then list three general packing essentials without waiting.',
583
+ });
584
+ ```
585
+
586
+ The generated tool call exposes the provider marker as
587
+ `providerMetadata.openai.async`. Use `providerMetadata.openai.responseId` as the
588
+ next request's `previousResponseId`, and submit the result in a tool message with
589
+ the original `toolCallId`.
590
+
591
+ With `streamText`, OpenAI can continue streaming text after the completed
592
+ `tool-call` part. Use the tool's `onInputAvailable` callback to start work as soon
593
+ as that part arrives. If `execute` returns the same already-running promise, tool
594
+ execution overlaps the rest of the model stream. Omit `execute` when the job
595
+ should outlive the current generation and submit its result in a later request.
596
+
597
+ Async calling applies to directly called function and custom tools. It does not
598
+ apply to hosted tools.
599
+
551
600
  #### Web Search Tool
552
601
 
553
602
  The OpenAI responses API supports web search through the `openai.tools.webSearch` tool.
@@ -736,6 +785,16 @@ for await (const part of result.fullStream) {
736
785
  setting `store: false`.
737
786
  </Note>
738
787
 
788
+ To use `xhigh` or `max` quality, select `gpt-image-2.5-flare` or
789
+ `gpt-image-2.5-sunburst` as the image generation tool's model:
790
+
791
+ ```ts
792
+ openai.tools.imageGeneration({
793
+ model: 'gpt-image-2.5-flare',
794
+ quality: 'xhigh',
795
+ });
796
+ ```
797
+
739
798
  For complete details on model availability, image quality controls, supported sizes, and tool-specific parameters,
740
799
  refer to the OpenAI documentation:
741
800
 
@@ -2560,7 +2619,7 @@ Transform an existing image using text prompts:
2560
2619
  const imageBuffer = readFileSync('./input-image.png');
2561
2620
 
2562
2621
  const { images } = await generateImage({
2563
- model: openai.image('gpt-image-2'),
2622
+ model: openai.image('gpt-image-2.5-sunburst'),
2564
2623
  prompt: {
2565
2624
  text: 'Turn the cat into a dog but retain the style of the original image',
2566
2625
  images: [imageBuffer],
@@ -2577,7 +2636,7 @@ const image = readFileSync('./input-image.png');
2577
2636
  const mask = readFileSync('./mask.png'); // Transparent areas = edit regions
2578
2637
 
2579
2638
  const { images } = await generateImage({
2580
- model: openai.image('gpt-image-2'),
2639
+ model: openai.image('gpt-image-2.5-sunburst'),
2581
2640
  prompt: {
2582
2641
  text: 'A sunlit indoor lounge area with a pool containing a flamingo',
2583
2642
  images: [image],
@@ -2622,7 +2681,7 @@ const owl = readFileSync('./owl.png');
2622
2681
  const bear = readFileSync('./bear.png');
2623
2682
 
2624
2683
  const { images } = await generateImage({
2625
- model: openai.image('gpt-image-2'),
2684
+ model: openai.image('gpt-image-2.5-sunburst'),
2626
2685
  prompt: {
2627
2686
  text: 'Combine these animals into a group photo, retaining the original style',
2628
2687
  images: [cat, dog, owl, bear],
@@ -2638,14 +2697,23 @@ const { images } = await generateImage({
2638
2697
 
2639
2698
  ### Model Capabilities
2640
2699
 
2641
- | Model | Sizes |
2642
- | ------------------ | ------------------------------- |
2643
- | `gpt-image-2` | 1024x1024, 1536x1024, 1024x1536 |
2644
- | `gpt-image-1.5` | 1024x1024, 1536x1024, 1024x1536 |
2645
- | `gpt-image-1-mini` | 1024x1024, 1536x1024, 1024x1536 |
2646
- | `gpt-image-1` | 1024x1024, 1536x1024, 1024x1536 |
2647
- | `dall-e-3` | 1024x1024, 1792x1024, 1024x1792 |
2648
- | `dall-e-2` | 256x256, 512x512, 1024x1024 |
2700
+ | Model | Sizes |
2701
+ | ------------------------ | -------------------------------------- |
2702
+ | `gpt-image-2.5-flare` | Standard presets and custom dimensions |
2703
+ | `gpt-image-2.5-sunburst` | Standard presets and custom dimensions |
2704
+ | `gpt-image-2` | 1024x1024, 1536x1024, 1024x1536 |
2705
+ | `gpt-image-1.5` | 1024x1024, 1536x1024, 1024x1536 |
2706
+ | `gpt-image-1-mini` | 1024x1024, 1536x1024, 1024x1536 |
2707
+ | `gpt-image-1` | 1024x1024, 1536x1024, 1024x1536 |
2708
+ | `dall-e-3` | 1024x1024, 1792x1024, 1024x1792 |
2709
+ | `dall-e-2` | 256x256, 512x512, 1024x1024 |
2710
+
2711
+ Use `gpt-image-2.5-flare` for fast, general-purpose image generation and
2712
+ `gpt-image-2.5-sunburst` when editing precision and instruction following are
2713
+ the priority. Both models accept custom `WIDTHxHEIGHT` sizes whose dimensions
2714
+ are multiples of 16, with aspect ratios from 1:3 through 3:1, no edge longer
2715
+ than 3840 pixels, and a total area from 655,360 through 8,294,400 pixels.
2716
+ Resolutions above 2560x1440 are experimental.
2649
2717
 
2650
2718
  You can pass optional `providerOptions` to the image model. These are prone to change by OpenAI and are model dependent. For example, the `gpt-image-*` models support the `quality` option:
2651
2719
 
@@ -2657,7 +2725,7 @@ import {
2657
2725
  import { generateImage } from 'ai';
2658
2726
 
2659
2727
  const { image, providerMetadata } = await generateImage({
2660
- model: openai.image('gpt-image-2'),
2728
+ model: openai.image('gpt-image-2.5-flare'),
2661
2729
  prompt: 'A salamander at sunrise in a forest pond in the Seychelles.',
2662
2730
  providerOptions: {
2663
2731
  openai: { quality: 'high' } satisfies OpenAIImageModelGenerationOptions,
@@ -2665,6 +2733,19 @@ const { image, providerMetadata } = await generateImage({
2665
2733
  });
2666
2734
  ```
2667
2735
 
2736
+ The `gpt-image-2.5-flare` and `gpt-image-2.5-sunburst` models also support
2737
+ `quality: 'xhigh'` and `quality: 'max'` for both image generation and editing:
2738
+
2739
+ ```ts
2740
+ const { image } = await generateImage({
2741
+ model: openai.image('gpt-image-2.5-sunburst'),
2742
+ prompt: 'A salamander at sunrise in a forest pond in the Seychelles.',
2743
+ providerOptions: {
2744
+ openai: { quality: 'max' } satisfies OpenAIImageModelGenerationOptions,
2745
+ },
2746
+ });
2747
+ ```
2748
+
2668
2749
  For more on `generateImage()` see [Image Generation](/docs/ai-sdk-core/image-generation).
2669
2750
 
2670
2751
  OpenAI's image models return additional metadata in the response that can be
@@ -2678,7 +2759,7 @@ is available:
2678
2759
  - `revisedPrompt` _string_ - The revised prompt that was actually used to generate the image (OpenAI may modify your prompt for safety or clarity)
2679
2760
  - `created` _number_ - The Unix timestamp (in seconds) of when the image was created
2680
2761
  - `size` _string_ - The size of the generated image. One of `1024x1024`, `1024x1536`, or `1536x1024`
2681
- - `quality` _string_ - The quality of the generated image. One of `low`, `medium`, or `high`
2762
+ - `quality` _string_ - The quality of the generated image. One of `low`, `medium`, `high`, `xhigh`, or `max`
2682
2763
  - `background` _string_ - The background parameter used for the image generation. Either `transparent` or `opaque`
2683
2764
  - `outputFormat` _string_ - The output format of the generated image. One of `png`, `webp`, or `jpeg`
2684
2765
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "3.0.109",
3
+ "version": "3.0.111",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -12,6 +12,10 @@ export type OpenAIImageModelId =
12
12
  | 'gpt-image-1-mini'
13
13
  | 'gpt-image-1.5'
14
14
  | 'gpt-image-2'
15
+ | 'gpt-image-2.5-flare'
16
+ | 'gpt-image-2.5-flare-2026-09-08'
17
+ | 'gpt-image-2.5-sunburst'
18
+ | 'gpt-image-2.5-sunburst-2026-09-08'
15
19
  | 'chatgpt-image-latest'
16
20
  | (string & {});
17
21
 
@@ -23,6 +27,10 @@ export const modelMaxImagesPerCall: Record<OpenAIImageModelId, number> = {
23
27
  'gpt-image-1-mini': 10,
24
28
  'gpt-image-1.5': 10,
25
29
  'gpt-image-2': 10,
30
+ 'gpt-image-2.5-flare': 10,
31
+ 'gpt-image-2.5-flare-2026-09-08': 10,
32
+ 'gpt-image-2.5-sunburst': 10,
33
+ 'gpt-image-2.5-sunburst-2026-09-08': 10,
26
34
  'chatgpt-image-latest': 10,
27
35
  };
28
36
 
@@ -45,10 +53,11 @@ const baseImageModelOptionsObject = z.object({
45
53
  /**
46
54
  * Quality of the generated image(s).
47
55
  *
48
- * Valid values: `standard`, `hd`, `low`, `medium`, `high`, `auto`.
56
+ * Valid values: `standard`, `hd`, `low`, `medium`, `high`, `xhigh`, `max`, `auto`.
57
+ * `xhigh` and `max` are supported by GPT Image 2.5 models.
49
58
  */
50
59
  quality: z
51
- .enum(['standard', 'hd', 'low', 'medium', 'high', 'auto'])
60
+ .enum(['standard', 'hd', 'low', 'medium', 'high', 'xhigh', 'max', 'auto'])
52
61
  .optional(),
53
62
 
54
63
  /**
package/src/index.ts CHANGED
@@ -19,9 +19,11 @@ export type { OpenAILanguageModelCompletionOptions } from './completion/openai-c
19
19
  export type { OpenAIEmbeddingModelOptions } from './embedding/openai-embedding-options';
20
20
  export type { OpenAISpeechModelOptions } from './speech/openai-speech-options';
21
21
  export type { OpenAITranscriptionModelOptions } from './transcription/openai-transcription-options';
22
+ export type { OpenAIToolOptions } from './responses/openai-responses-prepare-tools';
22
23
  export type {
23
24
  OpenaiResponsesProviderMetadata,
24
25
  OpenaiResponsesReasoningProviderMetadata,
26
+ OpenaiResponsesToolCallProviderMetadata,
25
27
  OpenaiResponsesTextProviderMetadata,
26
28
  OpenaiResponsesSourceDocumentProviderMetadata,
27
29
  } from './responses/openai-responses-provider-metadata';
@@ -6,6 +6,11 @@ export type OpenAIConfig = {
6
6
  headers: () => Record<string, string | undefined>;
7
7
  fetch?: FetchFunction;
8
8
  generateId?: () => string;
9
+ /**
10
+ * Whether Responses API message input items must include an explicit
11
+ * `type: 'message'` discriminator.
12
+ */
13
+ explicitMessageItemType?: boolean;
9
14
  /**
10
15
  * File ID prefixes used to identify file IDs in Responses API.
11
16
  * When undefined, all file data is treated as base64 content.
@@ -4,6 +4,7 @@ export type OpenAILanguageModelCapabilities = {
4
4
  supportsFlexProcessing: boolean;
5
5
  supportsPriorityProcessing: boolean;
6
6
  supportsConfigurationUpdate: boolean;
7
+ supportsAsyncToolCalling: boolean;
7
8
  supportedReasoningEfforts: readonly string[] | undefined;
8
9
 
9
10
  /**
@@ -55,6 +56,7 @@ export function getOpenAILanguageModelCapabilities(
55
56
  supportsFlexProcessing,
56
57
  supportsPriorityProcessing,
57
58
  supportsConfigurationUpdate: isGpt6OrLaterModel,
59
+ supportsAsyncToolCalling: isGpt6OrLaterModel,
58
60
  supportedReasoningEfforts: isGpt6OrLaterModel
59
61
  ? ['low', 'medium', 'high', 'xhigh', 'max']
60
62
  : undefined,
@@ -27,6 +27,7 @@ export const openaiTools = {
27
27
  *
28
28
  * @param name - The name of the custom tool.
29
29
  * @param description - An optional description of the tool.
30
+ * @param async - Whether the model can continue without waiting for the tool result.
30
31
  * @param format - The output format constraint (grammar type, syntax, and definition).
31
32
  */
32
33
  customTool,
@@ -65,7 +66,7 @@ export const openaiTools = {
65
66
  * @param outputCompression - Compression level for the output image (0-100).
66
67
  * @param outputFormat - The output format of the generated image. One of 'png', 'jpeg', or 'webp'.
67
68
  * @param partialImages - Number of partial images to generate in streaming mode (0-3).
68
- * @param quality - The quality of the generated image. One of 'auto', 'low', 'medium', or 'high'.
69
+ * @param quality - The quality of the generated image. One of 'auto', 'low', 'medium', 'high', 'xhigh', or 'max'. 'xhigh' and 'max' require a GPT Image 2.5 model.
69
70
  * @param size - The size of the generated image. One of 'auto', '1024x1024', '1024x1536', or '1536x1024'.
70
71
  */
71
72
  imageGeneration,
@@ -296,6 +296,7 @@ export async function convertToOpenAIResponsesInput({
296
296
  toolNameMapping,
297
297
  systemMessageMode,
298
298
  providerOptionsName,
299
+ explicitMessageItemType = false,
299
300
  fileIdPrefixes,
300
301
  passThroughUnsupportedFiles = false,
301
302
  store,
@@ -311,6 +312,7 @@ export async function convertToOpenAIResponsesInput({
311
312
  toolNameMapping: ToolNameMapping;
312
313
  systemMessageMode: 'system' | 'developer' | 'remove';
313
314
  providerOptionsName: string;
315
+ explicitMessageItemType?: boolean;
314
316
  fileIdPrefixes?: readonly string[];
315
317
  passThroughUnsupportedFiles?: boolean;
316
318
  store: boolean;
@@ -348,6 +350,7 @@ export async function convertToOpenAIResponsesInput({
348
350
  providerOptionsName,
349
351
  );
350
352
  input.push({
353
+ ...(explicitMessageItemType && { type: 'message' as const }),
351
354
  role: 'system',
352
355
  content:
353
356
  promptCacheBreakpoint == null
@@ -368,6 +371,7 @@ export async function convertToOpenAIResponsesInput({
368
371
  providerOptionsName,
369
372
  );
370
373
  input.push({
374
+ ...(explicitMessageItemType && { type: 'message' as const }),
371
375
  role: 'developer',
372
376
  content:
373
377
  promptCacheBreakpoint == null
@@ -401,6 +405,7 @@ export async function convertToOpenAIResponsesInput({
401
405
 
402
406
  case 'user': {
403
407
  input.push({
408
+ ...(explicitMessageItemType && { type: 'message' as const }),
404
409
  role: 'user',
405
410
  content: content.map((part, index) => {
406
411
  switch (part.type) {
@@ -514,6 +519,7 @@ export async function convertToOpenAIResponsesInput({
514
519
  }
515
520
 
516
521
  input.push({
522
+ ...(explicitMessageItemType && { type: 'message' as const }),
517
523
  role: 'assistant',
518
524
  content: [{ type: 'output_text', text: part.text }],
519
525
  id,
@@ -589,6 +595,18 @@ export async function convertToOpenAIResponsesInput({
589
595
  | string
590
596
  | undefined;
591
597
 
598
+ const isAsync = (part.providerOptions?.[providerOptionsName]
599
+ ?.async ??
600
+ (
601
+ part as {
602
+ providerMetadata?: {
603
+ [providerOptionsName]?: { async?: boolean };
604
+ };
605
+ }
606
+ ).providerMetadata?.[providerOptionsName]?.async) as
607
+ | boolean
608
+ | undefined;
609
+
592
610
  if (hasConversation && id != null) {
593
611
  break;
594
612
  }
@@ -739,6 +757,7 @@ export async function convertToOpenAIResponsesInput({
739
757
  typeof part.input === 'string'
740
758
  ? part.input
741
759
  : JSON.stringify(part.input),
760
+ ...(isAsync != null && { async: isAsync }),
742
761
  id,
743
762
  });
744
763
  break;
@@ -749,6 +768,7 @@ export async function convertToOpenAIResponsesInput({
749
768
  call_id: part.toolCallId,
750
769
  name: resolvedToolName,
751
770
  arguments: serializeToolCallArguments(part.input),
771
+ ...(isAsync != null && { async: isAsync }),
752
772
  ...(namespace != null && { namespace }),
753
773
  });
754
774
  break;
@@ -121,6 +121,7 @@ export type OpenAIResponsesApplyPatchOperationDiffDoneChunk = {
121
121
  };
122
122
 
123
123
  export type OpenAIResponsesSystemMessage = {
124
+ type?: 'message';
124
125
  role: 'system' | 'developer';
125
126
  content:
126
127
  | string
@@ -132,6 +133,7 @@ export type OpenAIResponsesSystemMessage = {
132
133
  };
133
134
 
134
135
  export type OpenAIResponsesUserMessage = {
136
+ type?: 'message';
135
137
  role: 'user';
136
138
  content: Array<
137
139
  | {
@@ -169,6 +171,7 @@ export type OpenAIResponsesUserMessage = {
169
171
  };
170
172
 
171
173
  export type OpenAIResponsesAssistantMessage = {
174
+ type?: 'message';
172
175
  role: 'assistant';
173
176
  content: Array<{ type: 'output_text'; text: string }>;
174
177
  id?: string;
@@ -180,6 +183,7 @@ export type OpenAIResponsesFunctionCall = {
180
183
  call_id: string;
181
184
  name: string;
182
185
  arguments: string;
186
+ async?: boolean;
183
187
  id?: string;
184
188
  namespace?: string;
185
189
  };
@@ -220,6 +224,7 @@ export type OpenAIResponsesCustomToolCall = {
220
224
  call_id: string;
221
225
  name: string;
222
226
  input: string;
227
+ async?: boolean;
223
228
  };
224
229
 
225
230
  export type OpenAIResponsesCustomToolCallOutput = {
@@ -373,6 +378,7 @@ export type OpenAIResponsesFunctionTool = {
373
378
  name: string;
374
379
  description: string | undefined;
375
380
  parameters: JSONSchema7;
381
+ async?: boolean;
376
382
  strict?: boolean;
377
383
  defer_loading?: boolean;
378
384
  };
@@ -467,7 +473,7 @@ export type OpenAIResponsesTool =
467
473
  output_compression: number | undefined;
468
474
  output_format: 'png' | 'jpeg' | 'webp' | undefined;
469
475
  partial_images: number | undefined;
470
- quality: 'auto' | 'low' | 'medium' | 'high' | undefined;
476
+ quality: 'auto' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | undefined;
471
477
  size: 'auto' | '1024x1024' | '1024x1536' | '1536x1024' | undefined;
472
478
  }
473
479
 
@@ -501,6 +507,7 @@ export type OpenAIResponsesTool =
501
507
  type: 'custom';
502
508
  name: string;
503
509
  description?: string;
510
+ async?: boolean;
504
511
  format?:
505
512
  | {
506
513
  type: 'grammar';
@@ -772,6 +779,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
772
779
  call_id: z.string(),
773
780
  name: z.string(),
774
781
  arguments: z.string(),
782
+ async: z.boolean().nullish(),
775
783
  namespace: z.string().nullish(),
776
784
  }),
777
785
  z.object({
@@ -850,6 +858,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
850
858
  call_id: z.string(),
851
859
  name: z.string(),
852
860
  input: z.string(),
861
+ async: z.boolean().nullish(),
853
862
  }),
854
863
  z.object({
855
864
  type: z.literal('shell_call'),
@@ -917,6 +926,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
917
926
  call_id: z.string(),
918
927
  name: z.string(),
919
928
  arguments: z.string(),
929
+ async: z.boolean().nullish(),
920
930
  status: z.literal('completed'),
921
931
  namespace: z.string().nullish(),
922
932
  }),
@@ -926,6 +936,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
926
936
  call_id: z.string(),
927
937
  name: z.string(),
928
938
  input: z.string(),
939
+ async: z.boolean().nullish(),
929
940
  status: z.literal('completed'),
930
941
  }),
931
942
  z.object({
@@ -1410,6 +1421,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1410
1421
  name: z.string(),
1411
1422
  arguments: z.string(),
1412
1423
  id: z.string(),
1424
+ async: z.boolean().nullish(),
1413
1425
  namespace: z.string().nullish(),
1414
1426
  }),
1415
1427
  z.object({
@@ -1418,6 +1430,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1418
1430
  name: z.string(),
1419
1431
  input: z.string(),
1420
1432
  id: z.string(),
1433
+ async: z.boolean().nullish(),
1421
1434
  }),
1422
1435
  z.object({
1423
1436
  type: z.literal('computer_call'),
@@ -80,6 +80,7 @@ import type {
80
80
  ResponsesReasoningProviderMetadata,
81
81
  ResponsesSourceDocumentProviderMetadata,
82
82
  ResponsesTextProviderMetadata,
83
+ ResponsesToolCallProviderMetadata,
83
84
  } from './openai-responses-provider-metadata';
84
85
 
85
86
  /**
@@ -242,6 +243,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
242
243
  allowedTools: openaiOptions?.allowedTools ?? undefined,
243
244
  toolNameMapping,
244
245
  customProviderToolNames,
246
+ supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling,
245
247
  });
246
248
 
247
249
  const { input, warnings: inputWarnings } =
@@ -254,6 +256,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
254
256
  ? 'developer'
255
257
  : modelCapabilities.systemMessageMode),
256
258
  providerOptionsName,
259
+ explicitMessageItemType: this.config.explicitMessageItemType,
257
260
  fileIdPrefixes: this.config.fileIdPrefixes,
258
261
  passThroughUnsupportedFiles:
259
262
  openaiOptions?.passThroughUnsupportedFiles ?? false,
@@ -910,8 +913,9 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
910
913
  providerMetadata: {
911
914
  [providerOptionsName]: {
912
915
  itemId: part.id,
916
+ ...(part.async != null && { async: part.async }),
913
917
  ...(part.namespace != null && { namespace: part.namespace }),
914
- },
918
+ } satisfies ResponsesToolCallProviderMetadata,
915
919
  },
916
920
  });
917
921
  break;
@@ -929,7 +933,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
929
933
  providerMetadata: {
930
934
  [providerOptionsName]: {
931
935
  itemId: part.id,
932
- },
936
+ ...(part.async != null && { async: part.async }),
937
+ } satisfies ResponsesToolCallProviderMetadata,
933
938
  },
934
939
  });
935
940
  break;
@@ -1242,6 +1247,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1242
1247
  toolSearchExecution?: 'server' | 'client';
1243
1248
  suppressInputStreaming?: boolean;
1244
1249
  bufferedInputDeltas?: string[];
1250
+ async?: boolean | null;
1245
1251
  }
1246
1252
  | undefined
1247
1253
  > = {};
@@ -1321,6 +1327,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1321
1327
  toolCallId: value.item.call_id,
1322
1328
  suppressInputStreaming,
1323
1329
  bufferedInputDeltas: suppressInputStreaming ? [] : undefined,
1330
+ async: value.item.async,
1324
1331
  };
1325
1332
 
1326
1333
  if (!suppressInputStreaming) {
@@ -1337,6 +1344,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1337
1344
  ongoingToolCalls[value.output_index] = {
1338
1345
  toolName,
1339
1346
  toolCallId: value.item.call_id,
1347
+ async: value.item.async,
1340
1348
  };
1341
1349
 
1342
1350
  controller.enqueue({
@@ -1620,10 +1628,15 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1620
1628
  providerMetadata: {
1621
1629
  [providerOptionsName]: {
1622
1630
  itemId: item.id,
1631
+ ...(item.async != null
1632
+ ? { async: item.async }
1633
+ : ongoingToolCall?.async != null
1634
+ ? { async: ongoingToolCall.async }
1635
+ : {}),
1623
1636
  ...(item.namespace != null && {
1624
1637
  namespace: item.namespace,
1625
1638
  }),
1626
- },
1639
+ } satisfies ResponsesToolCallProviderMetadata,
1627
1640
  },
1628
1641
  });
1629
1642
  };
@@ -1667,6 +1680,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1667
1680
  }
1668
1681
  });
1669
1682
  } else if (value.item.type === 'custom_tool_call') {
1683
+ const ongoingToolCall = ongoingToolCalls[value.output_index];
1670
1684
  ongoingToolCalls[value.output_index] = undefined;
1671
1685
  hasFunctionCall = true;
1672
1686
  const toolName = toolNameMapping.toCustomToolName(
@@ -1686,7 +1700,12 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1686
1700
  providerMetadata: {
1687
1701
  [providerOptionsName]: {
1688
1702
  itemId: value.item.id,
1689
- },
1703
+ ...(value.item.async != null
1704
+ ? { async: value.item.async }
1705
+ : ongoingToolCall?.async != null
1706
+ ? { async: ongoingToolCall.async }
1707
+ : {}),
1708
+ } satisfies ResponsesToolCallProviderMetadata,
1690
1709
  },
1691
1710
  });
1692
1711
  } else if (value.item.type === 'web_search_call') {
@@ -24,7 +24,12 @@ type AllowedToolResolution =
24
24
  | { supported: true; entry: OpenAIResponsesAllowedTool }
25
25
  | { supported: false; reason: string };
26
26
 
27
- type OpenAIToolOptions = {
27
+ export type OpenAIToolOptions = {
28
+ /**
29
+ * Whether the model can continue generating after calling this tool without
30
+ * waiting for its result.
31
+ */
32
+ async?: boolean;
28
33
  deferLoading?: boolean;
29
34
  namespace?: {
30
35
  name: string;
@@ -38,6 +43,7 @@ export async function prepareResponsesTools({
38
43
  allowedTools,
39
44
  toolNameMapping,
40
45
  customProviderToolNames,
46
+ supportsAsyncToolCalling = true,
41
47
  }: {
42
48
  tools: LanguageModelV3CallOptions['tools'];
43
49
  toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
@@ -47,6 +53,7 @@ export async function prepareResponsesTools({
47
53
  };
48
54
  toolNameMapping?: ToolNameMapping;
49
55
  customProviderToolNames?: Set<string>;
56
+ supportsAsyncToolCalling?: boolean;
50
57
  }): Promise<{
51
58
  tools?: Array<OpenAIResponsesTool>;
52
59
  toolChoice?:
@@ -124,6 +131,12 @@ export async function prepareResponsesTools({
124
131
  const openaiFunctionTool = prepareFunctionTool({
125
132
  tool,
126
133
  options: openaiOptions,
134
+ async: resolveAsyncToolOption({
135
+ value: openaiOptions?.async,
136
+ supportsAsyncToolCalling,
137
+ toolName: tool.name,
138
+ toolWarnings,
139
+ }),
127
140
  });
128
141
  const namespace = openaiOptions?.namespace;
129
142
 
@@ -355,6 +368,14 @@ export async function prepareResponsesTools({
355
368
  type: 'custom',
356
369
  name: args.name,
357
370
  description: args.description,
371
+ ...(resolveAsyncToolOption({
372
+ value: args.async,
373
+ supportsAsyncToolCalling,
374
+ toolName: args.name,
375
+ toolWarnings,
376
+ }) != null
377
+ ? { async: args.async }
378
+ : {}),
358
379
  format: args.format,
359
380
  });
360
381
  resolvedCustomProviderToolNames.add(args.name);
@@ -573,9 +594,11 @@ function toAllowedToolResolution(
573
594
  function prepareFunctionTool({
574
595
  tool,
575
596
  options,
597
+ async,
576
598
  }: {
577
599
  tool: LanguageModelV3FunctionTool;
578
600
  options: OpenAIToolOptions | undefined;
601
+ async: boolean | undefined;
579
602
  }): OpenAIResponsesFunctionTool {
580
603
  const deferLoading = options?.deferLoading;
581
604
 
@@ -584,11 +607,35 @@ function prepareFunctionTool({
584
607
  name: tool.name,
585
608
  description: tool.description,
586
609
  parameters: tool.inputSchema,
610
+ ...(async != null ? { async } : {}),
587
611
  ...(tool.strict != null ? { strict: tool.strict } : {}),
588
612
  ...(deferLoading != null ? { defer_loading: deferLoading } : {}),
589
613
  };
590
614
  }
591
615
 
616
+ function resolveAsyncToolOption({
617
+ value,
618
+ supportsAsyncToolCalling,
619
+ toolName,
620
+ toolWarnings,
621
+ }: {
622
+ value: boolean | undefined;
623
+ supportsAsyncToolCalling: boolean;
624
+ toolName: string;
625
+ toolWarnings: SharedV3Warning[];
626
+ }): boolean | undefined {
627
+ if (value !== true || supportsAsyncToolCalling) {
628
+ return value;
629
+ }
630
+
631
+ toolWarnings.push({
632
+ type: 'unsupported',
633
+ feature: `async tool calling for "${toolName}"`,
634
+ details: 'Async tool calling is only supported by GPT-6 and later models.',
635
+ });
636
+ return undefined;
637
+ }
638
+
592
639
  function mapShellEnvironment(environment: {
593
640
  type?: string;
594
641
  [key: string]: unknown;