@ai-sdk/openai 3.0.108 → 3.0.110

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.
@@ -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
  /**
@@ -186,6 +187,23 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
186
187
  const isReasoningModel =
187
188
  openaiOptions?.forceReasoning ?? modelCapabilities.isReasoningModel;
188
189
 
190
+ let resolvedReasoningEffort = openaiOptions?.reasoningEffort;
191
+
192
+ if (
193
+ resolvedReasoningEffort != null &&
194
+ modelCapabilities.supportedReasoningEfforts != null &&
195
+ !modelCapabilities.supportedReasoningEfforts.includes(
196
+ resolvedReasoningEffort,
197
+ )
198
+ ) {
199
+ warnings.push({
200
+ type: 'unsupported',
201
+ feature: 'reasoningEffort',
202
+ details: `${this.modelId} only supports the following reasoning efforts: ${modelCapabilities.supportedReasoningEfforts.join(', ')}`,
203
+ });
204
+ resolvedReasoningEffort = undefined;
205
+ }
206
+
189
207
  if (openaiOptions?.conversation && openaiOptions?.previousResponseId) {
190
208
  warnings.push({
191
209
  type: 'unsupported',
@@ -225,6 +243,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
225
243
  allowedTools: openaiOptions?.allowedTools ?? undefined,
226
244
  toolNameMapping,
227
245
  customProviderToolNames,
246
+ supportsAsyncToolCalling: modelCapabilities.supportsAsyncToolCalling,
228
247
  });
229
248
 
230
249
  const { input, warnings: inputWarnings } =
@@ -255,6 +274,28 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
255
274
 
256
275
  warnings.push(...inputWarnings);
257
276
 
277
+ const reasoningEffortUpdate = openaiOptions?.reasoningEffortUpdate;
278
+ const configurationUpdateIsSupported =
279
+ reasoningEffortUpdate == null ||
280
+ (modelCapabilities.supportsConfigurationUpdate &&
281
+ openaiOptions?.reasoningMode !== 'pro' &&
282
+ openaiOptions?.truncation !== 'auto');
283
+
284
+ if (reasoningEffortUpdate != null && !configurationUpdateIsSupported) {
285
+ warnings.push({
286
+ type: 'unsupported',
287
+ feature: 'reasoningEffortUpdate',
288
+ details: !modelCapabilities.supportsConfigurationUpdate
289
+ ? 'reasoningEffortUpdate is only supported by GPT-6 and later models'
290
+ : 'reasoningEffortUpdate requires standard reasoning mode without automatic truncation',
291
+ });
292
+ } else if (reasoningEffortUpdate != null) {
293
+ input.unshift({
294
+ type: 'configuration_update',
295
+ reasoning: { effort: reasoningEffortUpdate },
296
+ });
297
+ }
298
+
258
299
  const strictJsonSchema = openaiOptions?.strictJsonSchema ?? true;
259
300
 
260
301
  let include: OpenAIResponsesIncludeOptions = openaiOptions?.include;
@@ -361,13 +402,13 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
361
402
 
362
403
  // model-specific settings:
363
404
  ...(isReasoningModel &&
364
- (openaiOptions?.reasoningEffort != null ||
405
+ (resolvedReasoningEffort != null ||
365
406
  openaiOptions?.reasoningSummary != null ||
366
407
  openaiOptions?.reasoningMode != null ||
367
408
  openaiOptions?.reasoningContext != null) && {
368
409
  reasoning: {
369
- ...(openaiOptions?.reasoningEffort != null && {
370
- effort: openaiOptions.reasoningEffort,
410
+ ...(resolvedReasoningEffort != null && {
411
+ effort: resolvedReasoningEffort,
371
412
  }),
372
413
  ...(openaiOptions?.reasoningSummary != null && {
373
414
  summary: openaiOptions.reasoningSummary,
@@ -382,6 +423,19 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
382
423
  }),
383
424
  };
384
425
 
426
+ if (
427
+ modelCapabilities.supportsConfigurationUpdate &&
428
+ baseArgs.prompt_cache_retention != null
429
+ ) {
430
+ baseArgs.prompt_cache_retention = undefined;
431
+ warnings.push({
432
+ type: 'unsupported',
433
+ feature: 'promptCacheRetention',
434
+ details:
435
+ 'promptCacheRetention is not supported by GPT-6 and later models; use promptCacheOptions instead',
436
+ });
437
+ }
438
+
385
439
  // remove unsupported settings for reasoning models
386
440
  // see https://platform.openai.com/docs/guides/reasoning#limitations
387
441
  if (isReasoningModel) {
@@ -411,6 +465,26 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
411
465
  });
412
466
  }
413
467
  }
468
+
469
+ if (
470
+ modelCapabilities.supportedReasoningEfforts != null &&
471
+ (baseArgs.top_logprobs != null ||
472
+ baseArgs.include?.includes('message.output_text.logprobs'))
473
+ ) {
474
+ baseArgs.top_logprobs = undefined;
475
+ const filteredInclude = baseArgs.include?.filter(
476
+ value => value !== 'message.output_text.logprobs',
477
+ );
478
+ baseArgs.include =
479
+ filteredInclude != null && filteredInclude.length > 0
480
+ ? filteredInclude
481
+ : undefined;
482
+ warnings.push({
483
+ type: 'unsupported',
484
+ feature: 'logprobs',
485
+ details: 'logprobs is not supported for reasoning models',
486
+ });
487
+ }
414
488
  } else {
415
489
  if (openaiOptions?.reasoningEffort != null) {
416
490
  warnings.push({
@@ -838,8 +912,9 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
838
912
  providerMetadata: {
839
913
  [providerOptionsName]: {
840
914
  itemId: part.id,
915
+ ...(part.async != null && { async: part.async }),
841
916
  ...(part.namespace != null && { namespace: part.namespace }),
842
- },
917
+ } satisfies ResponsesToolCallProviderMetadata,
843
918
  },
844
919
  });
845
920
  break;
@@ -857,7 +932,8 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
857
932
  providerMetadata: {
858
933
  [providerOptionsName]: {
859
934
  itemId: part.id,
860
- },
935
+ ...(part.async != null && { async: part.async }),
936
+ } satisfies ResponsesToolCallProviderMetadata,
861
937
  },
862
938
  });
863
939
  break;
@@ -1170,6 +1246,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1170
1246
  toolSearchExecution?: 'server' | 'client';
1171
1247
  suppressInputStreaming?: boolean;
1172
1248
  bufferedInputDeltas?: string[];
1249
+ async?: boolean | null;
1173
1250
  }
1174
1251
  | undefined
1175
1252
  > = {};
@@ -1249,6 +1326,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1249
1326
  toolCallId: value.item.call_id,
1250
1327
  suppressInputStreaming,
1251
1328
  bufferedInputDeltas: suppressInputStreaming ? [] : undefined,
1329
+ async: value.item.async,
1252
1330
  };
1253
1331
 
1254
1332
  if (!suppressInputStreaming) {
@@ -1265,6 +1343,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1265
1343
  ongoingToolCalls[value.output_index] = {
1266
1344
  toolName,
1267
1345
  toolCallId: value.item.call_id,
1346
+ async: value.item.async,
1268
1347
  };
1269
1348
 
1270
1349
  controller.enqueue({
@@ -1548,10 +1627,15 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1548
1627
  providerMetadata: {
1549
1628
  [providerOptionsName]: {
1550
1629
  itemId: item.id,
1630
+ ...(item.async != null
1631
+ ? { async: item.async }
1632
+ : ongoingToolCall?.async != null
1633
+ ? { async: ongoingToolCall.async }
1634
+ : {}),
1551
1635
  ...(item.namespace != null && {
1552
1636
  namespace: item.namespace,
1553
1637
  }),
1554
- },
1638
+ } satisfies ResponsesToolCallProviderMetadata,
1555
1639
  },
1556
1640
  });
1557
1641
  };
@@ -1595,6 +1679,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1595
1679
  }
1596
1680
  });
1597
1681
  } else if (value.item.type === 'custom_tool_call') {
1682
+ const ongoingToolCall = ongoingToolCalls[value.output_index];
1598
1683
  ongoingToolCalls[value.output_index] = undefined;
1599
1684
  hasFunctionCall = true;
1600
1685
  const toolName = toolNameMapping.toCustomToolName(
@@ -1614,7 +1699,12 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV3 {
1614
1699
  providerMetadata: {
1615
1700
  [providerOptionsName]: {
1616
1701
  itemId: value.item.id,
1617
- },
1702
+ ...(value.item.async != null
1703
+ ? { async: value.item.async }
1704
+ : ongoingToolCall?.async != null
1705
+ ? { async: ongoingToolCall.async }
1706
+ : {}),
1707
+ } satisfies ResponsesToolCallProviderMetadata,
1618
1708
  },
1619
1709
  });
1620
1710
  } else if (value.item.type === 'web_search_call') {
@@ -260,10 +260,23 @@ export const openaiLanguageModelResponsesOptionsSchema = lazySchema(() =>
260
260
  * Reasoning effort for reasoning models. Defaults to `medium`. If you use
261
261
  * `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
262
262
  * GPT-5.6 supports 'none' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'.
263
+ * GPT-6 and later models support 'low' | 'medium' | 'high' | 'xhigh' | 'max'.
263
264
  * Supported values vary by model.
264
265
  */
265
266
  reasoningEffort: z.string().nullish(),
266
267
 
268
+ /**
269
+ * Updates the reasoning effort for GPT-6 and later models starting with this response
270
+ * without changing the request-level reasoning effort. This preserves the
271
+ * request prefix for prompt caching.
272
+ *
273
+ * Only supported by GPT-6 and later models in standard, single-agent mode. Cannot be
274
+ * combined with automatic truncation.
275
+ */
276
+ reasoningEffortUpdate: z
277
+ .enum(['low', 'medium', 'high', 'xhigh', 'max'])
278
+ .optional(),
279
+
267
280
  /**
268
281
  * Controls how much model work GPT-5.6 performs before returning a final answer.
269
282
  * `standard` is the default. `pro` increases quality, latency, and token usage.
@@ -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;
@@ -31,6 +31,16 @@ 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
+ };
39
+
40
+ export type OpenaiResponsesToolCallProviderMetadata = {
41
+ openai: ResponsesToolCallProviderMetadata;
42
+ };
43
+
34
44
  export type ResponsesTextProviderMetadata = {
35
45
  itemId: string;
36
46
  phase?: 'commentary' | 'final_answer' | null;
@@ -10,6 +10,7 @@ export const customArgsSchema = lazySchema(() =>
10
10
  z.object({
11
11
  name: z.string(),
12
12
  description: z.string().optional(),
13
+ async: z.boolean().optional(),
13
14
  format: z
14
15
  .union([
15
16
  z.object({
@@ -41,6 +42,12 @@ export const customToolFactory = createProviderToolFactory<
41
42
  */
42
43
  description?: string;
43
44
 
45
+ /**
46
+ * Whether the model can continue generating after calling this tool
47
+ * without waiting for its result.
48
+ */
49
+ async?: boolean;
50
+
44
51
  /**
45
52
  * The output format specification for the tool.
46
53
  * Omit for unconstrained text output.
@@ -22,7 +22,9 @@ export const imageGenerationArgsSchema = lazySchema(() =>
22
22
  outputCompression: z.number().int().min(0).max(100).optional(),
23
23
  outputFormat: z.enum(['png', 'jpeg', 'webp']).optional(),
24
24
  partialImages: z.number().int().min(0).max(3).optional(),
25
- quality: z.enum(['auto', 'low', 'medium', 'high']).optional(),
25
+ quality: z
26
+ .enum(['auto', 'low', 'medium', 'high', 'xhigh', 'max'])
27
+ .optional(),
26
28
  size: z
27
29
  .enum(['1024x1024', '1024x1536', '1536x1024', 'auto'])
28
30
  .optional(),
@@ -92,9 +94,10 @@ type ImageGenerationArgs = {
92
94
 
93
95
  /**
94
96
  * The quality of the generated image.
95
- * One of low, medium, high, or auto. Default: auto.
97
+ * One of low, medium, high, xhigh, max, or auto. Default: auto.
98
+ * xhigh and max are supported by GPT Image 2.5 models.
96
99
  */
97
- quality?: 'auto' | 'low' | 'medium' | 'high';
100
+ quality?: 'auto' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
98
101
 
99
102
  /**
100
103
  * The size of the generated image.