@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/togetherai/provider.ts
|
|
4
260
|
function togetherai(modelId, options = {}) {
|
|
5
261
|
const apiKey = options.apiKey ?? process.env.TOGETHER_API_KEY;
|
|
@@ -42,6 +298,10 @@ function togetherai(modelId, options = {}) {
|
|
|
42
298
|
if (params.tools) {
|
|
43
299
|
requestBody.tools = params.tools;
|
|
44
300
|
}
|
|
301
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
302
|
+
if (responseFormat) {
|
|
303
|
+
requestBody.response_format = responseFormat;
|
|
304
|
+
}
|
|
45
305
|
const response = await client2.chat.completions.create(requestBody);
|
|
46
306
|
const choice = response.choices[0];
|
|
47
307
|
const message = choice.message;
|
|
@@ -77,6 +337,10 @@ function togetherai(modelId, options = {}) {
|
|
|
77
337
|
if (params.tools) {
|
|
78
338
|
requestBody.tools = params.tools;
|
|
79
339
|
}
|
|
340
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
341
|
+
if (responseFormat) {
|
|
342
|
+
requestBody.response_format = responseFormat;
|
|
343
|
+
}
|
|
80
344
|
const stream = await client2.chat.completions.create(requestBody);
|
|
81
345
|
const toolCallMap = /* @__PURE__ */ new Map();
|
|
82
346
|
let totalPromptTokens = 0;
|
|
@@ -215,204 +479,6 @@ function generateToolCallId() {
|
|
|
215
479
|
return generateId("call");
|
|
216
480
|
}
|
|
217
481
|
|
|
218
|
-
// src/adapters/base.ts
|
|
219
|
-
function stringifyForDebug(value) {
|
|
220
|
-
return JSON.stringify(
|
|
221
|
-
value,
|
|
222
|
-
(_key, currentValue) => {
|
|
223
|
-
if (typeof currentValue === "bigint") {
|
|
224
|
-
return currentValue.toString();
|
|
225
|
-
}
|
|
226
|
-
if (currentValue instanceof Error) {
|
|
227
|
-
return {
|
|
228
|
-
name: currentValue.name,
|
|
229
|
-
message: currentValue.message,
|
|
230
|
-
stack: currentValue.stack
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
return currentValue;
|
|
234
|
-
},
|
|
235
|
-
2
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
239
|
-
if (!enabled) {
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
try {
|
|
246
|
-
console.log(
|
|
247
|
-
`[llm-sdk:${provider}] ${label}
|
|
248
|
-
${stringifyForDebug(payload)}`
|
|
249
|
-
);
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.log(
|
|
252
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
253
|
-
error
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
function parameterToJsonSchema(param) {
|
|
258
|
-
const schema = {
|
|
259
|
-
type: param.type
|
|
260
|
-
};
|
|
261
|
-
if (param.description) {
|
|
262
|
-
schema.description = param.description;
|
|
263
|
-
}
|
|
264
|
-
if (param.enum) {
|
|
265
|
-
schema.enum = param.enum;
|
|
266
|
-
}
|
|
267
|
-
if (param.type === "array" && param.items) {
|
|
268
|
-
schema.items = parameterToJsonSchema(
|
|
269
|
-
param.items
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
if (param.type === "object" && param.properties) {
|
|
273
|
-
schema.properties = Object.fromEntries(
|
|
274
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
275
|
-
key,
|
|
276
|
-
parameterToJsonSchema(
|
|
277
|
-
prop
|
|
278
|
-
)
|
|
279
|
-
])
|
|
280
|
-
);
|
|
281
|
-
schema.additionalProperties = false;
|
|
282
|
-
}
|
|
283
|
-
return schema;
|
|
284
|
-
}
|
|
285
|
-
function normalizeObjectJsonSchema(schema) {
|
|
286
|
-
if (!schema || typeof schema !== "object") {
|
|
287
|
-
return {
|
|
288
|
-
type: "object",
|
|
289
|
-
properties: {},
|
|
290
|
-
required: [],
|
|
291
|
-
additionalProperties: false
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
const normalized = { ...schema };
|
|
295
|
-
const type = normalized.type;
|
|
296
|
-
if (type === "object") {
|
|
297
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
298
|
-
normalized.properties = Object.fromEntries(
|
|
299
|
-
Object.entries(properties).map(([key, value]) => [
|
|
300
|
-
key,
|
|
301
|
-
normalizeObjectJsonSchema(value)
|
|
302
|
-
])
|
|
303
|
-
);
|
|
304
|
-
const propertyKeys = Object.keys(properties);
|
|
305
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
306
|
-
(value) => typeof value === "string"
|
|
307
|
-
) : [];
|
|
308
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
309
|
-
if (normalized.additionalProperties === void 0) {
|
|
310
|
-
normalized.additionalProperties = false;
|
|
311
|
-
}
|
|
312
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
313
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
314
|
-
normalized.items
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
return normalized;
|
|
318
|
-
}
|
|
319
|
-
function formatTools(actions) {
|
|
320
|
-
return actions.map((action) => ({
|
|
321
|
-
type: "function",
|
|
322
|
-
function: {
|
|
323
|
-
name: action.name,
|
|
324
|
-
description: action.description,
|
|
325
|
-
parameters: {
|
|
326
|
-
type: "object",
|
|
327
|
-
properties: action.parameters ? Object.fromEntries(
|
|
328
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
329
|
-
key,
|
|
330
|
-
parameterToJsonSchema(param)
|
|
331
|
-
])
|
|
332
|
-
) : {},
|
|
333
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
334
|
-
additionalProperties: false
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}));
|
|
338
|
-
}
|
|
339
|
-
function hasImageAttachments(message) {
|
|
340
|
-
const attachments = message.metadata?.attachments;
|
|
341
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
342
|
-
}
|
|
343
|
-
function attachmentToOpenAIImage(attachment) {
|
|
344
|
-
if (attachment.type !== "image") return null;
|
|
345
|
-
let imageUrl;
|
|
346
|
-
if (attachment.url) {
|
|
347
|
-
imageUrl = attachment.url;
|
|
348
|
-
} else if (attachment.data) {
|
|
349
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
350
|
-
} else {
|
|
351
|
-
return null;
|
|
352
|
-
}
|
|
353
|
-
return {
|
|
354
|
-
type: "image_url",
|
|
355
|
-
image_url: {
|
|
356
|
-
url: imageUrl,
|
|
357
|
-
detail: "auto"
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
function messageToOpenAIContent(message) {
|
|
362
|
-
const attachments = message.metadata?.attachments;
|
|
363
|
-
const content = message.content ?? "";
|
|
364
|
-
if (!hasImageAttachments(message)) {
|
|
365
|
-
return content;
|
|
366
|
-
}
|
|
367
|
-
const blocks = [];
|
|
368
|
-
if (content) {
|
|
369
|
-
blocks.push({ type: "text", text: content });
|
|
370
|
-
}
|
|
371
|
-
if (attachments) {
|
|
372
|
-
for (const attachment of attachments) {
|
|
373
|
-
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
374
|
-
if (imageBlock) {
|
|
375
|
-
blocks.push(imageBlock);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
return blocks;
|
|
380
|
-
}
|
|
381
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
382
|
-
const formatted = [];
|
|
383
|
-
if (systemPrompt) {
|
|
384
|
-
formatted.push({ role: "system", content: systemPrompt });
|
|
385
|
-
}
|
|
386
|
-
for (const msg of messages) {
|
|
387
|
-
if (msg.role === "system") {
|
|
388
|
-
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
389
|
-
} else if (msg.role === "user") {
|
|
390
|
-
formatted.push({
|
|
391
|
-
role: "user",
|
|
392
|
-
content: messageToOpenAIContent(msg)
|
|
393
|
-
});
|
|
394
|
-
} else if (msg.role === "assistant") {
|
|
395
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
396
|
-
const assistantMsg = {
|
|
397
|
-
role: "assistant",
|
|
398
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
399
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
400
|
-
};
|
|
401
|
-
if (hasToolCalls) {
|
|
402
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
403
|
-
}
|
|
404
|
-
formatted.push(assistantMsg);
|
|
405
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
406
|
-
formatted.push({
|
|
407
|
-
role: "tool",
|
|
408
|
-
content: msg.content ?? "",
|
|
409
|
-
tool_call_id: msg.tool_call_id
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
return formatted;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
482
|
// src/adapters/openai.ts
|
|
417
483
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
418
484
|
constructor(config) {
|
|
@@ -438,6 +504,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
438
504
|
return this.client;
|
|
439
505
|
}
|
|
440
506
|
shouldUseResponsesApi(request) {
|
|
507
|
+
if (request.config?.mcpServers && request.config.mcpServers.length > 0 || request.config?.reasoningEffort !== void 0) {
|
|
508
|
+
if (this.provider !== "openai" && this.provider !== "azure") {
|
|
509
|
+
throw new Error(
|
|
510
|
+
`[llm-sdk] Provider "${this.provider}" does not support MCP servers or per-request reasoning effort. Use OpenAI or Anthropic for these features.`
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
441
515
|
return request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false && Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
|
|
442
516
|
}
|
|
443
517
|
buildResponsesInput(request) {
|
|
@@ -498,7 +572,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
498
572
|
strict: true,
|
|
499
573
|
defer_loading: tool.deferLoading === true
|
|
500
574
|
}));
|
|
501
|
-
return [{ type: "tool_search" }, ...nativeTools];
|
|
575
|
+
return nativeTools.length > 0 ? [{ type: "tool_search" }, ...nativeTools] : [];
|
|
502
576
|
}
|
|
503
577
|
parseResponsesResult(response) {
|
|
504
578
|
const content = typeof response?.output_text === "string" ? response.output_text : "";
|
|
@@ -527,15 +601,33 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
527
601
|
async completeWithResponses(request) {
|
|
528
602
|
const client = await this.getClient();
|
|
529
603
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
604
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
605
|
+
request.config?.responseFormat
|
|
606
|
+
);
|
|
607
|
+
const mcpTools = toOpenAIResponsesMcpTools(request.config?.mcpServers);
|
|
608
|
+
const modelId = request.config?.model || this.model;
|
|
609
|
+
const reasoning = isOpenAIReasoningModel(modelId) ? toOpenAIReasoning(request.config?.reasoningEffort) : void 0;
|
|
610
|
+
if (request.config?.reasoningEffort && !isOpenAIReasoningModel(modelId)) {
|
|
611
|
+
console.warn(
|
|
612
|
+
`[llm-sdk] openai/${modelId} is not a reasoning model; \`reasoningEffort\` is ignored. Use o1/o3/o4/gpt-5.x for reasoning.`
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
const functionTools = this.buildResponsesTools(
|
|
616
|
+
request.toolDefinitions ?? []
|
|
617
|
+
);
|
|
618
|
+
const tools = [...functionTools, ...mcpTools];
|
|
530
619
|
const payload = {
|
|
531
620
|
model: request.config?.model || this.model,
|
|
532
621
|
instructions: request.systemPrompt,
|
|
533
622
|
input: this.buildResponsesInput(request),
|
|
534
|
-
tools:
|
|
623
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
535
624
|
tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
|
|
536
625
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
537
626
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
538
627
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
628
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
629
|
+
...reasoning ? { reasoning } : {},
|
|
630
|
+
store: false,
|
|
539
631
|
stream: false
|
|
540
632
|
};
|
|
541
633
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -657,14 +749,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
657
749
|
name: openaiToolOptions.toolChoice.name
|
|
658
750
|
}
|
|
659
751
|
} : openaiToolOptions?.toolChoice;
|
|
752
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
660
753
|
const payload = {
|
|
661
|
-
model:
|
|
754
|
+
model: modelIdForPayload,
|
|
662
755
|
messages,
|
|
663
756
|
tools: tools.length > 0 ? tools : void 0,
|
|
664
757
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
665
758
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
666
|
-
|
|
667
|
-
|
|
759
|
+
...buildOpenAITokenParams(
|
|
760
|
+
modelIdForPayload,
|
|
761
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
762
|
+
request.config?.temperature ?? this.config.temperature
|
|
763
|
+
),
|
|
764
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
668
765
|
stream: true,
|
|
669
766
|
stream_options: { include_usage: true }
|
|
670
767
|
};
|
|
@@ -806,14 +903,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
806
903
|
name: openaiToolOptions.toolChoice.name
|
|
807
904
|
}
|
|
808
905
|
} : openaiToolOptions?.toolChoice;
|
|
906
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
809
907
|
const payload = {
|
|
810
|
-
model:
|
|
908
|
+
model: modelIdForCompletePayload,
|
|
811
909
|
messages,
|
|
812
910
|
tools: tools.length > 0 ? tools : void 0,
|
|
813
911
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
814
912
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
815
|
-
|
|
816
|
-
|
|
913
|
+
...buildOpenAITokenParams(
|
|
914
|
+
modelIdForCompletePayload,
|
|
915
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
916
|
+
request.config?.temperature ?? this.config.temperature
|
|
917
|
+
),
|
|
918
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
817
919
|
stream: false
|
|
818
920
|
};
|
|
819
921
|
logProviderPayload("openai", "request payload", payload, request.debug);
|