@core-ai/openai 0.14.0 → 0.16.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 +8 -5
- package/dist/chunk-YORO2XQ3.js +1852 -0
- package/dist/compat.d.ts +11 -9
- package/dist/compat.js +19 -456
- package/dist/index.d.ts +4 -7
- package/dist/index.js +8 -740
- package/dist/{provider-options-DzqvHoId.d.ts → provider-options-CpxtGjm0.d.ts} +64 -6
- package/package.json +2 -2
- package/dist/chunk-7MAEB5C7.js +0 -568
|
@@ -0,0 +1,1852 @@
|
|
|
1
|
+
// src/model-capabilities.ts
|
|
2
|
+
import {
|
|
3
|
+
stripModelDateSuffix
|
|
4
|
+
} from "@core-ai/core-ai";
|
|
5
|
+
var STANDARD_EFFORTS = [
|
|
6
|
+
"low",
|
|
7
|
+
"medium",
|
|
8
|
+
"high"
|
|
9
|
+
];
|
|
10
|
+
var MAX_EFFORTS = [
|
|
11
|
+
"low",
|
|
12
|
+
"medium",
|
|
13
|
+
"high",
|
|
14
|
+
"max"
|
|
15
|
+
];
|
|
16
|
+
var MINIMAL_EFFORTS = [
|
|
17
|
+
"minimal",
|
|
18
|
+
"low",
|
|
19
|
+
"medium",
|
|
20
|
+
"high"
|
|
21
|
+
];
|
|
22
|
+
var PRO_EFFORTS = [
|
|
23
|
+
"medium",
|
|
24
|
+
"high",
|
|
25
|
+
"max"
|
|
26
|
+
];
|
|
27
|
+
var HIGH_EFFORT = ["high"];
|
|
28
|
+
function createCapabilities(supportedEfforts, restrictsSamplingParams, maxTokensParameter = "max_completion_tokens") {
|
|
29
|
+
return {
|
|
30
|
+
reasoning: {
|
|
31
|
+
supported: true,
|
|
32
|
+
supportedEfforts,
|
|
33
|
+
restrictsSamplingParams
|
|
34
|
+
},
|
|
35
|
+
chatCompletions: {
|
|
36
|
+
maxTokensParameter
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
var DEFAULT_CAPABILITIES = createCapabilities(STANDARD_EFFORTS, false);
|
|
41
|
+
var UNKNOWN_MODEL_CAPABILITIES = createCapabilities(
|
|
42
|
+
STANDARD_EFFORTS,
|
|
43
|
+
false,
|
|
44
|
+
"max_tokens"
|
|
45
|
+
);
|
|
46
|
+
var SAMPLING_RESTRICTED_STANDARD_CAPABILITIES = createCapabilities(
|
|
47
|
+
STANDARD_EFFORTS,
|
|
48
|
+
true
|
|
49
|
+
);
|
|
50
|
+
var GPT_5_MAX_REASONING_CAPABILITIES = createCapabilities(MAX_EFFORTS, true);
|
|
51
|
+
var GPT_5_MINIMAL_REASONING_CAPABILITIES = createCapabilities(
|
|
52
|
+
MINIMAL_EFFORTS,
|
|
53
|
+
true
|
|
54
|
+
);
|
|
55
|
+
var GPT_5_PRO_REASONING_CAPABILITIES = createCapabilities(PRO_EFFORTS, true);
|
|
56
|
+
var GPT_5_HIGH_REASONING_CAPABILITIES = createCapabilities(HIGH_EFFORT, true);
|
|
57
|
+
var NO_REASONING_EFFORT_CAPABILITIES = {
|
|
58
|
+
reasoning: {
|
|
59
|
+
supported: false,
|
|
60
|
+
supportedEfforts: [],
|
|
61
|
+
restrictsSamplingParams: false
|
|
62
|
+
},
|
|
63
|
+
chatCompletions: {
|
|
64
|
+
maxTokensParameter: "max_completion_tokens"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var O_SERIES_MAX_REASONING_CAPABILITIES = createCapabilities(
|
|
68
|
+
MAX_EFFORTS,
|
|
69
|
+
false
|
|
70
|
+
);
|
|
71
|
+
var MODEL_CAPABILITIES = {
|
|
72
|
+
"gpt-5.6-sol": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
73
|
+
"gpt-5.6-terra": SAMPLING_RESTRICTED_STANDARD_CAPABILITIES,
|
|
74
|
+
"gpt-5.6-luna": GPT_5_MINIMAL_REASONING_CAPABILITIES,
|
|
75
|
+
"gpt-5.5": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
76
|
+
"gpt-5.5-pro": GPT_5_PRO_REASONING_CAPABILITIES,
|
|
77
|
+
"gpt-5.4": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
78
|
+
"gpt-5.4-pro": GPT_5_PRO_REASONING_CAPABILITIES,
|
|
79
|
+
"gpt-5.4-mini": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
80
|
+
"gpt-5.4-nano": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
81
|
+
"gpt-5.3-codex": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
82
|
+
"gpt-5.2": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
83
|
+
"gpt-5.2-codex": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
84
|
+
"gpt-5.2-pro": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
85
|
+
"gpt-5.1-codex": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
86
|
+
"gpt-5.1-codex-max": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
87
|
+
"gpt-5.1-codex-mini": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
88
|
+
"gpt-5.1": SAMPLING_RESTRICTED_STANDARD_CAPABILITIES,
|
|
89
|
+
"gpt-5": GPT_5_MINIMAL_REASONING_CAPABILITIES,
|
|
90
|
+
"gpt-5-mini": GPT_5_MINIMAL_REASONING_CAPABILITIES,
|
|
91
|
+
"gpt-5-nano": GPT_5_MINIMAL_REASONING_CAPABILITIES,
|
|
92
|
+
"gpt-5-pro": GPT_5_HIGH_REASONING_CAPABILITIES,
|
|
93
|
+
"gpt-5-codex": GPT_5_MAX_REASONING_CAPABILITIES,
|
|
94
|
+
"o3-pro": O_SERIES_MAX_REASONING_CAPABILITIES,
|
|
95
|
+
o3: DEFAULT_CAPABILITIES,
|
|
96
|
+
"o3-mini": DEFAULT_CAPABILITIES,
|
|
97
|
+
"o4-mini": DEFAULT_CAPABILITIES,
|
|
98
|
+
o1: DEFAULT_CAPABILITIES,
|
|
99
|
+
"o1-mini": NO_REASONING_EFFORT_CAPABILITIES
|
|
100
|
+
};
|
|
101
|
+
var OPENAI_REASONING_EFFORT_MAP = {
|
|
102
|
+
minimal: "minimal",
|
|
103
|
+
low: "low",
|
|
104
|
+
medium: "medium",
|
|
105
|
+
high: "high",
|
|
106
|
+
max: "xhigh"
|
|
107
|
+
};
|
|
108
|
+
function getOpenAIModelCapabilities(modelId) {
|
|
109
|
+
const normalizedModelId = normalizeModelId(modelId);
|
|
110
|
+
return MODEL_CAPABILITIES[normalizedModelId] ?? UNKNOWN_MODEL_CAPABILITIES;
|
|
111
|
+
}
|
|
112
|
+
function normalizeModelId(modelId) {
|
|
113
|
+
return stripModelDateSuffix(modelId);
|
|
114
|
+
}
|
|
115
|
+
function toOpenAIReasoningEffort(effort) {
|
|
116
|
+
return OPENAI_REASONING_EFFORT_MAP[effort];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// src/provider-options.ts
|
|
120
|
+
import { z } from "zod";
|
|
121
|
+
var openaiResponsesGenerateProviderOptionsSchema = z.object({
|
|
122
|
+
store: z.boolean().optional(),
|
|
123
|
+
serviceTier: z.enum(["auto", "default", "flex", "scale", "priority"]).optional(),
|
|
124
|
+
include: z.array(z.string()).optional(),
|
|
125
|
+
parallelToolCalls: z.boolean().optional(),
|
|
126
|
+
user: z.string().optional()
|
|
127
|
+
}).strict();
|
|
128
|
+
var openaiChatGenerateProviderOptionsSchema = openaiResponsesGenerateProviderOptionsSchema.omit({
|
|
129
|
+
include: true
|
|
130
|
+
}).extend({
|
|
131
|
+
stopSequences: z.array(z.string()).optional(),
|
|
132
|
+
frequencyPenalty: z.number().optional(),
|
|
133
|
+
presencePenalty: z.number().optional(),
|
|
134
|
+
seed: z.number().int().optional()
|
|
135
|
+
}).strict();
|
|
136
|
+
var openaiEmbedProviderOptionsSchema = z.object({
|
|
137
|
+
encodingFormat: z.enum(["float", "base64"]).optional(),
|
|
138
|
+
user: z.string().optional()
|
|
139
|
+
}).strict();
|
|
140
|
+
var openaiImageProviderOptionsSchema = z.object({
|
|
141
|
+
background: z.enum(["transparent", "opaque", "auto"]).optional(),
|
|
142
|
+
moderation: z.enum(["low", "auto"]).optional(),
|
|
143
|
+
outputCompression: z.number().int().min(0).max(100).optional(),
|
|
144
|
+
outputFormat: z.enum(["png", "jpeg", "webp"]).optional(),
|
|
145
|
+
quality: z.enum(["standard", "hd", "low", "medium", "high", "auto"]).optional(),
|
|
146
|
+
responseFormat: z.enum(["url", "b64_json"]).optional(),
|
|
147
|
+
style: z.enum(["vivid", "natural"]).optional(),
|
|
148
|
+
user: z.string().optional()
|
|
149
|
+
}).strict();
|
|
150
|
+
function parseOpenAIProviderOptions(providerOptions, schema) {
|
|
151
|
+
const rawOptions = providerOptions?.openai;
|
|
152
|
+
if (rawOptions === void 0) {
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
return schema.parse(rawOptions);
|
|
156
|
+
}
|
|
157
|
+
function parseOpenAIResponsesGenerateProviderOptions(providerOptions) {
|
|
158
|
+
return parseOpenAIProviderOptions(
|
|
159
|
+
providerOptions,
|
|
160
|
+
openaiResponsesGenerateProviderOptionsSchema
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
function parseOpenAIChatGenerateProviderOptions(providerOptions) {
|
|
164
|
+
return parseOpenAIProviderOptions(
|
|
165
|
+
providerOptions,
|
|
166
|
+
openaiChatGenerateProviderOptionsSchema
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
function parseOpenAIEmbedProviderOptions(providerOptions) {
|
|
170
|
+
return parseOpenAIProviderOptions(
|
|
171
|
+
providerOptions,
|
|
172
|
+
openaiEmbedProviderOptionsSchema
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
function parseOpenAIImageProviderOptions(providerOptions) {
|
|
176
|
+
return parseOpenAIProviderOptions(
|
|
177
|
+
providerOptions,
|
|
178
|
+
openaiImageProviderOptionsSchema
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
var openaiResponsesProviderOptionsSchema = openaiResponsesGenerateProviderOptionsSchema;
|
|
182
|
+
var openaiCompatProviderOptionsSchema = openaiChatGenerateProviderOptionsSchema;
|
|
183
|
+
var openaiCompatGenerateProviderOptionsSchema = openaiChatGenerateProviderOptionsSchema;
|
|
184
|
+
|
|
185
|
+
// src/chat-completions/chat-model.ts
|
|
186
|
+
import { createObjectStream, createChatStream } from "@core-ai/core-ai";
|
|
187
|
+
|
|
188
|
+
// src/chat-completions/chat-adapter.ts
|
|
189
|
+
import { clampReasoningEffort } from "@core-ai/core-ai";
|
|
190
|
+
|
|
191
|
+
// src/shared/tools.ts
|
|
192
|
+
import { zodSchemaToJsonSchema } from "@core-ai/core-ai";
|
|
193
|
+
function convertTools(tools) {
|
|
194
|
+
return Object.values(tools).map((tool) => ({
|
|
195
|
+
type: "function",
|
|
196
|
+
function: {
|
|
197
|
+
name: tool.name,
|
|
198
|
+
description: tool.description,
|
|
199
|
+
parameters: zodSchemaToJsonSchema(tool.parameters)
|
|
200
|
+
}
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
function convertToolChoice(choice) {
|
|
204
|
+
if (typeof choice === "string") {
|
|
205
|
+
return choice;
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
type: "function",
|
|
209
|
+
function: {
|
|
210
|
+
name: choice.toolName
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/shared/utils.ts
|
|
216
|
+
import { ValidationError } from "@core-ai/core-ai";
|
|
217
|
+
function safeParseJsonObject(json) {
|
|
218
|
+
try {
|
|
219
|
+
const parsed = JSON.parse(json);
|
|
220
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
221
|
+
return parsed;
|
|
222
|
+
}
|
|
223
|
+
return {};
|
|
224
|
+
} catch {
|
|
225
|
+
return {};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
function validateOpenAIReasoningConfig(modelId, options) {
|
|
229
|
+
if (!options.reasoning) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const capabilities = getOpenAIModelCapabilities(modelId);
|
|
233
|
+
if (!capabilities.reasoning.restrictsSamplingParams) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const restrictedSamplingParams = [
|
|
237
|
+
{ name: "temperature", value: options.temperature },
|
|
238
|
+
{ name: "topP", value: options.topP }
|
|
239
|
+
];
|
|
240
|
+
for (const { name, value } of restrictedSamplingParams) {
|
|
241
|
+
if (value === void 0) {
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
throw new ValidationError(
|
|
245
|
+
`OpenAI model "${modelId}" does not support ${name} when reasoning is enabled`,
|
|
246
|
+
void 0,
|
|
247
|
+
"openai"
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/chat-completions/compatibility.ts
|
|
253
|
+
function extractCompatibleReasoningText(source) {
|
|
254
|
+
const { reasoning_content, reasoning } = source;
|
|
255
|
+
if (typeof reasoning_content === "string" && reasoning_content.length > 0) {
|
|
256
|
+
return reasoning_content;
|
|
257
|
+
}
|
|
258
|
+
if (typeof reasoning === "string" && reasoning.length > 0) {
|
|
259
|
+
return reasoning;
|
|
260
|
+
}
|
|
261
|
+
return void 0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/chat-completions/chat-adapter.ts
|
|
265
|
+
function convertMessages(messages) {
|
|
266
|
+
return messages.map(convertMessage);
|
|
267
|
+
}
|
|
268
|
+
function convertMessage(message) {
|
|
269
|
+
if (message.role === "system") {
|
|
270
|
+
return {
|
|
271
|
+
role: "system",
|
|
272
|
+
content: message.content
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
if (message.role === "user") {
|
|
276
|
+
return {
|
|
277
|
+
role: "user",
|
|
278
|
+
content: typeof message.content === "string" ? message.content : message.content.map(convertUserContentPart)
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
if (message.role === "assistant") {
|
|
282
|
+
const text = message.parts.flatMap((part) => {
|
|
283
|
+
if (part.type === "text") return [part.text];
|
|
284
|
+
if (part.type === "reasoning" && part.text.length > 0) {
|
|
285
|
+
return [`<thinking>${part.text}</thinking>`];
|
|
286
|
+
}
|
|
287
|
+
return [];
|
|
288
|
+
}).join("\n\n");
|
|
289
|
+
const toolCalls = message.parts.flatMap(
|
|
290
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
291
|
+
);
|
|
292
|
+
return {
|
|
293
|
+
role: "assistant",
|
|
294
|
+
content: text.length > 0 ? text : null,
|
|
295
|
+
...toolCalls.length > 0 ? {
|
|
296
|
+
tool_calls: toolCalls.map((toolCall) => ({
|
|
297
|
+
id: toolCall.id,
|
|
298
|
+
type: "function",
|
|
299
|
+
function: {
|
|
300
|
+
name: toolCall.name,
|
|
301
|
+
arguments: JSON.stringify(toolCall.arguments)
|
|
302
|
+
}
|
|
303
|
+
}))
|
|
304
|
+
} : {}
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
role: "tool",
|
|
309
|
+
tool_call_id: message.toolCallId,
|
|
310
|
+
content: message.content
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function convertUserContentPart(part) {
|
|
314
|
+
if (part.type === "text") {
|
|
315
|
+
return {
|
|
316
|
+
type: "text",
|
|
317
|
+
text: part.text
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (part.type === "image") {
|
|
321
|
+
const url = part.source.type === "url" ? part.source.url : `data:${part.source.mediaType};base64,${part.source.data}`;
|
|
322
|
+
return {
|
|
323
|
+
type: "image_url",
|
|
324
|
+
image_url: {
|
|
325
|
+
url
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
return {
|
|
330
|
+
type: "file",
|
|
331
|
+
file: {
|
|
332
|
+
file_data: part.data,
|
|
333
|
+
...part.filename ? { filename: part.filename } : {}
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
function createGenerateRequest(modelId, options, adapterOptions = {}) {
|
|
338
|
+
return createRequest(modelId, options, false, adapterOptions);
|
|
339
|
+
}
|
|
340
|
+
function createStreamRequest(modelId, options, adapterOptions = {}) {
|
|
341
|
+
return createRequest(modelId, options, true, adapterOptions);
|
|
342
|
+
}
|
|
343
|
+
function createRequest(modelId, options, stream, adapterOptions) {
|
|
344
|
+
const openaiOptions = parseOpenAIChatGenerateProviderOptions(
|
|
345
|
+
options.providerOptions
|
|
346
|
+
);
|
|
347
|
+
const structuredOutputFormat = options.structuredOutputFormat;
|
|
348
|
+
return {
|
|
349
|
+
...createRequestBase(modelId, options, adapterOptions),
|
|
350
|
+
...stream ? {
|
|
351
|
+
stream: true,
|
|
352
|
+
stream_options: {
|
|
353
|
+
include_usage: true
|
|
354
|
+
}
|
|
355
|
+
} : {},
|
|
356
|
+
...structuredOutputFormat ? {
|
|
357
|
+
response_format: {
|
|
358
|
+
type: "json_schema",
|
|
359
|
+
json_schema: {
|
|
360
|
+
name: structuredOutputFormat.name,
|
|
361
|
+
...structuredOutputFormat.description ? {
|
|
362
|
+
description: structuredOutputFormat.description
|
|
363
|
+
} : {},
|
|
364
|
+
strict: structuredOutputFormat.strict,
|
|
365
|
+
schema: structuredOutputFormat.schema
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
} : {},
|
|
369
|
+
...mapOpenAIProviderOptionsToRequestFields(openaiOptions)
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
function createRequestBase(modelId, options, adapterOptions) {
|
|
373
|
+
validateOpenAIReasoningConfig(modelId, options);
|
|
374
|
+
const reasoningFields = mapReasoningToRequestFields(modelId, options);
|
|
375
|
+
return {
|
|
376
|
+
model: modelId,
|
|
377
|
+
messages: convertMessages(options.messages),
|
|
378
|
+
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
379
|
+
...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
|
|
380
|
+
...reasoningFields,
|
|
381
|
+
...mapSamplingToRequestFields(modelId, options, adapterOptions)
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function mapSamplingToRequestFields(modelId, options, adapterOptions) {
|
|
385
|
+
const maxTokensParameter = adapterOptions.maxTokensParameter ?? getOpenAIModelCapabilities(modelId).chatCompletions.maxTokensParameter;
|
|
386
|
+
return {
|
|
387
|
+
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
388
|
+
...options.maxTokens !== void 0 ? maxTokensParameter === "max_completion_tokens" ? { max_completion_tokens: options.maxTokens } : { max_tokens: options.maxTokens } : {},
|
|
389
|
+
...options.topP !== void 0 ? { top_p: options.topP } : {}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function mapOpenAIProviderOptionsToRequestFields(options) {
|
|
393
|
+
return {
|
|
394
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
395
|
+
...options?.serviceTier !== void 0 ? { service_tier: options.serviceTier } : {},
|
|
396
|
+
...options?.parallelToolCalls !== void 0 ? { parallel_tool_calls: options.parallelToolCalls } : {},
|
|
397
|
+
...options?.user !== void 0 ? { user: options.user } : {},
|
|
398
|
+
...options?.stopSequences ? { stop: options.stopSequences } : {},
|
|
399
|
+
...options?.frequencyPenalty !== void 0 ? { frequency_penalty: options.frequencyPenalty } : {},
|
|
400
|
+
...options?.presencePenalty !== void 0 ? { presence_penalty: options.presencePenalty } : {},
|
|
401
|
+
...options?.seed !== void 0 ? { seed: options.seed } : {}
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function mapGenerateResponse(response, adapterOptions = {}) {
|
|
405
|
+
const firstChoice = response.choices[0];
|
|
406
|
+
if (!firstChoice) {
|
|
407
|
+
return {
|
|
408
|
+
parts: [],
|
|
409
|
+
content: null,
|
|
410
|
+
reasoning: null,
|
|
411
|
+
toolCalls: [],
|
|
412
|
+
finishReason: "unknown",
|
|
413
|
+
usage: {
|
|
414
|
+
inputTokens: 0,
|
|
415
|
+
outputTokens: 0,
|
|
416
|
+
inputTokenDetails: {
|
|
417
|
+
cacheReadTokens: 0,
|
|
418
|
+
cacheWriteTokens: 0
|
|
419
|
+
},
|
|
420
|
+
outputTokenDetails: {}
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
const reasoningTokens = response.usage?.completion_tokens_details?.reasoning_tokens;
|
|
425
|
+
const content = extractTextContent(firstChoice.message.content);
|
|
426
|
+
const reasoning = adapterOptions.compatibility ? extractCompatibleReasoningText(firstChoice.message) ?? null : null;
|
|
427
|
+
const toolCalls = parseToolCalls(firstChoice.message.tool_calls);
|
|
428
|
+
const parts = createAssistantParts(reasoning, content, toolCalls);
|
|
429
|
+
return {
|
|
430
|
+
parts,
|
|
431
|
+
content,
|
|
432
|
+
reasoning,
|
|
433
|
+
toolCalls,
|
|
434
|
+
finishReason: mapFinishReason(firstChoice.finish_reason),
|
|
435
|
+
usage: {
|
|
436
|
+
inputTokens: response.usage?.prompt_tokens ?? 0,
|
|
437
|
+
outputTokens: response.usage?.completion_tokens ?? 0,
|
|
438
|
+
inputTokenDetails: {
|
|
439
|
+
cacheReadTokens: response.usage?.prompt_tokens_details?.cached_tokens ?? 0,
|
|
440
|
+
cacheWriteTokens: 0
|
|
441
|
+
},
|
|
442
|
+
outputTokenDetails: {
|
|
443
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
function parseToolCalls(calls) {
|
|
449
|
+
if (!calls) {
|
|
450
|
+
return [];
|
|
451
|
+
}
|
|
452
|
+
return calls.flatMap((toolCall) => {
|
|
453
|
+
if (toolCall.type !== "function") {
|
|
454
|
+
return [];
|
|
455
|
+
}
|
|
456
|
+
return [mapFunctionToolCall(toolCall)];
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
function mapFunctionToolCall(toolCall) {
|
|
460
|
+
return {
|
|
461
|
+
id: toolCall.id,
|
|
462
|
+
name: toolCall.function.name,
|
|
463
|
+
arguments: safeParseJsonObject(toolCall.function.arguments)
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
function mapFinishReason(reason) {
|
|
467
|
+
if (reason === "stop") {
|
|
468
|
+
return "stop";
|
|
469
|
+
}
|
|
470
|
+
if (reason === "length") {
|
|
471
|
+
return "length";
|
|
472
|
+
}
|
|
473
|
+
if (reason === "tool_calls" || reason === "function_call") {
|
|
474
|
+
return "tool-calls";
|
|
475
|
+
}
|
|
476
|
+
if (reason === "content_filter") {
|
|
477
|
+
return "content-filter";
|
|
478
|
+
}
|
|
479
|
+
return "unknown";
|
|
480
|
+
}
|
|
481
|
+
async function* transformStream(stream, adapterOptions = {}) {
|
|
482
|
+
const bufferedToolCalls = /* @__PURE__ */ new Map();
|
|
483
|
+
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
484
|
+
let finishReason = "unknown";
|
|
485
|
+
let textOpen = false;
|
|
486
|
+
let reasoningOpen = false;
|
|
487
|
+
let usage = {
|
|
488
|
+
inputTokens: 0,
|
|
489
|
+
outputTokens: 0,
|
|
490
|
+
inputTokenDetails: {
|
|
491
|
+
cacheReadTokens: 0,
|
|
492
|
+
cacheWriteTokens: 0
|
|
493
|
+
},
|
|
494
|
+
outputTokenDetails: {}
|
|
495
|
+
};
|
|
496
|
+
const startText = function* () {
|
|
497
|
+
if (textOpen) {
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
textOpen = true;
|
|
501
|
+
yield { type: "text-start" };
|
|
502
|
+
};
|
|
503
|
+
const closeText = function* () {
|
|
504
|
+
if (!textOpen) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
textOpen = false;
|
|
508
|
+
yield { type: "text-end" };
|
|
509
|
+
};
|
|
510
|
+
const startReasoning = function* () {
|
|
511
|
+
if (reasoningOpen) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
reasoningOpen = true;
|
|
515
|
+
yield { type: "reasoning-start" };
|
|
516
|
+
};
|
|
517
|
+
const closeReasoning = function* () {
|
|
518
|
+
if (!reasoningOpen) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
reasoningOpen = false;
|
|
522
|
+
yield { type: "reasoning-end" };
|
|
523
|
+
};
|
|
524
|
+
for await (const chunk of stream) {
|
|
525
|
+
if (chunk.usage) {
|
|
526
|
+
const reasoningTokens = chunk.usage.completion_tokens_details?.reasoning_tokens;
|
|
527
|
+
usage = {
|
|
528
|
+
inputTokens: chunk.usage.prompt_tokens ?? 0,
|
|
529
|
+
outputTokens: chunk.usage.completion_tokens ?? 0,
|
|
530
|
+
inputTokenDetails: {
|
|
531
|
+
cacheReadTokens: chunk.usage.prompt_tokens_details?.cached_tokens ?? 0,
|
|
532
|
+
cacheWriteTokens: 0
|
|
533
|
+
},
|
|
534
|
+
outputTokenDetails: {
|
|
535
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {}
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const choice = chunk.choices[0];
|
|
540
|
+
if (!choice) {
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
const reasoningDelta = adapterOptions.compatibility ? extractCompatibleReasoningText(choice.delta) : void 0;
|
|
544
|
+
if (reasoningDelta !== void 0) {
|
|
545
|
+
yield* closeText();
|
|
546
|
+
yield* startReasoning();
|
|
547
|
+
yield {
|
|
548
|
+
type: "reasoning-delta",
|
|
549
|
+
text: reasoningDelta
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
if (choice.delta.content) {
|
|
553
|
+
yield* closeReasoning();
|
|
554
|
+
yield* startText();
|
|
555
|
+
yield {
|
|
556
|
+
type: "text-delta",
|
|
557
|
+
text: choice.delta.content
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
if (choice.delta.tool_calls) {
|
|
561
|
+
yield* closeReasoning();
|
|
562
|
+
yield* closeText();
|
|
563
|
+
for (const partialToolCall of choice.delta.tool_calls) {
|
|
564
|
+
const current = bufferedToolCalls.get(
|
|
565
|
+
partialToolCall.index
|
|
566
|
+
) ?? {
|
|
567
|
+
id: partialToolCall.id ?? `tool-${partialToolCall.index}`,
|
|
568
|
+
name: partialToolCall.function?.name ?? "",
|
|
569
|
+
arguments: ""
|
|
570
|
+
};
|
|
571
|
+
const wasNew = !bufferedToolCalls.has(partialToolCall.index);
|
|
572
|
+
if (partialToolCall.id) {
|
|
573
|
+
current.id = partialToolCall.id;
|
|
574
|
+
}
|
|
575
|
+
if (partialToolCall.function?.name) {
|
|
576
|
+
current.name = partialToolCall.function.name;
|
|
577
|
+
}
|
|
578
|
+
if (partialToolCall.function?.arguments) {
|
|
579
|
+
current.arguments += partialToolCall.function.arguments;
|
|
580
|
+
yield {
|
|
581
|
+
type: "tool-call-delta",
|
|
582
|
+
toolCallId: current.id,
|
|
583
|
+
argumentsDelta: partialToolCall.function.arguments
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
bufferedToolCalls.set(partialToolCall.index, current);
|
|
587
|
+
if (wasNew) {
|
|
588
|
+
yield {
|
|
589
|
+
type: "tool-call-start",
|
|
590
|
+
toolCallId: current.id,
|
|
591
|
+
toolName: current.name
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (choice.finish_reason) {
|
|
597
|
+
finishReason = mapFinishReason(choice.finish_reason);
|
|
598
|
+
}
|
|
599
|
+
if (finishReason === "tool-calls") {
|
|
600
|
+
yield* closeReasoning();
|
|
601
|
+
yield* closeText();
|
|
602
|
+
for (const toolCall of bufferedToolCalls.values()) {
|
|
603
|
+
if (emittedToolCalls.has(toolCall.id)) {
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
emittedToolCalls.add(toolCall.id);
|
|
607
|
+
yield {
|
|
608
|
+
type: "tool-call-end",
|
|
609
|
+
toolCall: {
|
|
610
|
+
id: toolCall.id,
|
|
611
|
+
name: toolCall.name,
|
|
612
|
+
arguments: safeParseJsonObject(toolCall.arguments)
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
yield* closeReasoning();
|
|
619
|
+
yield* closeText();
|
|
620
|
+
yield {
|
|
621
|
+
type: "finish",
|
|
622
|
+
finishReason,
|
|
623
|
+
usage
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function mapReasoningToRequestFields(modelId, options) {
|
|
627
|
+
if (!options.reasoning) {
|
|
628
|
+
return {};
|
|
629
|
+
}
|
|
630
|
+
const capabilities = getOpenAIModelCapabilities(modelId);
|
|
631
|
+
if (!capabilities.reasoning.supported) {
|
|
632
|
+
return {};
|
|
633
|
+
}
|
|
634
|
+
const clampedEffort = clampReasoningEffort(
|
|
635
|
+
options.reasoning.effort,
|
|
636
|
+
capabilities.reasoning.supportedEfforts
|
|
637
|
+
);
|
|
638
|
+
return {
|
|
639
|
+
reasoning_effort: toOpenAIReasoningEffort(clampedEffort)
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
function createAssistantParts(reasoning, content, toolCalls) {
|
|
643
|
+
const parts = [];
|
|
644
|
+
if (reasoning) {
|
|
645
|
+
parts.push({
|
|
646
|
+
type: "reasoning",
|
|
647
|
+
text: reasoning
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
if (content) {
|
|
651
|
+
parts.push({
|
|
652
|
+
type: "text",
|
|
653
|
+
text: content
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
for (const toolCall of toolCalls) {
|
|
657
|
+
parts.push({
|
|
658
|
+
type: "tool-call",
|
|
659
|
+
toolCall
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
return parts;
|
|
663
|
+
}
|
|
664
|
+
function extractTextContent(content) {
|
|
665
|
+
if (typeof content === "string") {
|
|
666
|
+
return content;
|
|
667
|
+
}
|
|
668
|
+
if (!Array.isArray(content)) {
|
|
669
|
+
return null;
|
|
670
|
+
}
|
|
671
|
+
const text = content.flatMap((item) => {
|
|
672
|
+
if (!item || typeof item !== "object") {
|
|
673
|
+
return [];
|
|
674
|
+
}
|
|
675
|
+
const textValue = item.text;
|
|
676
|
+
return typeof textValue === "string" ? [textValue] : [];
|
|
677
|
+
}).join("");
|
|
678
|
+
return text.length > 0 ? text : null;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/openai-error.ts
|
|
682
|
+
import { APIError, APIUserAbortError } from "openai";
|
|
683
|
+
import { AbortedError, ProviderError } from "@core-ai/core-ai";
|
|
684
|
+
function isOpenAIAbortError(error) {
|
|
685
|
+
return error instanceof APIUserAbortError || error instanceof Error && error.name === "AbortError";
|
|
686
|
+
}
|
|
687
|
+
function wrapOpenAIError(error, provider = "openai") {
|
|
688
|
+
if (isOpenAIAbortError(error)) {
|
|
689
|
+
return new AbortedError(error, provider);
|
|
690
|
+
}
|
|
691
|
+
if (error instanceof APIError) {
|
|
692
|
+
return new ProviderError(
|
|
693
|
+
error.message,
|
|
694
|
+
provider,
|
|
695
|
+
error.status,
|
|
696
|
+
error
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
return new ProviderError(
|
|
700
|
+
error instanceof Error ? error.message : String(error),
|
|
701
|
+
provider,
|
|
702
|
+
void 0,
|
|
703
|
+
error
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// src/shared/structured-output.ts
|
|
708
|
+
import { zodTextFormat } from "openai/helpers/zod";
|
|
709
|
+
import {
|
|
710
|
+
StructuredOutputNoObjectGeneratedError,
|
|
711
|
+
StructuredOutputParseError,
|
|
712
|
+
StructuredOutputValidationError
|
|
713
|
+
} from "@core-ai/core-ai";
|
|
714
|
+
var DEFAULT_STRUCTURED_OUTPUT_NAME = "core_ai_generate_object";
|
|
715
|
+
var DEFAULT_STRUCTURED_OUTPUT_DESCRIPTION = "Return a JSON object that matches the requested schema.";
|
|
716
|
+
function getStructuredOutputName(options) {
|
|
717
|
+
return options.schemaName?.trim() || DEFAULT_STRUCTURED_OUTPUT_NAME;
|
|
718
|
+
}
|
|
719
|
+
function createStructuredOutputRequestOptions(options, mode = "native") {
|
|
720
|
+
const baseOptions = {
|
|
721
|
+
messages: options.messages,
|
|
722
|
+
reasoning: options.reasoning,
|
|
723
|
+
temperature: options.temperature,
|
|
724
|
+
maxTokens: options.maxTokens,
|
|
725
|
+
topP: options.topP,
|
|
726
|
+
providerOptions: options.providerOptions,
|
|
727
|
+
signal: options.signal
|
|
728
|
+
};
|
|
729
|
+
if (mode === "tool") {
|
|
730
|
+
const name = getStructuredOutputName(options);
|
|
731
|
+
return {
|
|
732
|
+
...baseOptions,
|
|
733
|
+
tools: {
|
|
734
|
+
structured_output: {
|
|
735
|
+
name,
|
|
736
|
+
description: options.schemaDescription ?? DEFAULT_STRUCTURED_OUTPUT_DESCRIPTION,
|
|
737
|
+
parameters: options.schema
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
toolChoice: {
|
|
741
|
+
type: "tool",
|
|
742
|
+
toolName: name
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
return {
|
|
747
|
+
...baseOptions,
|
|
748
|
+
structuredOutputFormat: createOpenAIStructuredOutputFormat(options)
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
function createOpenAIStructuredOutputFormat(options) {
|
|
752
|
+
const name = getStructuredOutputName(options);
|
|
753
|
+
const format = zodTextFormat(
|
|
754
|
+
options.schema,
|
|
755
|
+
name,
|
|
756
|
+
options.schemaDescription ? { description: options.schemaDescription } : void 0
|
|
757
|
+
);
|
|
758
|
+
return {
|
|
759
|
+
type: "json_schema",
|
|
760
|
+
name,
|
|
761
|
+
...options.schemaDescription ? { description: options.schemaDescription } : {},
|
|
762
|
+
strict: true,
|
|
763
|
+
schema: format.schema
|
|
764
|
+
};
|
|
765
|
+
}
|
|
766
|
+
function extractStructuredObject(result, schema, provider, structuredOutputName) {
|
|
767
|
+
const structuredToolCall = result.toolCalls.find(
|
|
768
|
+
(toolCall) => toolCall.name === structuredOutputName
|
|
769
|
+
);
|
|
770
|
+
if (structuredToolCall) {
|
|
771
|
+
return validateStructuredToolArguments(
|
|
772
|
+
schema,
|
|
773
|
+
structuredToolCall.arguments,
|
|
774
|
+
provider
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
const rawOutput = result.content?.trim();
|
|
778
|
+
if (rawOutput && rawOutput.length > 0) {
|
|
779
|
+
return parseAndValidateStructuredPayload(schema, rawOutput, provider);
|
|
780
|
+
}
|
|
781
|
+
throw new StructuredOutputNoObjectGeneratedError(
|
|
782
|
+
"model did not emit a structured object payload",
|
|
783
|
+
provider
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
async function* transformStructuredOutputStream(stream, schema, provider, structuredOutputName) {
|
|
787
|
+
let validatedObject;
|
|
788
|
+
let contentBuffer = "";
|
|
789
|
+
const toolArgumentDeltas = /* @__PURE__ */ new Map();
|
|
790
|
+
for await (const event of stream) {
|
|
791
|
+
if (event.type === "text-delta") {
|
|
792
|
+
contentBuffer += event.text;
|
|
793
|
+
yield {
|
|
794
|
+
type: "object-delta",
|
|
795
|
+
text: event.text
|
|
796
|
+
};
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
799
|
+
if (event.type === "tool-call-delta") {
|
|
800
|
+
const previous = toolArgumentDeltas.get(event.toolCallId) ?? "";
|
|
801
|
+
toolArgumentDeltas.set(
|
|
802
|
+
event.toolCallId,
|
|
803
|
+
`${previous}${event.argumentsDelta}`
|
|
804
|
+
);
|
|
805
|
+
yield {
|
|
806
|
+
type: "object-delta",
|
|
807
|
+
text: event.argumentsDelta
|
|
808
|
+
};
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (event.type === "tool-call-end" && event.toolCall.name === structuredOutputName) {
|
|
812
|
+
validatedObject = validateStructuredToolArguments(
|
|
813
|
+
schema,
|
|
814
|
+
event.toolCall.arguments,
|
|
815
|
+
provider
|
|
816
|
+
);
|
|
817
|
+
yield {
|
|
818
|
+
type: "object",
|
|
819
|
+
object: validatedObject
|
|
820
|
+
};
|
|
821
|
+
continue;
|
|
822
|
+
}
|
|
823
|
+
if (event.type === "finish") {
|
|
824
|
+
if (validatedObject === void 0) {
|
|
825
|
+
const fallbackPayload = getFallbackStructuredPayload(
|
|
826
|
+
contentBuffer,
|
|
827
|
+
toolArgumentDeltas
|
|
828
|
+
);
|
|
829
|
+
if (!fallbackPayload) {
|
|
830
|
+
throw new StructuredOutputNoObjectGeneratedError(
|
|
831
|
+
"structured output stream ended without an object payload",
|
|
832
|
+
provider
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
validatedObject = parseAndValidateStructuredPayload(
|
|
836
|
+
schema,
|
|
837
|
+
fallbackPayload,
|
|
838
|
+
provider
|
|
839
|
+
);
|
|
840
|
+
yield {
|
|
841
|
+
type: "object",
|
|
842
|
+
object: validatedObject
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
yield {
|
|
846
|
+
type: "finish",
|
|
847
|
+
finishReason: event.finishReason,
|
|
848
|
+
usage: event.usage
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
function getFallbackStructuredPayload(contentBuffer, toolArgumentDeltas) {
|
|
854
|
+
for (const delta of toolArgumentDeltas.values()) {
|
|
855
|
+
const trimmed = delta.trim();
|
|
856
|
+
if (trimmed.length > 0) {
|
|
857
|
+
return trimmed;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
const trimmedContent = contentBuffer.trim();
|
|
861
|
+
if (trimmedContent.length > 0) {
|
|
862
|
+
return trimmedContent;
|
|
863
|
+
}
|
|
864
|
+
return void 0;
|
|
865
|
+
}
|
|
866
|
+
function validateStructuredToolArguments(schema, toolArguments, provider) {
|
|
867
|
+
return validateStructuredObject(
|
|
868
|
+
schema,
|
|
869
|
+
toolArguments,
|
|
870
|
+
provider,
|
|
871
|
+
JSON.stringify(toolArguments)
|
|
872
|
+
);
|
|
873
|
+
}
|
|
874
|
+
function parseAndValidateStructuredPayload(schema, rawPayload, provider) {
|
|
875
|
+
const parsedPayload = parseJson(rawPayload, provider);
|
|
876
|
+
return validateStructuredObject(
|
|
877
|
+
schema,
|
|
878
|
+
parsedPayload,
|
|
879
|
+
provider,
|
|
880
|
+
rawPayload
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
function parseJson(rawOutput, provider) {
|
|
884
|
+
try {
|
|
885
|
+
return JSON.parse(rawOutput);
|
|
886
|
+
} catch (error) {
|
|
887
|
+
throw new StructuredOutputParseError(
|
|
888
|
+
"failed to parse structured output as JSON",
|
|
889
|
+
provider,
|
|
890
|
+
{
|
|
891
|
+
rawOutput,
|
|
892
|
+
cause: error
|
|
893
|
+
}
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
function validateStructuredObject(schema, value, provider, rawOutput) {
|
|
898
|
+
const parsed = schema.safeParse(value);
|
|
899
|
+
if (parsed.success) {
|
|
900
|
+
return parsed.data;
|
|
901
|
+
}
|
|
902
|
+
throw new StructuredOutputValidationError(
|
|
903
|
+
"structured output does not match schema",
|
|
904
|
+
provider,
|
|
905
|
+
formatZodIssues(parsed.error.issues),
|
|
906
|
+
{
|
|
907
|
+
rawOutput
|
|
908
|
+
}
|
|
909
|
+
);
|
|
910
|
+
}
|
|
911
|
+
function formatZodIssues(issues) {
|
|
912
|
+
return issues.map((issue) => {
|
|
913
|
+
const path = issue.path.length > 0 ? issue.path.map((segment) => String(segment)).join(".") : "<root>";
|
|
914
|
+
return `${path}: ${issue.message}`;
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
// src/chat-completions/chat-model.ts
|
|
919
|
+
function createOpenAIChatCompletionsModel(client, modelId, modelOptions = {}) {
|
|
920
|
+
const provider = modelOptions.providerId ?? "openai";
|
|
921
|
+
const structuredOutputMode = modelOptions.structuredOutputMode ?? (modelOptions.compatibility ? "tool" : "native");
|
|
922
|
+
const nonStandardReasoning = modelOptions.nonStandardReasoning ?? modelOptions.compatibility;
|
|
923
|
+
async function callOpenAIChatCompletionsApi(request, signal) {
|
|
924
|
+
try {
|
|
925
|
+
return await client.chat.completions.create(request, {
|
|
926
|
+
signal
|
|
927
|
+
});
|
|
928
|
+
} catch (error) {
|
|
929
|
+
throw wrapOpenAIError(error, provider);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
async function generateChat(options) {
|
|
933
|
+
const request = createGenerateRequest(modelId, options, modelOptions);
|
|
934
|
+
const response = await callOpenAIChatCompletionsApi(request, options.signal);
|
|
935
|
+
return mapGenerateResponse(response, {
|
|
936
|
+
compatibility: nonStandardReasoning
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
async function streamChat(options) {
|
|
940
|
+
const request = createStreamRequest(modelId, options, modelOptions);
|
|
941
|
+
return createChatStream(
|
|
942
|
+
async () => transformStream(
|
|
943
|
+
await callOpenAIChatCompletionsApi(request, options.signal),
|
|
944
|
+
{
|
|
945
|
+
compatibility: nonStandardReasoning
|
|
946
|
+
}
|
|
947
|
+
),
|
|
948
|
+
{ signal: options.signal }
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
return {
|
|
952
|
+
provider,
|
|
953
|
+
modelId,
|
|
954
|
+
capabilities: getOpenAIModelCapabilities(modelId),
|
|
955
|
+
generate: generateChat,
|
|
956
|
+
stream: streamChat,
|
|
957
|
+
async generateObject(options) {
|
|
958
|
+
const structuredOptions = createStructuredOutputRequestOptions(
|
|
959
|
+
options,
|
|
960
|
+
structuredOutputMode
|
|
961
|
+
);
|
|
962
|
+
const result = await generateChat(structuredOptions);
|
|
963
|
+
const structuredOutputName = getStructuredOutputName(options);
|
|
964
|
+
const object = extractStructuredObject(
|
|
965
|
+
result,
|
|
966
|
+
options.schema,
|
|
967
|
+
provider,
|
|
968
|
+
structuredOutputName
|
|
969
|
+
);
|
|
970
|
+
return {
|
|
971
|
+
object,
|
|
972
|
+
finishReason: result.finishReason,
|
|
973
|
+
usage: result.usage
|
|
974
|
+
};
|
|
975
|
+
},
|
|
976
|
+
async streamObject(options) {
|
|
977
|
+
const structuredOptions = createStructuredOutputRequestOptions(
|
|
978
|
+
options,
|
|
979
|
+
structuredOutputMode
|
|
980
|
+
);
|
|
981
|
+
const stream = await streamChat(structuredOptions);
|
|
982
|
+
const structuredOutputName = getStructuredOutputName(options);
|
|
983
|
+
return createObjectStream(
|
|
984
|
+
transformStructuredOutputStream(
|
|
985
|
+
stream,
|
|
986
|
+
options.schema,
|
|
987
|
+
provider,
|
|
988
|
+
structuredOutputName
|
|
989
|
+
),
|
|
990
|
+
{
|
|
991
|
+
signal: options.signal
|
|
992
|
+
}
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// src/shared/provider-factory.ts
|
|
999
|
+
import OpenAI from "openai";
|
|
1000
|
+
|
|
1001
|
+
// src/chat-model.ts
|
|
1002
|
+
import { createObjectStream as createObjectStream2, createChatStream as createChatStream2 } from "@core-ai/core-ai";
|
|
1003
|
+
|
|
1004
|
+
// src/chat-adapter.ts
|
|
1005
|
+
import { getProviderMetadata, clampReasoningEffort as clampReasoningEffort2 } from "@core-ai/core-ai";
|
|
1006
|
+
var ENCRYPTED_REASONING_INCLUDE = "reasoning.encrypted_content";
|
|
1007
|
+
var REASONING_SUMMARY_SEPARATOR = "\n\n";
|
|
1008
|
+
function convertMessages2(messages) {
|
|
1009
|
+
return messages.flatMap(convertMessage2);
|
|
1010
|
+
}
|
|
1011
|
+
function convertMessage2(message) {
|
|
1012
|
+
if (message.role === "system") {
|
|
1013
|
+
return [
|
|
1014
|
+
{
|
|
1015
|
+
role: "developer",
|
|
1016
|
+
content: message.content
|
|
1017
|
+
}
|
|
1018
|
+
];
|
|
1019
|
+
}
|
|
1020
|
+
if (message.role === "user") {
|
|
1021
|
+
return [
|
|
1022
|
+
{
|
|
1023
|
+
role: "user",
|
|
1024
|
+
content: typeof message.content === "string" ? message.content : message.content.map(convertUserContentPart2)
|
|
1025
|
+
}
|
|
1026
|
+
];
|
|
1027
|
+
}
|
|
1028
|
+
if (message.role === "assistant") {
|
|
1029
|
+
return convertAssistantMessage(message.parts);
|
|
1030
|
+
}
|
|
1031
|
+
return [
|
|
1032
|
+
{
|
|
1033
|
+
type: "function_call_output",
|
|
1034
|
+
call_id: message.toolCallId,
|
|
1035
|
+
output: message.content
|
|
1036
|
+
}
|
|
1037
|
+
];
|
|
1038
|
+
}
|
|
1039
|
+
function convertAssistantMessage(parts) {
|
|
1040
|
+
const items = [];
|
|
1041
|
+
const textParts = [];
|
|
1042
|
+
const flushTextBuffer = () => {
|
|
1043
|
+
if (textParts.length === 0) {
|
|
1044
|
+
return;
|
|
1045
|
+
}
|
|
1046
|
+
items.push({
|
|
1047
|
+
role: "assistant",
|
|
1048
|
+
content: textParts.join("\n\n")
|
|
1049
|
+
});
|
|
1050
|
+
textParts.length = 0;
|
|
1051
|
+
};
|
|
1052
|
+
for (const part of parts) {
|
|
1053
|
+
if (part.type === "text") {
|
|
1054
|
+
textParts.push(part.text);
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
if (part.type === "reasoning") {
|
|
1058
|
+
if (getProviderMetadata(
|
|
1059
|
+
part.providerMetadata,
|
|
1060
|
+
"openai"
|
|
1061
|
+
) == null) {
|
|
1062
|
+
if (part.text.length > 0) {
|
|
1063
|
+
textParts.push(`<thinking>${part.text}</thinking>`);
|
|
1064
|
+
}
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
flushTextBuffer();
|
|
1068
|
+
const encryptedContent = getEncryptedReasoningContent(part);
|
|
1069
|
+
items.push({
|
|
1070
|
+
type: "reasoning",
|
|
1071
|
+
summary: [
|
|
1072
|
+
{
|
|
1073
|
+
type: "summary_text",
|
|
1074
|
+
text: part.text
|
|
1075
|
+
}
|
|
1076
|
+
],
|
|
1077
|
+
...encryptedContent ? { encrypted_content: encryptedContent } : {}
|
|
1078
|
+
});
|
|
1079
|
+
continue;
|
|
1080
|
+
}
|
|
1081
|
+
flushTextBuffer();
|
|
1082
|
+
items.push({
|
|
1083
|
+
type: "function_call",
|
|
1084
|
+
call_id: part.toolCall.id,
|
|
1085
|
+
name: part.toolCall.name,
|
|
1086
|
+
arguments: JSON.stringify(part.toolCall.arguments)
|
|
1087
|
+
});
|
|
1088
|
+
}
|
|
1089
|
+
flushTextBuffer();
|
|
1090
|
+
return items;
|
|
1091
|
+
}
|
|
1092
|
+
function getEncryptedReasoningContent(part) {
|
|
1093
|
+
const { encryptedContent } = getProviderMetadata(
|
|
1094
|
+
part.providerMetadata,
|
|
1095
|
+
"openai"
|
|
1096
|
+
) ?? {};
|
|
1097
|
+
return typeof encryptedContent === "string" && encryptedContent.length > 0 ? encryptedContent : void 0;
|
|
1098
|
+
}
|
|
1099
|
+
function convertUserContentPart2(part) {
|
|
1100
|
+
if (part.type === "text") {
|
|
1101
|
+
return {
|
|
1102
|
+
type: "input_text",
|
|
1103
|
+
text: part.text
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
if (part.type === "image") {
|
|
1107
|
+
const imageUrl = part.source.type === "url" ? part.source.url : `data:${part.source.mediaType};base64,${part.source.data}`;
|
|
1108
|
+
return {
|
|
1109
|
+
type: "input_image",
|
|
1110
|
+
image_url: imageUrl
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
type: "input_file",
|
|
1115
|
+
file_data: part.data,
|
|
1116
|
+
...part.filename ? { filename: part.filename } : {}
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1119
|
+
function createGenerateRequest2(modelId, options) {
|
|
1120
|
+
return createRequest2(
|
|
1121
|
+
modelId,
|
|
1122
|
+
options,
|
|
1123
|
+
false
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
function createStreamRequest2(modelId, options) {
|
|
1127
|
+
return createRequest2(
|
|
1128
|
+
modelId,
|
|
1129
|
+
options,
|
|
1130
|
+
true
|
|
1131
|
+
);
|
|
1132
|
+
}
|
|
1133
|
+
function createRequest2(modelId, options, stream) {
|
|
1134
|
+
const openaiOptions = parseOpenAIResponsesGenerateProviderOptions(
|
|
1135
|
+
options.providerOptions
|
|
1136
|
+
);
|
|
1137
|
+
const request = {
|
|
1138
|
+
...createRequestBase2(modelId, options),
|
|
1139
|
+
...stream ? { stream: true } : {},
|
|
1140
|
+
...options.structuredOutputFormat ? { text: { format: options.structuredOutputFormat } } : {},
|
|
1141
|
+
...mapOpenAIProviderOptionsToRequestFields2(openaiOptions)
|
|
1142
|
+
};
|
|
1143
|
+
if (options.reasoning && getOpenAIModelCapabilities(modelId).reasoning.supported) {
|
|
1144
|
+
request.include = mergeInclude(request.include, [
|
|
1145
|
+
ENCRYPTED_REASONING_INCLUDE
|
|
1146
|
+
]);
|
|
1147
|
+
}
|
|
1148
|
+
return request;
|
|
1149
|
+
}
|
|
1150
|
+
function createRequestBase2(modelId, options) {
|
|
1151
|
+
validateOpenAIReasoningConfig(modelId, options);
|
|
1152
|
+
return {
|
|
1153
|
+
model: modelId,
|
|
1154
|
+
store: false,
|
|
1155
|
+
input: convertMessages2(options.messages),
|
|
1156
|
+
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertResponseTools(options.tools) } : {},
|
|
1157
|
+
...options.toolChoice ? { tool_choice: convertResponseToolChoice(options.toolChoice) } : {},
|
|
1158
|
+
...mapReasoningToRequestFields2(modelId, options),
|
|
1159
|
+
...mapSamplingToRequestFields2(options)
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
function convertResponseTools(tools) {
|
|
1163
|
+
return convertTools(tools).map((tool) => ({
|
|
1164
|
+
type: "function",
|
|
1165
|
+
name: tool.function.name,
|
|
1166
|
+
description: tool.function.description,
|
|
1167
|
+
parameters: tool.function.parameters
|
|
1168
|
+
}));
|
|
1169
|
+
}
|
|
1170
|
+
function convertResponseToolChoice(choice) {
|
|
1171
|
+
const converted = convertToolChoice(choice);
|
|
1172
|
+
if (typeof converted === "string") {
|
|
1173
|
+
return converted;
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
type: "function",
|
|
1177
|
+
name: converted.function.name
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
function mergeInclude(value, requiredIncludes) {
|
|
1181
|
+
const include = Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
1182
|
+
for (const requiredInclude of requiredIncludes) {
|
|
1183
|
+
if (!include.includes(requiredInclude)) {
|
|
1184
|
+
include.push(requiredInclude);
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
return include.length > 0 ? include : void 0;
|
|
1188
|
+
}
|
|
1189
|
+
function mapSamplingToRequestFields2(options) {
|
|
1190
|
+
return {
|
|
1191
|
+
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
1192
|
+
...options.maxTokens !== void 0 ? { max_output_tokens: options.maxTokens } : {},
|
|
1193
|
+
...options.topP !== void 0 ? { top_p: options.topP } : {}
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
function mapOpenAIProviderOptionsToRequestFields2(options) {
|
|
1197
|
+
return {
|
|
1198
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1199
|
+
...options?.serviceTier !== void 0 ? { service_tier: options.serviceTier } : {},
|
|
1200
|
+
...options?.include ? { include: options.include } : {},
|
|
1201
|
+
...options?.parallelToolCalls !== void 0 ? { parallel_tool_calls: options.parallelToolCalls } : {},
|
|
1202
|
+
...options?.user !== void 0 ? { user: options.user } : {}
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
function mapGenerateResponse2(response) {
|
|
1206
|
+
const parts = [];
|
|
1207
|
+
for (const item of response.output) {
|
|
1208
|
+
if (isReasoningItem(item)) {
|
|
1209
|
+
const reasoningPart = mapReasoningPart(item);
|
|
1210
|
+
if (reasoningPart) {
|
|
1211
|
+
parts.push(reasoningPart);
|
|
1212
|
+
}
|
|
1213
|
+
continue;
|
|
1214
|
+
}
|
|
1215
|
+
if (isOutputMessage(item)) {
|
|
1216
|
+
parts.push(...mapMessageTextParts(item));
|
|
1217
|
+
continue;
|
|
1218
|
+
}
|
|
1219
|
+
if (isFunctionToolCall(item)) {
|
|
1220
|
+
parts.push({
|
|
1221
|
+
type: "tool-call",
|
|
1222
|
+
toolCall: {
|
|
1223
|
+
id: item.call_id,
|
|
1224
|
+
name: item.name,
|
|
1225
|
+
arguments: safeParseJsonObject(item.arguments)
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
const content = getTextContent(parts);
|
|
1231
|
+
const reasoning = getReasoningText(parts);
|
|
1232
|
+
const toolCalls = getToolCalls(parts);
|
|
1233
|
+
return {
|
|
1234
|
+
parts,
|
|
1235
|
+
content,
|
|
1236
|
+
reasoning,
|
|
1237
|
+
toolCalls,
|
|
1238
|
+
finishReason: mapFinishReason2(response, toolCalls.length > 0),
|
|
1239
|
+
usage: mapUsage(response.usage)
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
function mapReasoningPart(item) {
|
|
1243
|
+
const text = getReasoningSummaryText(item.summary);
|
|
1244
|
+
const encryptedContent = typeof item.encrypted_content === "string" && item.encrypted_content.length > 0 ? item.encrypted_content : void 0;
|
|
1245
|
+
if (text.length === 0 && !encryptedContent) {
|
|
1246
|
+
return null;
|
|
1247
|
+
}
|
|
1248
|
+
return {
|
|
1249
|
+
type: "reasoning",
|
|
1250
|
+
text,
|
|
1251
|
+
providerMetadata: {
|
|
1252
|
+
openai: { ...encryptedContent ? { encryptedContent } : {} }
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
function getReasoningSummaryText(summary) {
|
|
1257
|
+
return summary.map((item) => item.text).join(REASONING_SUMMARY_SEPARATOR);
|
|
1258
|
+
}
|
|
1259
|
+
function mapMessageTextParts(message) {
|
|
1260
|
+
return message.content.flatMap(
|
|
1261
|
+
(contentItem) => contentItem.type === "output_text" && contentItem.text.length > 0 ? [{ type: "text", text: contentItem.text }] : []
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
function getTextContent(parts) {
|
|
1265
|
+
return getJoinedPartText(parts, "text", "");
|
|
1266
|
+
}
|
|
1267
|
+
function getReasoningText(parts) {
|
|
1268
|
+
return getJoinedPartText(parts, "reasoning", REASONING_SUMMARY_SEPARATOR);
|
|
1269
|
+
}
|
|
1270
|
+
function getJoinedPartText(parts, type, separator) {
|
|
1271
|
+
const text = parts.flatMap(
|
|
1272
|
+
(part) => part.type === type && "text" in part ? [part.text] : []
|
|
1273
|
+
).join(separator);
|
|
1274
|
+
return text.length > 0 ? text : null;
|
|
1275
|
+
}
|
|
1276
|
+
function getToolCalls(parts) {
|
|
1277
|
+
return parts.flatMap(
|
|
1278
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
1279
|
+
);
|
|
1280
|
+
}
|
|
1281
|
+
function mapFinishReason2(response, hasToolCalls) {
|
|
1282
|
+
const incompleteReason = response.incomplete_details?.reason;
|
|
1283
|
+
if (incompleteReason === "max_output_tokens") {
|
|
1284
|
+
return "length";
|
|
1285
|
+
}
|
|
1286
|
+
if (incompleteReason === "content_filter") {
|
|
1287
|
+
return "content-filter";
|
|
1288
|
+
}
|
|
1289
|
+
if (hasToolCalls) {
|
|
1290
|
+
return "tool-calls";
|
|
1291
|
+
}
|
|
1292
|
+
if (response.status === "completed") {
|
|
1293
|
+
return "stop";
|
|
1294
|
+
}
|
|
1295
|
+
return "unknown";
|
|
1296
|
+
}
|
|
1297
|
+
function mapUsage(usage) {
|
|
1298
|
+
const reasoningTokens = usage?.output_tokens_details?.reasoning_tokens;
|
|
1299
|
+
return {
|
|
1300
|
+
inputTokens: usage?.input_tokens ?? 0,
|
|
1301
|
+
outputTokens: usage?.output_tokens ?? 0,
|
|
1302
|
+
inputTokenDetails: {
|
|
1303
|
+
cacheReadTokens: usage?.input_tokens_details?.cached_tokens ?? 0,
|
|
1304
|
+
cacheWriteTokens: 0
|
|
1305
|
+
},
|
|
1306
|
+
outputTokenDetails: {
|
|
1307
|
+
...reasoningTokens !== void 0 ? { reasoningTokens } : {}
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function getReasoningSummaryKey(part) {
|
|
1312
|
+
return `${part.itemId}:${part.summaryIndex}`;
|
|
1313
|
+
}
|
|
1314
|
+
function isSameReasoningSummaryPart(left, right) {
|
|
1315
|
+
return left.itemId === right.itemId && left.summaryIndex === right.summaryIndex;
|
|
1316
|
+
}
|
|
1317
|
+
function getReasoningStartTransition(reasoningStarted) {
|
|
1318
|
+
if (reasoningStarted) {
|
|
1319
|
+
return {
|
|
1320
|
+
nextReasoningStarted: true,
|
|
1321
|
+
event: null
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
return {
|
|
1325
|
+
nextReasoningStarted: true,
|
|
1326
|
+
event: { type: "reasoning-start" }
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
function getReasoningEndTransition(reasoningStarted, providerMetadata) {
|
|
1330
|
+
if (!reasoningStarted) {
|
|
1331
|
+
return {
|
|
1332
|
+
nextReasoningStarted: false,
|
|
1333
|
+
event: null
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
return {
|
|
1337
|
+
nextReasoningStarted: false,
|
|
1338
|
+
event: {
|
|
1339
|
+
type: "reasoning-end",
|
|
1340
|
+
providerMetadata
|
|
1341
|
+
}
|
|
1342
|
+
};
|
|
1343
|
+
}
|
|
1344
|
+
async function* transformStream2(stream) {
|
|
1345
|
+
const bufferedToolCalls = /* @__PURE__ */ new Map();
|
|
1346
|
+
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
1347
|
+
const startedToolCalls = /* @__PURE__ */ new Set();
|
|
1348
|
+
const seenSummaryDeltas = /* @__PURE__ */ new Set();
|
|
1349
|
+
const emittedReasoningItems = /* @__PURE__ */ new Set();
|
|
1350
|
+
let latestResponse;
|
|
1351
|
+
let textOpen = false;
|
|
1352
|
+
let reasoningStarted = false;
|
|
1353
|
+
let latestReasoningSummaryPart;
|
|
1354
|
+
const upsertBufferedToolCall = (outputIndex, getNextToolCall) => {
|
|
1355
|
+
const nextToolCall = getNextToolCall(
|
|
1356
|
+
bufferedToolCalls.get(outputIndex)
|
|
1357
|
+
);
|
|
1358
|
+
bufferedToolCalls.set(outputIndex, nextToolCall);
|
|
1359
|
+
return nextToolCall;
|
|
1360
|
+
};
|
|
1361
|
+
const getNextReasoningStartEvent = () => {
|
|
1362
|
+
const transition = getReasoningStartTransition(reasoningStarted);
|
|
1363
|
+
reasoningStarted = transition.nextReasoningStarted;
|
|
1364
|
+
return transition.event;
|
|
1365
|
+
};
|
|
1366
|
+
const startText = function* () {
|
|
1367
|
+
if (textOpen) {
|
|
1368
|
+
return;
|
|
1369
|
+
}
|
|
1370
|
+
textOpen = true;
|
|
1371
|
+
yield { type: "text-start" };
|
|
1372
|
+
};
|
|
1373
|
+
const closeText = function* () {
|
|
1374
|
+
if (!textOpen) {
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
textOpen = false;
|
|
1378
|
+
yield { type: "text-end" };
|
|
1379
|
+
};
|
|
1380
|
+
const getNextReasoningEndEvent = (providerMetadata) => {
|
|
1381
|
+
const transition = getReasoningEndTransition(
|
|
1382
|
+
reasoningStarted,
|
|
1383
|
+
providerMetadata
|
|
1384
|
+
);
|
|
1385
|
+
reasoningStarted = transition.nextReasoningStarted;
|
|
1386
|
+
if (transition.event) {
|
|
1387
|
+
latestReasoningSummaryPart = void 0;
|
|
1388
|
+
}
|
|
1389
|
+
return transition.event;
|
|
1390
|
+
};
|
|
1391
|
+
const getReasoningSummarySeparatorEvent = (currentPart) => {
|
|
1392
|
+
const previousPart = latestReasoningSummaryPart;
|
|
1393
|
+
latestReasoningSummaryPart = currentPart;
|
|
1394
|
+
if (previousPart === void 0 || isSameReasoningSummaryPart(previousPart, currentPart)) {
|
|
1395
|
+
return null;
|
|
1396
|
+
}
|
|
1397
|
+
return {
|
|
1398
|
+
type: "reasoning-delta",
|
|
1399
|
+
text: REASONING_SUMMARY_SEPARATOR
|
|
1400
|
+
};
|
|
1401
|
+
};
|
|
1402
|
+
for await (const event of stream) {
|
|
1403
|
+
if (event.type === "response.reasoning_summary_text.delta") {
|
|
1404
|
+
const summaryPart = {
|
|
1405
|
+
itemId: event.item_id,
|
|
1406
|
+
summaryIndex: event.summary_index
|
|
1407
|
+
};
|
|
1408
|
+
seenSummaryDeltas.add(getReasoningSummaryKey(summaryPart));
|
|
1409
|
+
emittedReasoningItems.add(event.item_id);
|
|
1410
|
+
const reasoningStartEvent = getNextReasoningStartEvent();
|
|
1411
|
+
if (reasoningStartEvent) {
|
|
1412
|
+
yield* closeText();
|
|
1413
|
+
yield reasoningStartEvent;
|
|
1414
|
+
}
|
|
1415
|
+
const separatorEvent = getReasoningSummarySeparatorEvent(summaryPart);
|
|
1416
|
+
if (separatorEvent) {
|
|
1417
|
+
yield separatorEvent;
|
|
1418
|
+
}
|
|
1419
|
+
yield {
|
|
1420
|
+
type: "reasoning-delta",
|
|
1421
|
+
text: event.delta
|
|
1422
|
+
};
|
|
1423
|
+
continue;
|
|
1424
|
+
}
|
|
1425
|
+
if (event.type === "response.reasoning_summary_text.done") {
|
|
1426
|
+
const summaryPart = {
|
|
1427
|
+
itemId: event.item_id,
|
|
1428
|
+
summaryIndex: event.summary_index
|
|
1429
|
+
};
|
|
1430
|
+
const key = getReasoningSummaryKey(summaryPart);
|
|
1431
|
+
if (!seenSummaryDeltas.has(key) && event.text.length > 0) {
|
|
1432
|
+
emittedReasoningItems.add(event.item_id);
|
|
1433
|
+
const reasoningStartEvent = getNextReasoningStartEvent();
|
|
1434
|
+
if (reasoningStartEvent) {
|
|
1435
|
+
yield* closeText();
|
|
1436
|
+
yield reasoningStartEvent;
|
|
1437
|
+
}
|
|
1438
|
+
const separatorEvent = getReasoningSummarySeparatorEvent(summaryPart);
|
|
1439
|
+
if (separatorEvent) {
|
|
1440
|
+
yield separatorEvent;
|
|
1441
|
+
}
|
|
1442
|
+
yield {
|
|
1443
|
+
type: "reasoning-delta",
|
|
1444
|
+
text: event.text
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
if (event.type === "response.output_text.delta") {
|
|
1450
|
+
const reasoningEndEvent2 = getNextReasoningEndEvent({ openai: {} });
|
|
1451
|
+
if (reasoningEndEvent2) {
|
|
1452
|
+
yield reasoningEndEvent2;
|
|
1453
|
+
}
|
|
1454
|
+
yield* startText();
|
|
1455
|
+
yield {
|
|
1456
|
+
type: "text-delta",
|
|
1457
|
+
text: event.delta
|
|
1458
|
+
};
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
if (event.type === "response.output_item.added") {
|
|
1462
|
+
if (!isFunctionToolCall(event.item)) {
|
|
1463
|
+
continue;
|
|
1464
|
+
}
|
|
1465
|
+
yield* closeText();
|
|
1466
|
+
const toolCallId = event.item.call_id;
|
|
1467
|
+
const toolCallName = event.item.name;
|
|
1468
|
+
const toolCallArguments = event.item.arguments;
|
|
1469
|
+
upsertBufferedToolCall(event.output_index, () => ({
|
|
1470
|
+
id: toolCallId,
|
|
1471
|
+
name: toolCallName,
|
|
1472
|
+
arguments: toolCallArguments
|
|
1473
|
+
}));
|
|
1474
|
+
const shouldStartToolCall = !startedToolCalls.has(toolCallId);
|
|
1475
|
+
if (shouldStartToolCall) {
|
|
1476
|
+
startedToolCalls.add(toolCallId);
|
|
1477
|
+
yield {
|
|
1478
|
+
type: "tool-call-start",
|
|
1479
|
+
toolCallId,
|
|
1480
|
+
toolName: toolCallName
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
continue;
|
|
1484
|
+
}
|
|
1485
|
+
if (event.type === "response.function_call_arguments.delta") {
|
|
1486
|
+
yield* closeText();
|
|
1487
|
+
const currentToolCall = upsertBufferedToolCall(
|
|
1488
|
+
event.output_index,
|
|
1489
|
+
(bufferedToolCall) => ({
|
|
1490
|
+
id: bufferedToolCall?.id ?? event.item_id,
|
|
1491
|
+
name: bufferedToolCall?.name ?? "",
|
|
1492
|
+
arguments: `${bufferedToolCall?.arguments ?? ""}${event.delta}`
|
|
1493
|
+
})
|
|
1494
|
+
);
|
|
1495
|
+
const shouldStartToolCall = !startedToolCalls.has(
|
|
1496
|
+
currentToolCall.id
|
|
1497
|
+
);
|
|
1498
|
+
if (shouldStartToolCall) {
|
|
1499
|
+
startedToolCalls.add(currentToolCall.id);
|
|
1500
|
+
yield {
|
|
1501
|
+
type: "tool-call-start",
|
|
1502
|
+
toolCallId: currentToolCall.id,
|
|
1503
|
+
toolName: currentToolCall.name
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
yield {
|
|
1507
|
+
type: "tool-call-delta",
|
|
1508
|
+
toolCallId: currentToolCall.id,
|
|
1509
|
+
argumentsDelta: event.delta
|
|
1510
|
+
};
|
|
1511
|
+
continue;
|
|
1512
|
+
}
|
|
1513
|
+
if (event.type === "response.output_item.done") {
|
|
1514
|
+
if (isReasoningItem(event.item)) {
|
|
1515
|
+
if (!emittedReasoningItems.has(event.item.id)) {
|
|
1516
|
+
const summaryText = getReasoningSummaryText(
|
|
1517
|
+
event.item.summary
|
|
1518
|
+
);
|
|
1519
|
+
if (summaryText.length > 0) {
|
|
1520
|
+
const reasoningStartEvent = getNextReasoningStartEvent();
|
|
1521
|
+
if (reasoningStartEvent) {
|
|
1522
|
+
yield* closeText();
|
|
1523
|
+
yield reasoningStartEvent;
|
|
1524
|
+
}
|
|
1525
|
+
yield {
|
|
1526
|
+
type: "reasoning-delta",
|
|
1527
|
+
text: summaryText
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
const encryptedContent = typeof event.item.encrypted_content === "string" && event.item.encrypted_content.length > 0 ? event.item.encrypted_content : void 0;
|
|
1532
|
+
if (encryptedContent) {
|
|
1533
|
+
const reasoningStartEvent = getNextReasoningStartEvent();
|
|
1534
|
+
if (reasoningStartEvent) {
|
|
1535
|
+
yield* closeText();
|
|
1536
|
+
yield reasoningStartEvent;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
const reasoningEndEvent2 = getNextReasoningEndEvent({
|
|
1540
|
+
openai: {
|
|
1541
|
+
...encryptedContent ? { encryptedContent } : {}
|
|
1542
|
+
}
|
|
1543
|
+
});
|
|
1544
|
+
if (reasoningEndEvent2) {
|
|
1545
|
+
yield reasoningEndEvent2;
|
|
1546
|
+
}
|
|
1547
|
+
continue;
|
|
1548
|
+
}
|
|
1549
|
+
if (!isFunctionToolCall(event.item)) {
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
yield* closeText();
|
|
1553
|
+
const toolCallId = event.item.call_id;
|
|
1554
|
+
const toolCallName = event.item.name;
|
|
1555
|
+
const toolCallArguments = event.item.arguments;
|
|
1556
|
+
const currentToolCall = upsertBufferedToolCall(
|
|
1557
|
+
event.output_index,
|
|
1558
|
+
(bufferedToolCall) => ({
|
|
1559
|
+
id: toolCallId,
|
|
1560
|
+
name: toolCallName,
|
|
1561
|
+
arguments: toolCallArguments || bufferedToolCall?.arguments || ""
|
|
1562
|
+
})
|
|
1563
|
+
);
|
|
1564
|
+
if (!emittedToolCalls.has(currentToolCall.id)) {
|
|
1565
|
+
emittedToolCalls.add(currentToolCall.id);
|
|
1566
|
+
yield {
|
|
1567
|
+
type: "tool-call-end",
|
|
1568
|
+
toolCall: {
|
|
1569
|
+
id: currentToolCall.id,
|
|
1570
|
+
name: currentToolCall.name,
|
|
1571
|
+
arguments: safeParseJsonObject(
|
|
1572
|
+
currentToolCall.arguments
|
|
1573
|
+
)
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
continue;
|
|
1578
|
+
}
|
|
1579
|
+
if (event.type === "response.completed") {
|
|
1580
|
+
latestResponse = event.response;
|
|
1581
|
+
yield* closeText();
|
|
1582
|
+
const reasoningEndEvent2 = getNextReasoningEndEvent({ openai: {} });
|
|
1583
|
+
if (reasoningEndEvent2) {
|
|
1584
|
+
yield reasoningEndEvent2;
|
|
1585
|
+
}
|
|
1586
|
+
for (const bufferedToolCall of bufferedToolCalls.values()) {
|
|
1587
|
+
if (emittedToolCalls.has(bufferedToolCall.id)) {
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
emittedToolCalls.add(bufferedToolCall.id);
|
|
1591
|
+
yield {
|
|
1592
|
+
type: "tool-call-end",
|
|
1593
|
+
toolCall: {
|
|
1594
|
+
id: bufferedToolCall.id,
|
|
1595
|
+
name: bufferedToolCall.name,
|
|
1596
|
+
arguments: safeParseJsonObject(
|
|
1597
|
+
bufferedToolCall.arguments
|
|
1598
|
+
)
|
|
1599
|
+
}
|
|
1600
|
+
};
|
|
1601
|
+
}
|
|
1602
|
+
const hasToolCalls2 = bufferedToolCalls.size > 0;
|
|
1603
|
+
yield {
|
|
1604
|
+
type: "finish",
|
|
1605
|
+
finishReason: mapFinishReason2(latestResponse, hasToolCalls2),
|
|
1606
|
+
usage: mapUsage(latestResponse.usage)
|
|
1607
|
+
};
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
const reasoningEndEvent = getNextReasoningEndEvent({
|
|
1612
|
+
openai: {}
|
|
1613
|
+
});
|
|
1614
|
+
yield* closeText();
|
|
1615
|
+
if (reasoningEndEvent) {
|
|
1616
|
+
yield reasoningEndEvent;
|
|
1617
|
+
}
|
|
1618
|
+
const hasToolCalls = bufferedToolCalls.size > 0;
|
|
1619
|
+
const usage = latestResponse ? mapUsage(latestResponse.usage) : mapUsage(void 0);
|
|
1620
|
+
const finishReason = latestResponse ? mapFinishReason2(latestResponse, hasToolCalls) : "unknown";
|
|
1621
|
+
yield {
|
|
1622
|
+
type: "finish",
|
|
1623
|
+
finishReason,
|
|
1624
|
+
usage
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
function mapReasoningToRequestFields2(modelId, options) {
|
|
1628
|
+
if (!options.reasoning) {
|
|
1629
|
+
return {};
|
|
1630
|
+
}
|
|
1631
|
+
const capabilities = getOpenAIModelCapabilities(modelId);
|
|
1632
|
+
if (!capabilities.reasoning.supported) {
|
|
1633
|
+
return {};
|
|
1634
|
+
}
|
|
1635
|
+
const effort = toOpenAIReasoningEffort(
|
|
1636
|
+
clampReasoningEffort2(
|
|
1637
|
+
options.reasoning.effort,
|
|
1638
|
+
capabilities.reasoning.supportedEfforts
|
|
1639
|
+
)
|
|
1640
|
+
);
|
|
1641
|
+
return {
|
|
1642
|
+
reasoning: {
|
|
1643
|
+
effort,
|
|
1644
|
+
summary: "auto"
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
function isFunctionToolCall(item) {
|
|
1649
|
+
return item.type === "function_call";
|
|
1650
|
+
}
|
|
1651
|
+
function isOutputMessage(item) {
|
|
1652
|
+
return item.type === "message";
|
|
1653
|
+
}
|
|
1654
|
+
function isReasoningItem(item) {
|
|
1655
|
+
return item.type === "reasoning";
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
// src/chat-model.ts
|
|
1659
|
+
function createOpenAIChatModel(client, modelId, providerId = "openai") {
|
|
1660
|
+
const provider = providerId;
|
|
1661
|
+
async function callOpenAIResponsesApi(request, signal) {
|
|
1662
|
+
try {
|
|
1663
|
+
return await client.responses.create(request, {
|
|
1664
|
+
signal
|
|
1665
|
+
});
|
|
1666
|
+
} catch (error) {
|
|
1667
|
+
throw wrapOpenAIError(error, provider);
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
async function generateChat(options) {
|
|
1671
|
+
const request = createGenerateRequest2(modelId, options);
|
|
1672
|
+
const response = await callOpenAIResponsesApi(
|
|
1673
|
+
request,
|
|
1674
|
+
options.signal
|
|
1675
|
+
);
|
|
1676
|
+
return mapGenerateResponse2(response);
|
|
1677
|
+
}
|
|
1678
|
+
async function streamChat(options) {
|
|
1679
|
+
const request = createStreamRequest2(modelId, options);
|
|
1680
|
+
return createChatStream2(
|
|
1681
|
+
async () => transformStream2(
|
|
1682
|
+
await callOpenAIResponsesApi(request, options.signal)
|
|
1683
|
+
),
|
|
1684
|
+
{ signal: options.signal }
|
|
1685
|
+
);
|
|
1686
|
+
}
|
|
1687
|
+
return {
|
|
1688
|
+
provider,
|
|
1689
|
+
modelId,
|
|
1690
|
+
capabilities: getOpenAIModelCapabilities(modelId),
|
|
1691
|
+
generate: generateChat,
|
|
1692
|
+
stream: streamChat,
|
|
1693
|
+
async generateObject(options) {
|
|
1694
|
+
const structuredOptions = createStructuredOutputRequestOptions(options);
|
|
1695
|
+
const result = await generateChat(structuredOptions);
|
|
1696
|
+
const structuredOutputName = getStructuredOutputName(options);
|
|
1697
|
+
const object = extractStructuredObject(
|
|
1698
|
+
result,
|
|
1699
|
+
options.schema,
|
|
1700
|
+
provider,
|
|
1701
|
+
structuredOutputName
|
|
1702
|
+
);
|
|
1703
|
+
return {
|
|
1704
|
+
object,
|
|
1705
|
+
finishReason: result.finishReason,
|
|
1706
|
+
usage: result.usage
|
|
1707
|
+
};
|
|
1708
|
+
},
|
|
1709
|
+
async streamObject(options) {
|
|
1710
|
+
const structuredOptions = createStructuredOutputRequestOptions(options);
|
|
1711
|
+
const stream = await streamChat(structuredOptions);
|
|
1712
|
+
const structuredOutputName = getStructuredOutputName(options);
|
|
1713
|
+
return createObjectStream2(
|
|
1714
|
+
transformStructuredOutputStream(
|
|
1715
|
+
stream,
|
|
1716
|
+
options.schema,
|
|
1717
|
+
provider,
|
|
1718
|
+
structuredOutputName
|
|
1719
|
+
),
|
|
1720
|
+
{
|
|
1721
|
+
signal: options.signal
|
|
1722
|
+
}
|
|
1723
|
+
);
|
|
1724
|
+
}
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
// src/embedding-model.ts
|
|
1729
|
+
function createOpenAIEmbeddingModel(client, modelId) {
|
|
1730
|
+
return {
|
|
1731
|
+
provider: "openai",
|
|
1732
|
+
modelId,
|
|
1733
|
+
async embed(options) {
|
|
1734
|
+
try {
|
|
1735
|
+
const openaiOptions = parseOpenAIEmbedProviderOptions(
|
|
1736
|
+
options.providerOptions
|
|
1737
|
+
);
|
|
1738
|
+
const response = await client.embeddings.create({
|
|
1739
|
+
model: modelId,
|
|
1740
|
+
input: options.input,
|
|
1741
|
+
...options.dimensions !== void 0 ? { dimensions: options.dimensions } : {},
|
|
1742
|
+
...mapOpenAIEmbedProviderOptionsToRequestFields(
|
|
1743
|
+
openaiOptions
|
|
1744
|
+
)
|
|
1745
|
+
});
|
|
1746
|
+
return {
|
|
1747
|
+
embeddings: response.data.slice().sort((a, b) => a.index - b.index).map((item) => item.embedding),
|
|
1748
|
+
usage: {
|
|
1749
|
+
inputTokens: response.usage.prompt_tokens
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
} catch (error) {
|
|
1753
|
+
throw wrapOpenAIError(error);
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
function mapOpenAIEmbedProviderOptionsToRequestFields(options) {
|
|
1759
|
+
return {
|
|
1760
|
+
...options?.encodingFormat !== void 0 ? { encoding_format: options.encodingFormat } : {},
|
|
1761
|
+
...options?.user !== void 0 ? { user: options.user } : {}
|
|
1762
|
+
};
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
// src/image-model.ts
|
|
1766
|
+
function createOpenAIImageModel(client, modelId) {
|
|
1767
|
+
return {
|
|
1768
|
+
provider: "openai",
|
|
1769
|
+
modelId,
|
|
1770
|
+
async generate(options) {
|
|
1771
|
+
try {
|
|
1772
|
+
const openaiOptions = parseOpenAIImageProviderOptions(
|
|
1773
|
+
options.providerOptions
|
|
1774
|
+
);
|
|
1775
|
+
const request = {
|
|
1776
|
+
model: modelId,
|
|
1777
|
+
prompt: options.prompt,
|
|
1778
|
+
...options.n !== void 0 ? { n: options.n } : {},
|
|
1779
|
+
...options.size !== void 0 ? { size: options.size } : {},
|
|
1780
|
+
...mapOpenAIImageProviderOptionsToRequestFields(
|
|
1781
|
+
openaiOptions
|
|
1782
|
+
)
|
|
1783
|
+
};
|
|
1784
|
+
const response = await client.images.generate(
|
|
1785
|
+
request
|
|
1786
|
+
);
|
|
1787
|
+
return {
|
|
1788
|
+
images: (response.data ?? []).map((image) => ({
|
|
1789
|
+
base64: image.b64_json ?? void 0,
|
|
1790
|
+
url: image.url ?? void 0,
|
|
1791
|
+
revisedPrompt: image.revised_prompt ?? void 0
|
|
1792
|
+
}))
|
|
1793
|
+
};
|
|
1794
|
+
} catch (error) {
|
|
1795
|
+
throw wrapOpenAIError(error);
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
function mapOpenAIImageProviderOptionsToRequestFields(options) {
|
|
1801
|
+
return {
|
|
1802
|
+
...options?.background !== void 0 ? { background: options.background } : {},
|
|
1803
|
+
...options?.moderation !== void 0 ? { moderation: options.moderation } : {},
|
|
1804
|
+
...options?.outputCompression !== void 0 ? { output_compression: options.outputCompression } : {},
|
|
1805
|
+
...options?.outputFormat !== void 0 ? { output_format: options.outputFormat } : {},
|
|
1806
|
+
...options?.quality !== void 0 ? { quality: options.quality } : {},
|
|
1807
|
+
...options?.responseFormat !== void 0 ? { response_format: options.responseFormat } : {},
|
|
1808
|
+
...options?.style !== void 0 ? { style: options.style } : {},
|
|
1809
|
+
...options?.user !== void 0 ? { user: options.user } : {}
|
|
1810
|
+
};
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
// src/shared/provider-factory.ts
|
|
1814
|
+
function createOpenAIProvider(options, factoryOptions = {}) {
|
|
1815
|
+
const client = options.client ?? new OpenAI({
|
|
1816
|
+
apiKey: options.apiKey,
|
|
1817
|
+
baseURL: options.baseURL
|
|
1818
|
+
});
|
|
1819
|
+
const providerId = factoryOptions.providerId ?? "openai";
|
|
1820
|
+
const compatibilityEnabled = factoryOptions.compatibility === true || typeof factoryOptions.compatibility === "object";
|
|
1821
|
+
const compatibilityOptions = typeof factoryOptions.compatibility === "object" ? factoryOptions.compatibility : void 0;
|
|
1822
|
+
const createResponsesModel = (modelId) => createOpenAIChatModel(client, modelId, providerId);
|
|
1823
|
+
const createChatCompletionsModel = (modelId) => createOpenAIChatCompletionsModel(client, modelId, {
|
|
1824
|
+
providerId,
|
|
1825
|
+
compatibility: compatibilityEnabled,
|
|
1826
|
+
nonStandardReasoning: compatibilityEnabled && (compatibilityOptions?.reasoning ?? true),
|
|
1827
|
+
structuredOutputMode: compatibilityOptions?.structuredOutputMode,
|
|
1828
|
+
maxTokensParameter: compatibilityOptions?.maxTokensParameter
|
|
1829
|
+
});
|
|
1830
|
+
const chat = {
|
|
1831
|
+
chatModel: createChatCompletionsModel
|
|
1832
|
+
};
|
|
1833
|
+
return {
|
|
1834
|
+
chatModel: factoryOptions.defaultApi === "chat-completions" ? createChatCompletionsModel : createResponsesModel,
|
|
1835
|
+
chat,
|
|
1836
|
+
embeddingModel: (modelId) => createOpenAIEmbeddingModel(client, modelId),
|
|
1837
|
+
imageModel: (modelId) => createOpenAIImageModel(client, modelId)
|
|
1838
|
+
};
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
export {
|
|
1842
|
+
getOpenAIModelCapabilities,
|
|
1843
|
+
openaiResponsesGenerateProviderOptionsSchema,
|
|
1844
|
+
openaiChatGenerateProviderOptionsSchema,
|
|
1845
|
+
openaiEmbedProviderOptionsSchema,
|
|
1846
|
+
openaiImageProviderOptionsSchema,
|
|
1847
|
+
openaiResponsesProviderOptionsSchema,
|
|
1848
|
+
openaiCompatProviderOptionsSchema,
|
|
1849
|
+
openaiCompatGenerateProviderOptionsSchema,
|
|
1850
|
+
createOpenAIChatCompletionsModel,
|
|
1851
|
+
createOpenAIProvider
|
|
1852
|
+
};
|