@core-ai/openai 0.4.0 → 0.6.0

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