@core-ai/openai 0.5.1 → 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,592 +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
- 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
+ for (const part of mapMessageTextParts(item)) {
246
+ parts.push(part);
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
+ });
259
+ }
323
260
  }
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);
261
+ const content = getTextContent(parts);
262
+ const reasoning = getReasoningText(parts);
263
+ const toolCalls = getToolCalls(parts);
328
264
  return {
329
265
  parts,
330
266
  content,
331
- reasoning: null,
267
+ reasoning,
332
268
  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
- }
269
+ finishReason: mapFinishReason(response, toolCalls.length > 0),
270
+ usage: mapUsage(response.usage)
345
271
  };
346
272
  }
347
- function parseToolCalls(calls) {
348
- if (!calls) {
349
- 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;
350
278
  }
351
- return calls.flatMap((toolCall) => {
352
- if (toolCall.type !== "function") {
353
- return [];
354
- }
355
- return [mapFunctionToolCall(toolCall)];
356
- });
357
- }
358
- function mapFunctionToolCall(toolCall) {
359
279
  return {
360
- id: toolCall.id,
361
- name: toolCall.function.name,
362
- arguments: safeParseJsonObject(toolCall.function.arguments)
280
+ type: "reasoning",
281
+ text,
282
+ providerMetadata: {
283
+ openai: { ...encryptedContent ? { encryptedContent } : {} }
284
+ }
363
285
  };
364
286
  }
365
- function mapFinishReason(reason) {
366
- if (reason === "stop") {
367
- return "stop";
368
- }
369
- 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") {
370
311
  return "length";
371
312
  }
372
- if (reason === "tool_calls" || reason === "function_call") {
313
+ if (incompleteReason === "content_filter") {
314
+ return "content-filter";
315
+ }
316
+ if (hasToolCalls) {
373
317
  return "tool-calls";
374
318
  }
375
- if (reason === "content_filter") {
376
- return "content-filter";
319
+ if (response.status === "completed") {
320
+ return "stop";
377
321
  }
378
322
  return "unknown";
379
323
  }
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,
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,
387
329
  inputTokenDetails: {
388
- cacheReadTokens: 0,
330
+ cacheReadTokens: usage?.input_tokens_details?.cached_tokens ?? 0,
389
331
  cacheWriteTokens: 0
390
332
  },
391
- outputTokenDetails: {}
333
+ outputTokenDetails: {
334
+ ...reasoningTokens !== void 0 ? { reasoningTokens } : {}
335
+ }
392
336
  };
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
- }
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
406
357
  };
358
+ continue;
407
359
  }
408
- const choice = chunk.choices[0];
409
- 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
+ }
410
373
  continue;
411
374
  }
412
- if (choice.delta.content) {
375
+ if (event.type === "response.output_text.delta") {
413
376
  yield {
414
377
  type: "text-delta",
415
- text: choice.delta.content
378
+ text: event.delta
416
379
  };
380
+ continue;
417
381
  }
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: ""
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
426
398
  };
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;
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
+ }
433
443
  }
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
- };
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" };
441
448
  }
442
- bufferedToolCalls.set(partialToolCall.index, current);
443
- if (wasNew) {
449
+ if (reasoningStarted) {
450
+ reasoningStarted = false;
444
451
  yield {
445
- type: "tool-call-start",
446
- toolCallId: current.id,
447
- toolName: current.name
452
+ type: "reasoning-end",
453
+ providerMetadata: {
454
+ openai: {
455
+ ...encryptedContent ? { encryptedContent } : {}
456
+ }
457
+ }
448
458
  };
449
459
  }
460
+ continue;
450
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;
451
489
  }
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)) {
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)) {
458
501
  continue;
459
502
  }
460
- emittedToolCalls.add(toolCall.id);
503
+ emittedToolCalls.add(bufferedToolCall.id);
461
504
  yield {
462
505
  type: "tool-call-end",
463
506
  toolCall: {
464
- id: toolCall.id,
465
- name: toolCall.name,
466
- arguments: safeParseJsonObject(toolCall.arguments)
507
+ id: bufferedToolCall.id,
508
+ name: bufferedToolCall.name,
509
+ arguments: safeParseJsonObject(
510
+ bufferedToolCall.arguments
511
+ )
467
512
  }
468
513
  };
469
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;
470
522
  }
471
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";
472
530
  yield {
473
531
  type: "finish",
474
532
  finishReason,
475
533
  usage
476
534
  };
477
535
  }
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
536
  function mapReasoningToRequestFields(modelId, options) {
511
537
  if (!options.reasoning) {
512
538
  return {};
513
539
  }
514
540
  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
- );
541
+ const effort = capabilities.reasoning.supportsEffort ? toOpenAIReasoningEffort(
542
+ clampReasoningEffort(
543
+ options.reasoning.effort,
544
+ capabilities.reasoning.supportedRange
545
+ )
546
+ ) : void 0;
522
547
  return {
523
- reasoning_effort: toOpenAIReasoningEffort(clampedEffort)
548
+ reasoning: {
549
+ ...effort ? { effort } : {},
550
+ summary: "auto"
551
+ }
524
552
  };
525
553
  }
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;
554
+ function isFunctionToolCall(item) {
555
+ return item.type === "function_call";
541
556
  }
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;
557
+ function isOutputMessage(item) {
558
+ return item.type === "message";
557
559
  }
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
- );
560
+ function isReasoningItem(item) {
561
+ return item.type === "reasoning";
572
562
  }
573
563
 
574
564
  // src/chat-model.ts
575
565
  function createOpenAIChatModel(client, modelId) {
576
566
  const provider = "openai";
577
- async function callOpenAIChatCompletionsApi(request) {
567
+ async function callOpenAIResponsesApi(request, signal) {
578
568
  try {
579
- return await client.chat.completions.create(
580
- request
581
- );
569
+ return await client.responses.create(request, {
570
+ signal
571
+ });
582
572
  } catch (error) {
583
573
  throw wrapOpenAIError(error);
584
574
  }
585
575
  }
586
576
  async function generateChat(options) {
587
577
  const request = createGenerateRequest(modelId, options);
588
- const response = await callOpenAIChatCompletionsApi(request);
578
+ const response = await callOpenAIResponsesApi(
579
+ request,
580
+ options.signal
581
+ );
589
582
  return mapGenerateResponse(response);
590
583
  }
591
584
  async function streamChat(options) {
592
585
  const request = createStreamRequest(modelId, options);
593
- const stream = await callOpenAIChatCompletionsApi(request);
594
- return createStreamResult(transformStream(stream));
586
+ return createChatStream(
587
+ async () => transformStream(
588
+ await callOpenAIResponsesApi(request, options.signal)
589
+ ),
590
+ { signal: options.signal }
591
+ );
595
592
  }
596
593
  return {
597
594
  provider,
@@ -618,13 +615,16 @@ function createOpenAIChatModel(client, modelId) {
618
615
  const structuredOptions = createStructuredOutputOptions(options);
619
616
  const stream = await streamChat(structuredOptions);
620
617
  const toolName = getStructuredOutputToolName(options);
621
- return createObjectStreamResult(
618
+ return createObjectStream(
622
619
  transformStructuredOutputStream(
623
620
  stream,
624
621
  options.schema,
625
622
  provider,
626
623
  toolName
627
- )
624
+ ),
625
+ {
626
+ signal: options.signal
627
+ }
628
628
  );
629
629
  }
630
630
  };
@@ -739,7 +739,12 @@ function validateStructuredToolArguments(schema, toolArguments, provider) {
739
739
  }
740
740
  function parseAndValidateStructuredPayload(schema, rawPayload, provider) {
741
741
  const parsedPayload = parseJson(rawPayload, provider);
742
- return validateStructuredObject(schema, parsedPayload, provider, rawPayload);
742
+ return validateStructuredObject(
743
+ schema,
744
+ parsedPayload,
745
+ provider,
746
+ rawPayload
747
+ );
743
748
  }
744
749
  function parseJson(rawOutput, provider) {
745
750
  try {
@@ -776,63 +781,6 @@ function formatZodIssues(issues) {
776
781
  });
777
782
  }
778
783
 
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
784
  // src/provider.ts
837
785
  function createOpenAI(options = {}) {
838
786
  const client = options.client ?? new OpenAI({
@@ -846,5 +794,11 @@ function createOpenAI(options = {}) {
846
794
  };
847
795
  }
848
796
  export {
849
- createOpenAI
797
+ createOpenAI,
798
+ openaiCompatGenerateProviderOptionsSchema,
799
+ openaiCompatProviderOptionsSchema,
800
+ openaiEmbedProviderOptionsSchema,
801
+ openaiImageProviderOptionsSchema,
802
+ openaiResponsesGenerateProviderOptionsSchema,
803
+ openaiResponsesProviderOptionsSchema
850
804
  };