@ai-sdk/openai 4.0.60 → 4.0.62

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.
@@ -273,6 +273,7 @@ export type OpenAIResponsesFunctionCall = {
273
273
  call_id: string;
274
274
  name: string;
275
275
  arguments: string;
276
+ async?: boolean;
276
277
  id?: string;
277
278
  namespace?: string;
278
279
  caller?: OpenAIResponsesToolCaller;
@@ -335,6 +336,7 @@ export type OpenAIResponsesCustomToolCall = {
335
336
  call_id: string;
336
337
  name: string;
337
338
  input: string;
339
+ async?: boolean;
338
340
  };
339
341
 
340
342
  export type OpenAIResponsesCustomToolCallOutput = {
@@ -523,6 +525,7 @@ export type OpenAIResponsesFunctionTool = {
523
525
  name: string;
524
526
  description: string | undefined;
525
527
  parameters: JSONSchema7;
528
+ async?: boolean;
526
529
  strict?: boolean;
527
530
  defer_loading?: boolean;
528
531
  allowed_callers?: Array<'direct' | 'programmatic'>;
@@ -623,7 +626,7 @@ export type OpenAIResponsesTool =
623
626
  output_compression: number | undefined;
624
627
  output_format: 'png' | 'jpeg' | 'webp' | undefined;
625
628
  partial_images: number | undefined;
626
- quality: 'auto' | 'low' | 'medium' | 'high' | undefined;
629
+ quality: 'auto' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | undefined;
627
630
  size:
628
631
  | 'auto'
629
632
  | '1024x1024'
@@ -663,6 +666,7 @@ export type OpenAIResponsesTool =
663
666
  type: 'custom';
664
667
  name: string;
665
668
  description?: string;
669
+ async?: boolean;
666
670
  format?:
667
671
  | {
668
672
  type: 'grammar';
@@ -944,6 +948,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
944
948
  call_id: z.string(),
945
949
  name: z.string(),
946
950
  arguments: z.string(),
951
+ async: z.boolean().nullish(),
947
952
  namespace: z.string().nullish(),
948
953
  caller: openaiResponsesToolCallerSchema.nullish(),
949
954
  }),
@@ -1021,6 +1026,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1021
1026
  call_id: z.string(),
1022
1027
  name: z.string(),
1023
1028
  input: z.string(),
1029
+ async: z.boolean().nullish(),
1024
1030
  }),
1025
1031
  z.object({
1026
1032
  type: z.literal('shell_call'),
@@ -1093,6 +1099,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1093
1099
  call_id: z.string(),
1094
1100
  name: z.string(),
1095
1101
  arguments: z.string(),
1102
+ async: z.boolean().nullish(),
1096
1103
  status: z.enum(['in_progress', 'completed', 'incomplete']),
1097
1104
  namespace: z.string().nullish(),
1098
1105
  caller: openaiResponsesToolCallerSchema.nullish(),
@@ -1105,6 +1112,7 @@ export const openaiResponsesChunkSchema = lazySchema(() =>
1105
1112
  call_id: z.string(),
1106
1113
  name: z.string(),
1107
1114
  input: z.string(),
1115
+ async: z.boolean().nullish(),
1108
1116
  status: z.literal('completed'),
1109
1117
  }),
1110
1118
  z.object({
@@ -1593,6 +1601,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1593
1601
  name: z.string(),
1594
1602
  arguments: z.string(),
1595
1603
  id: z.string(),
1604
+ async: z.boolean().nullish(),
1596
1605
  namespace: z.string().nullish(),
1597
1606
  caller: openaiResponsesToolCallerSchema.nullish(),
1598
1607
  }),
@@ -1604,6 +1613,7 @@ export const openaiResponsesResponseSchema = lazySchema(() =>
1604
1613
  name: z.string(),
1605
1614
  input: z.string(),
1606
1615
  id: z.string(),
1616
+ async: z.boolean().nullish(),
1607
1617
  }),
1608
1618
  openaiResponsesComputerCallSchema,
1609
1619
  z.object({
@@ -94,6 +94,7 @@ import type {
94
94
  ResponsesReasoningProviderMetadata,
95
95
  ResponsesSourceDocumentProviderMetadata,
96
96
  ResponsesTextProviderMetadata,
97
+ ResponsesToolCallProviderMetadata,
97
98
  } from './openai-responses-provider-metadata';
98
99
 
99
100
  /**
@@ -202,6 +203,11 @@ function mapComputerCallInput({
202
203
  };
203
204
  }
204
205
 
206
+ export const openaiResponsesSupportedUrls: Record<string, RegExp[]> = {
207
+ 'image/*': [/^https?:\/\/.*$/],
208
+ 'application/pdf': [/^https?:\/\/.*$/],
209
+ };
210
+
205
211
  export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
206
212
  readonly specificationVersion = 'v4';
207
213
 
@@ -231,33 +237,38 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
231
237
  this.config = config;
232
238
  }
233
239
 
234
- readonly supportedUrls: Record<string, RegExp[]> = {
235
- 'image/*': [/^https?:\/\/.*$/],
236
- 'application/pdf': [/^https?:\/\/.*$/],
237
- };
240
+ readonly supportedUrls = openaiResponsesSupportedUrls;
238
241
 
239
242
  get provider(): string {
240
243
  return this.config.provider;
241
244
  }
242
245
 
243
- protected async getArgs({
244
- maxOutputTokens,
245
- temperature,
246
- stopSequences,
247
- topP,
248
- topK,
249
- presencePenalty,
250
- frequencyPenalty,
251
- seed,
252
- prompt,
253
- reasoning,
254
- providerOptions,
255
- tools,
256
- toolChoice,
257
- responseFormat,
258
- }: LanguageModelV4CallOptions) {
246
+ static async prepareRequest({
247
+ modelId,
248
+ config,
249
+ options: {
250
+ maxOutputTokens,
251
+ temperature,
252
+ stopSequences,
253
+ topP,
254
+ topK,
255
+ presencePenalty,
256
+ frequencyPenalty,
257
+ seed,
258
+ prompt,
259
+ reasoning,
260
+ providerOptions,
261
+ tools,
262
+ toolChoice,
263
+ responseFormat,
264
+ },
265
+ }: {
266
+ modelId: OpenAIResponsesModelId;
267
+ config: OpenAIConfig;
268
+ options: LanguageModelV4CallOptions;
269
+ }) {
259
270
  const warnings: SharedV4Warning[] = [];
260
- const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
271
+ const modelCapabilities = getOpenAILanguageModelCapabilities(modelId);
261
272
 
262
273
  if (topK != null) {
263
274
  warnings.push({ type: 'unsupported', feature: 'topK' });
@@ -279,7 +290,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
279
290
  warnings.push({ type: 'unsupported', feature: 'stopSequences' });
280
291
  }
281
292
 
282
- const providerOptionsName = this.config.provider.includes('azure')
293
+ const providerOptionsName = config.provider.includes('azure')
283
294
  ? 'azure'
284
295
  : 'openai';
285
296
  let openaiOptions = await parseProviderOptions({
@@ -310,7 +321,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
310
321
  warnings.push({
311
322
  type: 'unsupported',
312
323
  feature: 'reasoningEffort',
313
- details: `${this.modelId} only supports the following reasoning efforts: ${modelCapabilities.supportedReasoningEfforts.join(', ')}`,
324
+ details: `${modelId} only supports the following reasoning efforts: ${modelCapabilities.supportedReasoningEfforts.join(', ')}`,
314
325
  });
315
326
  resolvedReasoningEffort = undefined;
316
327
  }
@@ -367,6 +378,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
367
378
  toolNameMapping,
368
379
  customProviderToolNames,
369
380
  outputSchemaToolNames,
381
+ supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling,
370
382
  });
371
383
 
372
384
  const { input, warnings: inputWarnings } =
@@ -379,7 +391,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
379
391
  ? 'developer'
380
392
  : modelCapabilities.systemMessageMode),
381
393
  providerOptionsName,
382
- fileIdPrefixes: this.config.fileIdPrefixes,
394
+ fileIdPrefixes: config.fileIdPrefixes,
383
395
  passThroughUnsupportedFiles:
384
396
  openaiOptions?.passThroughUnsupportedFiles ?? false,
385
397
  store: openaiOptions?.store ?? true,
@@ -490,7 +502,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
490
502
  }
491
503
 
492
504
  const baseArgs = {
493
- model: this.modelId,
505
+ model: modelId,
494
506
  input,
495
507
  temperature,
496
508
  top_p: topP,
@@ -717,6 +729,14 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
717
729
  };
718
730
  }
719
731
 
732
+ private getArgs(options: LanguageModelV4CallOptions) {
733
+ return OpenAIResponsesLanguageModel.prepareRequest({
734
+ modelId: this.modelId,
735
+ config: this.config,
736
+ options,
737
+ });
738
+ }
739
+
720
740
  async doGenerate(
721
741
  options: LanguageModelV4CallOptions,
722
742
  ): Promise<LanguageModelV4GenerateResult> {
@@ -1069,6 +1089,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1069
1089
  providerMetadata: {
1070
1090
  [providerOptionsName]: {
1071
1091
  itemId: part.id,
1092
+ ...(part.async != null && { async: part.async }),
1072
1093
  ...(part.namespace != null && { namespace: part.namespace }),
1073
1094
  ...(part.caller != null && {
1074
1095
  caller:
@@ -1079,7 +1100,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1079
1100
  }
1080
1101
  : part.caller,
1081
1102
  }),
1082
- },
1103
+ } satisfies ResponsesToolCallProviderMetadata,
1083
1104
  },
1084
1105
  });
1085
1106
  break;
@@ -1138,7 +1159,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1138
1159
  providerMetadata: {
1139
1160
  [providerOptionsName]: {
1140
1161
  itemId: part.id,
1141
- },
1162
+ ...(part.async != null && { async: part.async }),
1163
+ } satisfies ResponsesToolCallProviderMetadata,
1142
1164
  },
1143
1165
  });
1144
1166
  break;
@@ -1485,6 +1507,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1485
1507
  toolSearchExecution?: 'server' | 'client';
1486
1508
  suppressInputStreaming?: boolean;
1487
1509
  bufferedInputDeltas?: string[];
1510
+ async?: boolean | null;
1488
1511
  }
1489
1512
  | undefined
1490
1513
  > = {};
@@ -1578,6 +1601,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1578
1601
  toolCallId: value.item.call_id,
1579
1602
  suppressInputStreaming,
1580
1603
  bufferedInputDeltas: suppressInputStreaming ? [] : undefined,
1604
+ async: value.item.async,
1581
1605
  };
1582
1606
 
1583
1607
  if (!suppressInputStreaming) {
@@ -1594,6 +1618,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1594
1618
  ongoingToolCalls[value.output_index] = {
1595
1619
  toolName,
1596
1620
  toolCallId: value.item.call_id,
1621
+ async: value.item.async,
1597
1622
  };
1598
1623
 
1599
1624
  controller.enqueue({
@@ -1884,6 +1909,11 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1884
1909
  providerMetadata: {
1885
1910
  [providerOptionsName]: {
1886
1911
  itemId: item.id,
1912
+ ...(item.async != null
1913
+ ? { async: item.async }
1914
+ : ongoingToolCall?.async != null
1915
+ ? { async: ongoingToolCall.async }
1916
+ : {}),
1887
1917
  ...(item.namespace != null && {
1888
1918
  namespace: item.namespace,
1889
1919
  }),
@@ -1896,7 +1926,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1896
1926
  }
1897
1927
  : item.caller,
1898
1928
  }),
1899
- },
1929
+ } satisfies ResponsesToolCallProviderMetadata,
1900
1930
  },
1901
1931
  });
1902
1932
  };
@@ -1979,6 +2009,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1979
2009
  },
1980
2010
  });
1981
2011
  } else if (value.item.type === 'custom_tool_call') {
2012
+ const ongoingToolCall = ongoingToolCalls[value.output_index];
1982
2013
  ongoingToolCalls[value.output_index] = undefined;
1983
2014
  hasFunctionCall = true;
1984
2015
  const toolName = toolNameMapping.toCustomToolName(
@@ -1998,7 +2029,12 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
1998
2029
  providerMetadata: {
1999
2030
  [providerOptionsName]: {
2000
2031
  itemId: value.item.id,
2001
- },
2032
+ ...(value.item.async != null
2033
+ ? { async: value.item.async }
2034
+ : ongoingToolCall?.async != null
2035
+ ? { async: ongoingToolCall.async }
2036
+ : {}),
2037
+ } satisfies ResponsesToolCallProviderMetadata,
2002
2038
  },
2003
2039
  });
2004
2040
  } else if (value.item.type === 'web_search_call') {
@@ -33,6 +33,11 @@ type AllowedToolResolution =
33
33
 
34
34
  export type OpenAIToolOptions = {
35
35
  allowedCallers?: Array<'direct' | 'programmatic'>;
36
+ /**
37
+ * Whether the model can continue generating after calling this tool without
38
+ * waiting for its result.
39
+ */
40
+ async?: boolean;
36
41
  deferLoading?: boolean;
37
42
  outputSchema?: JSONObject;
38
43
  namespace?: {
@@ -48,6 +53,7 @@ export async function prepareResponsesTools({
48
53
  toolNameMapping,
49
54
  customProviderToolNames,
50
55
  outputSchemaToolNames,
56
+ supportsAsyncToolCalling = true,
51
57
  }: {
52
58
  tools: LanguageModelV4CallOptions['tools'];
53
59
  toolChoice: LanguageModelV4CallOptions['toolChoice'] | undefined;
@@ -58,6 +64,7 @@ export async function prepareResponsesTools({
58
64
  toolNameMapping?: ToolNameMapping;
59
65
  customProviderToolNames?: Set<string>;
60
66
  outputSchemaToolNames?: Set<string>;
67
+ supportsAsyncToolCalling?: boolean;
61
68
  }): Promise<{
62
69
  tools?: Array<OpenAIResponsesTool>;
63
70
  toolChoice?:
@@ -140,6 +147,12 @@ export async function prepareResponsesTools({
140
147
  const openaiFunctionTool = prepareFunctionTool({
141
148
  tool,
142
149
  options: openaiOptions,
150
+ async: resolveAsyncToolOption({
151
+ value: openaiOptions?.async,
152
+ supportsAsyncToolCalling,
153
+ toolName: tool.name,
154
+ toolWarnings,
155
+ }),
143
156
  });
144
157
  const namespace = openaiOptions?.namespace;
145
158
 
@@ -378,6 +391,14 @@ export async function prepareResponsesTools({
378
391
  type: 'custom',
379
392
  name: tool.name,
380
393
  description: args.description,
394
+ ...(resolveAsyncToolOption({
395
+ value: args.async,
396
+ supportsAsyncToolCalling,
397
+ toolName: tool.name,
398
+ toolWarnings,
399
+ }) != null
400
+ ? { async: args.async }
401
+ : {}),
381
402
  format: args.format,
382
403
  });
383
404
  resolvedCustomProviderToolNames.add(tool.name);
@@ -606,9 +627,11 @@ function toAllowedToolResolution(
606
627
  function prepareFunctionTool({
607
628
  tool,
608
629
  options,
630
+ async,
609
631
  }: {
610
632
  tool: LanguageModelV4FunctionTool;
611
633
  options: OpenAIToolOptions | undefined;
634
+ async: boolean | undefined;
612
635
  }): OpenAIResponsesFunctionTool {
613
636
  const deferLoading = options?.deferLoading;
614
637
 
@@ -617,6 +640,7 @@ function prepareFunctionTool({
617
640
  name: tool.name,
618
641
  description: tool.description,
619
642
  parameters: tool.inputSchema,
643
+ ...(async != null ? { async } : {}),
620
644
  ...(tool.strict != null ? { strict: tool.strict } : {}),
621
645
  ...(deferLoading != null ? { defer_loading: deferLoading } : {}),
622
646
  ...(options?.allowedCallers != null
@@ -628,6 +652,29 @@ function prepareFunctionTool({
628
652
  };
629
653
  }
630
654
 
655
+ function resolveAsyncToolOption({
656
+ value,
657
+ supportsAsyncToolCalling,
658
+ toolName,
659
+ toolWarnings,
660
+ }: {
661
+ value: boolean | undefined;
662
+ supportsAsyncToolCalling: boolean;
663
+ toolName: string;
664
+ toolWarnings: SharedV4Warning[];
665
+ }): boolean | undefined {
666
+ if (value !== true || supportsAsyncToolCalling) {
667
+ return value;
668
+ }
669
+
670
+ toolWarnings.push({
671
+ type: 'unsupported',
672
+ feature: `async tool calling for "${toolName}"`,
673
+ details: 'Async tool calling is only supported by GPT-6 and later models.',
674
+ });
675
+ return undefined;
676
+ }
677
+
631
678
  function mapShellEnvironment(environment: {
632
679
  type?: string;
633
680
  [key: string]: unknown;
@@ -31,6 +31,22 @@ export type OpenaiResponsesProviderMetadata = {
31
31
  openai: ResponsesProviderMetadata;
32
32
  };
33
33
 
34
+ export type ResponsesToolCallProviderMetadata = {
35
+ itemId: string;
36
+ async?: boolean;
37
+ namespace?: string;
38
+ caller?:
39
+ | { type: 'direct' }
40
+ | {
41
+ type: 'program';
42
+ callerId: string;
43
+ };
44
+ };
45
+
46
+ export type OpenaiResponsesToolCallProviderMetadata = {
47
+ openai: ResponsesToolCallProviderMetadata;
48
+ };
49
+
34
50
  export type ResponsesCompactionProviderMetadata = {
35
51
  type: 'compaction';
36
52
  itemId: string;
@@ -9,6 +9,7 @@ export const customArgsSchema = lazySchema(() =>
9
9
  zodSchema(
10
10
  z.object({
11
11
  description: z.string().optional(),
12
+ async: z.boolean().optional(),
12
13
  format: z
13
14
  .union([
14
15
  z.object({
@@ -35,6 +36,12 @@ export const customToolFactory = createProviderDefinedToolFactory<
35
36
  */
36
37
  description?: string;
37
38
 
39
+ /**
40
+ * Whether the model can continue generating after calling this tool
41
+ * without waiting for its result.
42
+ */
43
+ async?: boolean;
44
+
38
45
  /**
39
46
  * The output format specification for the tool.
40
47
  * Omit for unconstrained text output.
@@ -23,7 +23,9 @@ export const imageGenerationArgsSchema = lazySchema(() =>
23
23
  outputCompression: z.number().int().min(0).max(100).optional(),
24
24
  outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(),
25
25
  partialImages: z.number().int().min(0).max(3).optional(),
26
- quality: z.enum(['auto', 'low', 'medium', 'high']).optional(),
26
+ quality: z
27
+ .enum(['auto', 'low', 'medium', 'high', 'xhigh', 'max'])
28
+ .optional(),
27
29
  size: z
28
30
  .union([
29
31
  z.enum(['1024x1024', '1024x1536', '1536x1024', 'auto']),
@@ -101,9 +103,10 @@ type ImageGenerationArgs = {
101
103
 
102
104
  /**
103
105
  * The quality of the generated image.
104
- * One of low, medium, high, or auto. Default: auto.
106
+ * One of low, medium, high, xhigh, max, or auto. Default: auto.
107
+ * xhigh and max are supported by GPT Image 2.5 models.
105
108
  */
106
- quality?: 'auto' | 'low' | 'medium' | 'high';
109
+ quality?: 'auto' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
107
110
 
108
111
  /**
109
112
  * The size of the generated image.