@core-ai/openai 0.4.0 → 0.6.0
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/README.md +21 -0
- package/dist/chunk-7CU5JW63.js +402 -0
- package/dist/compat.d.ts +18 -0
- package/dist/compat.js +612 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.js +484 -315
- package/dist/provider-options-DK-Tz0pz.d.ts +157 -0
- package/package.json +9 -5
package/dist/index.js
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
import {
|
|
2
|
+
clampReasoningEffort,
|
|
3
|
+
convertToolChoice,
|
|
4
|
+
convertTools,
|
|
5
|
+
createOpenAIEmbeddingModel,
|
|
6
|
+
createOpenAIImageModel,
|
|
7
|
+
createStructuredOutputOptions,
|
|
8
|
+
getOpenAIModelCapabilities,
|
|
9
|
+
getStructuredOutputToolName,
|
|
10
|
+
openaiCompatGenerateProviderOptionsSchema,
|
|
11
|
+
openaiCompatProviderOptionsSchema,
|
|
12
|
+
openaiEmbedProviderOptionsSchema,
|
|
13
|
+
openaiImageProviderOptionsSchema,
|
|
14
|
+
openaiResponsesGenerateProviderOptionsSchema,
|
|
15
|
+
openaiResponsesProviderOptionsSchema,
|
|
16
|
+
parseOpenAIResponsesGenerateProviderOptions,
|
|
17
|
+
safeParseJsonObject,
|
|
18
|
+
toOpenAIReasoningEffort,
|
|
19
|
+
validateOpenAIReasoningConfig,
|
|
20
|
+
wrapOpenAIError
|
|
21
|
+
} from "./chunk-7CU5JW63.js";
|
|
22
|
+
|
|
1
23
|
// src/provider.ts
|
|
2
24
|
import OpenAI from "openai";
|
|
3
25
|
|
|
@@ -6,377 +28,567 @@ import {
|
|
|
6
28
|
StructuredOutputNoObjectGeneratedError,
|
|
7
29
|
StructuredOutputParseError,
|
|
8
30
|
StructuredOutputValidationError,
|
|
9
|
-
|
|
10
|
-
|
|
31
|
+
createObjectStream,
|
|
32
|
+
createChatStream
|
|
11
33
|
} from "@core-ai/core-ai";
|
|
12
34
|
|
|
13
35
|
// src/chat-adapter.ts
|
|
14
|
-
import {
|
|
15
|
-
var
|
|
16
|
-
var DEFAULT_STRUCTURED_OUTPUT_TOOL_DESCRIPTION = "Return a JSON object that matches the requested schema.";
|
|
36
|
+
import { getProviderMetadata } from "@core-ai/core-ai";
|
|
37
|
+
var ENCRYPTED_REASONING_INCLUDE = "reasoning.encrypted_content";
|
|
17
38
|
function convertMessages(messages) {
|
|
18
|
-
return messages.
|
|
39
|
+
return messages.flatMap(convertMessage);
|
|
19
40
|
}
|
|
20
41
|
function convertMessage(message) {
|
|
21
42
|
if (message.role === "system") {
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
43
|
+
return [
|
|
44
|
+
{
|
|
45
|
+
role: "developer",
|
|
46
|
+
content: message.content
|
|
47
|
+
}
|
|
48
|
+
];
|
|
26
49
|
}
|
|
27
50
|
if (message.role === "user") {
|
|
28
|
-
return
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
51
|
+
return [
|
|
52
|
+
{
|
|
53
|
+
role: "user",
|
|
54
|
+
content: typeof message.content === "string" ? message.content : message.content.map(convertUserContentPart)
|
|
55
|
+
}
|
|
56
|
+
];
|
|
32
57
|
}
|
|
33
58
|
if (message.role === "assistant") {
|
|
34
|
-
return
|
|
59
|
+
return convertAssistantMessage(message.parts);
|
|
60
|
+
}
|
|
61
|
+
return [
|
|
62
|
+
{
|
|
63
|
+
type: "function_call_output",
|
|
64
|
+
call_id: message.toolCallId,
|
|
65
|
+
output: message.content
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
function convertAssistantMessage(parts) {
|
|
70
|
+
const items = [];
|
|
71
|
+
const textParts = [];
|
|
72
|
+
const flushTextBuffer = () => {
|
|
73
|
+
if (textParts.length === 0) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
items.push({
|
|
35
77
|
role: "assistant",
|
|
36
|
-
content:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
78
|
+
content: textParts.join("\n\n")
|
|
79
|
+
});
|
|
80
|
+
textParts.length = 0;
|
|
81
|
+
};
|
|
82
|
+
for (const part of parts) {
|
|
83
|
+
if (part.type === "text") {
|
|
84
|
+
textParts.push(part.text);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (part.type === "reasoning") {
|
|
88
|
+
if (getProviderMetadata(
|
|
89
|
+
part.providerMetadata,
|
|
90
|
+
"openai"
|
|
91
|
+
) == null) {
|
|
92
|
+
if (part.text.length > 0) {
|
|
93
|
+
textParts.push(`<thinking>${part.text}</thinking>`);
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
flushTextBuffer();
|
|
98
|
+
const encryptedContent = getEncryptedReasoningContent(part);
|
|
99
|
+
items.push({
|
|
100
|
+
type: "reasoning",
|
|
101
|
+
summary: [
|
|
102
|
+
{
|
|
103
|
+
type: "summary_text",
|
|
104
|
+
text: part.text
|
|
44
105
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
106
|
+
],
|
|
107
|
+
...encryptedContent ? { encrypted_content: encryptedContent } : {}
|
|
108
|
+
});
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
flushTextBuffer();
|
|
112
|
+
items.push({
|
|
113
|
+
type: "function_call",
|
|
114
|
+
call_id: part.toolCall.id,
|
|
115
|
+
name: part.toolCall.name,
|
|
116
|
+
arguments: JSON.stringify(part.toolCall.arguments)
|
|
117
|
+
});
|
|
48
118
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
119
|
+
flushTextBuffer();
|
|
120
|
+
return items;
|
|
121
|
+
}
|
|
122
|
+
function getEncryptedReasoningContent(part) {
|
|
123
|
+
const { encryptedContent } = getProviderMetadata(
|
|
124
|
+
part.providerMetadata,
|
|
125
|
+
"openai"
|
|
126
|
+
) ?? {};
|
|
127
|
+
return typeof encryptedContent === "string" && encryptedContent.length > 0 ? encryptedContent : void 0;
|
|
54
128
|
}
|
|
55
129
|
function convertUserContentPart(part) {
|
|
56
130
|
if (part.type === "text") {
|
|
57
131
|
return {
|
|
58
|
-
type: "
|
|
132
|
+
type: "input_text",
|
|
59
133
|
text: part.text
|
|
60
134
|
};
|
|
61
135
|
}
|
|
62
136
|
if (part.type === "image") {
|
|
63
|
-
const
|
|
137
|
+
const imageUrl = part.source.type === "url" ? part.source.url : `data:${part.source.mediaType};base64,${part.source.data}`;
|
|
64
138
|
return {
|
|
65
|
-
type: "
|
|
66
|
-
image_url:
|
|
67
|
-
url
|
|
68
|
-
}
|
|
139
|
+
type: "input_image",
|
|
140
|
+
image_url: imageUrl
|
|
69
141
|
};
|
|
70
142
|
}
|
|
71
143
|
return {
|
|
72
|
-
type: "
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
...part.filename ? { filename: part.filename } : {}
|
|
76
|
-
}
|
|
144
|
+
type: "input_file",
|
|
145
|
+
file_data: part.data,
|
|
146
|
+
...part.filename ? { filename: part.filename } : {}
|
|
77
147
|
};
|
|
78
148
|
}
|
|
79
|
-
function
|
|
80
|
-
return
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
parameters: zodToJsonSchema(tool.parameters)
|
|
86
|
-
}
|
|
87
|
-
}));
|
|
149
|
+
function createGenerateRequest(modelId, options) {
|
|
150
|
+
return createRequest(
|
|
151
|
+
modelId,
|
|
152
|
+
options,
|
|
153
|
+
false
|
|
154
|
+
);
|
|
88
155
|
}
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
function: {
|
|
96
|
-
name: choice.toolName
|
|
97
|
-
}
|
|
98
|
-
};
|
|
156
|
+
function createStreamRequest(modelId, options) {
|
|
157
|
+
return createRequest(
|
|
158
|
+
modelId,
|
|
159
|
+
options,
|
|
160
|
+
true
|
|
161
|
+
);
|
|
99
162
|
}
|
|
100
|
-
function
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
163
|
+
function createRequest(modelId, options, stream) {
|
|
164
|
+
const openaiOptions = parseOpenAIResponsesGenerateProviderOptions(
|
|
165
|
+
options.providerOptions
|
|
166
|
+
);
|
|
167
|
+
const request = {
|
|
168
|
+
...createRequestBase(modelId, options),
|
|
169
|
+
...stream ? { stream: true } : {},
|
|
170
|
+
...mapOpenAIProviderOptionsToRequestFields(openaiOptions)
|
|
171
|
+
};
|
|
172
|
+
if (options.reasoning) {
|
|
173
|
+
request.include = mergeInclude(request.include, [
|
|
174
|
+
ENCRYPTED_REASONING_INCLUDE
|
|
175
|
+
]);
|
|
104
176
|
}
|
|
105
|
-
return
|
|
177
|
+
return request;
|
|
106
178
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
179
|
+
function createRequestBase(modelId, options) {
|
|
180
|
+
validateOpenAIReasoningConfig(modelId, options);
|
|
109
181
|
return {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
toolChoice: {
|
|
119
|
-
type: "tool",
|
|
120
|
-
toolName
|
|
121
|
-
},
|
|
122
|
-
config: options.config,
|
|
123
|
-
providerOptions: options.providerOptions,
|
|
124
|
-
signal: options.signal
|
|
182
|
+
model: modelId,
|
|
183
|
+
store: false,
|
|
184
|
+
input: convertMessages(options.messages),
|
|
185
|
+
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertResponseTools(options.tools) } : {},
|
|
186
|
+
...options.toolChoice ? { tool_choice: convertResponseToolChoice(options.toolChoice) } : {},
|
|
187
|
+
...mapReasoningToRequestFields(modelId, options),
|
|
188
|
+
...mapSamplingToRequestFields(options)
|
|
125
189
|
};
|
|
126
190
|
}
|
|
127
|
-
function
|
|
128
|
-
return {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
191
|
+
function convertResponseTools(tools) {
|
|
192
|
+
return convertTools(tools).map((tool) => ({
|
|
193
|
+
type: "function",
|
|
194
|
+
name: tool.function.name,
|
|
195
|
+
description: tool.function.description,
|
|
196
|
+
parameters: tool.function.parameters
|
|
197
|
+
}));
|
|
132
198
|
}
|
|
133
|
-
function
|
|
199
|
+
function convertResponseToolChoice(choice) {
|
|
200
|
+
const converted = convertToolChoice(choice);
|
|
201
|
+
if (typeof converted === "string") {
|
|
202
|
+
return converted;
|
|
203
|
+
}
|
|
134
204
|
return {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
stream_options: {
|
|
138
|
-
include_usage: true
|
|
139
|
-
},
|
|
140
|
-
...options.providerOptions
|
|
205
|
+
type: "function",
|
|
206
|
+
name: converted.function.name
|
|
141
207
|
};
|
|
142
208
|
}
|
|
143
|
-
function
|
|
209
|
+
function mergeInclude(value, requiredIncludes) {
|
|
210
|
+
const include = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
211
|
+
for (const requiredInclude of requiredIncludes) {
|
|
212
|
+
if (!include.includes(requiredInclude)) {
|
|
213
|
+
include.push(requiredInclude);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return include.length > 0 ? include : void 0;
|
|
217
|
+
}
|
|
218
|
+
function mapSamplingToRequestFields(options) {
|
|
144
219
|
return {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
...options.
|
|
148
|
-
...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
|
|
149
|
-
...mapConfigToRequestFields(options.config)
|
|
220
|
+
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
221
|
+
...options.maxTokens !== void 0 ? { max_output_tokens: options.maxTokens } : {},
|
|
222
|
+
...options.topP !== void 0 ? { top_p: options.topP } : {}
|
|
150
223
|
};
|
|
151
224
|
}
|
|
152
|
-
function
|
|
225
|
+
function mapOpenAIProviderOptionsToRequestFields(options) {
|
|
153
226
|
return {
|
|
154
|
-
...
|
|
155
|
-
...
|
|
156
|
-
...
|
|
157
|
-
...
|
|
158
|
-
...
|
|
159
|
-
...config?.presencePenalty !== void 0 ? { presence_penalty: config.presencePenalty } : {}
|
|
227
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
228
|
+
...options?.serviceTier !== void 0 ? { service_tier: options.serviceTier } : {},
|
|
229
|
+
...options?.include ? { include: options.include } : {},
|
|
230
|
+
...options?.parallelToolCalls !== void 0 ? { parallel_tool_calls: options.parallelToolCalls } : {},
|
|
231
|
+
...options?.user !== void 0 ? { user: options.user } : {}
|
|
160
232
|
};
|
|
161
233
|
}
|
|
162
234
|
function mapGenerateResponse(response) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
usage: {
|
|
170
|
-
inputTokens: 0,
|
|
171
|
-
outputTokens: 0,
|
|
172
|
-
inputTokenDetails: {
|
|
173
|
-
cacheReadTokens: 0,
|
|
174
|
-
cacheWriteTokens: 0
|
|
175
|
-
},
|
|
176
|
-
outputTokenDetails: {
|
|
177
|
-
reasoningTokens: 0
|
|
178
|
-
}
|
|
235
|
+
const parts = [];
|
|
236
|
+
for (const item of response.output) {
|
|
237
|
+
if (isReasoningItem(item)) {
|
|
238
|
+
const reasoningPart = mapReasoningPart(item);
|
|
239
|
+
if (reasoningPart) {
|
|
240
|
+
parts.push(reasoningPart);
|
|
179
241
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
toolCalls: parseToolCalls(firstChoice.message.tool_calls),
|
|
186
|
-
finishReason: mapFinishReason(firstChoice.finish_reason),
|
|
187
|
-
usage: {
|
|
188
|
-
inputTokens: response.usage?.prompt_tokens ?? 0,
|
|
189
|
-
outputTokens: response.usage?.completion_tokens ?? 0,
|
|
190
|
-
inputTokenDetails: {
|
|
191
|
-
cacheReadTokens: response.usage?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
192
|
-
cacheWriteTokens: 0
|
|
193
|
-
},
|
|
194
|
-
outputTokenDetails: {
|
|
195
|
-
reasoningTokens
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
if (isOutputMessage(item)) {
|
|
245
|
+
for (const part of mapMessageTextParts(item)) {
|
|
246
|
+
parts.push(part);
|
|
196
247
|
}
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (isFunctionToolCall(item)) {
|
|
251
|
+
parts.push({
|
|
252
|
+
type: "tool-call",
|
|
253
|
+
toolCall: {
|
|
254
|
+
id: item.call_id,
|
|
255
|
+
name: item.name,
|
|
256
|
+
arguments: safeParseJsonObject(item.arguments)
|
|
257
|
+
}
|
|
258
|
+
});
|
|
197
259
|
}
|
|
260
|
+
}
|
|
261
|
+
const content = getTextContent(parts);
|
|
262
|
+
const reasoning = getReasoningText(parts);
|
|
263
|
+
const toolCalls = getToolCalls(parts);
|
|
264
|
+
return {
|
|
265
|
+
parts,
|
|
266
|
+
content,
|
|
267
|
+
reasoning,
|
|
268
|
+
toolCalls,
|
|
269
|
+
finishReason: mapFinishReason(response, toolCalls.length > 0),
|
|
270
|
+
usage: mapUsage(response.usage)
|
|
198
271
|
};
|
|
199
272
|
}
|
|
200
|
-
function
|
|
201
|
-
|
|
202
|
-
|
|
273
|
+
function mapReasoningPart(item) {
|
|
274
|
+
const text = getReasoningSummaryText(item.summary);
|
|
275
|
+
const encryptedContent = typeof item.encrypted_content === "string" && item.encrypted_content.length > 0 ? item.encrypted_content : void 0;
|
|
276
|
+
if (text.length === 0 && !encryptedContent) {
|
|
277
|
+
return null;
|
|
203
278
|
}
|
|
204
|
-
return calls.flatMap((toolCall) => {
|
|
205
|
-
if (toolCall.type !== "function") {
|
|
206
|
-
return [];
|
|
207
|
-
}
|
|
208
|
-
return [mapFunctionToolCall(toolCall)];
|
|
209
|
-
});
|
|
210
|
-
}
|
|
211
|
-
function mapFunctionToolCall(toolCall) {
|
|
212
279
|
return {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
280
|
+
type: "reasoning",
|
|
281
|
+
text,
|
|
282
|
+
providerMetadata: {
|
|
283
|
+
openai: { ...encryptedContent ? { encryptedContent } : {} }
|
|
284
|
+
}
|
|
216
285
|
};
|
|
217
286
|
}
|
|
218
|
-
function
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
287
|
+
function getReasoningSummaryText(summary) {
|
|
288
|
+
return summary.map((item) => item.text).join("");
|
|
289
|
+
}
|
|
290
|
+
function mapMessageTextParts(message) {
|
|
291
|
+
return message.content.flatMap(
|
|
292
|
+
(contentItem) => contentItem.type === "output_text" && contentItem.text.length > 0 ? [{ type: "text", text: contentItem.text }] : []
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
function getTextContent(parts) {
|
|
296
|
+
const text = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
297
|
+
return text.length > 0 ? text : null;
|
|
298
|
+
}
|
|
299
|
+
function getReasoningText(parts) {
|
|
300
|
+
const reasoning = parts.flatMap((part) => part.type === "reasoning" ? [part.text] : []).join("");
|
|
301
|
+
return reasoning.length > 0 ? reasoning : null;
|
|
302
|
+
}
|
|
303
|
+
function getToolCalls(parts) {
|
|
304
|
+
return parts.flatMap(
|
|
305
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
function mapFinishReason(response, hasToolCalls) {
|
|
309
|
+
const incompleteReason = response.incomplete_details?.reason;
|
|
310
|
+
if (incompleteReason === "max_output_tokens") {
|
|
223
311
|
return "length";
|
|
224
312
|
}
|
|
225
|
-
if (
|
|
313
|
+
if (incompleteReason === "content_filter") {
|
|
314
|
+
return "content-filter";
|
|
315
|
+
}
|
|
316
|
+
if (hasToolCalls) {
|
|
226
317
|
return "tool-calls";
|
|
227
318
|
}
|
|
228
|
-
if (
|
|
229
|
-
return "
|
|
319
|
+
if (response.status === "completed") {
|
|
320
|
+
return "stop";
|
|
230
321
|
}
|
|
231
322
|
return "unknown";
|
|
232
323
|
}
|
|
233
|
-
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
inputTokens: 0,
|
|
239
|
-
outputTokens: 0,
|
|
324
|
+
function mapUsage(usage) {
|
|
325
|
+
const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;
|
|
326
|
+
return {
|
|
327
|
+
inputTokens: usage?.input_tokens ?? 0,
|
|
328
|
+
outputTokens: usage?.output_tokens ?? 0,
|
|
240
329
|
inputTokenDetails: {
|
|
241
|
-
cacheReadTokens: 0,
|
|
330
|
+
cacheReadTokens: usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
242
331
|
cacheWriteTokens: 0
|
|
243
332
|
},
|
|
244
333
|
outputTokenDetails: {
|
|
245
|
-
reasoningTokens:
|
|
334
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {}
|
|
246
335
|
}
|
|
247
336
|
};
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
337
|
+
}
|
|
338
|
+
async function* transformStream(stream) {
|
|
339
|
+
const bufferedToolCalls = /* @__PURE__ */ new Map();
|
|
340
|
+
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
341
|
+
const startedToolCalls = /* @__PURE__ */ new Set();
|
|
342
|
+
const seenSummaryDeltas = /* @__PURE__ */ new Set();
|
|
343
|
+
const emittedReasoningItems = /* @__PURE__ */ new Set();
|
|
344
|
+
let latestResponse;
|
|
345
|
+
let reasoningStarted = false;
|
|
346
|
+
for await (const event of stream) {
|
|
347
|
+
if (event.type === "response.reasoning_summary_text.delta") {
|
|
348
|
+
seenSummaryDeltas.add(`${event.item_id}:${event.summary_index}`);
|
|
349
|
+
emittedReasoningItems.add(event.item_id);
|
|
350
|
+
if (!reasoningStarted) {
|
|
351
|
+
reasoningStarted = true;
|
|
352
|
+
yield { type: "reasoning-start" };
|
|
353
|
+
}
|
|
354
|
+
yield {
|
|
355
|
+
type: "reasoning-delta",
|
|
356
|
+
text: event.delta
|
|
260
357
|
};
|
|
358
|
+
continue;
|
|
261
359
|
}
|
|
262
|
-
|
|
263
|
-
|
|
360
|
+
if (event.type === "response.reasoning_summary_text.done") {
|
|
361
|
+
const key = `${event.item_id}:${event.summary_index}`;
|
|
362
|
+
if (!seenSummaryDeltas.has(key) && event.text.length > 0) {
|
|
363
|
+
emittedReasoningItems.add(event.item_id);
|
|
364
|
+
if (!reasoningStarted) {
|
|
365
|
+
reasoningStarted = true;
|
|
366
|
+
yield { type: "reasoning-start" };
|
|
367
|
+
}
|
|
368
|
+
yield {
|
|
369
|
+
type: "reasoning-delta",
|
|
370
|
+
text: event.text
|
|
371
|
+
};
|
|
372
|
+
}
|
|
264
373
|
continue;
|
|
265
374
|
}
|
|
266
|
-
if (
|
|
375
|
+
if (event.type === "response.output_text.delta") {
|
|
267
376
|
yield {
|
|
268
|
-
type: "
|
|
269
|
-
text:
|
|
377
|
+
type: "text-delta",
|
|
378
|
+
text: event.delta
|
|
270
379
|
};
|
|
380
|
+
continue;
|
|
271
381
|
}
|
|
272
|
-
if (
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
382
|
+
if (event.type === "response.output_item.added") {
|
|
383
|
+
if (!isFunctionToolCall(event.item)) {
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
const toolCallId = event.item.call_id;
|
|
387
|
+
bufferedToolCalls.set(event.output_index, {
|
|
388
|
+
id: toolCallId,
|
|
389
|
+
name: event.item.name,
|
|
390
|
+
arguments: event.item.arguments
|
|
391
|
+
});
|
|
392
|
+
if (!startedToolCalls.has(toolCallId)) {
|
|
393
|
+
startedToolCalls.add(toolCallId);
|
|
394
|
+
yield {
|
|
395
|
+
type: "tool-call-start",
|
|
396
|
+
toolCallId,
|
|
397
|
+
toolName: event.item.name
|
|
280
398
|
};
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
399
|
+
}
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (event.type === "response.function_call_arguments.delta") {
|
|
403
|
+
const currentToolCall = bufferedToolCalls.get(
|
|
404
|
+
event.output_index
|
|
405
|
+
) ?? {
|
|
406
|
+
id: event.item_id,
|
|
407
|
+
name: "",
|
|
408
|
+
arguments: ""
|
|
409
|
+
};
|
|
410
|
+
currentToolCall.arguments += event.delta;
|
|
411
|
+
bufferedToolCalls.set(event.output_index, currentToolCall);
|
|
412
|
+
if (!startedToolCalls.has(currentToolCall.id)) {
|
|
413
|
+
startedToolCalls.add(currentToolCall.id);
|
|
414
|
+
yield {
|
|
415
|
+
type: "tool-call-start",
|
|
416
|
+
toolCallId: currentToolCall.id,
|
|
417
|
+
toolName: currentToolCall.name
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
yield {
|
|
421
|
+
type: "tool-call-delta",
|
|
422
|
+
toolCallId: currentToolCall.id,
|
|
423
|
+
argumentsDelta: event.delta
|
|
424
|
+
};
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (event.type === "response.output_item.done") {
|
|
428
|
+
if (isReasoningItem(event.item)) {
|
|
429
|
+
if (!emittedReasoningItems.has(event.item.id)) {
|
|
430
|
+
const summaryText = getReasoningSummaryText(
|
|
431
|
+
event.item.summary
|
|
432
|
+
);
|
|
433
|
+
if (summaryText.length > 0) {
|
|
434
|
+
if (!reasoningStarted) {
|
|
435
|
+
reasoningStarted = true;
|
|
436
|
+
yield { type: "reasoning-start" };
|
|
437
|
+
}
|
|
438
|
+
yield {
|
|
439
|
+
type: "reasoning-delta",
|
|
440
|
+
text: summaryText
|
|
441
|
+
};
|
|
442
|
+
}
|
|
287
443
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
toolCallId: current.id,
|
|
293
|
-
argumentsDelta: partialToolCall.function.arguments
|
|
294
|
-
};
|
|
444
|
+
const encryptedContent = typeof event.item.encrypted_content === "string" && event.item.encrypted_content.length > 0 ? event.item.encrypted_content : void 0;
|
|
445
|
+
if (!reasoningStarted && encryptedContent) {
|
|
446
|
+
reasoningStarted = true;
|
|
447
|
+
yield { type: "reasoning-start" };
|
|
295
448
|
}
|
|
296
|
-
|
|
297
|
-
|
|
449
|
+
if (reasoningStarted) {
|
|
450
|
+
reasoningStarted = false;
|
|
298
451
|
yield {
|
|
299
|
-
type: "
|
|
300
|
-
|
|
301
|
-
|
|
452
|
+
type: "reasoning-end",
|
|
453
|
+
providerMetadata: {
|
|
454
|
+
openai: {
|
|
455
|
+
...encryptedContent ? { encryptedContent } : {}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
302
458
|
};
|
|
303
459
|
}
|
|
460
|
+
continue;
|
|
304
461
|
}
|
|
462
|
+
if (!isFunctionToolCall(event.item)) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const currentToolCall = bufferedToolCalls.get(
|
|
466
|
+
event.output_index
|
|
467
|
+
) ?? {
|
|
468
|
+
id: event.item.call_id,
|
|
469
|
+
name: event.item.name,
|
|
470
|
+
arguments: ""
|
|
471
|
+
};
|
|
472
|
+
currentToolCall.id = event.item.call_id;
|
|
473
|
+
currentToolCall.name = event.item.name;
|
|
474
|
+
currentToolCall.arguments = event.item.arguments || currentToolCall.arguments;
|
|
475
|
+
if (!emittedToolCalls.has(currentToolCall.id)) {
|
|
476
|
+
emittedToolCalls.add(currentToolCall.id);
|
|
477
|
+
yield {
|
|
478
|
+
type: "tool-call-end",
|
|
479
|
+
toolCall: {
|
|
480
|
+
id: currentToolCall.id,
|
|
481
|
+
name: currentToolCall.name,
|
|
482
|
+
arguments: safeParseJsonObject(
|
|
483
|
+
currentToolCall.arguments
|
|
484
|
+
)
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
continue;
|
|
305
489
|
}
|
|
306
|
-
if (
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
490
|
+
if (event.type === "response.completed") {
|
|
491
|
+
latestResponse = event.response;
|
|
492
|
+
if (reasoningStarted) {
|
|
493
|
+
reasoningStarted = false;
|
|
494
|
+
yield {
|
|
495
|
+
type: "reasoning-end",
|
|
496
|
+
providerMetadata: { openai: {} }
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
for (const bufferedToolCall of bufferedToolCalls.values()) {
|
|
500
|
+
if (emittedToolCalls.has(bufferedToolCall.id)) {
|
|
312
501
|
continue;
|
|
313
502
|
}
|
|
314
|
-
emittedToolCalls.add(
|
|
503
|
+
emittedToolCalls.add(bufferedToolCall.id);
|
|
315
504
|
yield {
|
|
316
505
|
type: "tool-call-end",
|
|
317
506
|
toolCall: {
|
|
318
|
-
id:
|
|
319
|
-
name:
|
|
320
|
-
arguments: safeParseJsonObject(
|
|
507
|
+
id: bufferedToolCall.id,
|
|
508
|
+
name: bufferedToolCall.name,
|
|
509
|
+
arguments: safeParseJsonObject(
|
|
510
|
+
bufferedToolCall.arguments
|
|
511
|
+
)
|
|
321
512
|
}
|
|
322
513
|
};
|
|
323
514
|
}
|
|
515
|
+
const hasToolCalls2 = bufferedToolCalls.size > 0;
|
|
516
|
+
yield {
|
|
517
|
+
type: "finish",
|
|
518
|
+
finishReason: mapFinishReason(latestResponse, hasToolCalls2),
|
|
519
|
+
usage: mapUsage(latestResponse.usage)
|
|
520
|
+
};
|
|
521
|
+
return;
|
|
324
522
|
}
|
|
325
523
|
}
|
|
524
|
+
if (reasoningStarted) {
|
|
525
|
+
yield { type: "reasoning-end", providerMetadata: { openai: {} } };
|
|
526
|
+
}
|
|
527
|
+
const hasToolCalls = bufferedToolCalls.size > 0;
|
|
528
|
+
const usage = latestResponse ? mapUsage(latestResponse.usage) : mapUsage(void 0);
|
|
529
|
+
const finishReason = latestResponse ? mapFinishReason(latestResponse, hasToolCalls) : "unknown";
|
|
326
530
|
yield {
|
|
327
531
|
type: "finish",
|
|
328
532
|
finishReason,
|
|
329
533
|
usage
|
|
330
534
|
};
|
|
331
535
|
}
|
|
332
|
-
function
|
|
333
|
-
|
|
334
|
-
const parsed = JSON.parse(json);
|
|
335
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
336
|
-
return parsed;
|
|
337
|
-
}
|
|
338
|
-
return {};
|
|
339
|
-
} catch {
|
|
536
|
+
function mapReasoningToRequestFields(modelId, options) {
|
|
537
|
+
if (!options.reasoning) {
|
|
340
538
|
return {};
|
|
341
539
|
}
|
|
540
|
+
const capabilities = getOpenAIModelCapabilities(modelId);
|
|
541
|
+
const effort = capabilities.reasoning.supportsEffort ? toOpenAIReasoningEffort(
|
|
542
|
+
clampReasoningEffort(
|
|
543
|
+
options.reasoning.effort,
|
|
544
|
+
capabilities.reasoning.supportedRange
|
|
545
|
+
)
|
|
546
|
+
) : void 0;
|
|
547
|
+
return {
|
|
548
|
+
reasoning: {
|
|
549
|
+
...effort ? { effort } : {},
|
|
550
|
+
summary: "auto"
|
|
551
|
+
}
|
|
552
|
+
};
|
|
342
553
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return new ProviderError(
|
|
352
|
-
error instanceof Error ? error.message : String(error),
|
|
353
|
-
"openai",
|
|
354
|
-
void 0,
|
|
355
|
-
error
|
|
356
|
-
);
|
|
554
|
+
function isFunctionToolCall(item) {
|
|
555
|
+
return item.type === "function_call";
|
|
556
|
+
}
|
|
557
|
+
function isOutputMessage(item) {
|
|
558
|
+
return item.type === "message";
|
|
559
|
+
}
|
|
560
|
+
function isReasoningItem(item) {
|
|
561
|
+
return item.type === "reasoning";
|
|
357
562
|
}
|
|
358
563
|
|
|
359
564
|
// src/chat-model.ts
|
|
360
565
|
function createOpenAIChatModel(client, modelId) {
|
|
361
566
|
const provider = "openai";
|
|
362
|
-
async function
|
|
567
|
+
async function callOpenAIResponsesApi(request, signal) {
|
|
363
568
|
try {
|
|
364
|
-
return await client.
|
|
365
|
-
|
|
366
|
-
);
|
|
569
|
+
return await client.responses.create(request, {
|
|
570
|
+
signal
|
|
571
|
+
});
|
|
367
572
|
} catch (error) {
|
|
368
573
|
throw wrapOpenAIError(error);
|
|
369
574
|
}
|
|
370
575
|
}
|
|
371
576
|
async function generateChat(options) {
|
|
372
577
|
const request = createGenerateRequest(modelId, options);
|
|
373
|
-
const response = await
|
|
578
|
+
const response = await callOpenAIResponsesApi(
|
|
579
|
+
request,
|
|
580
|
+
options.signal
|
|
581
|
+
);
|
|
374
582
|
return mapGenerateResponse(response);
|
|
375
583
|
}
|
|
376
584
|
async function streamChat(options) {
|
|
377
585
|
const request = createStreamRequest(modelId, options);
|
|
378
|
-
|
|
379
|
-
|
|
586
|
+
return createChatStream(
|
|
587
|
+
async () => transformStream(
|
|
588
|
+
await callOpenAIResponsesApi(request, options.signal)
|
|
589
|
+
),
|
|
590
|
+
{ signal: options.signal }
|
|
591
|
+
);
|
|
380
592
|
}
|
|
381
593
|
return {
|
|
382
594
|
provider,
|
|
@@ -403,13 +615,16 @@ function createOpenAIChatModel(client, modelId) {
|
|
|
403
615
|
const structuredOptions = createStructuredOutputOptions(options);
|
|
404
616
|
const stream = await streamChat(structuredOptions);
|
|
405
617
|
const toolName = getStructuredOutputToolName(options);
|
|
406
|
-
return
|
|
618
|
+
return createObjectStream(
|
|
407
619
|
transformStructuredOutputStream(
|
|
408
620
|
stream,
|
|
409
621
|
options.schema,
|
|
410
622
|
provider,
|
|
411
623
|
toolName
|
|
412
|
-
)
|
|
624
|
+
),
|
|
625
|
+
{
|
|
626
|
+
signal: options.signal
|
|
627
|
+
}
|
|
413
628
|
);
|
|
414
629
|
}
|
|
415
630
|
};
|
|
@@ -439,7 +654,7 @@ async function* transformStructuredOutputStream(stream, schema, provider, toolNa
|
|
|
439
654
|
let contentBuffer = "";
|
|
440
655
|
const toolArgumentDeltas = /* @__PURE__ */ new Map();
|
|
441
656
|
for await (const event of stream) {
|
|
442
|
-
if (event.type === "
|
|
657
|
+
if (event.type === "text-delta") {
|
|
443
658
|
contentBuffer += event.text;
|
|
444
659
|
yield {
|
|
445
660
|
type: "object-delta",
|
|
@@ -524,7 +739,12 @@ function validateStructuredToolArguments(schema, toolArguments, provider) {
|
|
|
524
739
|
}
|
|
525
740
|
function parseAndValidateStructuredPayload(schema, rawPayload, provider) {
|
|
526
741
|
const parsedPayload = parseJson(rawPayload, provider);
|
|
527
|
-
return validateStructuredObject(
|
|
742
|
+
return validateStructuredObject(
|
|
743
|
+
schema,
|
|
744
|
+
parsedPayload,
|
|
745
|
+
provider,
|
|
746
|
+
rawPayload
|
|
747
|
+
);
|
|
528
748
|
}
|
|
529
749
|
function parseJson(rawOutput, provider) {
|
|
530
750
|
try {
|
|
@@ -561,63 +781,6 @@ function formatZodIssues(issues) {
|
|
|
561
781
|
});
|
|
562
782
|
}
|
|
563
783
|
|
|
564
|
-
// src/embedding-model.ts
|
|
565
|
-
function createOpenAIEmbeddingModel(client, modelId) {
|
|
566
|
-
return {
|
|
567
|
-
provider: "openai",
|
|
568
|
-
modelId,
|
|
569
|
-
async embed(options) {
|
|
570
|
-
try {
|
|
571
|
-
const response = await client.embeddings.create({
|
|
572
|
-
model: modelId,
|
|
573
|
-
input: options.input,
|
|
574
|
-
...options.dimensions !== void 0 ? { dimensions: options.dimensions } : {},
|
|
575
|
-
...options.providerOptions
|
|
576
|
-
});
|
|
577
|
-
return {
|
|
578
|
-
embeddings: response.data.slice().sort((a, b) => a.index - b.index).map((item) => item.embedding),
|
|
579
|
-
usage: {
|
|
580
|
-
inputTokens: response.usage.prompt_tokens
|
|
581
|
-
}
|
|
582
|
-
};
|
|
583
|
-
} catch (error) {
|
|
584
|
-
throw wrapOpenAIError(error);
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
// src/image-model.ts
|
|
591
|
-
function createOpenAIImageModel(client, modelId) {
|
|
592
|
-
return {
|
|
593
|
-
provider: "openai",
|
|
594
|
-
modelId,
|
|
595
|
-
async generate(options) {
|
|
596
|
-
try {
|
|
597
|
-
const request = {
|
|
598
|
-
model: modelId,
|
|
599
|
-
prompt: options.prompt,
|
|
600
|
-
...options.n !== void 0 ? { n: options.n } : {},
|
|
601
|
-
...options.size !== void 0 ? { size: options.size } : {},
|
|
602
|
-
...options.providerOptions
|
|
603
|
-
};
|
|
604
|
-
const response = await client.images.generate(
|
|
605
|
-
request
|
|
606
|
-
);
|
|
607
|
-
return {
|
|
608
|
-
images: (response.data ?? []).map((image) => ({
|
|
609
|
-
base64: image.b64_json ?? void 0,
|
|
610
|
-
url: image.url ?? void 0,
|
|
611
|
-
revisedPrompt: image.revised_prompt ?? void 0
|
|
612
|
-
}))
|
|
613
|
-
};
|
|
614
|
-
} catch (error) {
|
|
615
|
-
throw wrapOpenAIError(error);
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
|
|
621
784
|
// src/provider.ts
|
|
622
785
|
function createOpenAI(options = {}) {
|
|
623
786
|
const client = options.client ?? new OpenAI({
|
|
@@ -631,5 +794,11 @@ function createOpenAI(options = {}) {
|
|
|
631
794
|
};
|
|
632
795
|
}
|
|
633
796
|
export {
|
|
634
|
-
createOpenAI
|
|
797
|
+
createOpenAI,
|
|
798
|
+
openaiCompatGenerateProviderOptionsSchema,
|
|
799
|
+
openaiCompatProviderOptionsSchema,
|
|
800
|
+
openaiEmbedProviderOptionsSchema,
|
|
801
|
+
openaiImageProviderOptionsSchema,
|
|
802
|
+
openaiResponsesGenerateProviderOptionsSchema,
|
|
803
|
+
openaiResponsesProviderOptionsSchema
|
|
635
804
|
};
|