@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/xai/provider.ts
|
|
4
260
|
var XAI_MODELS = {
|
|
5
261
|
// Grok 4.1 Fast (Latest - December 2025)
|
|
@@ -53,8 +309,8 @@ function xai(modelId, options = {}) {
|
|
|
53
309
|
supportsVision: modelConfig.vision,
|
|
54
310
|
supportsTools: modelConfig.tools,
|
|
55
311
|
supportsStreaming: true,
|
|
56
|
-
supportsJsonMode:
|
|
57
|
-
//
|
|
312
|
+
supportsJsonMode: true,
|
|
313
|
+
// OpenAI-compatible `response_format`
|
|
58
314
|
supportsThinking: false,
|
|
59
315
|
supportsPDF: false,
|
|
60
316
|
maxTokens: modelConfig.maxTokens,
|
|
@@ -68,7 +324,8 @@ function xai(modelId, options = {}) {
|
|
|
68
324
|
messages,
|
|
69
325
|
tools: params.tools,
|
|
70
326
|
temperature: params.temperature,
|
|
71
|
-
max_tokens: params.maxTokens
|
|
327
|
+
max_tokens: params.maxTokens,
|
|
328
|
+
response_format: toOpenAIResponseFormat(params.responseFormat)
|
|
72
329
|
});
|
|
73
330
|
const choice = response.choices[0];
|
|
74
331
|
const message = choice.message;
|
|
@@ -100,6 +357,7 @@ function xai(modelId, options = {}) {
|
|
|
100
357
|
tools: params.tools,
|
|
101
358
|
temperature: params.temperature,
|
|
102
359
|
max_tokens: params.maxTokens,
|
|
360
|
+
response_format: toOpenAIResponseFormat(params.responseFormat),
|
|
103
361
|
stream: true
|
|
104
362
|
});
|
|
105
363
|
let currentToolCall = null;
|
|
@@ -245,204 +503,6 @@ function generateToolCallId() {
|
|
|
245
503
|
return generateId("call");
|
|
246
504
|
}
|
|
247
505
|
|
|
248
|
-
// src/adapters/base.ts
|
|
249
|
-
function stringifyForDebug(value) {
|
|
250
|
-
return JSON.stringify(
|
|
251
|
-
value,
|
|
252
|
-
(_key, currentValue) => {
|
|
253
|
-
if (typeof currentValue === "bigint") {
|
|
254
|
-
return currentValue.toString();
|
|
255
|
-
}
|
|
256
|
-
if (currentValue instanceof Error) {
|
|
257
|
-
return {
|
|
258
|
-
name: currentValue.name,
|
|
259
|
-
message: currentValue.message,
|
|
260
|
-
stack: currentValue.stack
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
return currentValue;
|
|
264
|
-
},
|
|
265
|
-
2
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
269
|
-
if (!enabled) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
try {
|
|
276
|
-
console.log(
|
|
277
|
-
`[llm-sdk:${provider}] ${label}
|
|
278
|
-
${stringifyForDebug(payload)}`
|
|
279
|
-
);
|
|
280
|
-
} catch (error) {
|
|
281
|
-
console.log(
|
|
282
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
283
|
-
error
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function parameterToJsonSchema(param) {
|
|
288
|
-
const schema = {
|
|
289
|
-
type: param.type
|
|
290
|
-
};
|
|
291
|
-
if (param.description) {
|
|
292
|
-
schema.description = param.description;
|
|
293
|
-
}
|
|
294
|
-
if (param.enum) {
|
|
295
|
-
schema.enum = param.enum;
|
|
296
|
-
}
|
|
297
|
-
if (param.type === "array" && param.items) {
|
|
298
|
-
schema.items = parameterToJsonSchema(
|
|
299
|
-
param.items
|
|
300
|
-
);
|
|
301
|
-
}
|
|
302
|
-
if (param.type === "object" && param.properties) {
|
|
303
|
-
schema.properties = Object.fromEntries(
|
|
304
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
305
|
-
key,
|
|
306
|
-
parameterToJsonSchema(
|
|
307
|
-
prop
|
|
308
|
-
)
|
|
309
|
-
])
|
|
310
|
-
);
|
|
311
|
-
schema.additionalProperties = false;
|
|
312
|
-
}
|
|
313
|
-
return schema;
|
|
314
|
-
}
|
|
315
|
-
function normalizeObjectJsonSchema(schema) {
|
|
316
|
-
if (!schema || typeof schema !== "object") {
|
|
317
|
-
return {
|
|
318
|
-
type: "object",
|
|
319
|
-
properties: {},
|
|
320
|
-
required: [],
|
|
321
|
-
additionalProperties: false
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
const normalized = { ...schema };
|
|
325
|
-
const type = normalized.type;
|
|
326
|
-
if (type === "object") {
|
|
327
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
328
|
-
normalized.properties = Object.fromEntries(
|
|
329
|
-
Object.entries(properties).map(([key, value]) => [
|
|
330
|
-
key,
|
|
331
|
-
normalizeObjectJsonSchema(value)
|
|
332
|
-
])
|
|
333
|
-
);
|
|
334
|
-
const propertyKeys = Object.keys(properties);
|
|
335
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
336
|
-
(value) => typeof value === "string"
|
|
337
|
-
) : [];
|
|
338
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
339
|
-
if (normalized.additionalProperties === void 0) {
|
|
340
|
-
normalized.additionalProperties = false;
|
|
341
|
-
}
|
|
342
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
343
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
344
|
-
normalized.items
|
|
345
|
-
);
|
|
346
|
-
}
|
|
347
|
-
return normalized;
|
|
348
|
-
}
|
|
349
|
-
function formatTools(actions) {
|
|
350
|
-
return actions.map((action) => ({
|
|
351
|
-
type: "function",
|
|
352
|
-
function: {
|
|
353
|
-
name: action.name,
|
|
354
|
-
description: action.description,
|
|
355
|
-
parameters: {
|
|
356
|
-
type: "object",
|
|
357
|
-
properties: action.parameters ? Object.fromEntries(
|
|
358
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
359
|
-
key,
|
|
360
|
-
parameterToJsonSchema(param)
|
|
361
|
-
])
|
|
362
|
-
) : {},
|
|
363
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
364
|
-
additionalProperties: false
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
}));
|
|
368
|
-
}
|
|
369
|
-
function hasImageAttachments(message) {
|
|
370
|
-
const attachments = message.metadata?.attachments;
|
|
371
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
372
|
-
}
|
|
373
|
-
function attachmentToOpenAIImage(attachment) {
|
|
374
|
-
if (attachment.type !== "image") return null;
|
|
375
|
-
let imageUrl;
|
|
376
|
-
if (attachment.url) {
|
|
377
|
-
imageUrl = attachment.url;
|
|
378
|
-
} else if (attachment.data) {
|
|
379
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
380
|
-
} else {
|
|
381
|
-
return null;
|
|
382
|
-
}
|
|
383
|
-
return {
|
|
384
|
-
type: "image_url",
|
|
385
|
-
image_url: {
|
|
386
|
-
url: imageUrl,
|
|
387
|
-
detail: "auto"
|
|
388
|
-
}
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function messageToOpenAIContent(message) {
|
|
392
|
-
const attachments = message.metadata?.attachments;
|
|
393
|
-
const content = message.content ?? "";
|
|
394
|
-
if (!hasImageAttachments(message)) {
|
|
395
|
-
return content;
|
|
396
|
-
}
|
|
397
|
-
const blocks = [];
|
|
398
|
-
if (content) {
|
|
399
|
-
blocks.push({ type: "text", text: content });
|
|
400
|
-
}
|
|
401
|
-
if (attachments) {
|
|
402
|
-
for (const attachment of attachments) {
|
|
403
|
-
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
404
|
-
if (imageBlock) {
|
|
405
|
-
blocks.push(imageBlock);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return blocks;
|
|
410
|
-
}
|
|
411
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
412
|
-
const formatted = [];
|
|
413
|
-
if (systemPrompt) {
|
|
414
|
-
formatted.push({ role: "system", content: systemPrompt });
|
|
415
|
-
}
|
|
416
|
-
for (const msg of messages) {
|
|
417
|
-
if (msg.role === "system") {
|
|
418
|
-
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
419
|
-
} else if (msg.role === "user") {
|
|
420
|
-
formatted.push({
|
|
421
|
-
role: "user",
|
|
422
|
-
content: messageToOpenAIContent(msg)
|
|
423
|
-
});
|
|
424
|
-
} else if (msg.role === "assistant") {
|
|
425
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
426
|
-
const assistantMsg = {
|
|
427
|
-
role: "assistant",
|
|
428
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
429
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
430
|
-
};
|
|
431
|
-
if (hasToolCalls) {
|
|
432
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
433
|
-
}
|
|
434
|
-
formatted.push(assistantMsg);
|
|
435
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
436
|
-
formatted.push({
|
|
437
|
-
role: "tool",
|
|
438
|
-
content: msg.content ?? "",
|
|
439
|
-
tool_call_id: msg.tool_call_id
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
return formatted;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
506
|
// src/adapters/openai.ts
|
|
447
507
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
448
508
|
constructor(config) {
|
|
@@ -468,6 +528,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
468
528
|
return this.client;
|
|
469
529
|
}
|
|
470
530
|
shouldUseResponsesApi(request) {
|
|
531
|
+
if (request.config?.mcpServers && request.config.mcpServers.length > 0 || request.config?.reasoningEffort !== void 0) {
|
|
532
|
+
if (this.provider !== "openai" && this.provider !== "azure") {
|
|
533
|
+
throw new Error(
|
|
534
|
+
`[llm-sdk] Provider "${this.provider}" does not support MCP servers or per-request reasoning effort. Use OpenAI or Anthropic for these features.`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
return true;
|
|
538
|
+
}
|
|
471
539
|
return request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false && Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
|
|
472
540
|
}
|
|
473
541
|
buildResponsesInput(request) {
|
|
@@ -528,7 +596,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
528
596
|
strict: true,
|
|
529
597
|
defer_loading: tool.deferLoading === true
|
|
530
598
|
}));
|
|
531
|
-
return [{ type: "tool_search" }, ...nativeTools];
|
|
599
|
+
return nativeTools.length > 0 ? [{ type: "tool_search" }, ...nativeTools] : [];
|
|
532
600
|
}
|
|
533
601
|
parseResponsesResult(response) {
|
|
534
602
|
const content = typeof response?.output_text === "string" ? response.output_text : "";
|
|
@@ -557,15 +625,33 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
557
625
|
async completeWithResponses(request) {
|
|
558
626
|
const client = await this.getClient();
|
|
559
627
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
628
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
629
|
+
request.config?.responseFormat
|
|
630
|
+
);
|
|
631
|
+
const mcpTools = toOpenAIResponsesMcpTools(request.config?.mcpServers);
|
|
632
|
+
const modelId = request.config?.model || this.model;
|
|
633
|
+
const reasoning = isOpenAIReasoningModel(modelId) ? toOpenAIReasoning(request.config?.reasoningEffort) : void 0;
|
|
634
|
+
if (request.config?.reasoningEffort && !isOpenAIReasoningModel(modelId)) {
|
|
635
|
+
console.warn(
|
|
636
|
+
`[llm-sdk] openai/${modelId} is not a reasoning model; \`reasoningEffort\` is ignored. Use o1/o3/o4/gpt-5.x for reasoning.`
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
const functionTools = this.buildResponsesTools(
|
|
640
|
+
request.toolDefinitions ?? []
|
|
641
|
+
);
|
|
642
|
+
const tools = [...functionTools, ...mcpTools];
|
|
560
643
|
const payload = {
|
|
561
644
|
model: request.config?.model || this.model,
|
|
562
645
|
instructions: request.systemPrompt,
|
|
563
646
|
input: this.buildResponsesInput(request),
|
|
564
|
-
tools:
|
|
647
|
+
tools: tools.length > 0 ? tools : void 0,
|
|
565
648
|
tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
|
|
566
649
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
567
650
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
568
651
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
652
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
653
|
+
...reasoning ? { reasoning } : {},
|
|
654
|
+
store: false,
|
|
569
655
|
stream: false
|
|
570
656
|
};
|
|
571
657
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -687,14 +773,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
687
773
|
name: openaiToolOptions.toolChoice.name
|
|
688
774
|
}
|
|
689
775
|
} : openaiToolOptions?.toolChoice;
|
|
776
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
690
777
|
const payload = {
|
|
691
|
-
model:
|
|
778
|
+
model: modelIdForPayload,
|
|
692
779
|
messages,
|
|
693
780
|
tools: tools.length > 0 ? tools : void 0,
|
|
694
781
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
695
782
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
696
|
-
|
|
697
|
-
|
|
783
|
+
...buildOpenAITokenParams(
|
|
784
|
+
modelIdForPayload,
|
|
785
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
786
|
+
request.config?.temperature ?? this.config.temperature
|
|
787
|
+
),
|
|
788
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
698
789
|
stream: true,
|
|
699
790
|
stream_options: { include_usage: true }
|
|
700
791
|
};
|
|
@@ -836,14 +927,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
836
927
|
name: openaiToolOptions.toolChoice.name
|
|
837
928
|
}
|
|
838
929
|
} : openaiToolOptions?.toolChoice;
|
|
930
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
839
931
|
const payload = {
|
|
840
|
-
model:
|
|
932
|
+
model: modelIdForCompletePayload,
|
|
841
933
|
messages,
|
|
842
934
|
tools: tools.length > 0 ? tools : void 0,
|
|
843
935
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
844
936
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
845
|
-
|
|
846
|
-
|
|
937
|
+
...buildOpenAITokenParams(
|
|
938
|
+
modelIdForCompletePayload,
|
|
939
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
940
|
+
request.config?.temperature ?? this.config.temperature
|
|
941
|
+
),
|
|
942
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
847
943
|
stream: false
|
|
848
944
|
};
|
|
849
945
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -1039,7 +1135,8 @@ function createXAI(config = {}) {
|
|
|
1039
1135
|
supportsVideo: false,
|
|
1040
1136
|
maxTokens: model.maxTokens,
|
|
1041
1137
|
supportedImageTypes: model.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : [],
|
|
1042
|
-
|
|
1138
|
+
// xAI accepts OpenAI-compatible `response_format` on grok-2-1212+.
|
|
1139
|
+
supportsJsonMode: true,
|
|
1043
1140
|
supportsSystemMessages: true
|
|
1044
1141
|
};
|
|
1045
1142
|
};
|