@yourgpt/llm-sdk 2.1.10-alpha.0 → 2.5.1-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/index.d.mts +4 -38
- package/dist/adapters/index.d.ts +4 -38
- package/dist/adapters/index.js +158 -325
- package/dist/adapters/index.mjs +158 -325
- package/dist/base-C58Dsr9p.d.ts +259 -0
- package/dist/base-tNgbBaSo.d.mts +259 -0
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/index.d.mts +8 -7
- package/dist/index.d.ts +8 -7
- package/dist/index.js +35 -43
- package/dist/index.mjs +35 -43
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +271 -212
- package/dist/providers/anthropic/index.mjs +271 -212
- 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 +254 -510
- package/dist/providers/google/index.mjs +254 -510
- 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 +269 -529
- package/dist/providers/openai/index.mjs +269 -529
- package/dist/providers/openrouter/index.d.mts +3 -7
- package/dist/providers/openrouter/index.d.ts +3 -7
- package/dist/providers/openrouter/index.js +365 -902
- package/dist/providers/openrouter/index.mjs +365 -902
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +259 -509
- package/dist/providers/togetherai/index.mjs +259 -509
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +258 -513
- package/dist/providers/xai/index.mjs +258 -513
- package/dist/{types-BNCmlJMs.d.mts → types-B6dhnguR.d.mts} +1 -1
- package/dist/{types-DhktekQ3.d.ts → types-BQ31QIsA.d.ts} +2 -1
- package/dist/{types-CMMQ8s2O.d.mts → types-BSSiJW2o.d.mts} +2 -1
- package/dist/{base-DN1EfKnE.d.mts → types-BkQCSiIt.d.mts} +388 -214
- package/dist/{base-DuUNxtVg.d.ts → types-BkQCSiIt.d.ts} +388 -214
- package/dist/{types-Pj-vpmoT.d.ts → types-CCxPmkmK.d.ts} +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/types-CMvvDo-E.d.mts +0 -428
- package/dist/types-CMvvDo-E.d.ts +0 -428
|
@@ -1,3 +1,232 @@
|
|
|
1
|
+
// src/adapters/base.ts
|
|
2
|
+
function stringifyForDebug(value) {
|
|
3
|
+
return JSON.stringify(
|
|
4
|
+
value,
|
|
5
|
+
(_key, currentValue) => {
|
|
6
|
+
if (typeof currentValue === "bigint") {
|
|
7
|
+
return currentValue.toString();
|
|
8
|
+
}
|
|
9
|
+
if (currentValue instanceof Error) {
|
|
10
|
+
return {
|
|
11
|
+
name: currentValue.name,
|
|
12
|
+
message: currentValue.message,
|
|
13
|
+
stack: currentValue.stack
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return currentValue;
|
|
17
|
+
},
|
|
18
|
+
2
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function logProviderPayload(provider, label, payload, enabled) {
|
|
22
|
+
if (!enabled) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
if (label.toLowerCase().includes("stream ")) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
console.log(
|
|
30
|
+
`[llm-sdk:${provider}] ${label}
|
|
31
|
+
${stringifyForDebug(payload)}`
|
|
32
|
+
);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.log(
|
|
35
|
+
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
36
|
+
error
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function parameterToJsonSchema(param) {
|
|
41
|
+
const schema = {
|
|
42
|
+
type: param.type
|
|
43
|
+
};
|
|
44
|
+
if (param.description) {
|
|
45
|
+
schema.description = param.description;
|
|
46
|
+
}
|
|
47
|
+
if (param.enum) {
|
|
48
|
+
schema.enum = param.enum;
|
|
49
|
+
}
|
|
50
|
+
if (param.type === "array" && param.items) {
|
|
51
|
+
schema.items = parameterToJsonSchema(
|
|
52
|
+
param.items
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
if (param.type === "object" && param.properties) {
|
|
56
|
+
schema.properties = Object.fromEntries(
|
|
57
|
+
Object.entries(param.properties).map(([key, prop]) => [
|
|
58
|
+
key,
|
|
59
|
+
parameterToJsonSchema(
|
|
60
|
+
prop
|
|
61
|
+
)
|
|
62
|
+
])
|
|
63
|
+
);
|
|
64
|
+
schema.additionalProperties = false;
|
|
65
|
+
}
|
|
66
|
+
return schema;
|
|
67
|
+
}
|
|
68
|
+
function normalizeObjectJsonSchema(schema) {
|
|
69
|
+
if (!schema || typeof schema !== "object") {
|
|
70
|
+
return {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {},
|
|
73
|
+
required: [],
|
|
74
|
+
additionalProperties: false
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
const normalized = { ...schema };
|
|
78
|
+
const type = normalized.type;
|
|
79
|
+
if (type === "object") {
|
|
80
|
+
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
81
|
+
normalized.properties = Object.fromEntries(
|
|
82
|
+
Object.entries(properties).map(([key, value]) => [
|
|
83
|
+
key,
|
|
84
|
+
normalizeObjectJsonSchema(value)
|
|
85
|
+
])
|
|
86
|
+
);
|
|
87
|
+
const propertyKeys = Object.keys(properties);
|
|
88
|
+
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
89
|
+
(value) => typeof value === "string"
|
|
90
|
+
) : [];
|
|
91
|
+
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
92
|
+
if (normalized.additionalProperties === void 0) {
|
|
93
|
+
normalized.additionalProperties = false;
|
|
94
|
+
}
|
|
95
|
+
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
96
|
+
normalized.items = normalizeObjectJsonSchema(
|
|
97
|
+
normalized.items
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return normalized;
|
|
101
|
+
}
|
|
102
|
+
function isOpenAIReasoningModel(modelId) {
|
|
103
|
+
if (!modelId) return false;
|
|
104
|
+
return /^(o1|o3|o4|gpt-5)/i.test(modelId);
|
|
105
|
+
}
|
|
106
|
+
function buildOpenAITokenParams(modelId, maxTokens, temperature) {
|
|
107
|
+
if (isOpenAIReasoningModel(modelId)) {
|
|
108
|
+
return { max_completion_tokens: maxTokens };
|
|
109
|
+
}
|
|
110
|
+
return { max_tokens: maxTokens, temperature };
|
|
111
|
+
}
|
|
112
|
+
function toOpenAIResponseFormat(rf) {
|
|
113
|
+
if (!rf) return void 0;
|
|
114
|
+
if (rf.type === "json_object") return { type: "json_object" };
|
|
115
|
+
return {
|
|
116
|
+
type: "json_schema",
|
|
117
|
+
json_schema: {
|
|
118
|
+
name: rf.json_schema.name,
|
|
119
|
+
schema: normalizeObjectJsonSchema(rf.json_schema.schema),
|
|
120
|
+
strict: rf.json_schema.strict ?? true
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function toOpenAIResponsesTextFormat(rf) {
|
|
125
|
+
if (!rf || rf.type !== "json_schema") return void 0;
|
|
126
|
+
return {
|
|
127
|
+
type: "json_schema",
|
|
128
|
+
name: rf.json_schema.name,
|
|
129
|
+
schema: normalizeObjectJsonSchema(rf.json_schema.schema),
|
|
130
|
+
strict: rf.json_schema.strict ?? true
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function formatTools(actions) {
|
|
134
|
+
return actions.map((action) => ({
|
|
135
|
+
type: "function",
|
|
136
|
+
function: {
|
|
137
|
+
name: action.name,
|
|
138
|
+
description: action.description,
|
|
139
|
+
parameters: {
|
|
140
|
+
type: "object",
|
|
141
|
+
properties: action.parameters ? Object.fromEntries(
|
|
142
|
+
Object.entries(action.parameters).map(([key, param]) => [
|
|
143
|
+
key,
|
|
144
|
+
parameterToJsonSchema(param)
|
|
145
|
+
])
|
|
146
|
+
) : {},
|
|
147
|
+
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
148
|
+
additionalProperties: false
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
function hasImageAttachments(message) {
|
|
154
|
+
const attachments = message.metadata?.attachments;
|
|
155
|
+
return attachments?.some((a) => a.type === "image") ?? false;
|
|
156
|
+
}
|
|
157
|
+
function attachmentToOpenAIImage(attachment) {
|
|
158
|
+
if (attachment.type !== "image") return null;
|
|
159
|
+
let imageUrl;
|
|
160
|
+
if (attachment.url) {
|
|
161
|
+
imageUrl = attachment.url;
|
|
162
|
+
} else if (attachment.data) {
|
|
163
|
+
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
164
|
+
} else {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
type: "image_url",
|
|
169
|
+
image_url: {
|
|
170
|
+
url: imageUrl,
|
|
171
|
+
detail: "auto"
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function messageToOpenAIContent(message) {
|
|
176
|
+
const attachments = message.metadata?.attachments;
|
|
177
|
+
const content = message.content ?? "";
|
|
178
|
+
if (!hasImageAttachments(message)) {
|
|
179
|
+
return content;
|
|
180
|
+
}
|
|
181
|
+
const blocks = [];
|
|
182
|
+
if (content) {
|
|
183
|
+
blocks.push({ type: "text", text: content });
|
|
184
|
+
}
|
|
185
|
+
if (attachments) {
|
|
186
|
+
for (const attachment of attachments) {
|
|
187
|
+
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
188
|
+
if (imageBlock) {
|
|
189
|
+
blocks.push(imageBlock);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return blocks;
|
|
194
|
+
}
|
|
195
|
+
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
196
|
+
const formatted = [];
|
|
197
|
+
if (systemPrompt) {
|
|
198
|
+
formatted.push({ role: "system", content: systemPrompt });
|
|
199
|
+
}
|
|
200
|
+
for (const msg of messages) {
|
|
201
|
+
if (msg.role === "system") {
|
|
202
|
+
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
203
|
+
} else if (msg.role === "user") {
|
|
204
|
+
formatted.push({
|
|
205
|
+
role: "user",
|
|
206
|
+
content: messageToOpenAIContent(msg)
|
|
207
|
+
});
|
|
208
|
+
} else if (msg.role === "assistant") {
|
|
209
|
+
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
210
|
+
const assistantMsg = {
|
|
211
|
+
role: "assistant",
|
|
212
|
+
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
213
|
+
content: hasToolCalls ? msg.content || null : msg.content
|
|
214
|
+
};
|
|
215
|
+
if (hasToolCalls) {
|
|
216
|
+
assistantMsg.tool_calls = msg.tool_calls;
|
|
217
|
+
}
|
|
218
|
+
formatted.push(assistantMsg);
|
|
219
|
+
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
220
|
+
formatted.push({
|
|
221
|
+
role: "tool",
|
|
222
|
+
content: msg.content ?? "",
|
|
223
|
+
tool_call_id: msg.tool_call_id
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return formatted;
|
|
228
|
+
}
|
|
229
|
+
|
|
1
230
|
// src/providers/xai/provider.ts
|
|
2
231
|
var XAI_MODELS = {
|
|
3
232
|
// Grok 4.1 Fast (Latest - December 2025)
|
|
@@ -51,8 +280,8 @@ function xai(modelId, options = {}) {
|
|
|
51
280
|
supportsVision: modelConfig.vision,
|
|
52
281
|
supportsTools: modelConfig.tools,
|
|
53
282
|
supportsStreaming: true,
|
|
54
|
-
supportsJsonMode:
|
|
55
|
-
//
|
|
283
|
+
supportsJsonMode: true,
|
|
284
|
+
// OpenAI-compatible `response_format`
|
|
56
285
|
supportsThinking: false,
|
|
57
286
|
supportsPDF: false,
|
|
58
287
|
maxTokens: modelConfig.maxTokens,
|
|
@@ -66,7 +295,8 @@ function xai(modelId, options = {}) {
|
|
|
66
295
|
messages,
|
|
67
296
|
tools: params.tools,
|
|
68
297
|
temperature: params.temperature,
|
|
69
|
-
max_tokens: params.maxTokens
|
|
298
|
+
max_tokens: params.maxTokens,
|
|
299
|
+
response_format: toOpenAIResponseFormat(params.responseFormat)
|
|
70
300
|
});
|
|
71
301
|
const choice = response.choices[0];
|
|
72
302
|
const message = choice.message;
|
|
@@ -98,6 +328,7 @@ function xai(modelId, options = {}) {
|
|
|
98
328
|
tools: params.tools,
|
|
99
329
|
temperature: params.temperature,
|
|
100
330
|
max_tokens: params.maxTokens,
|
|
331
|
+
response_format: toOpenAIResponseFormat(params.responseFormat),
|
|
101
332
|
stream: true
|
|
102
333
|
});
|
|
103
334
|
let currentToolCall = null;
|
|
@@ -243,204 +474,6 @@ function generateToolCallId() {
|
|
|
243
474
|
return generateId("call");
|
|
244
475
|
}
|
|
245
476
|
|
|
246
|
-
// src/adapters/base.ts
|
|
247
|
-
function stringifyForDebug(value) {
|
|
248
|
-
return JSON.stringify(
|
|
249
|
-
value,
|
|
250
|
-
(_key, currentValue) => {
|
|
251
|
-
if (typeof currentValue === "bigint") {
|
|
252
|
-
return currentValue.toString();
|
|
253
|
-
}
|
|
254
|
-
if (currentValue instanceof Error) {
|
|
255
|
-
return {
|
|
256
|
-
name: currentValue.name,
|
|
257
|
-
message: currentValue.message,
|
|
258
|
-
stack: currentValue.stack
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
return currentValue;
|
|
262
|
-
},
|
|
263
|
-
2
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
267
|
-
if (!enabled) {
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
try {
|
|
274
|
-
console.log(
|
|
275
|
-
`[llm-sdk:${provider}] ${label}
|
|
276
|
-
${stringifyForDebug(payload)}`
|
|
277
|
-
);
|
|
278
|
-
} catch (error) {
|
|
279
|
-
console.log(
|
|
280
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
281
|
-
error
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
function parameterToJsonSchema(param) {
|
|
286
|
-
const schema = {
|
|
287
|
-
type: param.type
|
|
288
|
-
};
|
|
289
|
-
if (param.description) {
|
|
290
|
-
schema.description = param.description;
|
|
291
|
-
}
|
|
292
|
-
if (param.enum) {
|
|
293
|
-
schema.enum = param.enum;
|
|
294
|
-
}
|
|
295
|
-
if (param.type === "array" && param.items) {
|
|
296
|
-
schema.items = parameterToJsonSchema(
|
|
297
|
-
param.items
|
|
298
|
-
);
|
|
299
|
-
}
|
|
300
|
-
if (param.type === "object" && param.properties) {
|
|
301
|
-
schema.properties = Object.fromEntries(
|
|
302
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
303
|
-
key,
|
|
304
|
-
parameterToJsonSchema(
|
|
305
|
-
prop
|
|
306
|
-
)
|
|
307
|
-
])
|
|
308
|
-
);
|
|
309
|
-
schema.additionalProperties = false;
|
|
310
|
-
}
|
|
311
|
-
return schema;
|
|
312
|
-
}
|
|
313
|
-
function normalizeObjectJsonSchema(schema) {
|
|
314
|
-
if (!schema || typeof schema !== "object") {
|
|
315
|
-
return {
|
|
316
|
-
type: "object",
|
|
317
|
-
properties: {},
|
|
318
|
-
required: [],
|
|
319
|
-
additionalProperties: false
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
const normalized = { ...schema };
|
|
323
|
-
const type = normalized.type;
|
|
324
|
-
if (type === "object") {
|
|
325
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
326
|
-
normalized.properties = Object.fromEntries(
|
|
327
|
-
Object.entries(properties).map(([key, value]) => [
|
|
328
|
-
key,
|
|
329
|
-
normalizeObjectJsonSchema(value)
|
|
330
|
-
])
|
|
331
|
-
);
|
|
332
|
-
const propertyKeys = Object.keys(properties);
|
|
333
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
334
|
-
(value) => typeof value === "string"
|
|
335
|
-
) : [];
|
|
336
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
337
|
-
if (normalized.additionalProperties === void 0) {
|
|
338
|
-
normalized.additionalProperties = false;
|
|
339
|
-
}
|
|
340
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
341
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
342
|
-
normalized.items
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
return normalized;
|
|
346
|
-
}
|
|
347
|
-
function formatTools(actions) {
|
|
348
|
-
return actions.map((action) => ({
|
|
349
|
-
type: "function",
|
|
350
|
-
function: {
|
|
351
|
-
name: action.name,
|
|
352
|
-
description: action.description,
|
|
353
|
-
parameters: {
|
|
354
|
-
type: "object",
|
|
355
|
-
properties: action.parameters ? Object.fromEntries(
|
|
356
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
357
|
-
key,
|
|
358
|
-
parameterToJsonSchema(param)
|
|
359
|
-
])
|
|
360
|
-
) : {},
|
|
361
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
362
|
-
additionalProperties: false
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}));
|
|
366
|
-
}
|
|
367
|
-
function hasImageAttachments(message) {
|
|
368
|
-
const attachments = message.metadata?.attachments;
|
|
369
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
370
|
-
}
|
|
371
|
-
function attachmentToOpenAIImage(attachment) {
|
|
372
|
-
if (attachment.type !== "image") return null;
|
|
373
|
-
let imageUrl;
|
|
374
|
-
if (attachment.url) {
|
|
375
|
-
imageUrl = attachment.url;
|
|
376
|
-
} else if (attachment.data) {
|
|
377
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
378
|
-
} else {
|
|
379
|
-
return null;
|
|
380
|
-
}
|
|
381
|
-
return {
|
|
382
|
-
type: "image_url",
|
|
383
|
-
image_url: {
|
|
384
|
-
url: imageUrl,
|
|
385
|
-
detail: "auto"
|
|
386
|
-
}
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
function messageToOpenAIContent(message) {
|
|
390
|
-
const attachments = message.metadata?.attachments;
|
|
391
|
-
const content = message.content ?? "";
|
|
392
|
-
if (!hasImageAttachments(message)) {
|
|
393
|
-
return content;
|
|
394
|
-
}
|
|
395
|
-
const blocks = [];
|
|
396
|
-
if (content) {
|
|
397
|
-
blocks.push({ type: "text", text: content });
|
|
398
|
-
}
|
|
399
|
-
if (attachments) {
|
|
400
|
-
for (const attachment of attachments) {
|
|
401
|
-
const imageBlock = attachmentToOpenAIImage(attachment);
|
|
402
|
-
if (imageBlock) {
|
|
403
|
-
blocks.push(imageBlock);
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
return blocks;
|
|
408
|
-
}
|
|
409
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
410
|
-
const formatted = [];
|
|
411
|
-
if (systemPrompt) {
|
|
412
|
-
formatted.push({ role: "system", content: systemPrompt });
|
|
413
|
-
}
|
|
414
|
-
for (const msg of messages) {
|
|
415
|
-
if (msg.role === "system") {
|
|
416
|
-
formatted.push({ role: "system", content: msg.content ?? "" });
|
|
417
|
-
} else if (msg.role === "user") {
|
|
418
|
-
formatted.push({
|
|
419
|
-
role: "user",
|
|
420
|
-
content: messageToOpenAIContent(msg)
|
|
421
|
-
});
|
|
422
|
-
} else if (msg.role === "assistant") {
|
|
423
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
424
|
-
const assistantMsg = {
|
|
425
|
-
role: "assistant",
|
|
426
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
427
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
428
|
-
};
|
|
429
|
-
if (hasToolCalls) {
|
|
430
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
431
|
-
}
|
|
432
|
-
formatted.push(assistantMsg);
|
|
433
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
434
|
-
formatted.push({
|
|
435
|
-
role: "tool",
|
|
436
|
-
content: msg.content ?? "",
|
|
437
|
-
tool_call_id: msg.tool_call_id
|
|
438
|
-
});
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
return formatted;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
477
|
// src/adapters/openai.ts
|
|
445
478
|
var OpenAIAdapter = class _OpenAIAdapter {
|
|
446
479
|
constructor(config) {
|
|
@@ -453,7 +486,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
453
486
|
if (baseUrl.includes("generativelanguage.googleapis.com")) return "google";
|
|
454
487
|
if (baseUrl.includes("x.ai")) return "xai";
|
|
455
488
|
if (baseUrl.includes("azure")) return "azure";
|
|
456
|
-
if (baseUrl.includes("openrouter.ai")) return "openrouter";
|
|
457
489
|
return "openai";
|
|
458
490
|
}
|
|
459
491
|
async getClient() {
|
|
@@ -553,259 +585,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
553
585
|
rawResponse: response
|
|
554
586
|
};
|
|
555
587
|
}
|
|
556
|
-
/**
|
|
557
|
-
* OpenAI reasoning models on OpenRouter (o1/o3/o4/gpt-5 family) hide their
|
|
558
|
-
* reasoning content on the chat-completions endpoint. To surface reasoning
|
|
559
|
-
* SUMMARIES (not raw CoT, which OpenAI never exposes) we have to use the
|
|
560
|
-
* Responses API, which streams `response.reasoning_summary_text.delta` events.
|
|
561
|
-
*
|
|
562
|
-
* Match by prefix on the OpenRouter model id. Excludes openai/gpt-4o,
|
|
563
|
-
* openai/gpt-4.1, openai/chatgpt-* — those continue on chat-completions.
|
|
564
|
-
*/
|
|
565
|
-
isOpenAIReasoningModelOnOpenRouter(activeModel) {
|
|
566
|
-
if (this.provider !== "openrouter") return false;
|
|
567
|
-
return activeModel.startsWith("openai/o1") || activeModel.startsWith("openai/o3") || activeModel.startsWith("openai/o4") || activeModel.startsWith("openai/gpt-5");
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* Convert ActionDefinition[] (the chat-completions tool shape used by the
|
|
571
|
-
* adapter) to the Responses API tool shape.
|
|
572
|
-
*/
|
|
573
|
-
buildResponsesToolsFromActions(actions) {
|
|
574
|
-
if (!actions || actions.length === 0) return void 0;
|
|
575
|
-
const formatted = formatTools(actions);
|
|
576
|
-
return formatted.map((t) => ({
|
|
577
|
-
type: "function",
|
|
578
|
-
name: t.function.name,
|
|
579
|
-
description: t.function.description,
|
|
580
|
-
parameters: t.function.parameters
|
|
581
|
-
}));
|
|
582
|
-
}
|
|
583
|
-
/**
|
|
584
|
-
* Streaming Responses API path for OpenAI reasoning models on OpenRouter.
|
|
585
|
-
*
|
|
586
|
-
* Maps Responses API SSE events back to the same StreamEvent shapes the
|
|
587
|
-
* chat-completions path emits, so downstream consumers (processChunk.ts,
|
|
588
|
-
* frontend tool handlers, plan approval, specialist delegations) see
|
|
589
|
-
* identical events regardless of which path produced them.
|
|
590
|
-
*
|
|
591
|
-
* response.reasoning_summary_text.delta → thinking:start (once) + thinking:delta
|
|
592
|
-
* response.output_text.delta → message:delta
|
|
593
|
-
* response.output_item.added (function_call) → action:start (queued buffer)
|
|
594
|
-
* response.function_call_arguments.delta → action:args (progressive)
|
|
595
|
-
* response.output_item.done (function_call) → final action:args + action:end
|
|
596
|
-
* response.completed → message:end + done(usage)
|
|
597
|
-
* response.error → error
|
|
598
|
-
*/
|
|
599
|
-
async *streamWithResponsesAPI(request, activeModel, messageId) {
|
|
600
|
-
const client = await this.getClient();
|
|
601
|
-
const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
|
|
602
|
-
const payload = {
|
|
603
|
-
model: activeModel,
|
|
604
|
-
input: this.buildResponsesInput(request),
|
|
605
|
-
stream: true,
|
|
606
|
-
reasoning: {
|
|
607
|
-
effort: request.config?.reasoningEffort ?? "medium",
|
|
608
|
-
summary: "auto"
|
|
609
|
-
}
|
|
610
|
-
};
|
|
611
|
-
if (request.systemPrompt) payload.instructions = request.systemPrompt;
|
|
612
|
-
if (typeof maxTokensValue === "number")
|
|
613
|
-
payload.max_output_tokens = maxTokensValue;
|
|
614
|
-
const tools = this.buildResponsesToolsFromActions(request.actions);
|
|
615
|
-
if (tools && tools.length > 0) payload.tools = tools;
|
|
616
|
-
logProviderPayload(
|
|
617
|
-
"openai",
|
|
618
|
-
"responses-api request payload",
|
|
619
|
-
payload,
|
|
620
|
-
request.debug
|
|
621
|
-
);
|
|
622
|
-
let stream;
|
|
623
|
-
try {
|
|
624
|
-
stream = await client.responses.create(payload);
|
|
625
|
-
} catch (error) {
|
|
626
|
-
yield {
|
|
627
|
-
type: "error",
|
|
628
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
629
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
630
|
-
};
|
|
631
|
-
return;
|
|
632
|
-
}
|
|
633
|
-
const toolBuffers = /* @__PURE__ */ new Map();
|
|
634
|
-
const itemIdToCallId = /* @__PURE__ */ new Map();
|
|
635
|
-
let usage;
|
|
636
|
-
let reasoningStarted = false;
|
|
637
|
-
let textStarted = false;
|
|
638
|
-
let finishEmitted = false;
|
|
639
|
-
const resolveCallId = (evt) => {
|
|
640
|
-
if (evt?.call_id) return evt.call_id;
|
|
641
|
-
if (evt?.item_id) return itemIdToCallId.get(evt.item_id) ?? evt.item_id;
|
|
642
|
-
if (evt?.item?.call_id) return evt.item.call_id;
|
|
643
|
-
if (evt?.item?.id) return evt.item.id;
|
|
644
|
-
return "";
|
|
645
|
-
};
|
|
646
|
-
try {
|
|
647
|
-
for await (const evt of stream) {
|
|
648
|
-
logProviderPayload(
|
|
649
|
-
"openai",
|
|
650
|
-
"responses-api stream chunk",
|
|
651
|
-
evt,
|
|
652
|
-
request.debug
|
|
653
|
-
);
|
|
654
|
-
if (request.signal?.aborted) break;
|
|
655
|
-
const t = evt?.type ?? "";
|
|
656
|
-
if (t === "response.reasoning_summary_text.delta") {
|
|
657
|
-
const delta = evt.delta ?? "";
|
|
658
|
-
if (!delta) continue;
|
|
659
|
-
if (!reasoningStarted) {
|
|
660
|
-
yield { type: "thinking:start" };
|
|
661
|
-
reasoningStarted = true;
|
|
662
|
-
}
|
|
663
|
-
yield { type: "thinking:delta", content: delta };
|
|
664
|
-
continue;
|
|
665
|
-
}
|
|
666
|
-
if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
if (t === "response.output_text.delta") {
|
|
670
|
-
const text = evt.delta ?? "";
|
|
671
|
-
if (!text) continue;
|
|
672
|
-
if (reasoningStarted && !textStarted) {
|
|
673
|
-
yield { type: "thinking:end" };
|
|
674
|
-
textStarted = true;
|
|
675
|
-
}
|
|
676
|
-
yield { type: "message:delta", content: text };
|
|
677
|
-
continue;
|
|
678
|
-
}
|
|
679
|
-
if (t === "response.output_item.added") {
|
|
680
|
-
const item = evt.item;
|
|
681
|
-
if (item?.type === "function_call") {
|
|
682
|
-
const callId = item.call_id ?? item.id ?? "";
|
|
683
|
-
const itemId = item.id ?? callId;
|
|
684
|
-
if (callId) {
|
|
685
|
-
if (itemId && itemId !== callId) {
|
|
686
|
-
itemIdToCallId.set(itemId, callId);
|
|
687
|
-
}
|
|
688
|
-
if (!toolBuffers.has(callId)) {
|
|
689
|
-
toolBuffers.set(callId, {
|
|
690
|
-
id: callId,
|
|
691
|
-
name: item.name ?? "",
|
|
692
|
-
arguments: item.arguments ?? "",
|
|
693
|
-
emittedStart: false
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
const buf = toolBuffers.get(callId);
|
|
697
|
-
if (buf.name && !buf.emittedStart) {
|
|
698
|
-
yield { type: "action:start", id: buf.id, name: buf.name };
|
|
699
|
-
buf.emittedStart = true;
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
if (t === "response.function_call_arguments.delta") {
|
|
706
|
-
const callId = resolveCallId(evt);
|
|
707
|
-
const delta = evt.delta ?? "";
|
|
708
|
-
if (!callId || !delta) continue;
|
|
709
|
-
let buf = toolBuffers.get(callId);
|
|
710
|
-
if (!buf) {
|
|
711
|
-
buf = { id: callId, name: "", arguments: "", emittedStart: false };
|
|
712
|
-
toolBuffers.set(callId, buf);
|
|
713
|
-
}
|
|
714
|
-
buf.arguments += delta;
|
|
715
|
-
if (buf.emittedStart) {
|
|
716
|
-
yield {
|
|
717
|
-
type: "action:args",
|
|
718
|
-
id: buf.id,
|
|
719
|
-
args: buf.arguments
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
continue;
|
|
723
|
-
}
|
|
724
|
-
if (t === "response.output_item.done") {
|
|
725
|
-
const item = evt.item;
|
|
726
|
-
if (item?.type === "function_call") {
|
|
727
|
-
const callId = item.call_id ?? item.id ?? "";
|
|
728
|
-
const buf = toolBuffers.get(callId);
|
|
729
|
-
const name = buf?.name || item.name || "";
|
|
730
|
-
const argsStr = buf?.arguments || item.arguments || "{}";
|
|
731
|
-
if (callId && name) {
|
|
732
|
-
if (!buf?.emittedStart) {
|
|
733
|
-
yield { type: "action:start", id: callId, name };
|
|
734
|
-
}
|
|
735
|
-
yield {
|
|
736
|
-
type: "action:args",
|
|
737
|
-
id: callId,
|
|
738
|
-
args: argsStr
|
|
739
|
-
};
|
|
740
|
-
yield {
|
|
741
|
-
type: "action:end",
|
|
742
|
-
id: callId,
|
|
743
|
-
name
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
|
-
toolBuffers.delete(callId);
|
|
747
|
-
}
|
|
748
|
-
continue;
|
|
749
|
-
}
|
|
750
|
-
if (t === "response.completed") {
|
|
751
|
-
const u = evt.response?.usage;
|
|
752
|
-
if (u) {
|
|
753
|
-
usage = {
|
|
754
|
-
prompt_tokens: u.input_tokens ?? 0,
|
|
755
|
-
completion_tokens: u.output_tokens ?? 0,
|
|
756
|
-
total_tokens: u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
|
|
757
|
-
};
|
|
758
|
-
}
|
|
759
|
-
for (const buf of toolBuffers.values()) {
|
|
760
|
-
if (!buf.id || !buf.name) continue;
|
|
761
|
-
if (!buf.emittedStart) {
|
|
762
|
-
yield { type: "action:start", id: buf.id, name: buf.name };
|
|
763
|
-
}
|
|
764
|
-
yield {
|
|
765
|
-
type: "action:args",
|
|
766
|
-
id: buf.id,
|
|
767
|
-
args: buf.arguments || "{}"
|
|
768
|
-
};
|
|
769
|
-
yield { type: "action:end", id: buf.id, name: buf.name };
|
|
770
|
-
}
|
|
771
|
-
toolBuffers.clear();
|
|
772
|
-
if (reasoningStarted && !textStarted) {
|
|
773
|
-
yield { type: "thinking:end" };
|
|
774
|
-
}
|
|
775
|
-
yield { type: "message:end" };
|
|
776
|
-
yield { type: "done", usage };
|
|
777
|
-
finishEmitted = true;
|
|
778
|
-
continue;
|
|
779
|
-
}
|
|
780
|
-
if (t === "response.error" || t === "error") {
|
|
781
|
-
const msg = evt.error?.message || evt.message || "Responses API error";
|
|
782
|
-
yield {
|
|
783
|
-
type: "error",
|
|
784
|
-
message: msg,
|
|
785
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
786
|
-
};
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
} catch (error) {
|
|
791
|
-
yield {
|
|
792
|
-
type: "error",
|
|
793
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
794
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
795
|
-
};
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
if (!finishEmitted) {
|
|
799
|
-
if (reasoningStarted && !textStarted) {
|
|
800
|
-
yield { type: "thinking:end" };
|
|
801
|
-
}
|
|
802
|
-
yield { type: "message:end" };
|
|
803
|
-
yield { type: "done", usage };
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
588
|
async completeWithResponses(request) {
|
|
807
589
|
const client = await this.getClient();
|
|
808
590
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
591
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
592
|
+
request.config?.responseFormat
|
|
593
|
+
);
|
|
809
594
|
const payload = {
|
|
810
595
|
model: request.config?.model || this.model,
|
|
811
596
|
instructions: request.systemPrompt,
|
|
@@ -815,6 +600,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
815
600
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
816
601
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
817
602
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
603
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
818
604
|
stream: false
|
|
819
605
|
};
|
|
820
606
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -936,37 +722,21 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
936
722
|
name: openaiToolOptions.toolChoice.name
|
|
937
723
|
}
|
|
938
724
|
} : openaiToolOptions?.toolChoice;
|
|
939
|
-
const
|
|
940
|
-
const activeModel = request.config?.model || this.model;
|
|
941
|
-
const modelSlug = activeModel.replace("openai/", "");
|
|
942
|
-
const isOSeries = /^o[1-9]/.test(modelSlug);
|
|
943
|
-
const isOpenAIOnOpenRouter = isOpenRouter && activeModel.startsWith("openai/");
|
|
944
|
-
if (!this.config.disableThinking && this.isOpenAIReasoningModelOnOpenRouter(activeModel)) {
|
|
945
|
-
yield* this.streamWithResponsesAPI(request, activeModel, messageId);
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
|
|
725
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
949
726
|
const payload = {
|
|
950
|
-
model:
|
|
727
|
+
model: modelIdForPayload,
|
|
951
728
|
messages,
|
|
952
729
|
tools: tools.length > 0 ? tools : void 0,
|
|
953
730
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
954
731
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
732
|
+
...buildOpenAITokenParams(
|
|
733
|
+
modelIdForPayload,
|
|
734
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
735
|
+
request.config?.temperature ?? this.config.temperature
|
|
736
|
+
),
|
|
737
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
955
738
|
stream: true,
|
|
956
|
-
stream_options: { include_usage: true }
|
|
957
|
-
// o-series: use max_completion_tokens + reasoning_effort, no temperature
|
|
958
|
-
// regular models: use max_tokens + temperature
|
|
959
|
-
...isOSeries ? {
|
|
960
|
-
max_completion_tokens: maxTokensValue,
|
|
961
|
-
reasoning_effort: request.config?.reasoningEffort ?? "medium"
|
|
962
|
-
} : {
|
|
963
|
-
temperature: request.config?.temperature ?? this.config.temperature,
|
|
964
|
-
max_tokens: maxTokensValue
|
|
965
|
-
},
|
|
966
|
-
// Non-OpenAI OpenRouter models support OR's reasoning/include_reasoning params.
|
|
967
|
-
// When disableThinking=true we must explicitly send include_reasoning:false because
|
|
968
|
-
// models like Qwen3 and DeepSeek-R1 reason by default even without the reasoning param.
|
|
969
|
-
...isOpenRouter && !isOpenAIOnOpenRouter ? this.config.disableThinking ? { include_reasoning: false } : { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
|
|
739
|
+
stream_options: { include_usage: true }
|
|
970
740
|
};
|
|
971
741
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
972
742
|
const stream = await client.chat.completions.create(payload);
|
|
@@ -974,7 +744,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
974
744
|
const collectedCitations = [];
|
|
975
745
|
let citationIndex = 0;
|
|
976
746
|
let usage;
|
|
977
|
-
let adapterReasoningStarted = false;
|
|
978
747
|
for await (const chunk of stream) {
|
|
979
748
|
logProviderPayload("openai", "stream chunk", chunk, request.debug);
|
|
980
749
|
if (request.signal?.aborted) {
|
|
@@ -985,22 +754,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
985
754
|
if (delta?.content) {
|
|
986
755
|
yield { type: "message:delta", content: delta.content };
|
|
987
756
|
}
|
|
988
|
-
if (isOpenRouter) {
|
|
989
|
-
const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
|
|
990
|
-
if (rc) {
|
|
991
|
-
const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
|
|
992
|
-
if (rcText) {
|
|
993
|
-
if (!adapterReasoningStarted) {
|
|
994
|
-
yield { type: "thinking:start" };
|
|
995
|
-
adapterReasoningStarted = true;
|
|
996
|
-
}
|
|
997
|
-
yield { type: "thinking:delta", content: rcText };
|
|
998
|
-
}
|
|
999
|
-
} else if (adapterReasoningStarted && (delta?.content || choice?.finish_reason)) {
|
|
1000
|
-
yield { type: "thinking:end" };
|
|
1001
|
-
adapterReasoningStarted = false;
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
757
|
const annotations = delta?.annotations;
|
|
1005
758
|
if (annotations && annotations.length > 0) {
|
|
1006
759
|
for (const annotation of annotations) {
|
|
@@ -1048,11 +801,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1048
801
|
};
|
|
1049
802
|
} else if (currentToolCall && toolCall.function?.arguments) {
|
|
1050
803
|
currentToolCall.arguments += toolCall.function.arguments;
|
|
1051
|
-
yield {
|
|
1052
|
-
type: "action:args",
|
|
1053
|
-
id: currentToolCall.id,
|
|
1054
|
-
args: currentToolCall.arguments
|
|
1055
|
-
};
|
|
1056
804
|
}
|
|
1057
805
|
}
|
|
1058
806
|
}
|
|
@@ -1128,24 +876,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1128
876
|
name: openaiToolOptions.toolChoice.name
|
|
1129
877
|
}
|
|
1130
878
|
} : openaiToolOptions?.toolChoice;
|
|
1131
|
-
const
|
|
1132
|
-
const modelSlug2 = activeModel2.replace("openai/", "");
|
|
1133
|
-
const isOSeries2 = /^o[1-9]/.test(modelSlug2);
|
|
1134
|
-
const maxTokensValue2 = request.config?.maxTokens ?? this.config.maxTokens;
|
|
879
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
1135
880
|
const payload = {
|
|
1136
|
-
model:
|
|
881
|
+
model: modelIdForCompletePayload,
|
|
1137
882
|
messages,
|
|
1138
883
|
tools: tools.length > 0 ? tools : void 0,
|
|
1139
884
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
1140
885
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
886
|
+
...buildOpenAITokenParams(
|
|
887
|
+
modelIdForCompletePayload,
|
|
888
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
889
|
+
request.config?.temperature ?? this.config.temperature
|
|
890
|
+
),
|
|
891
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
892
|
+
stream: false
|
|
1149
893
|
};
|
|
1150
894
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
1151
895
|
const response = await client.chat.completions.create(payload);
|
|
@@ -1340,7 +1084,8 @@ function createXAI(config = {}) {
|
|
|
1340
1084
|
supportsVideo: false,
|
|
1341
1085
|
maxTokens: model.maxTokens,
|
|
1342
1086
|
supportedImageTypes: model.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : [],
|
|
1343
|
-
|
|
1087
|
+
// xAI accepts OpenAI-compatible `response_format` on grok-2-1212+.
|
|
1088
|
+
supportsJsonMode: true,
|
|
1344
1089
|
supportsSystemMessages: true
|
|
1345
1090
|
};
|
|
1346
1091
|
};
|