@ai-sdk/openai 4.0.104 → 4.0.106
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 +34 -0
- package/dist/index.d.ts +50 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +651 -185
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +4 -4
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +573 -142
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +101 -9
- package/package.json +3 -3
- package/src/chat/openai-chat-language-model.ts +50 -28
- package/src/completion/openai-completion-language-model.ts +11 -3
- package/src/embedding/openai-embedding-model.ts +2 -1
- package/src/files/openai-files.ts +10 -8
- package/src/image/openai-image-model-options.ts +10 -20
- package/src/image/openai-image-model.ts +10 -21
- package/src/live/openai-realtime-model-live.ts +15 -16
- package/src/openai-batch.ts +22 -6
- package/src/openai-config.ts +2 -1
- package/src/openai-decision-model-options.ts +1 -0
- package/src/openai-decision-model.ts +48 -6
- package/src/openai-model-catalog.ts +935 -0
- package/src/openai-provider.ts +18 -13
- package/src/realtime/openai-realtime-factory.ts +6 -6
- package/src/realtime/openai-realtime-model.ts +7 -3
- package/src/resolve-openai-reasoning-effort.ts +45 -0
- package/src/responses/openai-responses-language-model.ts +35 -36
- package/src/skills/openai-skills.ts +4 -2
- package/src/speech/openai-speech-model.ts +5 -1
- package/src/speech-translation/openai-speech-translation-model.ts +5 -1
- package/src/transcription/openai-transcription-model.ts +25 -56
- package/src/openai-language-model-capabilities.ts +0 -101
|
@@ -4,6 +4,7 @@ import type {
|
|
|
4
4
|
SharedV4Warning,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import {
|
|
7
|
+
resolve,
|
|
7
8
|
combineHeaders,
|
|
8
9
|
convertBase64ToUint8Array,
|
|
9
10
|
convertToFormData,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
} from '@ai-sdk/provider-utils';
|
|
19
20
|
import type { OpenAIConfig } from '../openai-config';
|
|
20
21
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
22
|
+
import { getOpenAIImageModelEntry } from '../openai-model-catalog';
|
|
21
23
|
import { openaiImageResponseSchema } from './openai-image-api';
|
|
22
24
|
import {
|
|
23
25
|
getMaxImagesPerCall,
|
|
@@ -63,24 +65,9 @@ export class OpenAIImageModel implements ImageModelV4 {
|
|
|
63
65
|
return this.config.imageInputCapabilities.supportsFileInputs;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
'gpt-image-1',
|
|
70
|
-
'gpt-image-1-mini',
|
|
71
|
-
'gpt-image-1.5',
|
|
72
|
-
'gpt-image-2',
|
|
73
|
-
'gpt-image-2.5-flare',
|
|
74
|
-
'gpt-image-2.5-flare-2026-09-08',
|
|
75
|
-
'gpt-image-2.5-sunburst',
|
|
76
|
-
'gpt-image-2.5-sunburst-2026-09-08',
|
|
77
|
-
'chatgpt-image-latest',
|
|
78
|
-
].includes(this.modelId)
|
|
79
|
-
) {
|
|
80
|
-
return true;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return this.modelId === 'dall-e-3' ? false : undefined;
|
|
68
|
+
const support = getOpenAIImageModelEntry(this.modelId).capabilities.image
|
|
69
|
+
.fileInput;
|
|
70
|
+
return typeof support === 'boolean' ? support : undefined;
|
|
84
71
|
}
|
|
85
72
|
|
|
86
73
|
get supportsMaskInputs(): boolean | undefined {
|
|
@@ -88,7 +75,9 @@ export class OpenAIImageModel implements ImageModelV4 {
|
|
|
88
75
|
return this.config.imageInputCapabilities.supportsMaskInputs;
|
|
89
76
|
}
|
|
90
77
|
|
|
91
|
-
|
|
78
|
+
const support = getOpenAIImageModelEntry(this.modelId).capabilities.image
|
|
79
|
+
.maskInput;
|
|
80
|
+
return typeof support === 'boolean' ? support : undefined;
|
|
92
81
|
}
|
|
93
82
|
|
|
94
83
|
get provider(): string {
|
|
@@ -144,7 +133,7 @@ export class OpenAIImageModel implements ImageModelV4 {
|
|
|
144
133
|
path: '/images/edits',
|
|
145
134
|
modelId: this.modelId,
|
|
146
135
|
}),
|
|
147
|
-
headers: combineHeaders(this.config.headers
|
|
136
|
+
headers: combineHeaders(await resolve(this.config.headers), headers),
|
|
148
137
|
formData: convertToFormData<OpenAIImageEditInput>({
|
|
149
138
|
model: this.modelId,
|
|
150
139
|
prompt,
|
|
@@ -234,7 +223,7 @@ export class OpenAIImageModel implements ImageModelV4 {
|
|
|
234
223
|
path: '/images/generations',
|
|
235
224
|
modelId: this.modelId,
|
|
236
225
|
}),
|
|
237
|
-
headers: combineHeaders(this.config.headers
|
|
226
|
+
headers: combineHeaders(await resolve(this.config.headers), headers),
|
|
238
227
|
body: {
|
|
239
228
|
model: this.modelId,
|
|
240
229
|
prompt,
|
|
@@ -4,6 +4,8 @@ import {
|
|
|
4
4
|
type Experimental_RealtimeModelV4SessionConfig as RealtimeModelV4SessionConfig,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
6
|
import {
|
|
7
|
+
resolveWith,
|
|
8
|
+
resolve,
|
|
7
9
|
lazySchema,
|
|
8
10
|
zodSchema,
|
|
9
11
|
createJsonResponseHandler,
|
|
@@ -11,6 +13,7 @@ import {
|
|
|
11
13
|
} from '@ai-sdk/provider-utils';
|
|
12
14
|
import { z } from 'zod/v4';
|
|
13
15
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
16
|
+
import { openaiLiveRealtimeCapabilities } from '../openai-model-catalog';
|
|
14
17
|
import {
|
|
15
18
|
createOpenAILiveServerEventParser,
|
|
16
19
|
parseOpenAILiveServerEvent,
|
|
@@ -36,13 +39,7 @@ const webRTCSessionSchema = lazySchema(() =>
|
|
|
36
39
|
|
|
37
40
|
export class OpenAIRealtimeModelLive implements RealtimeModelV4 {
|
|
38
41
|
readonly specificationVersion = 'v4' as const;
|
|
39
|
-
readonly capabilities =
|
|
40
|
-
conversation: 'continuous',
|
|
41
|
-
transports: ['websocket', 'webrtc'],
|
|
42
|
-
connections: ['server-websocket', 'webrtc'],
|
|
43
|
-
startup: 'session-start',
|
|
44
|
-
finalization: 'session-close',
|
|
45
|
-
} as const;
|
|
42
|
+
readonly capabilities = openaiLiveRealtimeCapabilities;
|
|
46
43
|
|
|
47
44
|
constructor(
|
|
48
45
|
readonly modelId: OpenAIRealtimeModelLiveId,
|
|
@@ -57,14 +54,16 @@ export class OpenAIRealtimeModelLive implements RealtimeModelV4 {
|
|
|
57
54
|
return { dataChannelLabel: 'oai-events' };
|
|
58
55
|
}
|
|
59
56
|
|
|
60
|
-
getServerWebSocketConfig()
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
getServerWebSocketConfig() {
|
|
58
|
+
return resolveWith(this.config.headers, configHeaders => {
|
|
59
|
+
const url = new URL(`${this.config.baseURL}/live/sessions`);
|
|
60
|
+
url.protocol = url.protocol === 'http:' ? 'ws:' : 'wss:';
|
|
61
|
+
const headers: Record<string, string> = {};
|
|
62
|
+
for (const [key, value] of Object.entries(configHeaders)) {
|
|
63
|
+
if (value !== undefined) headers[key] = value;
|
|
64
|
+
}
|
|
65
|
+
return { url: url.toString(), headers };
|
|
66
|
+
});
|
|
68
67
|
}
|
|
69
68
|
|
|
70
69
|
async doCreateWebRTCSession({
|
|
@@ -83,7 +82,7 @@ export class OpenAIRealtimeModelLive implements RealtimeModelV4 {
|
|
|
83
82
|
);
|
|
84
83
|
const { value } = await postJsonToApi({
|
|
85
84
|
url: `${this.config.baseURL}/live/sessions`,
|
|
86
|
-
headers: this.config.headers
|
|
85
|
+
headers: await resolve(this.config.headers),
|
|
87
86
|
body: {
|
|
88
87
|
session,
|
|
89
88
|
transport: { type: 'webrtc', sdp: z.string().min(1).parse(sdp) },
|
package/src/openai-batch.ts
CHANGED
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
type SharedV4Warning,
|
|
20
20
|
} from '@ai-sdk/provider';
|
|
21
21
|
import {
|
|
22
|
+
resolve,
|
|
22
23
|
combineHeaders,
|
|
23
24
|
convertAsyncIteratorToReadableStream,
|
|
24
25
|
createJsonLinesResponseHandler,
|
|
@@ -267,7 +268,10 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
267
268
|
|
|
268
269
|
const { value: uploadedFile } = await postToApi({
|
|
269
270
|
url: this.getUrl('/files'),
|
|
270
|
-
headers: combineHeaders(
|
|
271
|
+
headers: combineHeaders(
|
|
272
|
+
await resolve(this.options.config.headers),
|
|
273
|
+
options.headers,
|
|
274
|
+
),
|
|
271
275
|
body: {
|
|
272
276
|
content: formData,
|
|
273
277
|
values: {
|
|
@@ -291,7 +295,10 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
291
295
|
|
|
292
296
|
const { value: batch } = await postJsonToApi({
|
|
293
297
|
url: this.getUrl('/batches'),
|
|
294
|
-
headers: combineHeaders(
|
|
298
|
+
headers: combineHeaders(
|
|
299
|
+
await resolve(this.options.config.headers),
|
|
300
|
+
options.headers,
|
|
301
|
+
),
|
|
295
302
|
body: {
|
|
296
303
|
input_file_id: uploadedFile.id,
|
|
297
304
|
endpoint: openaiBatchEndpoint,
|
|
@@ -357,7 +364,10 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
357
364
|
url: this.getUrl(
|
|
358
365
|
`/batches/${encodeURIComponent(options.batchId)}/cancel`,
|
|
359
366
|
),
|
|
360
|
-
headers: combineHeaders(
|
|
367
|
+
headers: combineHeaders(
|
|
368
|
+
await resolve(this.options.config.headers),
|
|
369
|
+
options.headers,
|
|
370
|
+
),
|
|
361
371
|
body: {},
|
|
362
372
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
363
373
|
successfulResponseHandler: createJsonResponseHandler(
|
|
@@ -381,7 +391,10 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
381
391
|
|
|
382
392
|
const { value: page } = await getFromApi({
|
|
383
393
|
url: url.toString(),
|
|
384
|
-
headers: combineHeaders(
|
|
394
|
+
headers: combineHeaders(
|
|
395
|
+
await resolve(this.options.config.headers),
|
|
396
|
+
options.headers,
|
|
397
|
+
),
|
|
385
398
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
386
399
|
successfulResponseHandler: createJsonResponseHandler(
|
|
387
400
|
openaiBatchListResponseSchema,
|
|
@@ -437,7 +450,10 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
437
450
|
): Promise<OpenAIBatchResponse> {
|
|
438
451
|
const { value: batch } = await getFromApi({
|
|
439
452
|
url: this.getUrl(`/batches/${encodeURIComponent(options.batchId)}`),
|
|
440
|
-
headers: combineHeaders(
|
|
453
|
+
headers: combineHeaders(
|
|
454
|
+
await resolve(this.options.config.headers),
|
|
455
|
+
options.headers,
|
|
456
|
+
),
|
|
441
457
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
442
458
|
successfulResponseHandler: createJsonResponseHandler(
|
|
443
459
|
openaiBatchResponseSchema,
|
|
@@ -461,7 +477,7 @@ export class OpenAIBatch implements BatchV4<OpenAIBatchModelIds> {
|
|
|
461
477
|
const { value: lines } = await getFromApi({
|
|
462
478
|
url: this.getUrl(`/files/${encodeURIComponent(fileId)}/content`),
|
|
463
479
|
headers: combineHeaders(
|
|
464
|
-
this.options.config.headers
|
|
480
|
+
await resolve(this.options.config.headers),
|
|
465
481
|
options.headers,
|
|
466
482
|
),
|
|
467
483
|
failedResponseHandler: openaiFailedResponseHandler,
|
package/src/openai-config.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
Resolvable,
|
|
2
3
|
FetchFunction,
|
|
3
4
|
WebSocketConstructor,
|
|
4
5
|
} from '@ai-sdk/provider-utils';
|
|
@@ -15,7 +16,7 @@ export type OpenAIConfig = {
|
|
|
15
16
|
requestModelId?: string;
|
|
16
17
|
baseURL?: string;
|
|
17
18
|
url: (options: { modelId: string; path: string }) => string;
|
|
18
|
-
headers?:
|
|
19
|
+
headers?: Resolvable<OpenAIHeaders>;
|
|
19
20
|
fetch?: FetchFunction;
|
|
20
21
|
webSocket?: WebSocketConstructor;
|
|
21
22
|
generateId?: () => string;
|
|
@@ -10,6 +10,7 @@ export const openaiDecisionModelOptions = lazySchema(() =>
|
|
|
10
10
|
z.object({
|
|
11
11
|
/** An opaque end-user identifier for safety monitoring, up to 128 characters. */
|
|
12
12
|
safetyIdentifier: z.string().max(128).optional(),
|
|
13
|
+
promptCacheKey: z.string().optional(),
|
|
13
14
|
}),
|
|
14
15
|
),
|
|
15
16
|
);
|
|
@@ -4,8 +4,11 @@ import {
|
|
|
4
4
|
type Experimental_DecisionModelV4 as DecisionModelV4,
|
|
5
5
|
type Experimental_DecisionModelV4Answer as DecisionModelV4Answer,
|
|
6
6
|
type Experimental_DecisionModelV4Input as DecisionModelV4Input,
|
|
7
|
+
type JSONObject,
|
|
8
|
+
type JSONValue,
|
|
7
9
|
} from '@ai-sdk/provider';
|
|
8
10
|
import {
|
|
11
|
+
resolve,
|
|
9
12
|
lazySchema,
|
|
10
13
|
zodSchema,
|
|
11
14
|
combineHeaders,
|
|
@@ -144,10 +147,11 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
|
|
|
144
147
|
responseHeaders,
|
|
145
148
|
} = await postJsonToApi({
|
|
146
149
|
url: this.config.url({ path: '/decisions', modelId: this.modelId }),
|
|
147
|
-
headers: combineHeaders(this.config.headers
|
|
150
|
+
headers: combineHeaders(await resolve(this.config.headers), headers),
|
|
148
151
|
body: {
|
|
149
152
|
model: this.modelId,
|
|
150
153
|
safety_identifier: openaiOptions?.safetyIdentifier,
|
|
154
|
+
prompt_cache_key: openaiOptions?.promptCacheKey,
|
|
151
155
|
input: [
|
|
152
156
|
{
|
|
153
157
|
role: 'user',
|
|
@@ -155,10 +159,9 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
|
|
|
155
159
|
if (part.type === 'text')
|
|
156
160
|
return { type: 'input_text', text: part.text };
|
|
157
161
|
if (part.type === 'json')
|
|
158
|
-
return
|
|
159
|
-
type: '
|
|
160
|
-
text: JSON.stringify(part.value)
|
|
161
|
-
};
|
|
162
|
+
return isInputJsonData(part.value)
|
|
163
|
+
? { type: 'input_json', data: part.value }
|
|
164
|
+
: { type: 'input_text', text: JSON.stringify(part.value) };
|
|
162
165
|
if (part.data.type !== 'data') {
|
|
163
166
|
throw new UnsupportedFunctionalityError({
|
|
164
167
|
functionality: `OpenAI decision file input: ${part.mediaType} (${part.data.type})`,
|
|
@@ -323,7 +326,7 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
|
|
|
323
326
|
? [{ type: 'unsupported' as const, feature: 'reasoning' }]
|
|
324
327
|
: []),
|
|
325
328
|
...Object.keys(providerOptions?.openai ?? {})
|
|
326
|
-
.filter(option => option
|
|
329
|
+
.filter(option => !SUPPORTED_PROVIDER_OPTIONS.has(option))
|
|
327
330
|
.map(option => ({
|
|
328
331
|
type: 'unsupported' as const,
|
|
329
332
|
feature: `providerOptions.openai.${option}`,
|
|
@@ -351,6 +354,45 @@ export class DecisionOpenAIModel implements DecisionModelV4 {
|
|
|
351
354
|
}
|
|
352
355
|
}
|
|
353
356
|
|
|
357
|
+
const SUPPORTED_PROVIDER_OPTIONS = new Set([
|
|
358
|
+
'safetyIdentifier',
|
|
359
|
+
'promptCacheKey',
|
|
360
|
+
]);
|
|
361
|
+
|
|
354
362
|
function toText(input: DecisionModelV4Input): string {
|
|
355
363
|
return typeof input === 'string' ? input : JSON.stringify(input);
|
|
356
364
|
}
|
|
365
|
+
|
|
366
|
+
const INPUT_JSON_MAX_DEPTH = 32;
|
|
367
|
+
const INPUT_JSON_MAX_VALUES = 10_000;
|
|
368
|
+
const INPUT_JSON_MAX_BYTES = 256 * 1024;
|
|
369
|
+
|
|
370
|
+
function isInputJsonData(value: JSONValue): value is JSONObject | JSONObject[] {
|
|
371
|
+
const hasInputJsonShape = Array.isArray(value)
|
|
372
|
+
? value.length > 0 && value.every(isJSONObject)
|
|
373
|
+
: isJSONObject(value);
|
|
374
|
+
return hasInputJsonShape && fitsInputJsonLimits(value);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function fitsInputJsonLimits(value: JSONValue): boolean {
|
|
378
|
+
let count = 0;
|
|
379
|
+
const visit = (node: JSONValue | undefined, depth: number): boolean => {
|
|
380
|
+
count += 1;
|
|
381
|
+
if (count > INPUT_JSON_MAX_VALUES) return false;
|
|
382
|
+
if (node === null || typeof node !== 'object') return true;
|
|
383
|
+
if (depth > INPUT_JSON_MAX_DEPTH) return false;
|
|
384
|
+
const children: readonly (JSONValue | undefined)[] = Array.isArray(node)
|
|
385
|
+
? node
|
|
386
|
+
: Object.values(node);
|
|
387
|
+
return children.every(child => visit(child, depth + 1));
|
|
388
|
+
};
|
|
389
|
+
return (
|
|
390
|
+
visit(value, 1) &&
|
|
391
|
+
new TextEncoder().encode(JSON.stringify(value)).length <=
|
|
392
|
+
INPUT_JSON_MAX_BYTES
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function isJSONObject(value: JSONValue): value is JSONObject {
|
|
397
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
398
|
+
}
|