@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,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/openrouter/provider.ts
|
|
4
260
|
var DEFAULT_MODEL_CONFIG = {
|
|
5
261
|
vision: true,
|
|
@@ -58,6 +314,10 @@ function openrouter(modelId, options = {}) {
|
|
|
58
314
|
if (options.providerPreferences) {
|
|
59
315
|
requestBody.provider = options.providerPreferences;
|
|
60
316
|
}
|
|
317
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
318
|
+
if (responseFormat) {
|
|
319
|
+
requestBody.response_format = responseFormat;
|
|
320
|
+
}
|
|
61
321
|
const response = await client2.chat.completions.create(requestBody);
|
|
62
322
|
const choice = response.choices[0];
|
|
63
323
|
const message = choice.message;
|
|
@@ -96,6 +356,10 @@ function openrouter(modelId, options = {}) {
|
|
|
96
356
|
if (options.providerPreferences) {
|
|
97
357
|
requestBody.provider = options.providerPreferences;
|
|
98
358
|
}
|
|
359
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
360
|
+
if (responseFormat) {
|
|
361
|
+
requestBody.response_format = responseFormat;
|
|
362
|
+
}
|
|
99
363
|
const stream = await client2.chat.completions.create(requestBody);
|
|
100
364
|
let currentToolCall = null;
|
|
101
365
|
let totalPromptTokens = 0;
|
|
@@ -263,204 +527,6 @@ function generateToolCallId() {
|
|
|
263
527
|
return generateId("call");
|
|
264
528
|
}
|
|
265
529
|
|
|
266
|
-
// src/adapters/base.ts
|
|
267
|
-
function stringifyForDebug(value) {
|
|
268
|
-
return JSON.stringify(
|
|
269
|
-
value,
|
|
270
|
-
(_key, currentValue) => {
|
|
271
|
-
if (typeof currentValue === "bigint") {
|
|
272
|
-
return currentValue.toString();
|
|
273
|
-
}
|
|
274
|
-
if (currentValue instanceof Error) {
|
|
275
|
-
return {
|
|
276
|
-
name: currentValue.name,
|
|
277
|
-
message: currentValue.message,
|
|
278
|
-
stack: currentValue.stack
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
return currentValue;
|
|
282
|
-
},
|
|
283
|
-
2
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
287
|
-
if (!enabled) {
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
290
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
try {
|
|
294
|
-
console.log(
|
|
295
|
-
`[llm-sdk:${provider}] ${label}
|
|
296
|
-
${stringifyForDebug(payload)}`
|
|
297
|
-
);
|
|
298
|
-
} catch (error) {
|
|
299
|
-
console.log(
|
|
300
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
301
|
-
error
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
function parameterToJsonSchema(param) {
|
|
306
|
-
const schema = {
|
|
307
|
-
type: param.type
|
|
308
|
-
};
|
|
309
|
-
if (param.description) {
|
|
310
|
-
schema.description = param.description;
|
|
311
|
-
}
|
|
312
|
-
if (param.enum) {
|
|
313
|
-
schema.enum = param.enum;
|
|
314
|
-
}
|
|
315
|
-
if (param.type === "array" && param.items) {
|
|
316
|
-
schema.items = parameterToJsonSchema(
|
|
317
|
-
param.items
|
|
318
|
-
);
|
|
319
|
-
}
|
|
320
|
-
if (param.type === "object" && param.properties) {
|
|
321
|
-
schema.properties = Object.fromEntries(
|
|
322
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
323
|
-
key,
|
|
324
|
-
parameterToJsonSchema(
|
|
325
|
-
prop
|
|
326
|
-
)
|
|
327
|
-
])
|
|
328
|
-
);
|
|
329
|
-
schema.additionalProperties = false;
|
|
330
|
-
}
|
|
331
|
-
return schema;
|
|
332
|
-
}
|
|
333
|
-
function normalizeObjectJsonSchema(schema) {
|
|
334
|
-
if (!schema || typeof schema !== "object") {
|
|
335
|
-
return {
|
|
336
|
-
type: "object",
|
|
337
|
-
properties: {},
|
|
338
|
-
required: [],
|
|
339
|
-
additionalProperties: false
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
const normalized = { ...schema };
|
|
343
|
-
const type = normalized.type;
|
|
344
|
-
if (type === "object") {
|
|
345
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
346
|
-
normalized.properties = Object.fromEntries(
|
|
347
|
-
Object.entries(properties).map(([key, value]) => [
|
|
348
|
-
key,
|
|
349
|
-
normalizeObjectJsonSchema(value)
|
|
350
|
-
])
|
|
351
|
-
);
|
|
352
|
-
const propertyKeys = Object.keys(properties);
|
|
353
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
354
|
-
(value) => typeof value === "string"
|
|
355
|
-
) : [];
|
|
356
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
357
|
-
if (normalized.additionalProperties === void 0) {
|
|
358
|
-
normalized.additionalProperties = false;
|
|
359
|
-
}
|
|
360
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
361
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
362
|
-
normalized.items
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
return normalized;
|
|
366
|
-
}
|
|
367
|
-
function formatTools(actions) {
|
|
368
|
-
return actions.map((action) => ({
|
|
369
|
-
type: "function",
|
|
370
|
-
function: {
|
|
371
|
-
name: action.name,
|
|
372
|
-
description: action.description,
|
|
373
|
-
parameters: {
|
|
374
|
-
type: "object",
|
|
375
|
-
properties: action.parameters ? Object.fromEntries(
|
|
376
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
377
|
-
key,
|
|
378
|
-
parameterToJsonSchema(param)
|
|
379
|
-
])
|
|
380
|
-
) : {},
|
|
381
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
382
|
-
additionalProperties: false
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}));
|
|
386
|
-
}
|
|
387
|
-
function hasImageAttachments(message) {
|
|
388
|
-
const attachments = message.metadata?.attachments;
|
|
389
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
390
|
-
}
|
|
391
|
-
function attachmentToOpenAIImage(attachment) {
|
|
392
|
-
if (attachment.type !== "image") return null;
|
|
393
|
-
let imageUrl;
|
|
394
|
-
if (attachment.url) {
|
|
395
|
-
imageUrl = attachment.url;
|
|
396
|
-
} else if (attachment.data) {
|
|
397
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
398
|
-
} else {
|
|
399
|
-
return null;
|
|
400
|
-
}
|
|
401
|
-
return {
|
|
402
|
-
type: "image_url",
|
|
403
|
-
image_url: {
|
|
404
|
-
url: imageUrl,
|
|
405
|
-
detail: "auto"
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
function messageToOpenAIContent(message) {
|
|
410
|
-
const attachments = message.metadata?.attachments;
|
|
411
|
-
const content = message.content ?? "";
|
|
412
|
-
if (!hasImageAttachments(message)) {
|
|
413
|
-
return content;
|
|
414
|
-
}
|
|
415
|
-
const blocks = [];
|
|
416
|
-
if (content) {
|
|
417
|
-
blocks.push({ type: "text", text: content });
|
|
418
|
-
}
|
|
419
|
-
if (attachments) {
|
|
420
|
-
for (const attachment of attachments) {
|
|
421
|
-
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
422
|
-
if (imageBlock) {
|
|
423
|
-
blocks.push(imageBlock);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
return blocks;
|
|
428
|
-
}
|
|
429
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
430
|
-
const formatted = [];
|
|
431
|
-
if (systemPrompt) {
|
|
432
|
-
formatted.push({ role: "system", content: systemPrompt });
|
|
433
|
-
}
|
|
434
|
-
for (const msg of messages) {
|
|
435
|
-
if (msg.role === "system") {
|
|
436
|
-
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
437
|
-
} else if (msg.role === "user") {
|
|
438
|
-
formatted.push({
|
|
439
|
-
role: "user",
|
|
440
|
-
content: messageToOpenAIContent(msg)
|
|
441
|
-
});
|
|
442
|
-
} else if (msg.role === "assistant") {
|
|
443
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
444
|
-
const assistantMsg = {
|
|
445
|
-
role: "assistant",
|
|
446
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
447
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
448
|
-
};
|
|
449
|
-
if (hasToolCalls) {
|
|
450
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
451
|
-
}
|
|
452
|
-
formatted.push(assistantMsg);
|
|
453
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
454
|
-
formatted.push({
|
|
455
|
-
role: "tool",
|
|
456
|
-
content: msg.content ?? "",
|
|
457
|
-
tool_call_id: msg.tool_call_id
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
return formatted;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
530
|
// src/adapters/openai.ts
|
|
465
531
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
466
532
|
constructor(config) {
|
|
@@ -486,6 +552,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
486
552
|
return this.client;
|
|
487
553
|
}
|
|
488
554
|
shouldUseResponsesApi(request) {
|
|
555
|
+
if (request.config?.mcpServers && request.config.mcpServers.length > 0 || request.config?.reasoningEffort !== void 0) {
|
|
556
|
+
if (this.provider !== "openai" && this.provider !== "azure") {
|
|
557
|
+
throw new Error(
|
|
558
|
+
`[llm-sdk] Provider "${this.provider}" does not support MCP servers or per-request reasoning effort. Use OpenAI or Anthropic for these features.`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
489
563
|
return request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false && Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
|
|
490
564
|
}
|
|
491
565
|
buildResponsesInput(request) {
|
|
@@ -546,7 +620,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
546
620
|
strict: true,
|
|
547
621
|
defer_loading: tool.deferLoading === true
|
|
548
622
|
}));
|
|
549
|
-
return [{ type: "tool_search" }, ...nativeTools];
|
|
623
|
+
return nativeTools.length > 0 ? [{ type: "tool_search" }, ...nativeTools] : [];
|
|
550
624
|
}
|
|
551
625
|
parseResponsesResult(response) {
|
|
552
626
|
const content = typeof response?.output_text === "string" ? response.output_text : "";
|
|
@@ -575,15 +649,33 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
575
649
|
async completeWithResponses(request) {
|
|
576
650
|
const client = await this.getClient();
|
|
577
651
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
652
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
653
|
+
request.config?.responseFormat
|
|
654
|
+
);
|
|
655
|
+
const mcpTools = toOpenAIResponsesMcpTools(request.config?.mcpServers);
|
|
656
|
+
const modelId = request.config?.model || this.model;
|
|
657
|
+
const reasoning = isOpenAIReasoningModel(modelId) ? toOpenAIReasoning(request.config?.reasoningEffort) : void 0;
|
|
658
|
+
if (request.config?.reasoningEffort && !isOpenAIReasoningModel(modelId)) {
|
|
659
|
+
console.warn(
|
|
660
|
+
`[llm-sdk] openai/${modelId} is not a reasoning model; \`reasoningEffort\` is ignored. Use o1/o3/o4/gpt-5.x for reasoning.`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
const functionTools = this.buildResponsesTools(
|
|
664
|
+
request.toolDefinitions ?? []
|
|
665
|
+
);
|
|
666
|
+
const tools = [...functionTools, ...mcpTools];
|
|
578
667
|
const payload = {
|
|
579
668
|
model: request.config?.model || this.model,
|
|
580
669
|
instructions: request.systemPrompt,
|
|
581
670
|
input: this.buildResponsesInput(request),
|
|
582
|
-
tools:
|
|
671
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
583
672
|
tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
|
|
584
673
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
585
674
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
586
675
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
676
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
677
|
+
...reasoning ? { reasoning } : {},
|
|
678
|
+
store: false,
|
|
587
679
|
stream: false
|
|
588
680
|
};
|
|
589
681
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -705,14 +797,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
705
797
|
name: openaiToolOptions.toolChoice.name
|
|
706
798
|
}
|
|
707
799
|
} : openaiToolOptions?.toolChoice;
|
|
800
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
708
801
|
const payload = {
|
|
709
|
-
model:
|
|
802
|
+
model: modelIdForPayload,
|
|
710
803
|
messages,
|
|
711
804
|
tools: tools.length > 0 ? tools : void 0,
|
|
712
805
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
713
806
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
714
|
-
|
|
715
|
-
|
|
807
|
+
...buildOpenAITokenParams(
|
|
808
|
+
modelIdForPayload,
|
|
809
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
810
|
+
request.config?.temperature ?? this.config.temperature
|
|
811
|
+
),
|
|
812
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
716
813
|
stream: true,
|
|
717
814
|
stream_options: { include_usage: true }
|
|
718
815
|
};
|
|
@@ -854,14 +951,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
854
951
|
name: openaiToolOptions.toolChoice.name
|
|
855
952
|
}
|
|
856
953
|
} : openaiToolOptions?.toolChoice;
|
|
954
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
857
955
|
const payload = {
|
|
858
|
-
model:
|
|
956
|
+
model: modelIdForCompletePayload,
|
|
859
957
|
messages,
|
|
860
958
|
tools: tools.length > 0 ? tools : void 0,
|
|
861
959
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
862
960
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
863
|
-
|
|
864
|
-
|
|
961
|
+
...buildOpenAITokenParams(
|
|
962
|
+
modelIdForCompletePayload,
|
|
963
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
964
|
+
request.config?.temperature ?? this.config.temperature
|
|
965
|
+
),
|
|
966
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
865
967
|
stream: false
|
|
866
968
|
};
|
|
867
969
|
logProviderPayload("openai", "request payload", payload, request.debug);
|