@ai-sdk/openai 4.0.0-beta.7 → 4.0.0-beta.74
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 +636 -24
- package/README.md +2 -0
- package/dist/index.d.ts +240 -44
- package/dist/index.js +3345 -1683
- package/dist/index.js.map +1 -1
- package/dist/internal/index.d.ts +390 -36
- package/dist/internal/index.js +2707 -1706
- package/dist/internal/index.js.map +1 -1
- package/docs/03-openai.mdx +413 -39
- package/package.json +16 -17
- package/src/chat/convert-openai-chat-usage.ts +1 -1
- package/src/chat/convert-to-openai-chat-messages.ts +96 -68
- package/src/chat/map-openai-finish-reason.ts +1 -1
- package/src/chat/openai-chat-api.ts +6 -2
- package/src/chat/{openai-chat-options.ts → openai-chat-language-model-options.ts} +11 -1
- package/src/chat/openai-chat-language-model.ts +82 -148
- package/src/chat/openai-chat-prepare-tools.ts +3 -3
- package/src/completion/convert-openai-completion-usage.ts +1 -1
- package/src/completion/convert-to-openai-completion-prompt.ts +1 -2
- package/src/completion/map-openai-finish-reason.ts +1 -1
- package/src/completion/openai-completion-api.ts +5 -2
- package/src/completion/{openai-completion-options.ts → openai-completion-language-model-options.ts} +5 -1
- package/src/completion/openai-completion-language-model.ts +53 -17
- package/src/embedding/{openai-embedding-options.ts → openai-embedding-model-options.ts} +5 -1
- package/src/embedding/openai-embedding-model.ts +22 -5
- package/src/files/openai-files-api.ts +17 -0
- package/src/files/openai-files-options.ts +22 -0
- package/src/files/openai-files.ts +100 -0
- package/src/image/openai-image-model-options.ts +123 -0
- package/src/image/openai-image-model.ts +62 -83
- package/src/index.ts +15 -6
- package/src/internal/index.ts +7 -6
- package/src/openai-config.ts +7 -7
- package/src/openai-language-model-capabilities.ts +5 -4
- package/src/openai-provider.ts +80 -9
- package/src/openai-stream-error.ts +181 -0
- package/src/openai-tools.ts +12 -1
- package/src/realtime/index.ts +2 -0
- package/src/realtime/openai-realtime-event-mapper.ts +436 -0
- package/src/realtime/openai-realtime-model-options.ts +3 -0
- package/src/realtime/openai-realtime-model.ts +111 -0
- package/src/responses/convert-openai-responses-usage.ts +1 -1
- package/src/responses/convert-to-openai-responses-input.ts +345 -90
- package/src/responses/map-openai-responses-finish-reason.ts +1 -1
- package/src/responses/openai-responses-api.ts +186 -17
- package/src/responses/{openai-responses-options.ts → openai-responses-language-model-options.ts} +55 -1
- package/src/responses/openai-responses-language-model.ts +330 -52
- package/src/responses/openai-responses-prepare-tools.ts +129 -18
- package/src/responses/openai-responses-provider-metadata.ts +12 -2
- package/src/skills/openai-skills-api.ts +31 -0
- package/src/skills/openai-skills.ts +83 -0
- package/src/speech/{openai-speech-options.ts → openai-speech-model-options.ts} +5 -1
- package/src/speech/openai-speech-model.ts +23 -7
- package/src/tool/apply-patch.ts +33 -32
- package/src/tool/code-interpreter.ts +40 -41
- package/src/tool/custom.ts +2 -8
- package/src/tool/file-search.ts +3 -3
- package/src/tool/image-generation.ts +2 -2
- package/src/tool/local-shell.ts +2 -2
- package/src/tool/mcp.ts +3 -3
- package/src/tool/shell.ts +9 -4
- package/src/tool/tool-search.ts +98 -0
- package/src/tool/web-search-preview.ts +2 -2
- package/src/tool/web-search.ts +10 -2
- package/src/transcription/{openai-transcription-options.ts → openai-transcription-model-options.ts} +5 -1
- package/src/transcription/openai-transcription-model.ts +35 -13
- package/dist/index.d.mts +0 -1107
- package/dist/index.mjs +0 -6509
- package/dist/index.mjs.map +0 -1
- package/dist/internal/index.d.mts +0 -1137
- package/dist/internal/index.mjs +0 -6322
- package/dist/internal/index.mjs.map +0 -1
- package/src/image/openai-image-options.ts +0 -31
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
InvalidResponseDataError,
|
|
1
|
+
import type {
|
|
3
2
|
LanguageModelV4,
|
|
4
3
|
LanguageModelV4CallOptions,
|
|
5
4
|
LanguageModelV4Content,
|
|
@@ -11,39 +10,44 @@ import {
|
|
|
11
10
|
SharedV4Warning,
|
|
12
11
|
} from '@ai-sdk/provider';
|
|
13
12
|
import {
|
|
14
|
-
|
|
15
|
-
ParseResult,
|
|
13
|
+
StreamingToolCallTracker,
|
|
16
14
|
combineHeaders,
|
|
17
15
|
createEventSourceResponseHandler,
|
|
18
16
|
createJsonResponseHandler,
|
|
19
17
|
generateId,
|
|
20
|
-
|
|
18
|
+
isCustomReasoning,
|
|
21
19
|
parseProviderOptions,
|
|
22
20
|
postJsonToApi,
|
|
21
|
+
serializeModelOptions,
|
|
22
|
+
WORKFLOW_DESERIALIZE,
|
|
23
|
+
WORKFLOW_SERIALIZE,
|
|
24
|
+
type FetchFunction,
|
|
25
|
+
type ParseResult,
|
|
23
26
|
} from '@ai-sdk/provider-utils';
|
|
24
27
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
25
28
|
import { getOpenAILanguageModelCapabilities } from '../openai-language-model-capabilities';
|
|
29
|
+
import { throwIfOpenAIStreamErrorBeforeOutput } from '../openai-stream-error';
|
|
26
30
|
import {
|
|
27
|
-
OpenAIChatUsage,
|
|
28
31
|
convertOpenAIChatUsage,
|
|
32
|
+
type OpenAIChatUsage,
|
|
29
33
|
} from './convert-openai-chat-usage';
|
|
30
34
|
import { convertToOpenAIChatMessages } from './convert-to-openai-chat-messages';
|
|
31
35
|
import { getResponseMetadata } from './get-response-metadata';
|
|
32
36
|
import { mapOpenAIFinishReason } from './map-openai-finish-reason';
|
|
33
37
|
import {
|
|
34
|
-
OpenAIChatChunk,
|
|
35
38
|
openaiChatChunkSchema,
|
|
36
39
|
openaiChatResponseSchema,
|
|
40
|
+
type OpenAIChatChunk,
|
|
37
41
|
} from './openai-chat-api';
|
|
38
42
|
import {
|
|
39
|
-
OpenAIChatModelId,
|
|
40
43
|
openaiLanguageModelChatOptions,
|
|
41
|
-
|
|
44
|
+
type OpenAIChatModelId,
|
|
45
|
+
} from './openai-chat-language-model-options';
|
|
42
46
|
import { prepareChatTools } from './openai-chat-prepare-tools';
|
|
43
47
|
|
|
44
48
|
type OpenAIChatConfig = {
|
|
45
49
|
provider: string;
|
|
46
|
-
headers
|
|
50
|
+
headers?: () => Record<string, string | undefined>;
|
|
47
51
|
url: (options: { modelId: string; path: string }) => string;
|
|
48
52
|
fetch?: FetchFunction;
|
|
49
53
|
};
|
|
@@ -59,6 +63,20 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
59
63
|
|
|
60
64
|
private readonly config: OpenAIChatConfig;
|
|
61
65
|
|
|
66
|
+
static [WORKFLOW_SERIALIZE](model: OpenAIChatLanguageModel) {
|
|
67
|
+
return serializeModelOptions({
|
|
68
|
+
modelId: model.modelId,
|
|
69
|
+
config: model.config,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
74
|
+
modelId: OpenAIChatModelId;
|
|
75
|
+
config: OpenAIChatConfig;
|
|
76
|
+
}) {
|
|
77
|
+
return new OpenAIChatLanguageModel(options.modelId, options.config);
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
constructor(modelId: OpenAIChatModelId, config: OpenAIChatConfig) {
|
|
63
81
|
this.modelId = modelId;
|
|
64
82
|
this.config = config;
|
|
@@ -81,6 +99,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
81
99
|
seed,
|
|
82
100
|
tools,
|
|
83
101
|
toolChoice,
|
|
102
|
+
reasoning,
|
|
84
103
|
providerOptions,
|
|
85
104
|
}: LanguageModelV4CallOptions) {
|
|
86
105
|
const warnings: SharedV4Warning[] = [];
|
|
@@ -94,6 +113,12 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
94
113
|
})) ?? {};
|
|
95
114
|
|
|
96
115
|
const modelCapabilities = getOpenAILanguageModelCapabilities(this.modelId);
|
|
116
|
+
|
|
117
|
+
// AI SDK reasoning values map directly to the OpenAI reasoning values.
|
|
118
|
+
const resolvedReasoningEffort =
|
|
119
|
+
openaiOptions.reasoningEffort ??
|
|
120
|
+
(isCustomReasoning(reasoning) ? reasoning : undefined);
|
|
121
|
+
|
|
97
122
|
const isReasoningModel =
|
|
98
123
|
openaiOptions.forceReasoning ?? modelCapabilities.isReasoningModel;
|
|
99
124
|
|
|
@@ -168,7 +193,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
168
193
|
store: openaiOptions.store,
|
|
169
194
|
metadata: openaiOptions.metadata,
|
|
170
195
|
prediction: openaiOptions.prediction,
|
|
171
|
-
reasoning_effort:
|
|
196
|
+
reasoning_effort: resolvedReasoningEffort,
|
|
172
197
|
service_tier: openaiOptions.serviceTier,
|
|
173
198
|
prompt_cache_key: openaiOptions.promptCacheKey,
|
|
174
199
|
prompt_cache_retention: openaiOptions.promptCacheRetention,
|
|
@@ -184,7 +209,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
184
209
|
// when reasoning effort is none, gpt-5.1 models allow temperature, topP, logprobs
|
|
185
210
|
// https://platform.openai.com/docs/guides/latest-model#gpt-5-1-parameter-compatibility
|
|
186
211
|
if (
|
|
187
|
-
|
|
212
|
+
resolvedReasoningEffort !== 'none' ||
|
|
188
213
|
!modelCapabilities.supportsNonReasoningParameters
|
|
189
214
|
) {
|
|
190
215
|
if (baseArgs.temperature != null) {
|
|
@@ -327,7 +352,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
327
352
|
path: '/chat/completions',
|
|
328
353
|
modelId: this.modelId,
|
|
329
354
|
}),
|
|
330
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
355
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
331
356
|
body,
|
|
332
357
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
333
358
|
successfulResponseHandler: createJsonResponseHandler(
|
|
@@ -369,7 +394,6 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
369
394
|
|
|
370
395
|
// provider metadata:
|
|
371
396
|
const completionTokenDetails = response.usage?.completion_tokens_details;
|
|
372
|
-
const promptTokenDetails = response.usage?.prompt_tokens_details;
|
|
373
397
|
const providerMetadata: SharedV4ProviderMetadata = { openai: {} };
|
|
374
398
|
if (completionTokenDetails?.accepted_prediction_tokens != null) {
|
|
375
399
|
providerMetadata.openai.acceptedPredictionTokens =
|
|
@@ -414,12 +438,14 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
414
438
|
},
|
|
415
439
|
};
|
|
416
440
|
|
|
441
|
+
const url = this.config.url({
|
|
442
|
+
path: '/chat/completions',
|
|
443
|
+
modelId: this.modelId,
|
|
444
|
+
});
|
|
445
|
+
|
|
417
446
|
const { responseHeaders, value: response } = await postJsonToApi({
|
|
418
|
-
url
|
|
419
|
-
|
|
420
|
-
modelId: this.modelId,
|
|
421
|
-
}),
|
|
422
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
447
|
+
url,
|
|
448
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
423
449
|
body,
|
|
424
450
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
425
451
|
successfulResponseHandler: createEventSourceResponseHandler(
|
|
@@ -429,15 +455,16 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
429
455
|
fetch: this.config.fetch,
|
|
430
456
|
});
|
|
431
457
|
|
|
432
|
-
const
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
458
|
+
const checkedResponse = await throwIfOpenAIStreamErrorBeforeOutput({
|
|
459
|
+
stream: response,
|
|
460
|
+
getError: chunk => ('error' in chunk ? chunk.error : undefined),
|
|
461
|
+
isOutputChunk: isOpenAIChatOutputChunk,
|
|
462
|
+
url,
|
|
463
|
+
requestBodyValues: body,
|
|
464
|
+
responseHeaders,
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
let toolCallTracker: StreamingToolCallTracker;
|
|
441
468
|
|
|
442
469
|
let finishReason: LanguageModelV4FinishReason = {
|
|
443
470
|
unified: 'other',
|
|
@@ -449,13 +476,17 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
449
476
|
|
|
450
477
|
const providerMetadata: SharedV4ProviderMetadata = { openai: {} };
|
|
451
478
|
|
|
452
|
-
|
|
453
|
-
stream:
|
|
479
|
+
const result = {
|
|
480
|
+
stream: checkedResponse.pipeThrough(
|
|
454
481
|
new TransformStream<
|
|
455
482
|
ParseResult<OpenAIChatChunk>,
|
|
456
483
|
LanguageModelV4StreamPart
|
|
457
484
|
>({
|
|
458
485
|
start(controller) {
|
|
486
|
+
toolCallTracker = new StreamingToolCallTracker(controller, {
|
|
487
|
+
generateId,
|
|
488
|
+
typeValidation: 'if-present',
|
|
489
|
+
});
|
|
459
490
|
controller.enqueue({ type: 'stream-start', warnings });
|
|
460
491
|
},
|
|
461
492
|
|
|
@@ -547,124 +578,7 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
547
578
|
|
|
548
579
|
if (delta.tool_calls != null) {
|
|
549
580
|
for (const toolCallDelta of delta.tool_calls) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
// Tool call start. OpenAI returns all information except the arguments in the first chunk.
|
|
553
|
-
if (toolCalls[index] == null) {
|
|
554
|
-
if (
|
|
555
|
-
toolCallDelta.type != null &&
|
|
556
|
-
toolCallDelta.type !== 'function'
|
|
557
|
-
) {
|
|
558
|
-
throw new InvalidResponseDataError({
|
|
559
|
-
data: toolCallDelta,
|
|
560
|
-
message: `Expected 'function' type.`,
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
if (toolCallDelta.id == null) {
|
|
565
|
-
throw new InvalidResponseDataError({
|
|
566
|
-
data: toolCallDelta,
|
|
567
|
-
message: `Expected 'id' to be a string.`,
|
|
568
|
-
});
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
if (toolCallDelta.function?.name == null) {
|
|
572
|
-
throw new InvalidResponseDataError({
|
|
573
|
-
data: toolCallDelta,
|
|
574
|
-
message: `Expected 'function.name' to be a string.`,
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
controller.enqueue({
|
|
579
|
-
type: 'tool-input-start',
|
|
580
|
-
id: toolCallDelta.id,
|
|
581
|
-
toolName: toolCallDelta.function.name,
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
toolCalls[index] = {
|
|
585
|
-
id: toolCallDelta.id,
|
|
586
|
-
type: 'function',
|
|
587
|
-
function: {
|
|
588
|
-
name: toolCallDelta.function.name,
|
|
589
|
-
arguments: toolCallDelta.function.arguments ?? '',
|
|
590
|
-
},
|
|
591
|
-
hasFinished: false,
|
|
592
|
-
};
|
|
593
|
-
|
|
594
|
-
const toolCall = toolCalls[index];
|
|
595
|
-
|
|
596
|
-
if (
|
|
597
|
-
toolCall.function?.name != null &&
|
|
598
|
-
toolCall.function?.arguments != null
|
|
599
|
-
) {
|
|
600
|
-
// send delta if the argument text has already started:
|
|
601
|
-
if (toolCall.function.arguments.length > 0) {
|
|
602
|
-
controller.enqueue({
|
|
603
|
-
type: 'tool-input-delta',
|
|
604
|
-
id: toolCall.id,
|
|
605
|
-
delta: toolCall.function.arguments,
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// check if tool call is complete
|
|
610
|
-
// (some providers send the full tool call in one chunk):
|
|
611
|
-
if (isParsableJson(toolCall.function.arguments)) {
|
|
612
|
-
controller.enqueue({
|
|
613
|
-
type: 'tool-input-end',
|
|
614
|
-
id: toolCall.id,
|
|
615
|
-
});
|
|
616
|
-
|
|
617
|
-
controller.enqueue({
|
|
618
|
-
type: 'tool-call',
|
|
619
|
-
toolCallId: toolCall.id ?? generateId(),
|
|
620
|
-
toolName: toolCall.function.name,
|
|
621
|
-
input: toolCall.function.arguments,
|
|
622
|
-
});
|
|
623
|
-
toolCall.hasFinished = true;
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
continue;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// existing tool call, merge if not finished
|
|
631
|
-
const toolCall = toolCalls[index];
|
|
632
|
-
|
|
633
|
-
if (toolCall.hasFinished) {
|
|
634
|
-
continue;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
if (toolCallDelta.function?.arguments != null) {
|
|
638
|
-
toolCall.function!.arguments +=
|
|
639
|
-
toolCallDelta.function?.arguments ?? '';
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// send delta
|
|
643
|
-
controller.enqueue({
|
|
644
|
-
type: 'tool-input-delta',
|
|
645
|
-
id: toolCall.id,
|
|
646
|
-
delta: toolCallDelta.function.arguments ?? '',
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
// check if tool call is complete
|
|
650
|
-
if (
|
|
651
|
-
toolCall.function?.name != null &&
|
|
652
|
-
toolCall.function?.arguments != null &&
|
|
653
|
-
isParsableJson(toolCall.function.arguments)
|
|
654
|
-
) {
|
|
655
|
-
controller.enqueue({
|
|
656
|
-
type: 'tool-input-end',
|
|
657
|
-
id: toolCall.id,
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
controller.enqueue({
|
|
661
|
-
type: 'tool-call',
|
|
662
|
-
toolCallId: toolCall.id ?? generateId(),
|
|
663
|
-
toolName: toolCall.function.name,
|
|
664
|
-
input: toolCall.function.arguments,
|
|
665
|
-
});
|
|
666
|
-
toolCall.hasFinished = true;
|
|
667
|
-
}
|
|
581
|
+
toolCallTracker.processDelta(toolCallDelta);
|
|
668
582
|
}
|
|
669
583
|
}
|
|
670
584
|
|
|
@@ -687,6 +601,8 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
687
601
|
controller.enqueue({ type: 'text-end', id: '0' });
|
|
688
602
|
}
|
|
689
603
|
|
|
604
|
+
toolCallTracker.flush();
|
|
605
|
+
|
|
690
606
|
controller.enqueue({
|
|
691
607
|
type: 'finish',
|
|
692
608
|
finishReason,
|
|
@@ -699,5 +615,23 @@ export class OpenAIChatLanguageModel implements LanguageModelV4 {
|
|
|
699
615
|
request: { body },
|
|
700
616
|
response: { headers: responseHeaders },
|
|
701
617
|
};
|
|
618
|
+
|
|
619
|
+
return result;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
function isOpenAIChatOutputChunk(chunk: OpenAIChatChunk): boolean {
|
|
624
|
+
if ('error' in chunk) {
|
|
625
|
+
return false;
|
|
702
626
|
}
|
|
627
|
+
|
|
628
|
+
return chunk.choices.some(choice => {
|
|
629
|
+
const delta = choice.delta;
|
|
630
|
+
|
|
631
|
+
return (
|
|
632
|
+
(delta?.content != null && delta.content.length > 0) ||
|
|
633
|
+
(delta?.tool_calls != null && delta.tool_calls.length > 0) ||
|
|
634
|
+
(delta?.annotations != null && delta.annotations.length > 0)
|
|
635
|
+
);
|
|
636
|
+
});
|
|
703
637
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
|
-
LanguageModelV4CallOptions,
|
|
3
|
-
SharedV4Warning,
|
|
4
2
|
UnsupportedFunctionalityError,
|
|
3
|
+
type LanguageModelV4CallOptions,
|
|
4
|
+
type SharedV4Warning,
|
|
5
5
|
} from '@ai-sdk/provider';
|
|
6
|
-
import {
|
|
6
|
+
import type {
|
|
7
7
|
OpenAIChatToolChoice,
|
|
8
8
|
OpenAIChatFunctionTool,
|
|
9
9
|
} from './openai-chat-api';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { openaiErrorDataSchema } from '../openai-error';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
lazySchema,
|
|
5
|
+
zodSchema,
|
|
6
|
+
type InferSchema,
|
|
7
|
+
} from '@ai-sdk/provider-utils';
|
|
5
8
|
// limited version of the schema, focussed on what is needed for the implementation
|
|
6
9
|
// this approach limits breakages when the API changes and increases efficiency
|
|
7
10
|
export const openaiCompletionResponseSchema = lazySchema(() =>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
2
|
LanguageModelV4,
|
|
3
3
|
LanguageModelV4CallOptions,
|
|
4
4
|
LanguageModelV4FinishReason,
|
|
@@ -12,32 +12,35 @@ import {
|
|
|
12
12
|
combineHeaders,
|
|
13
13
|
createEventSourceResponseHandler,
|
|
14
14
|
createJsonResponseHandler,
|
|
15
|
-
FetchFunction,
|
|
16
15
|
parseProviderOptions,
|
|
17
|
-
ParseResult,
|
|
18
16
|
postJsonToApi,
|
|
17
|
+
serializeModelOptions,
|
|
18
|
+
WORKFLOW_DESERIALIZE,
|
|
19
|
+
WORKFLOW_SERIALIZE,
|
|
20
|
+
type FetchFunction,
|
|
21
|
+
type ParseResult,
|
|
19
22
|
} from '@ai-sdk/provider-utils';
|
|
20
23
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
24
|
+
import { throwIfOpenAIStreamErrorBeforeOutput } from '../openai-stream-error';
|
|
21
25
|
import {
|
|
22
26
|
convertOpenAICompletionUsage,
|
|
23
|
-
OpenAICompletionUsage,
|
|
27
|
+
type OpenAICompletionUsage,
|
|
24
28
|
} from './convert-openai-completion-usage';
|
|
25
29
|
import { convertToOpenAICompletionPrompt } from './convert-to-openai-completion-prompt';
|
|
26
30
|
import { getResponseMetadata } from './get-response-metadata';
|
|
27
31
|
import { mapOpenAIFinishReason } from './map-openai-finish-reason';
|
|
28
32
|
import {
|
|
29
|
-
OpenAICompletionChunk,
|
|
30
33
|
openaiCompletionChunkSchema,
|
|
31
34
|
openaiCompletionResponseSchema,
|
|
35
|
+
type OpenAICompletionChunk,
|
|
32
36
|
} from './openai-completion-api';
|
|
33
37
|
import {
|
|
34
|
-
OpenAICompletionModelId,
|
|
35
38
|
openaiLanguageModelCompletionOptions,
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
type OpenAICompletionModelId,
|
|
40
|
+
} from './openai-completion-language-model-options';
|
|
38
41
|
type OpenAICompletionConfig = {
|
|
39
42
|
provider: string;
|
|
40
|
-
headers
|
|
43
|
+
headers?: () => Record<string, string | undefined>;
|
|
41
44
|
url: (options: { modelId: string; path: string }) => string;
|
|
42
45
|
fetch?: FetchFunction;
|
|
43
46
|
};
|
|
@@ -53,6 +56,20 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
53
56
|
return this.config.provider.split('.')[0].trim();
|
|
54
57
|
}
|
|
55
58
|
|
|
59
|
+
static [WORKFLOW_SERIALIZE](model: OpenAICompletionLanguageModel) {
|
|
60
|
+
return serializeModelOptions({
|
|
61
|
+
modelId: model.modelId,
|
|
62
|
+
config: model.config,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
67
|
+
modelId: OpenAICompletionModelId;
|
|
68
|
+
config: OpenAICompletionConfig;
|
|
69
|
+
}) {
|
|
70
|
+
return new OpenAICompletionLanguageModel(options.modelId, options.config);
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
constructor(
|
|
57
74
|
modelId: OpenAICompletionModelId,
|
|
58
75
|
config: OpenAICompletionConfig,
|
|
@@ -174,7 +191,7 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
174
191
|
path: '/completions',
|
|
175
192
|
modelId: this.modelId,
|
|
176
193
|
}),
|
|
177
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
194
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
178
195
|
body: args,
|
|
179
196
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
180
197
|
successfulResponseHandler: createJsonResponseHandler(
|
|
@@ -224,12 +241,14 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
224
241
|
},
|
|
225
242
|
};
|
|
226
243
|
|
|
244
|
+
const url = this.config.url({
|
|
245
|
+
path: '/completions',
|
|
246
|
+
modelId: this.modelId,
|
|
247
|
+
});
|
|
248
|
+
|
|
227
249
|
const { responseHeaders, value: response } = await postJsonToApi({
|
|
228
|
-
url
|
|
229
|
-
|
|
230
|
-
modelId: this.modelId,
|
|
231
|
-
}),
|
|
232
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
250
|
+
url,
|
|
251
|
+
headers: combineHeaders(this.config.headers?.(), options.headers),
|
|
233
252
|
body,
|
|
234
253
|
failedResponseHandler: openaiFailedResponseHandler,
|
|
235
254
|
successfulResponseHandler: createEventSourceResponseHandler(
|
|
@@ -239,6 +258,15 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
239
258
|
fetch: this.config.fetch,
|
|
240
259
|
});
|
|
241
260
|
|
|
261
|
+
const checkedResponse = await throwIfOpenAIStreamErrorBeforeOutput({
|
|
262
|
+
stream: response,
|
|
263
|
+
getError: chunk => ('error' in chunk ? chunk.error : undefined),
|
|
264
|
+
isOutputChunk: isOpenAICompletionOutputChunk,
|
|
265
|
+
url,
|
|
266
|
+
requestBodyValues: body,
|
|
267
|
+
responseHeaders,
|
|
268
|
+
});
|
|
269
|
+
|
|
242
270
|
let finishReason: LanguageModelV4FinishReason = {
|
|
243
271
|
unified: 'other',
|
|
244
272
|
raw: undefined,
|
|
@@ -247,8 +275,8 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
247
275
|
let usage: OpenAICompletionUsage | undefined = undefined;
|
|
248
276
|
let isFirstChunk = true;
|
|
249
277
|
|
|
250
|
-
|
|
251
|
-
stream:
|
|
278
|
+
const result = {
|
|
279
|
+
stream: checkedResponse.pipeThrough(
|
|
252
280
|
new TransformStream<
|
|
253
281
|
ParseResult<OpenAICompletionChunk>,
|
|
254
282
|
LanguageModelV4StreamPart
|
|
@@ -332,5 +360,13 @@ export class OpenAICompletionLanguageModel implements LanguageModelV4 {
|
|
|
332
360
|
request: { body },
|
|
333
361
|
response: { headers: responseHeaders },
|
|
334
362
|
};
|
|
363
|
+
|
|
364
|
+
return result;
|
|
335
365
|
}
|
|
336
366
|
}
|
|
367
|
+
|
|
368
|
+
function isOpenAICompletionOutputChunk(chunk: OpenAICompletionChunk): boolean {
|
|
369
|
+
return (
|
|
370
|
+
!('error' in chunk) && chunk.choices.some(choice => choice.text.length > 0)
|
|
371
|
+
);
|
|
372
|
+
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import {
|
|
2
|
-
EmbeddingModelV4,
|
|
3
2
|
TooManyEmbeddingValuesForCallError,
|
|
3
|
+
type EmbeddingModelV4,
|
|
4
4
|
} from '@ai-sdk/provider';
|
|
5
5
|
import {
|
|
6
6
|
combineHeaders,
|
|
7
7
|
createJsonResponseHandler,
|
|
8
8
|
parseProviderOptions,
|
|
9
9
|
postJsonToApi,
|
|
10
|
+
serializeModelOptions,
|
|
11
|
+
WORKFLOW_DESERIALIZE,
|
|
12
|
+
WORKFLOW_SERIALIZE,
|
|
10
13
|
} from '@ai-sdk/provider-utils';
|
|
11
|
-
import { OpenAIConfig } from '../openai-config';
|
|
14
|
+
import type { OpenAIConfig } from '../openai-config';
|
|
12
15
|
import { openaiFailedResponseHandler } from '../openai-error';
|
|
13
16
|
import {
|
|
14
|
-
OpenAIEmbeddingModelId,
|
|
15
17
|
openaiEmbeddingModelOptions,
|
|
16
|
-
|
|
18
|
+
type OpenAIEmbeddingModelId,
|
|
19
|
+
} from './openai-embedding-model-options';
|
|
17
20
|
import { openaiTextEmbeddingResponseSchema } from './openai-embedding-api';
|
|
18
21
|
|
|
19
22
|
export class OpenAIEmbeddingModel implements EmbeddingModelV4 {
|
|
@@ -24,6 +27,20 @@ export class OpenAIEmbeddingModel implements EmbeddingModelV4 {
|
|
|
24
27
|
|
|
25
28
|
private readonly config: OpenAIConfig;
|
|
26
29
|
|
|
30
|
+
static [WORKFLOW_SERIALIZE](model: OpenAIEmbeddingModel) {
|
|
31
|
+
return serializeModelOptions({
|
|
32
|
+
modelId: model.modelId,
|
|
33
|
+
config: model.config,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static [WORKFLOW_DESERIALIZE](options: {
|
|
38
|
+
modelId: OpenAIEmbeddingModelId;
|
|
39
|
+
config: OpenAIConfig;
|
|
40
|
+
}) {
|
|
41
|
+
return new OpenAIEmbeddingModel(options.modelId, options.config);
|
|
42
|
+
}
|
|
43
|
+
|
|
27
44
|
get provider(): string {
|
|
28
45
|
return this.config.provider;
|
|
29
46
|
}
|
|
@@ -67,7 +84,7 @@ export class OpenAIEmbeddingModel implements EmbeddingModelV4 {
|
|
|
67
84
|
path: '/embeddings',
|
|
68
85
|
modelId: this.modelId,
|
|
69
86
|
}),
|
|
70
|
-
headers: combineHeaders(this.config.headers(), headers),
|
|
87
|
+
headers: combineHeaders(this.config.headers?.(), headers),
|
|
71
88
|
body: {
|
|
72
89
|
model: this.modelId,
|
|
73
90
|
input: values,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { lazySchema, zodSchema } from '@ai-sdk/provider-utils';
|
|
2
|
+
import { z } from 'zod/v4';
|
|
3
|
+
|
|
4
|
+
export const openaiFilesResponseSchema = lazySchema(() =>
|
|
5
|
+
zodSchema(
|
|
6
|
+
z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
object: z.string().nullish(),
|
|
9
|
+
bytes: z.number().nullish(),
|
|
10
|
+
created_at: z.number().nullish(),
|
|
11
|
+
filename: z.string().nullish(),
|
|
12
|
+
purpose: z.string().nullish(),
|
|
13
|
+
status: z.string().nullish(),
|
|
14
|
+
expires_at: z.number().nullish(),
|
|
15
|
+
}),
|
|
16
|
+
),
|
|
17
|
+
);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lazySchema,
|
|
3
|
+
zodSchema,
|
|
4
|
+
type InferSchema,
|
|
5
|
+
} from '@ai-sdk/provider-utils';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
|
|
8
|
+
export const openaiFilesOptionsSchema = lazySchema(() =>
|
|
9
|
+
zodSchema(
|
|
10
|
+
z.object({
|
|
11
|
+
/*
|
|
12
|
+
* Required by the OpenAI API, but optional here because
|
|
13
|
+
* the SDK defaults to "assistants" — by far the most common
|
|
14
|
+
* purpose when uploading files in this context.
|
|
15
|
+
*/
|
|
16
|
+
purpose: z.string().optional(),
|
|
17
|
+
expiresAfter: z.number().optional(),
|
|
18
|
+
}),
|
|
19
|
+
),
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
export type OpenAIFilesOptions = InferSchema<typeof openaiFilesOptionsSchema>;
|