@core-ai/openai 0.5.1 → 0.6.1

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