@ai-sdk/openai 4.0.59 → 4.0.61

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.
@@ -192,9 +192,23 @@ The following provider options are available:
192
192
 
193
193
  <Note>
194
194
  Supported reasoning efforts vary by model. GPT-5.6 supports `'none'`, `'low'`,
195
- `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
195
+ `'medium'`, `'high'`, `'xhigh'`, and `'max'`. GPT-6 and later models support
196
+ `'low'`, `'medium'`, `'high'`, `'xhigh'`, and `'max'`.
196
197
  </Note>
197
198
 
199
+ <Note type="warning">
200
+ GPT-6 and later models do not support `temperature`, `topP`, `logprobs`, or
201
+ the legacy `promptCacheRetention` option. The provider removes these settings
202
+ and returns a warning. Use the Responses API for GPT-6 tool calling.
203
+ </Note>
204
+
205
+ - **reasoningEffortUpdate** _'low' | 'medium' | 'high' | 'xhigh' | 'max'_
206
+ Updates the reasoning effort for GPT-6 and later models starting with the
207
+ current response without changing the request-level effort. Use this with
208
+ `previousResponseId` to preserve the original prompt prefix for caching.
209
+ Configuration updates require standard, single-agent mode and cannot be
210
+ combined with automatic compaction or automatic truncation.
211
+
198
212
  - **reasoningMode** _'standard' | 'pro'_
199
213
  Controls how much model work GPT-5.6 performs before returning a final answer. `'standard'` is the default. Use `'pro'` for difficult tasks where quality matters more than latency and token usage.
200
214
 
@@ -302,6 +316,57 @@ The following OpenAI-specific metadata may be returned:
302
316
  - **reasoningContext** _(optional)_
303
317
  Effective persisted-reasoning context returned by GPT-5.6 (`'current_turn'` or `'all_turns'`).
304
318
 
319
+ #### Changing Reasoning Effort Mid-Conversation
320
+
321
+ GPT-6 and later models can change reasoning effort between responses without
322
+ changing the request-level `reasoning` setting. The provider sends
323
+ `reasoningEffortUpdate` as an OpenAI `configuration_update` input item before
324
+ the next user message. Keeping the request-level effort unchanged preserves the
325
+ original prompt prefix for prompt caching.
326
+
327
+ ```ts highlight="8,26,32"
328
+ import {
329
+ openai,
330
+ type OpenAILanguageModelResponsesOptions,
331
+ type OpenaiResponsesProviderMetadata,
332
+ } from '@ai-sdk/openai';
333
+ import { generateText } from 'ai';
334
+
335
+ const first = await generateText({
336
+ model: openai.responses('gpt-6-astra'),
337
+ reasoning: 'low',
338
+ prompt: 'Draft a database migration plan.',
339
+ });
340
+
341
+ const metadata = first.finalStep.providerMetadata as
342
+ | OpenaiResponsesProviderMetadata
343
+ | undefined;
344
+ const previousResponseId = metadata?.openai.responseId;
345
+
346
+ if (!previousResponseId) {
347
+ throw new Error('OpenAI did not return a response ID.');
348
+ }
349
+
350
+ const second = await generateText({
351
+ model: openai.responses('gpt-6-astra'),
352
+ reasoning: 'low',
353
+ prompt: 'Analyze the failure modes and propose rollback steps.',
354
+ providerOptions: {
355
+ openai: {
356
+ previousResponseId,
357
+ reasoningEffortUpdate: 'high',
358
+ } satisfies OpenAILanguageModelResponsesOptions,
359
+ },
360
+ });
361
+ ```
362
+
363
+ The response metadata continues to report the request-level reasoning effort,
364
+ not the effective effort selected by `reasoningEffortUpdate`. Configuration
365
+ updates are not supported with `reasoningMode: 'pro'`,
366
+ `contextManagement`, or `truncation: 'auto'`. Explicit compaction with
367
+ `compactionTrigger` remains supported; send a new `reasoningEffortUpdate` after
368
+ compaction when the effort should change again.
369
+
305
370
  #### Reasoning Output
306
371
 
307
372
  For reasoning models like `gpt-5`, you can enable reasoning summaries to see the model's thought process. Different models support different summarizers—for example, `o4-mini` supports detailed summaries. Set `reasoningSummary: "auto"` to automatically receive the richest level available. When `reasoningEffort` is set to a value other than `'none'`, the OpenAI Responses provider defaults `reasoningSummary` to `'detailed'`; set `reasoningSummary: null` to omit reasoning summaries.
@@ -463,6 +528,55 @@ metadata on tool-call parts. The SDK uses `providerMetadata.openai.namespace` or
463
528
  `providerOptions.openai.namespace` to round-trip the namespace back to OpenAI on
464
529
  subsequent requests.
465
530
 
531
+ #### Async Tool Calling
532
+
533
+ GPT-6 Astra and later Responses models support
534
+ [async tool calling](https://developers.openai.com/api/docs/guides/async-tool-calling).
535
+ An async tool lets the model continue generating independent output after issuing
536
+ the call instead of waiting for its result. Your application still executes the
537
+ tool and sends its result in a later request using the original tool call ID.
538
+
539
+ Enable async calling on a function tool with `providerOptions.openai.async`:
540
+
541
+ ```ts
542
+ import { openai, type OpenAIToolOptions } from '@ai-sdk/openai';
543
+ import { generateText, tool } from 'ai';
544
+ import { z } from 'zod';
545
+
546
+ const result = await generateText({
547
+ model: openai.responses('gpt-6-astra'),
548
+ tools: {
549
+ getWeather: tool({
550
+ description: 'Get the weather for a city.',
551
+ inputSchema: z.object({ city: z.string() }),
552
+ outputSchema: z.object({
553
+ city: z.string(),
554
+ temperatureC: z.number(),
555
+ }),
556
+ providerOptions: {
557
+ openai: { async: true } satisfies OpenAIToolOptions,
558
+ },
559
+ }),
560
+ },
561
+ prompt:
562
+ 'Start the weather lookup for Paris, then list three general packing essentials without waiting.',
563
+ });
564
+ ```
565
+
566
+ The generated tool call exposes the provider marker as
567
+ `providerMetadata.openai.async`. Use `providerMetadata.openai.responseId` as the
568
+ next request's `previousResponseId`, and submit the result in a tool message with
569
+ the original `toolCallId`.
570
+
571
+ With `streamText`, OpenAI can continue streaming text after the completed
572
+ `tool-call` part. Use the tool's `onInputAvailable` callback to start work as soon
573
+ as that part arrives. If `execute` returns the same already-running promise, tool
574
+ execution overlaps the rest of the model stream. Omit `execute` when the job
575
+ should outlive the current generation and submit its result in a later request.
576
+
577
+ Async calling applies to directly called function and custom tools. It does not
578
+ apply to hosted tools and should not be combined with programmatic tool calling.
579
+
466
580
  #### Programmatic Tool Calling
467
581
 
468
582
  OpenAI Programmatic Tool Calling lets supported Responses models generate and run
@@ -1970,27 +2084,37 @@ import { openai } from '@ai-sdk/openai';
1970
2084
  import {
1971
2085
  experimental_getBatchResults as getBatchResults,
1972
2086
  experimental_getBatchStatus as getBatchStatus,
1973
- experimental_startTextBatch as startTextBatch,
2087
+ experimental_startBatch as startBatch,
1974
2088
  } from 'ai';
1975
2089
  import { setTimeout } from 'node:timers/promises';
1976
2090
 
1977
- const model = openai('gpt-4.1-nano');
2091
+ const model = 'gpt-4.1-nano';
1978
2092
 
1979
- const batch = await startTextBatch({
1980
- model,
2093
+ const batch = await startBatch({
2094
+ provider: openai,
1981
2095
  requests: [
1982
- { id: 'capital-france', prompt: 'What is the capital of France?' },
1983
- { id: 'capital-germany', prompt: 'What is the capital of Germany?' },
2096
+ {
2097
+ id: 'capital-france',
2098
+ type: 'text',
2099
+ model,
2100
+ prompt: 'What is the capital of France?',
2101
+ },
2102
+ {
2103
+ id: 'capital-germany',
2104
+ type: 'text',
2105
+ model,
2106
+ prompt: 'What is the capital of Germany?',
2107
+ },
1984
2108
  ],
1985
2109
  });
1986
2110
 
1987
2111
  let status = batch.status;
1988
2112
  while (status === 'pending') {
1989
2113
  await setTimeout(60_000);
1990
- ({ status } = await getBatchStatus({ model, batch }));
2114
+ ({ status } = await getBatchStatus({ provider: openai, batch }));
1991
2115
  }
1992
2116
 
1993
- for await (const item of getBatchResults({ model, batch })) {
2117
+ for await (const item of getBatchResults({ provider: openai, batch })) {
1994
2118
  if (item.status === 'succeeded') {
1995
2119
  console.log(item.id, item.text);
1996
2120
  } else {
@@ -1999,11 +2123,15 @@ for await (const item of getBatchResults({ model, batch })) {
1999
2123
  }
2000
2124
  ```
2001
2125
 
2002
- `startTextBatch` returns a serializable batch reference. Persist this reference
2126
+ `startBatch` returns a serializable batch reference. Persist this reference
2003
2127
  to check the batch status or retrieve its results from another process. Results
2004
2128
  can arrive in a different order from the input requests, so match each result by
2005
2129
  its `id`.
2006
2130
 
2131
+ Each request specifies its `type` and `model`. OpenAI requires every text
2132
+ request in a batch to use the same model and throws before submission when the
2133
+ models differ.
2134
+
2007
2135
  #### Webhooks
2008
2136
 
2009
2137
  <Note>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.59",
3
+ "version": "4.0.61",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -35,8 +35,8 @@
35
35
  }
36
36
  },
37
37
  "dependencies": {
38
- "@ai-sdk/provider": "4.0.10",
39
- "@ai-sdk/provider-utils": "5.0.36"
38
+ "@ai-sdk/provider": "4.0.11",
39
+ "@ai-sdk/provider-utils": "5.0.37"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@ai-sdk/test-server": "2.0.1",
@@ -118,10 +118,25 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
118
118
  const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
119
119
 
120
120
  // AI SDK reasoning values map directly to the OpenAI reasoning values.
121
- const resolvedReasoningEffort =
121
+ let resolvedReasoningEffort =
122
122
  openaiOptions.reasoningEffort ??
123
123
  (isCustomReasoning(reasoning) ? reasoning : undefined);
124
124
 
125
+ if (
126
+ resolvedReasoningEffort != null &&
127
+ modelCapabilities.supportedReasoningEfforts != null &&
128
+ !modelCapabilities.supportedReasoningEfforts.includes(
129
+ resolvedReasoningEffort,
130
+ )
131
+ ) {
132
+ warnings.push({
133
+ type: 'unsupported',
134
+ feature: 'reasoningEffort',
135
+ details: `${this.modelId} only supports the following reasoning efforts: ${modelCapabilities.supportedReasoningEfforts.join(', ')}`,
136
+ });
137
+ resolvedReasoningEffort = undefined;
138
+ }
139
+
125
140
  const isReasoningModel =
126
141
  openaiOptions.forceReasoning ?? modelCapabilities.isReasoningModel;
127
142
 
@@ -207,6 +222,19 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
207
222
  messages,
208
223
  };
209
224
 
225
+ if (
226
+ modelCapabilities.supportedReasoningEfforts != null &&
227
+ baseArgs.prompt_cache_retention != null
228
+ ) {
229
+ baseArgs.prompt_cache_retention = undefined;
230
+ warnings.push({
231
+ type: 'unsupported',
232
+ feature: 'promptCacheRetention',
233
+ details:
234
+ 'promptCacheRetention is not supported by GPT-6 and later models; use promptCacheOptions instead',
235
+ });
236
+ }
237
+
210
238
  // remove unsupported settings for reasoning models
211
239
  // see https://platform.openai.com/docs/guides/reasoning#limitations
212
240
  if (isReasoningModel) {
package/src/index.ts CHANGED
@@ -44,6 +44,7 @@ export type {
44
44
  OpenaiResponsesCompactionProviderMetadata,
45
45
  OpenaiResponsesProviderMetadata,
46
46
  OpenaiResponsesReasoningProviderMetadata,
47
+ OpenaiResponsesToolCallProviderMetadata,
47
48
  OpenaiResponsesTextProviderMetadata,
48
49
  OpenaiResponsesSourceDocumentProviderMetadata,
49
50
  } from './responses/openai-responses-provider-metadata';
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  InvalidArgumentError,
3
3
  InvalidResponseDataError,
4
- type Experimental_BatchLanguageModelV4 as BatchLanguageModelV4,
5
- type Experimental_BatchV4StartOptions as BatchV4StartOptions,
4
+ type Experimental_BatchV4 as BatchV4,
6
5
  type Experimental_BatchV4StartResult as BatchV4StartResult,
7
6
  type Experimental_BatchV4Error as BatchV4Error,
8
7
  type Experimental_BatchV4ItemResult as BatchV4ItemResult,
9
8
  type Experimental_BatchV4OperationOptions as BatchV4OperationOptions,
10
9
  type Experimental_BatchV4Status as BatchV4Status,
10
+ type Experimental_TextBatchV4ItemResult as TextBatchV4ItemResult,
11
+ type Experimental_BatchV4StartOptions as BatchV4StartOptions,
12
+ type Experimental_TextBatchV4Request as TextBatchV4Request,
11
13
  type LanguageModelV4GenerateResult,
12
14
  type SharedV4ProviderMetadata,
13
15
  type SharedV4Warning,
@@ -24,8 +26,6 @@ import {
24
26
  postJsonToApi,
25
27
  postToApi,
26
28
  safeValidateTypes,
27
- WORKFLOW_DESERIALIZE,
28
- WORKFLOW_SERIALIZE,
29
29
  zodSchema,
30
30
  type InferSchema,
31
31
  } from '@ai-sdk/provider-utils';
@@ -34,10 +34,7 @@ import {
34
34
  openaiErrorDataSchema,
35
35
  openaiFailedResponseHandler,
36
36
  } from './openai-error';
37
- import {
38
- prepareOpenAIConfigForWorkflowDeserialize,
39
- type OpenAIConfig,
40
- } from './openai-config';
37
+ import type { OpenAIConfig } from './openai-config';
41
38
  import { openaiFilesResponseSchema } from './files/openai-files-api';
42
39
  import { convertOpenAIResponsesUsage } from './responses/convert-openai-responses-usage';
43
40
  import { mapOpenAIResponseFinishReason } from './responses/map-openai-responses-finish-reason';
@@ -48,6 +45,7 @@ import {
48
45
  import {
49
46
  mapWebSearchOutput,
50
47
  OpenAIResponsesLanguageModel,
48
+ openaiResponsesSupportedUrls,
51
49
  } from './responses/openai-responses-language-model';
52
50
  import type { OpenAIResponsesModelId } from './responses/openai-responses-language-model-options';
53
51
  import type { ResponsesReasoningProviderMetadata } from './responses/openai-responses-provider-metadata';
@@ -73,16 +71,18 @@ const openaiBatchProviderOptionsSchema = lazySchema(() =>
73
71
  ),
74
72
  );
75
73
 
76
- type OpenAIBatchRequest = Parameters<
77
- BatchLanguageModelV4['experimental_doStartBatch']
78
- >[0]['requests'][number];
74
+ type OpenAIBatchModelIds = {
75
+ readonly text: OpenAIResponsesModelId;
76
+ };
77
+
78
+ type OpenAIBatchRequest = TextBatchV4Request<OpenAIResponsesModelId>;
79
79
 
80
80
  type OpenAIBatchPreparedRequest = {
81
81
  body: unknown;
82
82
  warnings: SharedV4Warning[];
83
83
  };
84
84
 
85
- type OpenAIBatchResponseConversion =
85
+ type OpenAIBatchResultConversion =
86
86
  | { success: true; result: LanguageModelV4GenerateResult }
87
87
  | { success: false; error: BatchV4Error };
88
88
 
@@ -143,20 +143,25 @@ const openaiBatchResultLineSchema = lazySchema(() =>
143
143
 
144
144
  type OpenAIBatchResultLine = InferSchema<typeof openaiBatchResultLineSchema>;
145
145
 
146
- class OpenAIResponsesBatch {
146
+ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
147
+ readonly specificationVersion = 'v4' as const;
148
+ readonly provider: string;
149
+ readonly supportedUrls = openaiResponsesSupportedUrls;
150
+
147
151
  constructor(
148
152
  private readonly options: {
149
- modelId: string;
153
+ provider: string;
150
154
  config: OpenAIConfig;
151
- prepareRequest: (
152
- request: OpenAIBatchRequest,
153
- ) => PromiseLike<OpenAIBatchPreparedRequest>;
154
155
  },
155
- ) {}
156
+ ) {
157
+ this.provider = options.provider;
158
+ }
156
159
 
157
- async startBatch(
158
- options: BatchV4StartOptions<OpenAIBatchRequest>,
160
+ async doStartBatch(
161
+ options: BatchV4StartOptions<OpenAIBatchModelIds>,
159
162
  ): Promise<BatchV4StartResult> {
163
+ validateSingleModel(options.requests);
164
+
160
165
  const fileParts: string[] = [];
161
166
  const warnings: BatchV4StartResult['warnings'] =
162
167
  options.webhookUrl == null
@@ -180,7 +185,7 @@ class OpenAIResponsesBatch {
180
185
  openaiBatchInputFileDefaultExpiresAfterSeconds;
181
186
 
182
187
  for (const request of options.requests) {
183
- const preparedRequest = await this.options.prepareRequest(request);
188
+ const preparedRequest = await this.prepareRequest(request);
184
189
 
185
190
  fileParts.push(
186
191
  JSON.stringify({
@@ -285,7 +290,7 @@ class OpenAIResponsesBatch {
285
290
  }
286
291
 
287
292
  private async parseBatchProviderOptions(
288
- providerOptions: BatchV4StartOptions<OpenAIBatchRequest>['providerOptions'],
293
+ providerOptions: BatchV4StartOptions<OpenAIBatchModelIds>['providerOptions'],
289
294
  ) {
290
295
  const providerOptionsName = this.options.config.provider.includes('azure')
291
296
  ? 'azure'
@@ -307,16 +312,16 @@ class OpenAIResponsesBatch {
307
312
  return batchOptions;
308
313
  }
309
314
 
310
- async getBatchStatus(
315
+ async doGetBatchStatus(
311
316
  options: BatchV4OperationOptions,
312
317
  ): Promise<BatchV4Status> {
313
318
  const batch = await this.retrieveBatch(options);
314
319
  return convertOpenAIBatchStatus(batch);
315
320
  }
316
321
 
317
- async getBatchResults(
322
+ async doGetBatchResults(
318
323
  options: BatchV4OperationOptions,
319
- ): Promise<ReadableStream<BatchV4ItemResult<LanguageModelV4GenerateResult>>> {
324
+ ): Promise<ReadableStream<BatchV4ItemResult>> {
320
325
  const batch = await this.retrieveBatch(options);
321
326
 
322
327
  const batchStatus = convertOpenAIBatchStatus(batch);
@@ -368,7 +373,7 @@ class OpenAIResponsesBatch {
368
373
  }: {
369
374
  fileIds: string[];
370
375
  options: BatchV4OperationOptions;
371
- }): AsyncGenerator<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
376
+ }): AsyncGenerator<BatchV4ItemResult> {
372
377
  for (const fileId of fileIds) {
373
378
  const { value: lines } = await getFromApi({
374
379
  url: this.getUrl(`/files/${encodeURIComponent(fileId)}/content`),
@@ -393,7 +398,7 @@ class OpenAIResponsesBatch {
393
398
 
394
399
  private async convertResultLine(
395
400
  line: OpenAIBatchResultLine,
396
- ): Promise<BatchV4ItemResult<LanguageModelV4GenerateResult>> {
401
+ ): Promise<TextBatchV4ItemResult> {
397
402
  if (line.error != null) {
398
403
  const error = {
399
404
  message: line.error.message,
@@ -401,18 +406,19 @@ class OpenAIResponsesBatch {
401
406
  };
402
407
 
403
408
  if (line.error.code === 'batch_cancelled') {
404
- return { id: line.custom_id, status: 'cancelled', error };
409
+ return { type: 'text', id: line.custom_id, status: 'cancelled', error };
405
410
  }
406
411
 
407
412
  if (line.error.code === 'batch_expired') {
408
- return { id: line.custom_id, status: 'expired', error };
413
+ return { type: 'text', id: line.custom_id, status: 'expired', error };
409
414
  }
410
415
 
411
- return { id: line.custom_id, status: 'failed', error };
416
+ return { type: 'text', id: line.custom_id, status: 'failed', error };
412
417
  }
413
418
 
414
419
  if (line.response == null) {
415
420
  return {
421
+ type: 'text',
416
422
  id: line.custom_id,
417
423
  status: 'failed',
418
424
  error: {
@@ -425,6 +431,7 @@ class OpenAIResponsesBatch {
425
431
 
426
432
  if (line.response.status_code < 200 || line.response.status_code >= 300) {
427
433
  return {
434
+ type: 'text',
428
435
  id: line.custom_id,
429
436
  status: 'failed',
430
437
  error: await convertOpenAIErrorResponse({
@@ -434,11 +441,10 @@ class OpenAIResponsesBatch {
434
441
  };
435
442
  }
436
443
 
437
- const conversion = await convertOpenAIResponsesBatchResponse(
438
- line.response.body,
439
- );
444
+ const conversion = await convertOpenAIBatchResult(line.response.body);
440
445
  if (!conversion.success) {
441
446
  return {
447
+ type: 'text',
442
448
  id: line.custom_id,
443
449
  status: 'failed',
444
450
  error: conversion.error,
@@ -446,17 +452,43 @@ class OpenAIResponsesBatch {
446
452
  }
447
453
 
448
454
  return {
455
+ type: 'text',
449
456
  id: line.custom_id,
450
457
  status: 'succeeded',
451
458
  result: conversion.result,
452
459
  };
453
460
  }
454
461
 
462
+ private async prepareRequest(
463
+ request: OpenAIBatchRequest,
464
+ ): Promise<OpenAIBatchPreparedRequest> {
465
+ const { args: body, warnings } =
466
+ await OpenAIResponsesLanguageModel.prepareRequest({
467
+ modelId: request.modelId,
468
+ config: this.options.config,
469
+ options: request.options,
470
+ });
471
+
472
+ return { body, warnings };
473
+ }
474
+
455
475
  private getUrl(path: string) {
456
- return this.options.config.url({
457
- modelId: this.options.modelId,
458
- path,
459
- });
476
+ return this.options.config.url({ path, modelId: '' });
477
+ }
478
+ }
479
+
480
+ function validateSingleModel(requests: ReadonlyArray<OpenAIBatchRequest>) {
481
+ const modelId = requests[0]?.modelId;
482
+
483
+ for (const request of requests) {
484
+ if (request.modelId !== modelId) {
485
+ throw new InvalidArgumentError({
486
+ argument: 'requests',
487
+ message:
488
+ 'The OpenAI Batch API requires all requests in a batch to use the ' +
489
+ `same model. Found "${modelId}" and "${request.modelId}".`,
490
+ });
491
+ }
460
492
  }
461
493
  }
462
494
 
@@ -468,54 +500,6 @@ const openAIBatchConvertibleProviderToolIds = new Set([
468
500
  'openai.web_search_preview',
469
501
  ]);
470
502
 
471
- export class OpenAIResponsesBatchLanguageModel
472
- extends OpenAIResponsesLanguageModel
473
- implements BatchLanguageModelV4
474
- {
475
- private readonly batch: OpenAIResponsesBatch;
476
-
477
- static [WORKFLOW_SERIALIZE](model: OpenAIResponsesLanguageModel) {
478
- return OpenAIResponsesLanguageModel[WORKFLOW_SERIALIZE](model);
479
- }
480
-
481
- static [WORKFLOW_DESERIALIZE](options: {
482
- modelId: string;
483
- config: Parameters<typeof prepareOpenAIConfigForWorkflowDeserialize>[0];
484
- }) {
485
- return new OpenAIResponsesBatchLanguageModel(
486
- options.modelId as OpenAIResponsesModelId,
487
- prepareOpenAIConfigForWorkflowDeserialize(options.config),
488
- );
489
- }
490
-
491
- constructor(modelId: OpenAIResponsesModelId, config: OpenAIConfig) {
492
- super(modelId, config);
493
- this.batch = new OpenAIResponsesBatch({
494
- modelId,
495
- config,
496
- prepareRequest: async request => {
497
- const { args: body, warnings } = await this.getArgs(request.options);
498
-
499
- return { body, warnings };
500
- },
501
- });
502
- }
503
-
504
- experimental_doStartBatch(
505
- options: Parameters<BatchLanguageModelV4['experimental_doStartBatch']>[0],
506
- ) {
507
- return this.batch.startBatch(options);
508
- }
509
-
510
- experimental_doGetBatchStatus(options: BatchV4OperationOptions) {
511
- return this.batch.getBatchStatus(options);
512
- }
513
-
514
- experimental_doGetBatchResults(options: BatchV4OperationOptions) {
515
- return this.batch.getBatchResults(options);
516
- }
517
- }
518
-
519
503
  function convertOpenAIBatchStatus(batch: OpenAIBatchResponse): BatchV4Status {
520
504
  const status = mapOpenAIBatchStatus(batch.status);
521
505
  const firstError = batch.errors?.data?.[0];
@@ -616,9 +600,9 @@ async function convertOpenAIErrorResponse({
616
600
  };
617
601
  }
618
602
 
619
- async function convertOpenAIResponsesBatchResponse(
603
+ async function convertOpenAIBatchResult(
620
604
  body: unknown,
621
- ): Promise<OpenAIBatchResponseConversion> {
605
+ ): Promise<OpenAIBatchResultConversion> {
622
606
  const validation = await safeValidateTypes({
623
607
  value: body,
624
608
  schema: openaiResponsesResponseSchema,
@@ -3,6 +3,9 @@ export type OpenAILanguageModelCapabilities = {
3
3
  systemMessageMode: 'remove' | 'system' | 'developer';
4
4
  supportsFlexProcessing: boolean;
5
5
  supportsPriorityProcessing: boolean;
6
+ supportsConfigurationUpdate: boolean;
7
+ supportsAsyncToolCalling: boolean;
8
+ supportedReasoningEfforts: readonly string[] | undefined;
6
9
 
7
10
  /**
8
11
  * Allow temperature, topP, logProbs when reasoningEffort is none.
@@ -19,6 +22,7 @@ export function getOpenAILanguageModelCapabilities(
19
22
  gptVersion?.minor == null &&
20
23
  (gptVersion?.variant?.startsWith('chat') ?? false);
21
24
  const isGptNanoModel = gptVersion?.variant?.startsWith('nano') ?? false;
25
+ const isGpt6OrLaterModel = gptVersion != null && gptVersion.major >= 6;
22
26
 
23
27
  const supportsFlexProcessing =
24
28
  (oSeriesVersion != null && oSeriesVersion >= 3) ||
@@ -41,6 +45,7 @@ export function getOpenAILanguageModelCapabilities(
41
45
  // https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
42
46
  // GPT-5.1 and later model families support temperature, topP, logProbs when reasoningEffort is none.
43
47
  const supportsNonReasoningParameters =
48
+ !isGpt6OrLaterModel &&
44
49
  gptVersion != null &&
45
50
  (gptVersion.major > 5 ||
46
51
  (gptVersion.major === 5 && (gptVersion.minor ?? 0) >= 1));
@@ -50,6 +55,11 @@ export function getOpenAILanguageModelCapabilities(
50
55
  return {
51
56
  supportsFlexProcessing,
52
57
  supportsPriorityProcessing,
58
+ supportsConfigurationUpdate: isGpt6OrLaterModel,
59
+ supportsAsyncToolCalling: isGpt6OrLaterModel,
60
+ supportedReasoningEfforts: isGpt6OrLaterModel
61
+ ? ['low', 'medium', 'high', 'xhigh', 'max']
62
+ : undefined,
53
63
  isReasoningModel,
54
64
  systemMessageMode,
55
65
  supportsNonReasoningParameters,