@ai-sdk/openai 4.0.103 → 4.0.104
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.
- package/CHANGELOG.md +20 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -46
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +14 -4
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +67 -42
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +10 -6
- package/package.json +2 -2
- package/src/chat/openai-chat-language-model-options.ts +1 -0
- package/src/normalize-openai-json-schema.ts +2 -1
- package/src/openai-batch.ts +2 -4
- package/src/openai-language-model-capabilities.ts +8 -5
- package/src/responses/openai-responses-language-model-options.ts +2 -0
- package/src/responses/openai-responses-language-model.ts +17 -8
- package/src/transcription/openai-transcription-model-options.ts +5 -6
- package/src/transcription/openai-transcription-model.ts +89 -48
package/docs/03-openai.mdx
CHANGED
|
@@ -245,9 +245,9 @@ The following provider options are available:
|
|
|
245
245
|
Reasoning effort for reasoning models. Defaults to `medium`. If you use `providerOptions` to set the `reasoningEffort` option, this model setting will be ignored.
|
|
246
246
|
|
|
247
247
|
<Note>
|
|
248
|
-
Supported reasoning efforts vary by model. GPT-5.6, GPT-6 Sol,
|
|
249
|
-
support `'none'`, `'low'`, `'medium'`, `'high'`, `'xhigh'`, and
|
|
250
|
-
Astra and GPT-6.1 Sol do not support `'none'`.
|
|
248
|
+
Supported reasoning efforts vary by model. GPT-5.6, GPT-6 Sol, GPT-6 Luna, and
|
|
249
|
+
GPT-6.1 Terra support `'none'`, `'low'`, `'medium'`, `'high'`, `'xhigh'`, and
|
|
250
|
+
`'max'`. GPT-6 Astra and GPT-6.1 Sol do not support `'none'`.
|
|
251
251
|
</Note>
|
|
252
252
|
|
|
253
253
|
<Note type="warning">
|
|
@@ -3069,6 +3069,7 @@ The following optional provider options are available for OpenAI completion mode
|
|
|
3069
3069
|
| --------------------- | ----------- | ----------- | ----------------- | ---------- |
|
|
3070
3070
|
| `gpt-6-astra` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
3071
3071
|
| `gpt-6.1-sol` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
3072
|
+
| `gpt-6.1-terra` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
3072
3073
|
| `gpt-6-luna` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
3073
3074
|
| `gpt-6-sol` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
3074
3075
|
| `gpt-5.6` | <Check /> | <Cross /> | <Check /> | <Check /> |
|
|
@@ -3508,12 +3509,13 @@ The following provider options are available:
|
|
|
3508
3509
|
|
|
3509
3510
|
- **timestampGranularities** _string[]_
|
|
3510
3511
|
The granularity of the timestamps in the transcription.
|
|
3511
|
-
Defaults to `['segment']`.
|
|
3512
|
+
Defaults to `['segment']` when `responseFormat` is `verbose_json`.
|
|
3512
3513
|
Possible values are `['word']`, `['segment']`, and `['word', 'segment']`.
|
|
3513
3514
|
Note: There is no additional latency for segment timestamps, but generating word timestamps incurs additional latency.
|
|
3514
3515
|
|
|
3515
3516
|
- **language** _string_
|
|
3516
3517
|
The language of the input audio. Supplying the input language in ISO-639-1 format (e.g. 'en') will improve accuracy and latency.
|
|
3518
|
+
For streaming with `gpt-transcribe` and `gpt-live-transcribe`, it is sent as a single-entry `languages` list.
|
|
3517
3519
|
Optional.
|
|
3518
3520
|
|
|
3519
3521
|
- **prompt** _string_
|
|
@@ -3529,13 +3531,13 @@ The following provider options are available:
|
|
|
3529
3531
|
Additional information to include in the transcription response.
|
|
3530
3532
|
|
|
3531
3533
|
- **responseFormat** _'json' | 'verbose_json' | 'diarized_json'_
|
|
3532
|
-
The format of the transcription response. `gpt-4o-transcribe-diarize` defaults to `diarized_json`.
|
|
3534
|
+
The format of the transcription response. `whisper-1` defaults to `verbose_json` and `gpt-4o-transcribe-diarize` defaults to `diarized_json`. Other models use the service default unless this option is set.
|
|
3533
3535
|
|
|
3534
3536
|
- **chunkingStrategy** _'auto' | object_
|
|
3535
3537
|
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.
|
|
3536
3538
|
|
|
3537
3539
|
- **streaming** _object_
|
|
3538
|
-
Options for streaming transcription models such as `gpt-
|
|
3540
|
+
Options for streaming transcription models such as `gpt-live-transcribe`.
|
|
3539
3541
|
Use with `experimental_streamTranscribe`.
|
|
3540
3542
|
- **delay** _'minimal' | 'low' | 'medium' | 'high' | 'xhigh'_
|
|
3541
3543
|
Latency/accuracy tradeoff for realtime transcription.
|
|
@@ -3551,6 +3553,8 @@ The following provider options are available:
|
|
|
3551
3553
|
| `gpt-4o-mini-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
3552
3554
|
| `gpt-4o-transcribe` | <Check /> | <Cross /> | <Cross /> | <Cross /> | <Cross /> |
|
|
3553
3555
|
| `gpt-4o-transcribe-diarize` | <Check /> | <Cross /> | <Check /> | <Check /> | <Cross /> |
|
|
3556
|
+
| `gpt-transcribe` | <Check /> | <Check /> | <Cross /> | <Cross /> | <Check /> |
|
|
3557
|
+
| `gpt-live-transcribe` | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
|
|
3554
3558
|
| `gpt-realtime-whisper` | <Cross /> | <Check /> | <Cross /> | <Cross /> | <Cross /> |
|
|
3555
3559
|
|
|
3556
3560
|
## Translation Models
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-sdk/openai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.104",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@ai-sdk/provider": "4.0.34",
|
|
39
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
39
|
+
"@ai-sdk/provider-utils": "5.0.70"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@ai-sdk/test-server": "2.0.4",
|
|
@@ -58,9 +58,10 @@ export function normalizeOpenAIJsonSchema(schema: JSONSchema7): {
|
|
|
58
58
|
const propertyNames = schema.propertyNames;
|
|
59
59
|
|
|
60
60
|
if (propertyNames != null) {
|
|
61
|
+
// Property names are always strings in JSON, so omitted type is a string schema.
|
|
61
62
|
if (
|
|
62
63
|
typeof propertyNames === 'boolean' ||
|
|
63
|
-
propertyNames.type !== 'string'
|
|
64
|
+
(propertyNames.type != null && propertyNames.type !== 'string')
|
|
64
65
|
) {
|
|
65
66
|
throw new UnsupportedFunctionalityError({
|
|
66
67
|
functionality:
|
package/src/openai-batch.ts
CHANGED
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
type OpenAIResponsesLogprobs,
|
|
48
48
|
} from './responses/openai-responses-api';
|
|
49
49
|
import {
|
|
50
|
-
|
|
50
|
+
mapWebSearchResult,
|
|
51
51
|
OpenAIResponsesLanguageModel,
|
|
52
52
|
openaiResponsesSupportedUrls,
|
|
53
53
|
} from './responses/openai-responses-language-model';
|
|
@@ -812,9 +812,7 @@ async function convertOpenAIBatchResult(
|
|
|
812
812
|
type: 'tool-result',
|
|
813
813
|
toolCallId: part.id,
|
|
814
814
|
toolName: 'web_search',
|
|
815
|
-
...(part
|
|
816
|
-
? { isError: true, result: { status: part.status } }
|
|
817
|
-
: { result: mapWebSearchOutput(part.action) }),
|
|
815
|
+
...mapWebSearchResult(part),
|
|
818
816
|
dynamic: true,
|
|
819
817
|
});
|
|
820
818
|
break;
|
|
@@ -24,7 +24,10 @@ export function getOpenAILanguageModelCapabilities(
|
|
|
24
24
|
const isGptNanoModel = gptVersion?.variant?.startsWith('nano') ?? false;
|
|
25
25
|
const isGpt6OrLaterModel = gptVersion != null && gptVersion.major >= 6;
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const isGpt6OrLaterModelWithNoneEffort =
|
|
28
|
+
modelId === 'gpt-6-sol' ||
|
|
29
|
+
modelId === 'gpt-6-luna' ||
|
|
30
|
+
modelId === 'gpt-6.1-terra';
|
|
28
31
|
|
|
29
32
|
const supportsFlexProcessing =
|
|
30
33
|
(oSeriesVersion != null && oSeriesVersion >= 3) ||
|
|
@@ -45,10 +48,10 @@ export function getOpenAILanguageModelCapabilities(
|
|
|
45
48
|
(gptVersion != null && gptVersion.major >= 5 && !isGptChatModel);
|
|
46
49
|
|
|
47
50
|
// https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
|
|
48
|
-
// GPT-5.1 through GPT-5.x
|
|
49
|
-
// topP, and logProbs when reasoningEffort is none.
|
|
51
|
+
// GPT-5.1 through GPT-5.x, GPT-6 Sol/Luna, and GPT-6.1 Terra support
|
|
52
|
+
// temperature, topP, and logProbs when reasoningEffort is none.
|
|
50
53
|
const supportsNonReasoningParameters =
|
|
51
|
-
|
|
54
|
+
isGpt6OrLaterModelWithNoneEffort ||
|
|
52
55
|
(!isGpt6OrLaterModel &&
|
|
53
56
|
gptVersion != null &&
|
|
54
57
|
(gptVersion.major > 5 ||
|
|
@@ -61,7 +64,7 @@ export function getOpenAILanguageModelCapabilities(
|
|
|
61
64
|
supportsPriorityProcessing,
|
|
62
65
|
supportsConfigurationUpdate: isGpt6OrLaterModel,
|
|
63
66
|
supportsAsyncToolCalling: isGpt6OrLaterModel,
|
|
64
|
-
supportedReasoningEfforts:
|
|
67
|
+
supportedReasoningEfforts: isGpt6OrLaterModelWithNoneEffort
|
|
65
68
|
? ['none', 'low', 'medium', 'high', 'xhigh', 'max']
|
|
66
69
|
: isGpt6OrLaterModel
|
|
67
70
|
? ['low', 'medium', 'high', 'xhigh', 'max']
|
|
@@ -59,6 +59,7 @@ export const openaiResponsesReasoningModelIds = [
|
|
|
59
59
|
'gpt-5.6-terra',
|
|
60
60
|
'gpt-6-astra',
|
|
61
61
|
'gpt-6.1-sol',
|
|
62
|
+
'gpt-6.1-terra',
|
|
62
63
|
'gpt-6-luna',
|
|
63
64
|
'gpt-6-sol',
|
|
64
65
|
] as const;
|
|
@@ -135,6 +136,7 @@ export type OpenAIResponsesModelId =
|
|
|
135
136
|
| 'gpt-5.6-terra'
|
|
136
137
|
| 'gpt-6-astra'
|
|
137
138
|
| 'gpt-6.1-sol'
|
|
139
|
+
| 'gpt-6.1-terra'
|
|
138
140
|
| 'gpt-6-luna'
|
|
139
141
|
| 'gpt-6-sol'
|
|
140
142
|
| 'gpt-5-2025-08-07'
|
|
@@ -1275,9 +1275,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
1275
1275
|
toolName: toolNameMapping.toCustomToolName(
|
|
1276
1276
|
webSearchToolName ?? 'web_search',
|
|
1277
1277
|
),
|
|
1278
|
-
...(part
|
|
1279
|
-
? { isError: true, result: { status: part.status } }
|
|
1280
|
-
: { result: mapWebSearchOutput(part.action) }),
|
|
1278
|
+
...mapWebSearchResult(part),
|
|
1281
1279
|
});
|
|
1282
1280
|
|
|
1283
1281
|
if (part.action?.type === 'search') {
|
|
@@ -2190,10 +2188,7 @@ export class OpenAIResponsesLanguageModel implements LanguageModelV4 {
|
|
|
2190
2188
|
toolName: toolNameMapping.toCustomToolName(
|
|
2191
2189
|
webSearchToolName ?? 'web_search',
|
|
2192
2190
|
),
|
|
2193
|
-
...(value.item
|
|
2194
|
-
value.item.status === 'incomplete'
|
|
2195
|
-
? { isError: true, result: { status: value.item.status } }
|
|
2196
|
-
: { result: mapWebSearchOutput(value.item.action) }),
|
|
2191
|
+
...mapWebSearchResult(value.item),
|
|
2197
2192
|
});
|
|
2198
2193
|
|
|
2199
2194
|
if (value.item.action?.type === 'search') {
|
|
@@ -3180,7 +3175,21 @@ function isResponseOutputChunk(chunk: OpenAIResponsesChunk): boolean {
|
|
|
3180
3175
|
);
|
|
3181
3176
|
}
|
|
3182
3177
|
|
|
3183
|
-
export function
|
|
3178
|
+
export function mapWebSearchResult({
|
|
3179
|
+
action,
|
|
3180
|
+
status,
|
|
3181
|
+
}: {
|
|
3182
|
+
action?: OpenAIResponsesWebSearchAction | null;
|
|
3183
|
+
status: string;
|
|
3184
|
+
}):
|
|
3185
|
+
| { isError: true; result: { status: string } }
|
|
3186
|
+
| { result: InferSchema<typeof webSearchOutputSchema> } {
|
|
3187
|
+
return status === 'completed'
|
|
3188
|
+
? { result: mapWebSearchOutput(action) }
|
|
3189
|
+
: { isError: true, result: { status } };
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
function mapWebSearchOutput(
|
|
3184
3193
|
action: OpenAIResponsesWebSearchAction | null | undefined,
|
|
3185
3194
|
): InferSchema<typeof webSearchOutputSchema> {
|
|
3186
3195
|
if (action == null) {
|
|
@@ -12,7 +12,9 @@ export type OpenAITranscriptionModelId =
|
|
|
12
12
|
| 'gpt-4o-mini-transcribe-2025-12-15'
|
|
13
13
|
| 'gpt-4o-transcribe'
|
|
14
14
|
| 'gpt-4o-transcribe-diarize'
|
|
15
|
+
| 'gpt-live-transcribe'
|
|
15
16
|
| 'gpt-realtime-whisper'
|
|
17
|
+
| 'gpt-transcribe'
|
|
16
18
|
| (string & {});
|
|
17
19
|
|
|
18
20
|
// https://platform.openai.com/docs/api-reference/audio/createTranscription
|
|
@@ -43,12 +45,9 @@ export const openAITranscriptionModelOptions = lazySchema(() =>
|
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* The timestamp granularities to populate for this transcription.
|
|
46
|
-
*
|
|
48
|
+
* Defaults to ['segment'] when the response format is verbose_json.
|
|
47
49
|
*/
|
|
48
|
-
timestampGranularities: z
|
|
49
|
-
.array(z.enum(['word', 'segment']))
|
|
50
|
-
.default(['segment'])
|
|
51
|
-
.optional(),
|
|
50
|
+
timestampGranularities: z.array(z.enum(['word', 'segment'])).optional(),
|
|
52
51
|
|
|
53
52
|
/**
|
|
54
53
|
* The format of the transcription response.
|
|
@@ -73,7 +72,7 @@ export const openAITranscriptionModelOptions = lazySchema(() =>
|
|
|
73
72
|
.optional(),
|
|
74
73
|
|
|
75
74
|
/**
|
|
76
|
-
* Options for streaming transcription models such as `gpt-
|
|
75
|
+
* Options for streaming transcription models such as `gpt-live-transcribe`.
|
|
77
76
|
*/
|
|
78
77
|
streaming: z
|
|
79
78
|
.object({
|
|
@@ -58,14 +58,43 @@ type OpenAIRealtimeTranscriptionEvent = {
|
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
61
|
+
* Whether `modelId` is `base` or one of its dated snapshots
|
|
62
|
+
* (e.g. `gpt-realtime-whisper-2026-01-01`).
|
|
63
|
+
*/
|
|
64
|
+
function isModelOrSnapshot(modelId: string, base: string): boolean {
|
|
65
|
+
return modelId === base || modelId.startsWith(`${base}-`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Model IDs that stream over the realtime transcription WebSocket and do not
|
|
70
|
+
* support the REST transcription endpoint.
|
|
64
71
|
*/
|
|
65
72
|
function isRealtimeTranscriptionModelId(modelId: string): boolean {
|
|
66
73
|
return (
|
|
67
|
-
modelId
|
|
68
|
-
modelId
|
|
74
|
+
isModelOrSnapshot(modelId, 'gpt-realtime-whisper') ||
|
|
75
|
+
isModelOrSnapshot(modelId, 'gpt-live-transcribe')
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Model IDs that support streaming transcription. `gpt-transcribe` also
|
|
81
|
+
* supports the REST transcription endpoint.
|
|
82
|
+
*/
|
|
83
|
+
function supportsStreamingTranscription(modelId: string): boolean {
|
|
84
|
+
return (
|
|
85
|
+
isRealtimeTranscriptionModelId(modelId) ||
|
|
86
|
+
isModelOrSnapshot(modelId, 'gpt-transcribe')
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Models whose realtime transcription session takes a `languages` list
|
|
92
|
+
* instead of the singular `language` field.
|
|
93
|
+
*/
|
|
94
|
+
function usesLanguagesList(modelId: string): boolean {
|
|
95
|
+
return (
|
|
96
|
+
isModelOrSnapshot(modelId, 'gpt-live-transcribe') ||
|
|
97
|
+
isModelOrSnapshot(modelId, 'gpt-transcribe')
|
|
69
98
|
);
|
|
70
99
|
}
|
|
71
100
|
|
|
@@ -197,54 +226,45 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
|
|
|
197
226
|
`audio.${fileExtension}`,
|
|
198
227
|
);
|
|
199
228
|
|
|
200
|
-
if (this.modelId === 'whisper-1') {
|
|
201
|
-
formData.append('response_format', 'verbose_json');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
229
|
const isDiarizationModel = this.modelId === 'gpt-4o-transcribe-diarize';
|
|
230
|
+
|
|
231
|
+
const responseFormat =
|
|
232
|
+
openAIOptions?.responseFormat ??
|
|
233
|
+
(isDiarizationModel
|
|
234
|
+
? 'diarized_json'
|
|
235
|
+
: this.modelId === 'whisper-1'
|
|
236
|
+
? 'verbose_json'
|
|
237
|
+
: undefined);
|
|
238
|
+
|
|
239
|
+
// Timestamps are only returned with verbose_json, so only default to
|
|
240
|
+
// segments when that format is used.
|
|
241
|
+
const timestampGranularities =
|
|
242
|
+
openAIOptions?.timestampGranularities ??
|
|
243
|
+
(responseFormat === 'verbose_json' ? ['segment'] : undefined);
|
|
244
|
+
|
|
205
245
|
const chunkingStrategy =
|
|
206
246
|
openAIOptions?.chunkingStrategy ??
|
|
207
247
|
(isDiarizationModel ? 'auto' : undefined);
|
|
208
248
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
include: openAIOptions.include,
|
|
218
|
-
language: openAIOptions.language,
|
|
219
|
-
prompt: openAIOptions.prompt,
|
|
220
|
-
// https://platform.openai.com/docs/api-reference/audio/createTranscription#audio_createtranscription-response_format
|
|
221
|
-
// prefer verbose_json to get segments for models that support it
|
|
222
|
-
...(this.modelId !== 'whisper-1' && {
|
|
223
|
-
response_format:
|
|
224
|
-
openAIOptions.responseFormat ??
|
|
225
|
-
(isDiarizationModel
|
|
226
|
-
? 'diarized_json'
|
|
227
|
-
: isGpt4oTranscribeModel
|
|
228
|
-
? 'json'
|
|
229
|
-
: 'verbose_json'),
|
|
230
|
-
}),
|
|
231
|
-
temperature: openAIOptions.temperature,
|
|
232
|
-
timestamp_granularities: openAIOptions.timestampGranularities,
|
|
233
|
-
};
|
|
249
|
+
const transcriptionModelOptions = {
|
|
250
|
+
response_format: responseFormat,
|
|
251
|
+
include: openAIOptions?.include,
|
|
252
|
+
language: openAIOptions?.language,
|
|
253
|
+
prompt: openAIOptions?.prompt,
|
|
254
|
+
temperature: openAIOptions?.temperature,
|
|
255
|
+
timestamp_granularities: timestampGranularities,
|
|
256
|
+
};
|
|
234
257
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
} else {
|
|
242
|
-
formData.append(key, String(value));
|
|
258
|
+
for (const [key, value] of Object.entries(transcriptionModelOptions)) {
|
|
259
|
+
if (value != null) {
|
|
260
|
+
if (Array.isArray(value)) {
|
|
261
|
+
for (const item of value) {
|
|
262
|
+
formData.append(`${key}[]`, String(item));
|
|
243
263
|
}
|
|
264
|
+
} else {
|
|
265
|
+
formData.append(key, String(value));
|
|
244
266
|
}
|
|
245
267
|
}
|
|
246
|
-
} else if (isDiarizationModel) {
|
|
247
|
-
formData.append('response_format', 'diarized_json');
|
|
248
268
|
}
|
|
249
269
|
|
|
250
270
|
if (chunkingStrategy != null) {
|
|
@@ -344,7 +364,13 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
|
|
|
344
364
|
})) ??
|
|
345
365
|
[],
|
|
346
366
|
language,
|
|
347
|
-
|
|
367
|
+
// Duration-billed json responses report the duration only in `usage`:
|
|
368
|
+
durationInSeconds:
|
|
369
|
+
response.duration ??
|
|
370
|
+
(response.usage?.type === 'duration' &&
|
|
371
|
+
typeof response.usage.seconds === 'number'
|
|
372
|
+
? response.usage.seconds
|
|
373
|
+
: undefined),
|
|
348
374
|
warnings,
|
|
349
375
|
...(response.usage != null && { usage: response.usage }),
|
|
350
376
|
response: {
|
|
@@ -375,7 +401,7 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
|
|
|
375
401
|
): Promise<
|
|
376
402
|
Awaited<ReturnType<NonNullable<TranscriptionModelV4['doStream']>>>
|
|
377
403
|
> {
|
|
378
|
-
if (!
|
|
404
|
+
if (!supportsStreamingTranscription(this.modelId)) {
|
|
379
405
|
throw new UnsupportedFunctionalityError({
|
|
380
406
|
functionality: `streaming transcription with ${this.modelId}`,
|
|
381
407
|
});
|
|
@@ -407,11 +433,22 @@ export class OpenAITranscriptionModel implements TranscriptionModelV4 {
|
|
|
407
433
|
}
|
|
408
434
|
}
|
|
409
435
|
|
|
436
|
+
// gpt-transcribe transcribes each committed turn, so it has no delay setting:
|
|
437
|
+
const supportsDelay = !isModelOrSnapshot(this.modelId, 'gpt-transcribe');
|
|
438
|
+
if (!supportsDelay && openAIOptions?.streaming?.delay != null) {
|
|
439
|
+
warnings.push({
|
|
440
|
+
type: 'unsupported',
|
|
441
|
+
feature: 'providerOptions.openai.streaming.delay',
|
|
442
|
+
details: `OpenAI streaming transcription with ${this.modelId} does not support delay.`,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
410
446
|
const headers = combineHeaders(this.config.headers?.(), options.headers);
|
|
411
447
|
const sessionUpdate = buildOpenAIRealtimeTranscriptionSession({
|
|
412
448
|
modelId: this.modelId,
|
|
413
449
|
inputAudioFormat: options.inputAudioFormat,
|
|
414
450
|
providerOptions: openAIOptions,
|
|
451
|
+
supportsDelay,
|
|
415
452
|
});
|
|
416
453
|
|
|
417
454
|
return {
|
|
@@ -600,10 +637,12 @@ function buildOpenAIRealtimeTranscriptionSession({
|
|
|
600
637
|
modelId,
|
|
601
638
|
inputAudioFormat,
|
|
602
639
|
providerOptions,
|
|
640
|
+
supportsDelay,
|
|
603
641
|
}: {
|
|
604
642
|
modelId: string;
|
|
605
643
|
inputAudioFormat: TranscriptionModelV4StreamOptions['inputAudioFormat'];
|
|
606
644
|
providerOptions: OpenAITranscriptionModelOptions | undefined;
|
|
645
|
+
supportsDelay: boolean;
|
|
607
646
|
}) {
|
|
608
647
|
return {
|
|
609
648
|
type: 'session.update',
|
|
@@ -620,9 +659,11 @@ function buildOpenAIRealtimeTranscriptionSession({
|
|
|
620
659
|
transcription: {
|
|
621
660
|
model: modelId,
|
|
622
661
|
...(providerOptions?.language != null
|
|
623
|
-
?
|
|
662
|
+
? usesLanguagesList(modelId)
|
|
663
|
+
? { languages: [providerOptions.language] }
|
|
664
|
+
: { language: providerOptions.language }
|
|
624
665
|
: {}),
|
|
625
|
-
...(providerOptions?.streaming?.delay != null
|
|
666
|
+
...(supportsDelay && providerOptions?.streaming?.delay != null
|
|
626
667
|
? { delay: providerOptions.streaming.delay }
|
|
627
668
|
: {}),
|
|
628
669
|
},
|