@yourgpt/llm-sdk 2.5.0 → 2.5.1-beta.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/README.md +19 -1
- package/dist/adapters/index.d.mts +4 -4
- package/dist/adapters/index.d.ts +4 -4
- package/dist/adapters/index.js +293 -23
- package/dist/adapters/index.mjs +293 -23
- package/dist/base-BYQKp9TW.d.mts +263 -0
- package/dist/base-Cxq3ni0t.d.ts +263 -0
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/index.d.mts +61 -8
- package/dist/index.d.ts +61 -8
- package/dist/index.js +71 -0
- package/dist/index.mjs +71 -0
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +360 -203
- package/dist/providers/anthropic/index.mjs +360 -203
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/azure/index.js +49 -1
- package/dist/providers/azure/index.mjs +49 -1
- package/dist/providers/fireworks/index.d.mts +1 -1
- package/dist/providers/fireworks/index.d.ts +1 -1
- package/dist/providers/fireworks/index.js +56 -0
- package/dist/providers/fireworks/index.mjs +56 -0
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +303 -207
- package/dist/providers/google/index.mjs +303 -207
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/ollama/index.js +10 -2
- package/dist/providers/ollama/index.mjs +10 -2
- package/dist/providers/openai/index.d.mts +3 -3
- package/dist/providers/openai/index.d.ts +3 -3
- package/dist/providers/openai/index.js +318 -216
- package/dist/providers/openai/index.mjs +318 -216
- package/dist/providers/openrouter/index.d.mts +3 -3
- package/dist/providers/openrouter/index.d.ts +3 -3
- package/dist/providers/openrouter/index.js +308 -206
- package/dist/providers/openrouter/index.mjs +308 -206
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +308 -206
- package/dist/providers/togetherai/index.mjs +308 -206
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +307 -210
- package/dist/providers/xai/index.mjs +307 -210
- package/dist/{types-BctsnC3g.d.ts → types-BvkiJ1dd.d.mts} +2 -1
- package/dist/{types-38yolWJn.d.ts → types-ChORafYS.d.ts} +1 -1
- package/dist/types-D774b0dg.d.mts +1018 -0
- package/dist/types-D774b0dg.d.ts +1018 -0
- package/dist/{types-DRqxMIjF.d.mts → types-TMilS-Dz.d.ts} +2 -1
- package/dist/{types-D4YfrQJR.d.mts → types-mwMhCwOq.d.mts} +1 -1
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/base-D-U61JaB.d.mts +0 -788
- package/dist/base-iGi9Va6Z.d.ts +0 -788
- package/dist/types-CR8mi9I0.d.mts +0 -417
- package/dist/types-CR8mi9I0.d.ts +0 -417
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { O as OpenAIProviderConfig, A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-D774b0dg.js';
|
|
2
|
+
import { O as OpenAIProviderConfig, A as AIProvider } from '../../types-TMilS-Dz.js';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-Cxq3ni0t.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenAI Provider - Modern Pattern
|
|
@@ -1,5 +1,261 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/adapters/base.ts
|
|
4
|
+
function stringifyForDebug(value) {
|
|
5
|
+
return JSON.stringify(
|
|
6
|
+
value,
|
|
7
|
+
(_key, currentValue) => {
|
|
8
|
+
if (typeof currentValue === "bigint") {
|
|
9
|
+
return currentValue.toString();
|
|
10
|
+
}
|
|
11
|
+
if (currentValue instanceof Error) {
|
|
12
|
+
return {
|
|
13
|
+
name: currentValue.name,
|
|
14
|
+
message: currentValue.message,
|
|
15
|
+
stack: currentValue.stack
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return currentValue;
|
|
19
|
+
},
|
|
20
|
+
2
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
function logProviderPayload(provider, label, payload, enabled) {
|
|
24
|
+
if (!enabled) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (label.toLowerCase().includes("stream ")) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
console.log(
|
|
32
|
+
`[llm-sdk:${provider}] ${label}
|
|
33
|
+
${stringifyForDebug(payload)}`
|
|
34
|
+
);
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.log(
|
|
37
|
+
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
38
|
+
error
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function parameterToJsonSchema(param) {
|
|
43
|
+
const schema = {
|
|
44
|
+
type: param.type
|
|
45
|
+
};
|
|
46
|
+
if (param.description) {
|
|
47
|
+
schema.description = param.description;
|
|
48
|
+
}
|
|
49
|
+
if (param.enum) {
|
|
50
|
+
schema.enum = param.enum;
|
|
51
|
+
}
|
|
52
|
+
if (param.type === "array" && param.items) {
|
|
53
|
+
schema.items = parameterToJsonSchema(
|
|
54
|
+
param.items
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
if (param.type === "object" && param.properties) {
|
|
58
|
+
schema.properties = Object.fromEntries(
|
|
59
|
+
Object.entries(param.properties).map(([key, prop]) => [
|
|
60
|
+
key,
|
|
61
|
+
parameterToJsonSchema(
|
|
62
|
+
prop
|
|
63
|
+
)
|
|
64
|
+
])
|
|
65
|
+
);
|
|
66
|
+
schema.additionalProperties = false;
|
|
67
|
+
}
|
|
68
|
+
return schema;
|
|
69
|
+
}
|
|
70
|
+
function normalizeObjectJsonSchema(schema) {
|
|
71
|
+
if (!schema || typeof schema !== "object") {
|
|
72
|
+
return {
|
|
73
|
+
type: "object",
|
|
74
|
+
properties: {},
|
|
75
|
+
required: [],
|
|
76
|
+
additionalProperties: false
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const normalized = { ...schema };
|
|
80
|
+
const type = normalized.type;
|
|
81
|
+
if (type === "object") {
|
|
82
|
+
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
83
|
+
normalized.properties = Object.fromEntries(
|
|
84
|
+
Object.entries(properties).map(([key, value]) => [
|
|
85
|
+
key,
|
|
86
|
+
normalizeObjectJsonSchema(value)
|
|
87
|
+
])
|
|
88
|
+
);
|
|
89
|
+
const propertyKeys = Object.keys(properties);
|
|
90
|
+
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
91
|
+
(value) => typeof value === "string"
|
|
92
|
+
) : [];
|
|
93
|
+
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
94
|
+
if (normalized.additionalProperties === void 0) {
|
|
95
|
+
normalized.additionalProperties = false;
|
|
96
|
+
}
|
|
97
|
+
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
98
|
+
normalized.items = normalizeObjectJsonSchema(
|
|
99
|
+
normalized.items
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return normalized;
|
|
103
|
+
}
|
|
104
|
+
function isOpenAIReasoningModel(modelId) {
|
|
105
|
+
if (!modelId) return false;
|
|
106
|
+
return /^(o1|o3|o4|gpt-5)/i.test(modelId);
|
|
107
|
+
}
|
|
108
|
+
function buildOpenAITokenParams(modelId, maxTokens, temperature) {
|
|
109
|
+
if (isOpenAIReasoningModel(modelId)) {
|
|
110
|
+
return { max_completion_tokens: maxTokens };
|
|
111
|
+
}
|
|
112
|
+
return { max_tokens: maxTokens, temperature };
|
|
113
|
+
}
|
|
114
|
+
function toOpenAIResponseFormat(rf) {
|
|
115
|
+
if (!rf) return void 0;
|
|
116
|
+
if (rf.type === "json_object") return { type: "json_object" };
|
|
117
|
+
return {
|
|
118
|
+
type: "json_schema",
|
|
119
|
+
json_schema: {
|
|
120
|
+
name: rf.json_schema.name,
|
|
121
|
+
schema: normalizeObjectJsonSchema(rf.json_schema.schema),
|
|
122
|
+
strict: rf.json_schema.strict ?? true
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function toOpenAIResponsesTextFormat(rf) {
|
|
127
|
+
if (!rf || rf.type !== "json_schema") return void 0;
|
|
128
|
+
return {
|
|
129
|
+
type: "json_schema",
|
|
130
|
+
name: rf.json_schema.name,
|
|
131
|
+
schema: normalizeObjectJsonSchema(rf.json_schema.schema),
|
|
132
|
+
strict: rf.json_schema.strict ?? true
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function toOpenAIResponsesMcpTools(mcpServers) {
|
|
136
|
+
if (!mcpServers || mcpServers.length === 0) return [];
|
|
137
|
+
return mcpServers.map((mcp) => ({
|
|
138
|
+
type: "mcp",
|
|
139
|
+
server_label: mcp.label,
|
|
140
|
+
server_url: mcp.url,
|
|
141
|
+
...mcp.headers ? { headers: mcp.headers } : {},
|
|
142
|
+
...mcp.allowedTools ? { allowed_tools: mcp.allowedTools } : {},
|
|
143
|
+
require_approval: mcp.requireApproval ?? "never"
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
function isStringEffort(effort) {
|
|
147
|
+
return typeof effort === "string" && (effort === "minimal" || effort === "low" || effort === "medium" || effort === "high");
|
|
148
|
+
}
|
|
149
|
+
function toOpenAIReasoning(effort) {
|
|
150
|
+
if (!effort) return void 0;
|
|
151
|
+
if (typeof effort === "object" && "raw" in effort) return effort.raw;
|
|
152
|
+
if (typeof effort === "object" && "budgetTokens" in effort) {
|
|
153
|
+
const budget = effort.budgetTokens;
|
|
154
|
+
const mapped = budget >= 16e3 ? "high" : budget >= 8e3 ? "medium" : "low";
|
|
155
|
+
return { effort: mapped, summary: "auto" };
|
|
156
|
+
}
|
|
157
|
+
if (isStringEffort(effort)) {
|
|
158
|
+
return { effort, summary: "auto" };
|
|
159
|
+
}
|
|
160
|
+
return void 0;
|
|
161
|
+
}
|
|
162
|
+
function formatTools(actions) {
|
|
163
|
+
return actions.map((action) => ({
|
|
164
|
+
type: "function",
|
|
165
|
+
function: {
|
|
166
|
+
name: action.name,
|
|
167
|
+
description: action.description,
|
|
168
|
+
parameters: {
|
|
169
|
+
type: "object",
|
|
170
|
+
properties: action.parameters ? Object.fromEntries(
|
|
171
|
+
Object.entries(action.parameters).map(([key, param]) => [
|
|
172
|
+
key,
|
|
173
|
+
parameterToJsonSchema(param)
|
|
174
|
+
])
|
|
175
|
+
) : {},
|
|
176
|
+
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
177
|
+
additionalProperties: false
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}));
|
|
181
|
+
}
|
|
182
|
+
function hasImageAttachments(message) {
|
|
183
|
+
const attachments = message.metadata?.attachments;
|
|
184
|
+
return attachments?.some((a) => a.type === "image") ?? false;
|
|
185
|
+
}
|
|
186
|
+
function attachmentToOpenAIImage(attachment) {
|
|
187
|
+
if (attachment.type !== "image") return null;
|
|
188
|
+
let imageUrl;
|
|
189
|
+
if (attachment.url) {
|
|
190
|
+
imageUrl = attachment.url;
|
|
191
|
+
} else if (attachment.data) {
|
|
192
|
+
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
193
|
+
} else {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
type: "image_url",
|
|
198
|
+
image_url: {
|
|
199
|
+
url: imageUrl,
|
|
200
|
+
detail: "auto"
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function messageToOpenAIContent(message) {
|
|
205
|
+
const attachments = message.metadata?.attachments;
|
|
206
|
+
const content = message.content ?? "";
|
|
207
|
+
if (!hasImageAttachments(message)) {
|
|
208
|
+
return content;
|
|
209
|
+
}
|
|
210
|
+
const blocks = [];
|
|
211
|
+
if (content) {
|
|
212
|
+
blocks.push({ type: "text", text: content });
|
|
213
|
+
}
|
|
214
|
+
if (attachments) {
|
|
215
|
+
for (const attachment of attachments) {
|
|
216
|
+
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
217
|
+
if (imageBlock) {
|
|
218
|
+
blocks.push(imageBlock);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return blocks;
|
|
223
|
+
}
|
|
224
|
+
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
225
|
+
const formatted = [];
|
|
226
|
+
if (systemPrompt) {
|
|
227
|
+
formatted.push({ role: "system", content: systemPrompt });
|
|
228
|
+
}
|
|
229
|
+
for (const msg of messages) {
|
|
230
|
+
if (msg.role === "system") {
|
|
231
|
+
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
232
|
+
} else if (msg.role === "user") {
|
|
233
|
+
formatted.push({
|
|
234
|
+
role: "user",
|
|
235
|
+
content: messageToOpenAIContent(msg)
|
|
236
|
+
});
|
|
237
|
+
} else if (msg.role === "assistant") {
|
|
238
|
+
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
239
|
+
const assistantMsg = {
|
|
240
|
+
role: "assistant",
|
|
241
|
+
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
242
|
+
content: hasToolCalls ? msg.content || null : msg.content
|
|
243
|
+
};
|
|
244
|
+
if (hasToolCalls) {
|
|
245
|
+
assistantMsg.tool_calls = msg.tool_calls;
|
|
246
|
+
}
|
|
247
|
+
formatted.push(assistantMsg);
|
|
248
|
+
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
249
|
+
formatted.push({
|
|
250
|
+
role: "tool",
|
|
251
|
+
content: msg.content ?? "",
|
|
252
|
+
tool_call_id: msg.tool_call_id
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return formatted;
|
|
257
|
+
}
|
|
258
|
+
|
|
3
259
|
// src/providers/openai/provider.ts
|
|
4
260
|
var OPENAI_MODELS = {
|
|
5
261
|
// GPT-4o series
|
|
@@ -94,13 +350,17 @@ function openai(modelId, options = {}) {
|
|
|
94
350
|
},
|
|
95
351
|
async doGenerate(params) {
|
|
96
352
|
const client2 = await getClient();
|
|
97
|
-
const messages =
|
|
353
|
+
const messages = formatMessagesForOpenAI2(params.messages);
|
|
98
354
|
const response = await client2.chat.completions.create({
|
|
99
355
|
model: modelId,
|
|
100
356
|
messages,
|
|
101
357
|
tools: params.tools,
|
|
102
|
-
|
|
103
|
-
|
|
358
|
+
...buildOpenAITokenParams(
|
|
359
|
+
modelId,
|
|
360
|
+
params.maxTokens,
|
|
361
|
+
params.temperature
|
|
362
|
+
),
|
|
363
|
+
response_format: toOpenAIResponseFormat(params.responseFormat)
|
|
104
364
|
});
|
|
105
365
|
const choice = response.choices[0];
|
|
106
366
|
const message = choice.message;
|
|
@@ -125,13 +385,17 @@ function openai(modelId, options = {}) {
|
|
|
125
385
|
},
|
|
126
386
|
async *doStream(params) {
|
|
127
387
|
const client2 = await getClient();
|
|
128
|
-
const messages =
|
|
388
|
+
const messages = formatMessagesForOpenAI2(params.messages);
|
|
129
389
|
const stream = await client2.chat.completions.create({
|
|
130
390
|
model: modelId,
|
|
131
391
|
messages,
|
|
132
392
|
tools: params.tools,
|
|
133
|
-
|
|
134
|
-
|
|
393
|
+
...buildOpenAITokenParams(
|
|
394
|
+
modelId,
|
|
395
|
+
params.maxTokens,
|
|
396
|
+
params.temperature
|
|
397
|
+
),
|
|
398
|
+
response_format: toOpenAIResponseFormat(params.responseFormat),
|
|
135
399
|
stream: true
|
|
136
400
|
});
|
|
137
401
|
let currentToolCall = null;
|
|
@@ -215,7 +479,7 @@ function mapFinishReason(reason) {
|
|
|
215
479
|
return "unknown";
|
|
216
480
|
}
|
|
217
481
|
}
|
|
218
|
-
function
|
|
482
|
+
function formatMessagesForOpenAI2(messages) {
|
|
219
483
|
return messages.map((msg) => {
|
|
220
484
|
switch (msg.role) {
|
|
221
485
|
case "system":
|
|
@@ -277,204 +541,6 @@ function generateToolCallId() {
|
|
|
277
541
|
return generateId("call");
|
|
278
542
|
}
|
|
279
543
|
|
|
280
|
-
// src/adapters/base.ts
|
|
281
|
-
function stringifyForDebug(value) {
|
|
282
|
-
return JSON.stringify(
|
|
283
|
-
value,
|
|
284
|
-
(_key, currentValue) => {
|
|
285
|
-
if (typeof currentValue === "bigint") {
|
|
286
|
-
return currentValue.toString();
|
|
287
|
-
}
|
|
288
|
-
if (currentValue instanceof Error) {
|
|
289
|
-
return {
|
|
290
|
-
name: currentValue.name,
|
|
291
|
-
message: currentValue.message,
|
|
292
|
-
stack: currentValue.stack
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
return currentValue;
|
|
296
|
-
},
|
|
297
|
-
2
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
301
|
-
if (!enabled) {
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
try {
|
|
308
|
-
console.log(
|
|
309
|
-
`[llm-sdk:${provider}] ${label}
|
|
310
|
-
${stringifyForDebug(payload)}`
|
|
311
|
-
);
|
|
312
|
-
} catch (error) {
|
|
313
|
-
console.log(
|
|
314
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
315
|
-
error
|
|
316
|
-
);
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
function parameterToJsonSchema(param) {
|
|
320
|
-
const schema = {
|
|
321
|
-
type: param.type
|
|
322
|
-
};
|
|
323
|
-
if (param.description) {
|
|
324
|
-
schema.description = param.description;
|
|
325
|
-
}
|
|
326
|
-
if (param.enum) {
|
|
327
|
-
schema.enum = param.enum;
|
|
328
|
-
}
|
|
329
|
-
if (param.type === "array" && param.items) {
|
|
330
|
-
schema.items = parameterToJsonSchema(
|
|
331
|
-
param.items
|
|
332
|
-
);
|
|
333
|
-
}
|
|
334
|
-
if (param.type === "object" && param.properties) {
|
|
335
|
-
schema.properties = Object.fromEntries(
|
|
336
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
337
|
-
key,
|
|
338
|
-
parameterToJsonSchema(
|
|
339
|
-
prop
|
|
340
|
-
)
|
|
341
|
-
])
|
|
342
|
-
);
|
|
343
|
-
schema.additionalProperties = false;
|
|
344
|
-
}
|
|
345
|
-
return schema;
|
|
346
|
-
}
|
|
347
|
-
function normalizeObjectJsonSchema(schema) {
|
|
348
|
-
if (!schema || typeof schema !== "object") {
|
|
349
|
-
return {
|
|
350
|
-
type: "object",
|
|
351
|
-
properties: {},
|
|
352
|
-
required: [],
|
|
353
|
-
additionalProperties: false
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
const normalized = { ...schema };
|
|
357
|
-
const type = normalized.type;
|
|
358
|
-
if (type === "object") {
|
|
359
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
360
|
-
normalized.properties = Object.fromEntries(
|
|
361
|
-
Object.entries(properties).map(([key, value]) => [
|
|
362
|
-
key,
|
|
363
|
-
normalizeObjectJsonSchema(value)
|
|
364
|
-
])
|
|
365
|
-
);
|
|
366
|
-
const propertyKeys = Object.keys(properties);
|
|
367
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
368
|
-
(value) => typeof value === "string"
|
|
369
|
-
) : [];
|
|
370
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
371
|
-
if (normalized.additionalProperties === void 0) {
|
|
372
|
-
normalized.additionalProperties = false;
|
|
373
|
-
}
|
|
374
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
375
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
376
|
-
normalized.items
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
return normalized;
|
|
380
|
-
}
|
|
381
|
-
function formatTools(actions) {
|
|
382
|
-
return actions.map((action) => ({
|
|
383
|
-
type: "function",
|
|
384
|
-
function: {
|
|
385
|
-
name: action.name,
|
|
386
|
-
description: action.description,
|
|
387
|
-
parameters: {
|
|
388
|
-
type: "object",
|
|
389
|
-
properties: action.parameters ? Object.fromEntries(
|
|
390
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
391
|
-
key,
|
|
392
|
-
parameterToJsonSchema(param)
|
|
393
|
-
])
|
|
394
|
-
) : {},
|
|
395
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
396
|
-
additionalProperties: false
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}));
|
|
400
|
-
}
|
|
401
|
-
function hasImageAttachments(message) {
|
|
402
|
-
const attachments = message.metadata?.attachments;
|
|
403
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
404
|
-
}
|
|
405
|
-
function attachmentToOpenAIImage(attachment) {
|
|
406
|
-
if (attachment.type !== "image") return null;
|
|
407
|
-
let imageUrl;
|
|
408
|
-
if (attachment.url) {
|
|
409
|
-
imageUrl = attachment.url;
|
|
410
|
-
} else if (attachment.data) {
|
|
411
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
412
|
-
} else {
|
|
413
|
-
return null;
|
|
414
|
-
}
|
|
415
|
-
return {
|
|
416
|
-
type: "image_url",
|
|
417
|
-
image_url: {
|
|
418
|
-
url: imageUrl,
|
|
419
|
-
detail: "auto"
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
}
|
|
423
|
-
function messageToOpenAIContent(message) {
|
|
424
|
-
const attachments = message.metadata?.attachments;
|
|
425
|
-
const content = message.content ?? "";
|
|
426
|
-
if (!hasImageAttachments(message)) {
|
|
427
|
-
return content;
|
|
428
|
-
}
|
|
429
|
-
const blocks = [];
|
|
430
|
-
if (content) {
|
|
431
|
-
blocks.push({ type: "text", text: content });
|
|
432
|
-
}
|
|
433
|
-
if (attachments) {
|
|
434
|
-
for (const attachment of attachments) {
|
|
435
|
-
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
436
|
-
if (imageBlock) {
|
|
437
|
-
blocks.push(imageBlock);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
return blocks;
|
|
442
|
-
}
|
|
443
|
-
function formatMessagesForOpenAI2(messages, systemPrompt) {
|
|
444
|
-
const formatted = [];
|
|
445
|
-
if (systemPrompt) {
|
|
446
|
-
formatted.push({ role: "system", content: systemPrompt });
|
|
447
|
-
}
|
|
448
|
-
for (const msg of messages) {
|
|
449
|
-
if (msg.role === "system") {
|
|
450
|
-
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
451
|
-
} else if (msg.role === "user") {
|
|
452
|
-
formatted.push({
|
|
453
|
-
role: "user",
|
|
454
|
-
content: messageToOpenAIContent(msg)
|
|
455
|
-
});
|
|
456
|
-
} else if (msg.role === "assistant") {
|
|
457
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
458
|
-
const assistantMsg = {
|
|
459
|
-
role: "assistant",
|
|
460
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
461
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
462
|
-
};
|
|
463
|
-
if (hasToolCalls) {
|
|
464
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
465
|
-
}
|
|
466
|
-
formatted.push(assistantMsg);
|
|
467
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
468
|
-
formatted.push({
|
|
469
|
-
role: "tool",
|
|
470
|
-
content: msg.content ?? "",
|
|
471
|
-
tool_call_id: msg.tool_call_id
|
|
472
|
-
});
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
return formatted;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
544
|
// src/adapters/openai.ts
|
|
479
545
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
480
546
|
constructor(config) {
|
|
@@ -500,10 +566,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
500
566
|
return this.client;
|
|
501
567
|
}
|
|
502
568
|
shouldUseResponsesApi(request) {
|
|
569
|
+
if (request.config?.mcpServers && request.config.mcpServers.length > 0 || request.config?.reasoningEffort !== void 0) {
|
|
570
|
+
if (this.provider !== "openai" && this.provider !== "azure") {
|
|
571
|
+
throw new Error(
|
|
572
|
+
`[llm-sdk] Provider "${this.provider}" does not support MCP servers or per-request reasoning effort. Use OpenAI or Anthropic for these features.`
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
return true;
|
|
576
|
+
}
|
|
503
577
|
return request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false && Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
|
|
504
578
|
}
|
|
505
579
|
buildResponsesInput(request) {
|
|
506
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages :
|
|
580
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
|
|
507
581
|
const input = [];
|
|
508
582
|
for (const message of sourceMessages) {
|
|
509
583
|
if (message.role === "system") {
|
|
@@ -560,7 +634,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
560
634
|
strict: true,
|
|
561
635
|
defer_loading: tool.deferLoading === true
|
|
562
636
|
}));
|
|
563
|
-
return [{ type: "tool_search" }, ...nativeTools];
|
|
637
|
+
return nativeTools.length > 0 ? [{ type: "tool_search" }, ...nativeTools] : [];
|
|
564
638
|
}
|
|
565
639
|
parseResponsesResult(response) {
|
|
566
640
|
const content = typeof response?.output_text === "string" ? response.output_text : "";
|
|
@@ -589,15 +663,33 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
589
663
|
async completeWithResponses(request) {
|
|
590
664
|
const client = await this.getClient();
|
|
591
665
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
666
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
667
|
+
request.config?.responseFormat
|
|
668
|
+
);
|
|
669
|
+
const mcpTools = toOpenAIResponsesMcpTools(request.config?.mcpServers);
|
|
670
|
+
const modelId = request.config?.model || this.model;
|
|
671
|
+
const reasoning = isOpenAIReasoningModel(modelId) ? toOpenAIReasoning(request.config?.reasoningEffort) : void 0;
|
|
672
|
+
if (request.config?.reasoningEffort && !isOpenAIReasoningModel(modelId)) {
|
|
673
|
+
console.warn(
|
|
674
|
+
`[llm-sdk] openai/${modelId} is not a reasoning model; \`reasoningEffort\` is ignored. Use o1/o3/o4/gpt-5.x for reasoning.`
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
const functionTools = this.buildResponsesTools(
|
|
678
|
+
request.toolDefinitions ?? []
|
|
679
|
+
);
|
|
680
|
+
const tools = [...functionTools, ...mcpTools];
|
|
592
681
|
const payload = {
|
|
593
682
|
model: request.config?.model || this.model,
|
|
594
683
|
instructions: request.systemPrompt,
|
|
595
684
|
input: this.buildResponsesInput(request),
|
|
596
|
-
tools:
|
|
685
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
597
686
|
tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
|
|
598
687
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
599
688
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
600
689
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
690
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
691
|
+
...reasoning ? { reasoning } : {},
|
|
692
|
+
store: false,
|
|
601
693
|
stream: false
|
|
602
694
|
};
|
|
603
695
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -692,7 +784,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
692
784
|
messages = processedMessages;
|
|
693
785
|
}
|
|
694
786
|
} else {
|
|
695
|
-
messages =
|
|
787
|
+
messages = formatMessagesForOpenAI(
|
|
696
788
|
request.messages,
|
|
697
789
|
request.systemPrompt
|
|
698
790
|
);
|
|
@@ -719,14 +811,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
719
811
|
name: openaiToolOptions.toolChoice.name
|
|
720
812
|
}
|
|
721
813
|
} : openaiToolOptions?.toolChoice;
|
|
814
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
722
815
|
const payload = {
|
|
723
|
-
model:
|
|
816
|
+
model: modelIdForPayload,
|
|
724
817
|
messages,
|
|
725
818
|
tools: tools.length > 0 ? tools : void 0,
|
|
726
819
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
727
820
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
728
|
-
|
|
729
|
-
|
|
821
|
+
...buildOpenAITokenParams(
|
|
822
|
+
modelIdForPayload,
|
|
823
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
824
|
+
request.config?.temperature ?? this.config.temperature
|
|
825
|
+
),
|
|
826
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
730
827
|
stream: true,
|
|
731
828
|
stream_options: { include_usage: true }
|
|
732
829
|
};
|
|
@@ -855,7 +952,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
855
952
|
messages = sanitized;
|
|
856
953
|
}
|
|
857
954
|
} else {
|
|
858
|
-
messages =
|
|
955
|
+
messages = formatMessagesForOpenAI(
|
|
859
956
|
request.messages,
|
|
860
957
|
request.systemPrompt
|
|
861
958
|
);
|
|
@@ -868,14 +965,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
868
965
|
name: openaiToolOptions.toolChoice.name
|
|
869
966
|
}
|
|
870
967
|
} : openaiToolOptions?.toolChoice;
|
|
968
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
871
969
|
const payload = {
|
|
872
|
-
model:
|
|
970
|
+
model: modelIdForCompletePayload,
|
|
873
971
|
messages,
|
|
874
972
|
tools: tools.length > 0 ? tools : void 0,
|
|
875
973
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
876
974
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
877
|
-
|
|
878
|
-
|
|
975
|
+
...buildOpenAITokenParams(
|
|
976
|
+
modelIdForCompletePayload,
|
|
977
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
978
|
+
request.config?.temperature ?? this.config.temperature
|
|
979
|
+
),
|
|
980
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
879
981
|
stream: false
|
|
880
982
|
};
|
|
881
983
|
logProviderPayload("openai", "request payload", payload, request.debug);
|