@ai-sdk/openai 4.0.58 → 4.0.59

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.
@@ -2720,6 +2720,7 @@ The following optional provider options are available for OpenAI completion mode
2720
2720
 
2721
2721
  | Model | Image Input | Audio Input | Object Generation | Tool Usage |
2722
2722
  | --------------------- | ----------- | ----------- | ----------------- | ---------- |
2723
+ | `gpt-6-astra` | <Check /> | <Cross /> | <Check /> | <Check /> |
2723
2724
  | `gpt-5.6` | <Check /> | <Cross /> | <Check /> | <Check /> |
2724
2725
  | `gpt-5.6-luna` | <Check /> | <Cross /> | <Check /> | <Check /> |
2725
2726
  | `gpt-5.6-sol` | <Check /> | <Cross /> | <Check /> | <Check /> |
@@ -3022,6 +3023,21 @@ const result = await transcribe({
3022
3023
  console.log(result.segments); // Array of segments with startSecond/endSecond
3023
3024
  ```
3024
3025
 
3026
+ `gpt-4o-transcribe-diarize` identifies speakers in a recording. It defaults to
3027
+ the `diarized_json` response format and automatic chunking:
3028
+
3029
+ ```ts
3030
+ import { transcribe } from 'ai';
3031
+ import { openai } from '@ai-sdk/openai';
3032
+
3033
+ const result = await transcribe({
3034
+ model: openai.transcription('gpt-4o-transcribe-diarize'),
3035
+ audio: new Uint8Array([1, 2, 3, 4]),
3036
+ });
3037
+
3038
+ console.log(result.providerMetadata.openai.segments);
3039
+ ```
3040
+
3025
3041
  The following provider options are available:
3026
3042
 
3027
3043
  - **timestampGranularities** _string[]_
@@ -3046,6 +3062,12 @@ The following provider options are available:
3046
3062
  - **include** _string[]_
3047
3063
  Additional information to include in the transcription response.
3048
3064
 
3065
+ - **responseFormat** _'json' | 'verbose_json' | 'diarized_json'_
3066
+ The format of the transcription response. `gpt-4o-transcribe-diarize` defaults to `diarized_json`.
3067
+
3068
+ - **chunkingStrategy** _'auto' | object_
3069
+ Controls how the audio is split into chunks. `gpt-4o-transcribe-diarize` defaults to `'auto'`; provide this option to override the default. The object form configures OpenAI server-side VAD with `type: 'server_vad'` and optional `threshold`, `prefixPaddingMs`, and `silenceDurationMs` fields.
3070
+
3049
3071
  - **streaming** _object_
3050
3072
  Options for streaming transcription models such as `gpt-realtime-whisper`.
3051
3073
  Use with `experimental_streamTranscribe`.
@@ -3057,12 +3079,13 @@ The following provider options are available:
3057
3079
 
3058
3080
  ### Model Capabilities
3059
3081
 
3060
- | Model | Transcription | Streaming | Duration | Segments | Language |
3061
- | ------------------------ | ------------- | --------- | --------- | --------- | --------- |
3062
- | `whisper-1` | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> |
3063
- | `gpt-4o-mini-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
3064
- | `gpt-4o-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
3065
- | `gpt-realtime-whisper` | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
3082
+ | Model | Transcription | Streaming | Duration | Segments | Language |
3083
+ | --------------------------- | ------------- | --------- | --------- | --------- | --------- |
3084
+ | `whisper-1` | <Check /> | <Cross /> | <Check /> | <Check /> | <Check /> |
3085
+ | `gpt-4o-mini-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
3086
+ | `gpt-4o-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
3087
+ | `gpt-4o-transcribe-diarize` | <Check /> | <Cross /> | <Check /> | <Check /> | <Cross /> |
3088
+ | `gpt-realtime-whisper` | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
3066
3089
 
3067
3090
  ## Translation Models
3068
3091
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/openai",
3
- "version": "4.0.58",
3
+ "version": "4.0.59",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "sideEffects": false,
@@ -70,6 +70,7 @@ export type OpenAIChatModelId =
70
70
  | 'gpt-5.6-luna'
71
71
  | 'gpt-5.6-sol'
72
72
  | 'gpt-5.6-terra'
73
+ | 'gpt-6-astra'
73
74
  | (string & {});
74
75
 
75
76
  export const openaiLanguageModelChatOptions = lazySchema(() =>
@@ -57,6 +57,7 @@ export const openaiResponsesReasoningModelIds = [
57
57
  'gpt-5.6-luna',
58
58
  'gpt-5.6-sol',
59
59
  'gpt-5.6-terra',
60
+ 'gpt-6-astra',
60
61
  ] as const;
61
62
 
62
63
  export const openaiResponsesModelIds = [
@@ -129,6 +130,7 @@ export type OpenAIResponsesModelId =
129
130
  | 'gpt-5.6-luna'
130
131
  | 'gpt-5.6-sol'
131
132
  | 'gpt-5.6-terra'
133
+ | 'gpt-6-astra'
132
134
  | 'gpt-5-2025-08-07'
133
135
  | 'gpt-5-chat-latest'
134
136
  | 'gpt-5-codex'
@@ -18,18 +18,28 @@ export const openaiTranscriptionResponseSchema = lazySchema(() =>
18
18
  .nullish(),
19
19
  segments: z
20
20
  .array(
21
- z.object({
22
- id: z.number(),
23
- seek: z.number(),
24
- start: z.number(),
25
- end: z.number(),
26
- text: z.string(),
27
- tokens: z.array(z.number()),
28
- temperature: z.number(),
29
- avg_logprob: z.number(),
30
- compression_ratio: z.number(),
31
- no_speech_prob: z.number(),
32
- }),
21
+ z.union([
22
+ z.object({
23
+ id: z.number(),
24
+ seek: z.number(),
25
+ start: z.number(),
26
+ end: z.number(),
27
+ text: z.string(),
28
+ tokens: z.array(z.number()),
29
+ temperature: z.number(),
30
+ avg_logprob: z.number(),
31
+ compression_ratio: z.number(),
32
+ no_speech_prob: z.number(),
33
+ }),
34
+ z.object({
35
+ type: z.literal('transcript.text.segment'),
36
+ id: z.string(),
37
+ start: z.number(),
38
+ end: z.number(),
39
+ text: z.string(),
40
+ speaker: z.string(),
41
+ }),
42
+ ]),
33
43
  )
34
44
  .nullish(),
35
45
  }),
@@ -50,6 +50,28 @@ export const openAITranscriptionModelOptions = lazySchema(() =>
50
50
  .default(['segment'])
51
51
  .optional(),
52
52
 
53
+ /**
54
+ * The format of the transcription response.
55
+ */
56
+ responseFormat: z
57
+ .enum(['json', 'verbose_json', 'diarized_json'])
58
+ .optional(),
59
+
60
+ /**
61
+ * Controls how the audio is split into chunks before transcription.
62
+ */
63
+ chunkingStrategy: z
64
+ .union([
65
+ z.literal('auto'),
66
+ z.object({
67
+ type: z.literal('server_vad'),
68
+ threshold: z.number().min(0).max(1).optional(),
69
+ prefixPaddingMs: z.number().int().min(0).optional(),
70
+ silenceDurationMs: z.number().int().min(0).optional(),
71
+ }),
72
+ ])
73
+ .optional(),
74
+
53
75
  /**
54
76
  * Options for streaming transcription models such as `gpt-realtime-whisper`.
55
77
  */
@@ -195,6 +195,11 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
195
195
  formData.append('response_format', 'verbose_json');
196
196
  }
197
197
 
198
+ const isDiarizationModel = this.modelId === 'gpt-4o-transcribe-diarize';
199
+ const chunkingStrategy =
200
+ openAIOptions?.chunkingStrategy ??
201
+ (isDiarizationModel ? 'auto' : undefined);
202
+
198
203
  // Add provider-specific options
199
204
  if (openAIOptions) {
200
205
  const isGpt4oTranscribeModel = [
@@ -209,7 +214,13 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
209
214
  // https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
210
215
  // prefer verbose_json to get segments for models that support it
211
216
  ...(this.modelId !== 'whisper-1' && {
212
- response_format: isGpt4oTranscribeModel ? 'json' : 'verbose_json',
217
+ response_format:
218
+ openAIOptions.responseFormat ??
219
+ (isDiarizationModel
220
+ ? 'diarized_json'
221
+ : isGpt4oTranscribeModel
222
+ ? 'json'
223
+ : 'verbose_json'),
213
224
  }),
214
225
  temperature: openAIOptions.temperature,
215
226
  timestamp_granularities: openAIOptions.timestampGranularities,
@@ -226,6 +237,28 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
226
237
  }
227
238
  }
228
239
  }
240
+ } else if (isDiarizationModel) {
241
+ formData.append('response_format', 'diarized_json');
242
+ }
243
+
244
+ if (chunkingStrategy != null) {
245
+ formData.append(
246
+ 'chunking_strategy',
247
+ typeof chunkingStrategy === 'string'
248
+ ? chunkingStrategy
249
+ : JSON.stringify({
250
+ type: chunkingStrategy.type,
251
+ ...(chunkingStrategy.threshold != null && {
252
+ threshold: chunkingStrategy.threshold,
253
+ }),
254
+ ...(chunkingStrategy.prefixPaddingMs != null && {
255
+ prefix_padding_ms: chunkingStrategy.prefixPaddingMs,
256
+ }),
257
+ ...(chunkingStrategy.silenceDurationMs != null && {
258
+ silence_duration_ms: chunkingStrategy.silenceDurationMs,
259
+ }),
260
+ }),
261
+ );
229
262
  }
230
263
 
231
264
  return {
@@ -270,6 +303,19 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
270
303
  ? languageMap[response.language as keyof typeof languageMap]
271
304
  : undefined;
272
305
 
306
+ const diarizedSegments = response.segments?.flatMap(segment =>
307
+ 'speaker' in segment
308
+ ? [
309
+ {
310
+ text: segment.text,
311
+ startSecond: segment.start,
312
+ endSecond: segment.end,
313
+ speaker: segment.speaker,
314
+ },
315
+ ]
316
+ : [],
317
+ );
318
+
273
319
  return {
274
320
  text: response.text,
275
321
  segments:
@@ -293,6 +339,14 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
293
339
  headers: responseHeaders,
294
340
  body: rawResponse,
295
341
  },
342
+ ...(diarizedSegments != null &&
343
+ diarizedSegments.length > 0 && {
344
+ providerMetadata: {
345
+ openai: {
346
+ segments: diarizedSegments,
347
+ },
348
+ },
349
+ }),
296
350
  };
297
351
  }
298
352