@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/openrouter/provider.ts
|
|
2
231
|
var DEFAULT_MODEL_CONFIG = {
|
|
3
232
|
vision: true,
|
|
@@ -5,9 +234,6 @@ var DEFAULT_MODEL_CONFIG = {
|
|
|
5
234
|
jsonMode: true,
|
|
6
235
|
maxTokens: 128e3
|
|
7
236
|
};
|
|
8
|
-
function isOpenAIReasoningModel(modelId) {
|
|
9
|
-
return modelId.startsWith("openai/o1") || modelId.startsWith("openai/o3") || modelId.startsWith("openai/o4") || modelId.startsWith("openai/gpt-5");
|
|
10
|
-
}
|
|
11
237
|
function openrouter(modelId, options = {}) {
|
|
12
238
|
const apiKey = options.apiKey ?? process.env.OPENROUTER_API_KEY;
|
|
13
239
|
const baseURL = options.baseURL ?? "https://openrouter.ai/api/v1";
|
|
@@ -39,7 +265,7 @@ function openrouter(modelId, options = {}) {
|
|
|
39
265
|
supportsTools: modelConfig.tools,
|
|
40
266
|
supportsStreaming: true,
|
|
41
267
|
supportsJsonMode: modelConfig.jsonMode,
|
|
42
|
-
supportsThinking:
|
|
268
|
+
supportsThinking: false,
|
|
43
269
|
supportsPDF: false,
|
|
44
270
|
maxTokens: modelConfig.maxTokens,
|
|
45
271
|
supportedImageTypes: modelConfig.vision ? ["image/png", "image/jpeg", "image/gif", "image/webp"] : []
|
|
@@ -59,6 +285,10 @@ function openrouter(modelId, options = {}) {
|
|
|
59
285
|
if (options.providerPreferences) {
|
|
60
286
|
requestBody.provider = options.providerPreferences;
|
|
61
287
|
}
|
|
288
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
289
|
+
if (responseFormat) {
|
|
290
|
+
requestBody.response_format = responseFormat;
|
|
291
|
+
}
|
|
62
292
|
const response = await client2.chat.completions.create(requestBody);
|
|
63
293
|
const choice = response.choices[0];
|
|
64
294
|
const message = choice.message;
|
|
@@ -82,11 +312,6 @@ function openrouter(modelId, options = {}) {
|
|
|
82
312
|
};
|
|
83
313
|
},
|
|
84
314
|
async *doStream(params) {
|
|
85
|
-
if (!options.disableThinking && isOpenAIReasoningModel(modelId)) {
|
|
86
|
-
const client3 = await getClient();
|
|
87
|
-
yield* doStreamResponsesAPI(client3, modelId, params);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
315
|
const client2 = await getClient();
|
|
91
316
|
const messages = formatMessagesForOpenRouter(params.messages);
|
|
92
317
|
const requestBody = {
|
|
@@ -94,8 +319,7 @@ function openrouter(modelId, options = {}) {
|
|
|
94
319
|
messages,
|
|
95
320
|
temperature: params.temperature,
|
|
96
321
|
max_tokens: params.maxTokens,
|
|
97
|
-
stream: true
|
|
98
|
-
...!options.disableThinking ? { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
|
|
322
|
+
stream: true
|
|
99
323
|
};
|
|
100
324
|
if (params.tools) {
|
|
101
325
|
requestBody.tools = params.tools;
|
|
@@ -103,11 +327,14 @@ function openrouter(modelId, options = {}) {
|
|
|
103
327
|
if (options.providerPreferences) {
|
|
104
328
|
requestBody.provider = options.providerPreferences;
|
|
105
329
|
}
|
|
330
|
+
const responseFormat = toOpenAIResponseFormat(params.responseFormat);
|
|
331
|
+
if (responseFormat) {
|
|
332
|
+
requestBody.response_format = responseFormat;
|
|
333
|
+
}
|
|
106
334
|
const stream = await client2.chat.completions.create(requestBody);
|
|
107
335
|
let currentToolCall = null;
|
|
108
336
|
let totalPromptTokens = 0;
|
|
109
337
|
let totalCompletionTokens = 0;
|
|
110
|
-
let orReasoningStarted = false;
|
|
111
338
|
for await (const chunk of stream) {
|
|
112
339
|
if (params.signal?.aborted) {
|
|
113
340
|
yield { type: "error", error: new Error("Aborted") };
|
|
@@ -118,20 +345,6 @@ function openrouter(modelId, options = {}) {
|
|
|
118
345
|
if (delta?.content) {
|
|
119
346
|
yield { type: "text-delta", text: delta.content };
|
|
120
347
|
}
|
|
121
|
-
const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
|
|
122
|
-
if (rc) {
|
|
123
|
-
const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
|
|
124
|
-
if (rcText) {
|
|
125
|
-
if (!orReasoningStarted) {
|
|
126
|
-
yield { type: "thinking:start" };
|
|
127
|
-
orReasoningStarted = true;
|
|
128
|
-
}
|
|
129
|
-
yield { type: "thinking:delta", content: rcText };
|
|
130
|
-
}
|
|
131
|
-
} else if (orReasoningStarted && (delta?.content || choice?.finish_reason)) {
|
|
132
|
-
yield { type: "thinking:end" };
|
|
133
|
-
orReasoningStarted = false;
|
|
134
|
-
}
|
|
135
348
|
if (delta?.tool_calls) {
|
|
136
349
|
for (const tc of delta.tool_calls) {
|
|
137
350
|
if (tc.id) {
|
|
@@ -171,578 +384,118 @@ function openrouter(modelId, options = {}) {
|
|
|
171
384
|
totalPromptTokens = chunk.usage.prompt_tokens;
|
|
172
385
|
totalCompletionTokens = chunk.usage.completion_tokens;
|
|
173
386
|
}
|
|
174
|
-
yield {
|
|
175
|
-
type: "finish",
|
|
176
|
-
finishReason: mapFinishReason(choice.finish_reason),
|
|
177
|
-
usage: {
|
|
178
|
-
promptTokens: totalPromptTokens,
|
|
179
|
-
completionTokens: totalCompletionTokens,
|
|
180
|
-
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
181
|
-
}
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
function mapFinishReason(reason) {
|
|
189
|
-
switch (reason) {
|
|
190
|
-
case "stop":
|
|
191
|
-
return "stop";
|
|
192
|
-
case "length":
|
|
193
|
-
return "length";
|
|
194
|
-
case "tool_calls":
|
|
195
|
-
case "function_call":
|
|
196
|
-
return "tool-calls";
|
|
197
|
-
case "content_filter":
|
|
198
|
-
return "content-filter";
|
|
199
|
-
default:
|
|
200
|
-
return "unknown";
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function formatMessagesForOpenRouter(messages) {
|
|
204
|
-
return messages.map((msg) => {
|
|
205
|
-
switch (msg.role) {
|
|
206
|
-
case "system":
|
|
207
|
-
return { role: "system", content: msg.content };
|
|
208
|
-
case "user":
|
|
209
|
-
if (typeof msg.content === "string") {
|
|
210
|
-
return { role: "user", content: msg.content };
|
|
211
|
-
}
|
|
212
|
-
return {
|
|
213
|
-
role: "user",
|
|
214
|
-
content: msg.content.map((part) => {
|
|
215
|
-
if (part.type === "text") {
|
|
216
|
-
return { type: "text", text: part.text };
|
|
217
|
-
}
|
|
218
|
-
if (part.type === "image") {
|
|
219
|
-
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
220
|
-
const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
|
|
221
|
-
return { type: "image_url", image_url: { url, detail: "auto" } };
|
|
222
|
-
}
|
|
223
|
-
return { type: "text", text: "" };
|
|
224
|
-
})
|
|
225
|
-
};
|
|
226
|
-
case "assistant":
|
|
227
|
-
const assistantMsg = {
|
|
228
|
-
role: "assistant",
|
|
229
|
-
content: msg.content
|
|
230
|
-
};
|
|
231
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
232
|
-
assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
|
|
233
|
-
id: tc.id,
|
|
234
|
-
type: "function",
|
|
235
|
-
function: {
|
|
236
|
-
name: tc.name,
|
|
237
|
-
arguments: JSON.stringify(tc.args)
|
|
238
|
-
}
|
|
239
|
-
}));
|
|
240
|
-
}
|
|
241
|
-
return assistantMsg;
|
|
242
|
-
case "tool":
|
|
243
|
-
return {
|
|
244
|
-
role: "tool",
|
|
245
|
-
tool_call_id: msg.toolCallId,
|
|
246
|
-
content: msg.content
|
|
247
|
-
};
|
|
248
|
-
default:
|
|
249
|
-
return msg;
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
function formatMessagesForResponsesAPI(messages) {
|
|
254
|
-
const out = [];
|
|
255
|
-
for (const msg of messages) {
|
|
256
|
-
if (msg.role === "system") {
|
|
257
|
-
out.push({
|
|
258
|
-
type: "message",
|
|
259
|
-
role: "system",
|
|
260
|
-
content: [
|
|
261
|
-
{
|
|
262
|
-
type: "input_text",
|
|
263
|
-
text: typeof msg.content === "string" ? msg.content : ""
|
|
264
|
-
}
|
|
265
|
-
]
|
|
266
|
-
});
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
if (msg.role === "user") {
|
|
270
|
-
const parts = [];
|
|
271
|
-
if (typeof msg.content === "string") {
|
|
272
|
-
parts.push({ type: "input_text", text: msg.content });
|
|
273
|
-
} else {
|
|
274
|
-
for (const part of msg.content) {
|
|
275
|
-
if (part.type === "text") {
|
|
276
|
-
parts.push({ type: "input_text", text: part.text });
|
|
277
|
-
} else if (part.type === "image") {
|
|
278
|
-
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
279
|
-
const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
|
|
280
|
-
parts.push({ type: "input_image", image_url: url });
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
out.push({ type: "message", role: "user", content: parts });
|
|
285
|
-
continue;
|
|
286
|
-
}
|
|
287
|
-
if (msg.role === "assistant") {
|
|
288
|
-
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
289
|
-
for (const tc of msg.toolCalls) {
|
|
290
|
-
out.push({
|
|
291
|
-
type: "function_call",
|
|
292
|
-
call_id: tc.id,
|
|
293
|
-
name: tc.name,
|
|
294
|
-
arguments: JSON.stringify(tc.args ?? {})
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
if (typeof msg.content === "string" && msg.content.length > 0) {
|
|
298
|
-
out.push({
|
|
299
|
-
type: "message",
|
|
300
|
-
role: "assistant",
|
|
301
|
-
content: [{ type: "output_text", text: msg.content }]
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
} else {
|
|
305
|
-
const text = typeof msg.content === "string" ? msg.content : "";
|
|
306
|
-
out.push({
|
|
307
|
-
type: "message",
|
|
308
|
-
role: "assistant",
|
|
309
|
-
content: [{ type: "output_text", text }]
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if (msg.role === "tool") {
|
|
315
|
-
out.push({
|
|
316
|
-
type: "function_call_output",
|
|
317
|
-
call_id: msg.toolCallId,
|
|
318
|
-
output: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
319
|
-
});
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
return out;
|
|
324
|
-
}
|
|
325
|
-
function formatToolsForResponsesAPI(tools) {
|
|
326
|
-
if (!tools || tools.length === 0) return void 0;
|
|
327
|
-
return tools.map((t) => {
|
|
328
|
-
if (t?.name && t?.parameters && t?.type === "function") return t;
|
|
329
|
-
const fn = t?.function ?? t;
|
|
330
|
-
return {
|
|
331
|
-
type: "function",
|
|
332
|
-
name: fn.name,
|
|
333
|
-
description: fn.description,
|
|
334
|
-
parameters: fn.parameters ?? { type: "object", properties: {} }
|
|
335
|
-
};
|
|
336
|
-
});
|
|
337
|
-
}
|
|
338
|
-
async function* doStreamResponsesAPI(client, modelId, params) {
|
|
339
|
-
const systemTexts = [];
|
|
340
|
-
const nonSystem = [];
|
|
341
|
-
for (const m of params.messages) {
|
|
342
|
-
if (m.role === "system" && typeof m.content === "string") {
|
|
343
|
-
systemTexts.push(m.content);
|
|
344
|
-
} else {
|
|
345
|
-
nonSystem.push(m);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
const instructions = systemTexts.join("\n\n") || void 0;
|
|
349
|
-
const input = formatMessagesForResponsesAPI(nonSystem);
|
|
350
|
-
const requestBody = {
|
|
351
|
-
model: modelId,
|
|
352
|
-
input,
|
|
353
|
-
stream: true,
|
|
354
|
-
reasoning: { effort: "medium", summary: "auto" }
|
|
355
|
-
};
|
|
356
|
-
if (instructions) requestBody.instructions = instructions;
|
|
357
|
-
if (typeof params.maxTokens === "number")
|
|
358
|
-
requestBody.max_output_tokens = params.maxTokens;
|
|
359
|
-
if (typeof params.temperature === "number")
|
|
360
|
-
requestBody.temperature = params.temperature;
|
|
361
|
-
const tools = formatToolsForResponsesAPI(params.tools);
|
|
362
|
-
if (tools) requestBody.tools = tools;
|
|
363
|
-
let stream;
|
|
364
|
-
try {
|
|
365
|
-
stream = await client.responses.create(requestBody);
|
|
366
|
-
} catch (err) {
|
|
367
|
-
yield {
|
|
368
|
-
type: "error",
|
|
369
|
-
error: err instanceof Error ? err : new Error(String(err))
|
|
370
|
-
};
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
const toolCalls = /* @__PURE__ */ new Map();
|
|
374
|
-
let reasoningStarted = false;
|
|
375
|
-
let textStarted = false;
|
|
376
|
-
let totalPromptTokens = 0;
|
|
377
|
-
let totalCompletionTokens = 0;
|
|
378
|
-
let finishEmitted = false;
|
|
379
|
-
for await (const evt of stream) {
|
|
380
|
-
if (params.signal?.aborted) {
|
|
381
|
-
yield { type: "error", error: new Error("Aborted") };
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
const t = evt?.type ?? "";
|
|
385
|
-
if (t === "response.reasoning_summary_text.delta") {
|
|
386
|
-
const delta = evt.delta ?? "";
|
|
387
|
-
if (!delta) continue;
|
|
388
|
-
if (!reasoningStarted) {
|
|
389
|
-
yield { type: "thinking:start" };
|
|
390
|
-
reasoningStarted = true;
|
|
391
|
-
}
|
|
392
|
-
yield { type: "thinking:delta", content: delta };
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
|
|
396
|
-
continue;
|
|
397
|
-
}
|
|
398
|
-
if (t === "response.output_text.delta") {
|
|
399
|
-
const text = evt.delta ?? "";
|
|
400
|
-
if (!text) continue;
|
|
401
|
-
if (reasoningStarted && !textStarted) {
|
|
402
|
-
yield { type: "thinking:end" };
|
|
403
|
-
textStarted = true;
|
|
404
|
-
}
|
|
405
|
-
yield { type: "text-delta", text };
|
|
406
|
-
continue;
|
|
407
|
-
}
|
|
408
|
-
if (t === "response.output_item.added") {
|
|
409
|
-
const item = evt.item;
|
|
410
|
-
if (item?.type === "function_call") {
|
|
411
|
-
const id = item.call_id ?? item.id ?? "";
|
|
412
|
-
if (id) {
|
|
413
|
-
toolCalls.set(id, {
|
|
414
|
-
id,
|
|
415
|
-
name: item.name ?? "",
|
|
416
|
-
arguments: item.arguments ?? ""
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
if (t === "response.function_call_arguments.delta") {
|
|
423
|
-
const id = evt.call_id ?? evt.item_id ?? "";
|
|
424
|
-
const delta = evt.delta ?? "";
|
|
425
|
-
if (!id || !delta) continue;
|
|
426
|
-
const existing = toolCalls.get(id);
|
|
427
|
-
if (existing) {
|
|
428
|
-
existing.arguments += delta;
|
|
429
|
-
} else {
|
|
430
|
-
toolCalls.set(id, { id, name: "", arguments: delta });
|
|
431
|
-
}
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
if (t === "response.output_item.done") {
|
|
435
|
-
const item = evt.item;
|
|
436
|
-
if (item?.type === "function_call") {
|
|
437
|
-
const id = item.call_id ?? item.id ?? "";
|
|
438
|
-
const tc = toolCalls.get(id);
|
|
439
|
-
const name = tc?.name || item.name || "";
|
|
440
|
-
const argsStr = tc?.arguments || item.arguments || "{}";
|
|
441
|
-
let args = {};
|
|
442
|
-
try {
|
|
443
|
-
args = JSON.parse(argsStr || "{}");
|
|
444
|
-
} catch {
|
|
445
|
-
args = {};
|
|
446
|
-
}
|
|
447
|
-
if (id && name) {
|
|
448
|
-
yield {
|
|
449
|
-
type: "tool-call",
|
|
450
|
-
toolCall: { id, name, args }
|
|
451
|
-
};
|
|
452
|
-
}
|
|
453
|
-
toolCalls.delete(id);
|
|
454
|
-
}
|
|
455
|
-
continue;
|
|
456
|
-
}
|
|
457
|
-
if (t === "response.completed") {
|
|
458
|
-
const usage = evt.response?.usage;
|
|
459
|
-
if (usage) {
|
|
460
|
-
totalPromptTokens = usage.input_tokens ?? 0;
|
|
461
|
-
totalCompletionTokens = usage.output_tokens ?? 0;
|
|
462
|
-
}
|
|
463
|
-
for (const tc of toolCalls.values()) {
|
|
464
|
-
let args = {};
|
|
465
|
-
try {
|
|
466
|
-
args = JSON.parse(tc.arguments || "{}");
|
|
467
|
-
} catch {
|
|
468
|
-
args = {};
|
|
469
|
-
}
|
|
470
|
-
if (tc.id && tc.name) {
|
|
471
|
-
yield {
|
|
472
|
-
type: "tool-call",
|
|
473
|
-
toolCall: { id: tc.id, name: tc.name, args }
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
toolCalls.clear();
|
|
478
|
-
if (reasoningStarted && !textStarted) {
|
|
479
|
-
yield { type: "thinking:end" };
|
|
480
|
-
}
|
|
481
|
-
const finishReason = toolCalls.size > 0 ? "tool-calls" : "stop";
|
|
482
|
-
yield {
|
|
483
|
-
type: "finish",
|
|
484
|
-
finishReason,
|
|
485
|
-
usage: {
|
|
486
|
-
promptTokens: totalPromptTokens,
|
|
487
|
-
completionTokens: totalCompletionTokens,
|
|
488
|
-
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
489
|
-
}
|
|
490
|
-
};
|
|
491
|
-
finishEmitted = true;
|
|
492
|
-
continue;
|
|
493
|
-
}
|
|
494
|
-
if (t === "response.error" || t === "error") {
|
|
495
|
-
const msg = evt.error?.message || evt.message || "Responses API error";
|
|
496
|
-
yield { type: "error", error: new Error(msg) };
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
if (!finishEmitted) {
|
|
501
|
-
if (reasoningStarted && !textStarted) {
|
|
502
|
-
yield { type: "thinking:end" };
|
|
503
|
-
}
|
|
504
|
-
yield {
|
|
505
|
-
type: "finish",
|
|
506
|
-
finishReason: "stop",
|
|
507
|
-
usage: {
|
|
508
|
-
promptTokens: totalPromptTokens,
|
|
509
|
-
completionTokens: totalCompletionTokens,
|
|
510
|
-
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
511
|
-
}
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
async function fetchOpenRouterModels(apiKey) {
|
|
516
|
-
const headers = {
|
|
517
|
-
"Content-Type": "application/json"
|
|
518
|
-
};
|
|
519
|
-
if (apiKey) {
|
|
520
|
-
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
521
|
-
}
|
|
522
|
-
const response = await fetch("https://openrouter.ai/api/v1/models", {
|
|
523
|
-
headers
|
|
524
|
-
});
|
|
525
|
-
if (!response.ok) {
|
|
526
|
-
throw new Error(`Failed to fetch models: ${response.statusText}`);
|
|
527
|
-
}
|
|
528
|
-
const data = await response.json();
|
|
529
|
-
return data.data || [];
|
|
530
|
-
}
|
|
531
|
-
async function searchOpenRouterModels(query, apiKey) {
|
|
532
|
-
const models = await fetchOpenRouterModels(apiKey);
|
|
533
|
-
const lowerQuery = query.toLowerCase();
|
|
534
|
-
return models.filter(
|
|
535
|
-
(model) => model.id.toLowerCase().includes(lowerQuery) || model.name.toLowerCase().includes(lowerQuery)
|
|
536
|
-
);
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
// src/core/utils.ts
|
|
540
|
-
function generateId(prefix = "id") {
|
|
541
|
-
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
542
|
-
}
|
|
543
|
-
function generateMessageId() {
|
|
544
|
-
return generateId("msg");
|
|
545
|
-
}
|
|
546
|
-
function generateToolCallId() {
|
|
547
|
-
return generateId("call");
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// src/adapters/base.ts
|
|
551
|
-
function stringifyForDebug(value) {
|
|
552
|
-
return JSON.stringify(
|
|
553
|
-
value,
|
|
554
|
-
(_key, currentValue) => {
|
|
555
|
-
if (typeof currentValue === "bigint") {
|
|
556
|
-
return currentValue.toString();
|
|
557
|
-
}
|
|
558
|
-
if (currentValue instanceof Error) {
|
|
559
|
-
return {
|
|
560
|
-
name: currentValue.name,
|
|
561
|
-
message: currentValue.message,
|
|
562
|
-
stack: currentValue.stack
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
return currentValue;
|
|
566
|
-
},
|
|
567
|
-
2
|
|
568
|
-
);
|
|
569
|
-
}
|
|
570
|
-
function logProviderPayload(provider, label, payload, enabled) {
|
|
571
|
-
if (!enabled) {
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
if (label.toLowerCase().includes("stream ")) {
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
try {
|
|
578
|
-
console.log(
|
|
579
|
-
`[llm-sdk:${provider}] ${label}
|
|
580
|
-
${stringifyForDebug(payload)}`
|
|
581
|
-
);
|
|
582
|
-
} catch (error) {
|
|
583
|
-
console.log(
|
|
584
|
-
`[llm-sdk:${provider}] ${label} (failed to stringify payload)`,
|
|
585
|
-
error
|
|
586
|
-
);
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
function parameterToJsonSchema(param) {
|
|
590
|
-
const schema = {
|
|
591
|
-
type: param.type
|
|
592
|
-
};
|
|
593
|
-
if (param.description) {
|
|
594
|
-
schema.description = param.description;
|
|
595
|
-
}
|
|
596
|
-
if (param.enum) {
|
|
597
|
-
schema.enum = param.enum;
|
|
598
|
-
}
|
|
599
|
-
if (param.type === "array" && param.items) {
|
|
600
|
-
schema.items = parameterToJsonSchema(
|
|
601
|
-
param.items
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
if (param.type === "object" && param.properties) {
|
|
605
|
-
schema.properties = Object.fromEntries(
|
|
606
|
-
Object.entries(param.properties).map(([key, prop]) => [
|
|
607
|
-
key,
|
|
608
|
-
parameterToJsonSchema(
|
|
609
|
-
prop
|
|
610
|
-
)
|
|
611
|
-
])
|
|
612
|
-
);
|
|
613
|
-
schema.additionalProperties = false;
|
|
614
|
-
}
|
|
615
|
-
return schema;
|
|
616
|
-
}
|
|
617
|
-
function normalizeObjectJsonSchema(schema) {
|
|
618
|
-
if (!schema || typeof schema !== "object") {
|
|
619
|
-
return {
|
|
620
|
-
type: "object",
|
|
621
|
-
properties: {},
|
|
622
|
-
required: [],
|
|
623
|
-
additionalProperties: false
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
const normalized = { ...schema };
|
|
627
|
-
const type = normalized.type;
|
|
628
|
-
if (type === "object") {
|
|
629
|
-
const properties = normalized.properties && typeof normalized.properties === "object" && !Array.isArray(normalized.properties) ? normalized.properties : {};
|
|
630
|
-
normalized.properties = Object.fromEntries(
|
|
631
|
-
Object.entries(properties).map(([key, value]) => [
|
|
632
|
-
key,
|
|
633
|
-
normalizeObjectJsonSchema(value)
|
|
634
|
-
])
|
|
635
|
-
);
|
|
636
|
-
const propertyKeys = Object.keys(properties);
|
|
637
|
-
const required = Array.isArray(normalized.required) ? normalized.required.filter(
|
|
638
|
-
(value) => typeof value === "string"
|
|
639
|
-
) : [];
|
|
640
|
-
normalized.required = Array.from(/* @__PURE__ */ new Set([...required, ...propertyKeys]));
|
|
641
|
-
if (normalized.additionalProperties === void 0) {
|
|
642
|
-
normalized.additionalProperties = false;
|
|
643
|
-
}
|
|
644
|
-
} else if (type === "array" && normalized.items && typeof normalized.items === "object") {
|
|
645
|
-
normalized.items = normalizeObjectJsonSchema(
|
|
646
|
-
normalized.items
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
|
-
return normalized;
|
|
650
|
-
}
|
|
651
|
-
function formatTools(actions) {
|
|
652
|
-
return actions.map((action) => ({
|
|
653
|
-
type: "function",
|
|
654
|
-
function: {
|
|
655
|
-
name: action.name,
|
|
656
|
-
description: action.description,
|
|
657
|
-
parameters: {
|
|
658
|
-
type: "object",
|
|
659
|
-
properties: action.parameters ? Object.fromEntries(
|
|
660
|
-
Object.entries(action.parameters).map(([key, param]) => [
|
|
661
|
-
key,
|
|
662
|
-
parameterToJsonSchema(param)
|
|
663
|
-
])
|
|
664
|
-
) : {},
|
|
665
|
-
required: action.parameters ? Object.entries(action.parameters).filter(([, param]) => param.required).map(([key]) => key) : [],
|
|
666
|
-
additionalProperties: false
|
|
387
|
+
yield {
|
|
388
|
+
type: "finish",
|
|
389
|
+
finishReason: mapFinishReason(choice.finish_reason),
|
|
390
|
+
usage: {
|
|
391
|
+
promptTokens: totalPromptTokens,
|
|
392
|
+
completionTokens: totalCompletionTokens,
|
|
393
|
+
totalTokens: totalPromptTokens + totalCompletionTokens
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
}
|
|
667
397
|
}
|
|
668
398
|
}
|
|
669
|
-
}));
|
|
670
|
-
}
|
|
671
|
-
function hasImageAttachments(message) {
|
|
672
|
-
const attachments = message.metadata?.attachments;
|
|
673
|
-
return attachments?.some((a) => a.type === "image") ?? false;
|
|
674
|
-
}
|
|
675
|
-
function attachmentToOpenAIImage(attachment) {
|
|
676
|
-
if (attachment.type !== "image") return null;
|
|
677
|
-
let imageUrl;
|
|
678
|
-
if (attachment.url) {
|
|
679
|
-
imageUrl = attachment.url;
|
|
680
|
-
} else if (attachment.data) {
|
|
681
|
-
imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
|
|
682
|
-
} else {
|
|
683
|
-
return null;
|
|
684
|
-
}
|
|
685
|
-
return {
|
|
686
|
-
type: "image_url",
|
|
687
|
-
image_url: {
|
|
688
|
-
url: imageUrl,
|
|
689
|
-
detail: "auto"
|
|
690
|
-
}
|
|
691
399
|
};
|
|
692
400
|
}
|
|
693
|
-
function
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
401
|
+
function mapFinishReason(reason) {
|
|
402
|
+
switch (reason) {
|
|
403
|
+
case "stop":
|
|
404
|
+
return "stop";
|
|
405
|
+
case "length":
|
|
406
|
+
return "length";
|
|
407
|
+
case "tool_calls":
|
|
408
|
+
case "function_call":
|
|
409
|
+
return "tool-calls";
|
|
410
|
+
case "content_filter":
|
|
411
|
+
return "content-filter";
|
|
412
|
+
default:
|
|
413
|
+
return "unknown";
|
|
702
414
|
}
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
415
|
+
}
|
|
416
|
+
function formatMessagesForOpenRouter(messages) {
|
|
417
|
+
return messages.map((msg) => {
|
|
418
|
+
switch (msg.role) {
|
|
419
|
+
case "system":
|
|
420
|
+
return { role: "system", content: msg.content };
|
|
421
|
+
case "user":
|
|
422
|
+
if (typeof msg.content === "string") {
|
|
423
|
+
return { role: "user", content: msg.content };
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
role: "user",
|
|
427
|
+
content: msg.content.map((part) => {
|
|
428
|
+
if (part.type === "text") {
|
|
429
|
+
return { type: "text", text: part.text };
|
|
430
|
+
}
|
|
431
|
+
if (part.type === "image") {
|
|
432
|
+
const imageData = typeof part.image === "string" ? part.image : Buffer.from(part.image).toString("base64");
|
|
433
|
+
const url = imageData.startsWith("data:") ? imageData : `data:${part.mimeType ?? "image/png"};base64,${imageData}`;
|
|
434
|
+
return { type: "image_url", image_url: { url, detail: "auto" } };
|
|
435
|
+
}
|
|
436
|
+
return { type: "text", text: "" };
|
|
437
|
+
})
|
|
438
|
+
};
|
|
439
|
+
case "assistant":
|
|
440
|
+
const assistantMsg = {
|
|
441
|
+
role: "assistant",
|
|
442
|
+
content: msg.content
|
|
443
|
+
};
|
|
444
|
+
if (msg.toolCalls && msg.toolCalls.length > 0) {
|
|
445
|
+
assistantMsg.tool_calls = msg.toolCalls.map((tc) => ({
|
|
446
|
+
id: tc.id,
|
|
447
|
+
type: "function",
|
|
448
|
+
function: {
|
|
449
|
+
name: tc.name,
|
|
450
|
+
arguments: JSON.stringify(tc.args)
|
|
451
|
+
}
|
|
452
|
+
}));
|
|
453
|
+
}
|
|
454
|
+
return assistantMsg;
|
|
455
|
+
case "tool":
|
|
456
|
+
return {
|
|
457
|
+
role: "tool",
|
|
458
|
+
tool_call_id: msg.toolCallId,
|
|
459
|
+
content: msg.content
|
|
460
|
+
};
|
|
461
|
+
default:
|
|
462
|
+
return msg;
|
|
709
463
|
}
|
|
710
|
-
}
|
|
711
|
-
return blocks;
|
|
464
|
+
});
|
|
712
465
|
}
|
|
713
|
-
function
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
466
|
+
async function fetchOpenRouterModels(apiKey) {
|
|
467
|
+
const headers = {
|
|
468
|
+
"Content-Type": "application/json"
|
|
469
|
+
};
|
|
470
|
+
if (apiKey) {
|
|
471
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
717
472
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
role: "user",
|
|
724
|
-
content: messageToOpenAIContent(msg)
|
|
725
|
-
});
|
|
726
|
-
} else if (msg.role === "assistant") {
|
|
727
|
-
const hasToolCalls = msg.tool_calls && msg.tool_calls.length > 0;
|
|
728
|
-
const assistantMsg = {
|
|
729
|
-
role: "assistant",
|
|
730
|
-
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
731
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
732
|
-
};
|
|
733
|
-
if (hasToolCalls) {
|
|
734
|
-
assistantMsg.tool_calls = msg.tool_calls;
|
|
735
|
-
}
|
|
736
|
-
formatted.push(assistantMsg);
|
|
737
|
-
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
738
|
-
formatted.push({
|
|
739
|
-
role: "tool",
|
|
740
|
-
content: msg.content ?? "",
|
|
741
|
-
tool_call_id: msg.tool_call_id
|
|
742
|
-
});
|
|
743
|
-
}
|
|
473
|
+
const response = await fetch("https://openrouter.ai/api/v1/models", {
|
|
474
|
+
headers
|
|
475
|
+
});
|
|
476
|
+
if (!response.ok) {
|
|
477
|
+
throw new Error(`Failed to fetch models: ${response.statusText}`);
|
|
744
478
|
}
|
|
745
|
-
|
|
479
|
+
const data = await response.json();
|
|
480
|
+
return data.data || [];
|
|
481
|
+
}
|
|
482
|
+
async function searchOpenRouterModels(query, apiKey) {
|
|
483
|
+
const models = await fetchOpenRouterModels(apiKey);
|
|
484
|
+
const lowerQuery = query.toLowerCase();
|
|
485
|
+
return models.filter(
|
|
486
|
+
(model) => model.id.toLowerCase().includes(lowerQuery) || model.name.toLowerCase().includes(lowerQuery)
|
|
487
|
+
);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/core/utils.ts
|
|
491
|
+
function generateId(prefix = "id") {
|
|
492
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
493
|
+
}
|
|
494
|
+
function generateMessageId() {
|
|
495
|
+
return generateId("msg");
|
|
496
|
+
}
|
|
497
|
+
function generateToolCallId() {
|
|
498
|
+
return generateId("call");
|
|
746
499
|
}
|
|
747
500
|
|
|
748
501
|
// src/adapters/openai.ts
|
|
@@ -757,7 +510,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
757
510
|
if (baseUrl.includes("generativelanguage.googleapis.com")) return "google";
|
|
758
511
|
if (baseUrl.includes("x.ai")) return "xai";
|
|
759
512
|
if (baseUrl.includes("azure")) return "azure";
|
|
760
|
-
if (baseUrl.includes("openrouter.ai")) return "openrouter";
|
|
761
513
|
return "openai";
|
|
762
514
|
}
|
|
763
515
|
async getClient() {
|
|
@@ -857,259 +609,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
857
609
|
rawResponse: response
|
|
858
610
|
};
|
|
859
611
|
}
|
|
860
|
-
/**
|
|
861
|
-
* OpenAI reasoning models on OpenRouter (o1/o3/o4/gpt-5 family) hide their
|
|
862
|
-
* reasoning content on the chat-completions endpoint. To surface reasoning
|
|
863
|
-
* SUMMARIES (not raw CoT, which OpenAI never exposes) we have to use the
|
|
864
|
-
* Responses API, which streams `response.reasoning_summary_text.delta` events.
|
|
865
|
-
*
|
|
866
|
-
* Match by prefix on the OpenRouter model id. Excludes openai/gpt-4o,
|
|
867
|
-
* openai/gpt-4.1, openai/chatgpt-* — those continue on chat-completions.
|
|
868
|
-
*/
|
|
869
|
-
isOpenAIReasoningModelOnOpenRouter(activeModel) {
|
|
870
|
-
if (this.provider !== "openrouter") return false;
|
|
871
|
-
return activeModel.startsWith("openai/o1") || activeModel.startsWith("openai/o3") || activeModel.startsWith("openai/o4") || activeModel.startsWith("openai/gpt-5");
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Convert ActionDefinition[] (the chat-completions tool shape used by the
|
|
875
|
-
* adapter) to the Responses API tool shape.
|
|
876
|
-
*/
|
|
877
|
-
buildResponsesToolsFromActions(actions) {
|
|
878
|
-
if (!actions || actions.length === 0) return void 0;
|
|
879
|
-
const formatted = formatTools(actions);
|
|
880
|
-
return formatted.map((t) => ({
|
|
881
|
-
type: "function",
|
|
882
|
-
name: t.function.name,
|
|
883
|
-
description: t.function.description,
|
|
884
|
-
parameters: t.function.parameters
|
|
885
|
-
}));
|
|
886
|
-
}
|
|
887
|
-
/**
|
|
888
|
-
* Streaming Responses API path for OpenAI reasoning models on OpenRouter.
|
|
889
|
-
*
|
|
890
|
-
* Maps Responses API SSE events back to the same StreamEvent shapes the
|
|
891
|
-
* chat-completions path emits, so downstream consumers (processChunk.ts,
|
|
892
|
-
* frontend tool handlers, plan approval, specialist delegations) see
|
|
893
|
-
* identical events regardless of which path produced them.
|
|
894
|
-
*
|
|
895
|
-
* response.reasoning_summary_text.delta → thinking:start (once) + thinking:delta
|
|
896
|
-
* response.output_text.delta → message:delta
|
|
897
|
-
* response.output_item.added (function_call) → action:start (queued buffer)
|
|
898
|
-
* response.function_call_arguments.delta → action:args (progressive)
|
|
899
|
-
* response.output_item.done (function_call) → final action:args + action:end
|
|
900
|
-
* response.completed → message:end + done(usage)
|
|
901
|
-
* response.error → error
|
|
902
|
-
*/
|
|
903
|
-
async *streamWithResponsesAPI(request, activeModel, messageId) {
|
|
904
|
-
const client = await this.getClient();
|
|
905
|
-
const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
|
|
906
|
-
const payload = {
|
|
907
|
-
model: activeModel,
|
|
908
|
-
input: this.buildResponsesInput(request),
|
|
909
|
-
stream: true,
|
|
910
|
-
reasoning: {
|
|
911
|
-
effort: request.config?.reasoningEffort ?? "medium",
|
|
912
|
-
summary: "auto"
|
|
913
|
-
}
|
|
914
|
-
};
|
|
915
|
-
if (request.systemPrompt) payload.instructions = request.systemPrompt;
|
|
916
|
-
if (typeof maxTokensValue === "number")
|
|
917
|
-
payload.max_output_tokens = maxTokensValue;
|
|
918
|
-
const tools = this.buildResponsesToolsFromActions(request.actions);
|
|
919
|
-
if (tools && tools.length > 0) payload.tools = tools;
|
|
920
|
-
logProviderPayload(
|
|
921
|
-
"openai",
|
|
922
|
-
"responses-api request payload",
|
|
923
|
-
payload,
|
|
924
|
-
request.debug
|
|
925
|
-
);
|
|
926
|
-
let stream;
|
|
927
|
-
try {
|
|
928
|
-
stream = await client.responses.create(payload);
|
|
929
|
-
} catch (error) {
|
|
930
|
-
yield {
|
|
931
|
-
type: "error",
|
|
932
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
933
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
934
|
-
};
|
|
935
|
-
return;
|
|
936
|
-
}
|
|
937
|
-
const toolBuffers = /* @__PURE__ */ new Map();
|
|
938
|
-
const itemIdToCallId = /* @__PURE__ */ new Map();
|
|
939
|
-
let usage;
|
|
940
|
-
let reasoningStarted = false;
|
|
941
|
-
let textStarted = false;
|
|
942
|
-
let finishEmitted = false;
|
|
943
|
-
const resolveCallId = (evt) => {
|
|
944
|
-
if (evt?.call_id) return evt.call_id;
|
|
945
|
-
if (evt?.item_id) return itemIdToCallId.get(evt.item_id) ?? evt.item_id;
|
|
946
|
-
if (evt?.item?.call_id) return evt.item.call_id;
|
|
947
|
-
if (evt?.item?.id) return evt.item.id;
|
|
948
|
-
return "";
|
|
949
|
-
};
|
|
950
|
-
try {
|
|
951
|
-
for await (const evt of stream) {
|
|
952
|
-
logProviderPayload(
|
|
953
|
-
"openai",
|
|
954
|
-
"responses-api stream chunk",
|
|
955
|
-
evt,
|
|
956
|
-
request.debug
|
|
957
|
-
);
|
|
958
|
-
if (request.signal?.aborted) break;
|
|
959
|
-
const t = evt?.type ?? "";
|
|
960
|
-
if (t === "response.reasoning_summary_text.delta") {
|
|
961
|
-
const delta = evt.delta ?? "";
|
|
962
|
-
if (!delta) continue;
|
|
963
|
-
if (!reasoningStarted) {
|
|
964
|
-
yield { type: "thinking:start" };
|
|
965
|
-
reasoningStarted = true;
|
|
966
|
-
}
|
|
967
|
-
yield { type: "thinking:delta", content: delta };
|
|
968
|
-
continue;
|
|
969
|
-
}
|
|
970
|
-
if (t === "response.reasoning_summary_text.done" || t === "response.reasoning.done") {
|
|
971
|
-
continue;
|
|
972
|
-
}
|
|
973
|
-
if (t === "response.output_text.delta") {
|
|
974
|
-
const text = evt.delta ?? "";
|
|
975
|
-
if (!text) continue;
|
|
976
|
-
if (reasoningStarted && !textStarted) {
|
|
977
|
-
yield { type: "thinking:end" };
|
|
978
|
-
textStarted = true;
|
|
979
|
-
}
|
|
980
|
-
yield { type: "message:delta", content: text };
|
|
981
|
-
continue;
|
|
982
|
-
}
|
|
983
|
-
if (t === "response.output_item.added") {
|
|
984
|
-
const item = evt.item;
|
|
985
|
-
if (item?.type === "function_call") {
|
|
986
|
-
const callId = item.call_id ?? item.id ?? "";
|
|
987
|
-
const itemId = item.id ?? callId;
|
|
988
|
-
if (callId) {
|
|
989
|
-
if (itemId && itemId !== callId) {
|
|
990
|
-
itemIdToCallId.set(itemId, callId);
|
|
991
|
-
}
|
|
992
|
-
if (!toolBuffers.has(callId)) {
|
|
993
|
-
toolBuffers.set(callId, {
|
|
994
|
-
id: callId,
|
|
995
|
-
name: item.name ?? "",
|
|
996
|
-
arguments: item.arguments ?? "",
|
|
997
|
-
emittedStart: false
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
const buf = toolBuffers.get(callId);
|
|
1001
|
-
if (buf.name && !buf.emittedStart) {
|
|
1002
|
-
yield { type: "action:start", id: buf.id, name: buf.name };
|
|
1003
|
-
buf.emittedStart = true;
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
continue;
|
|
1008
|
-
}
|
|
1009
|
-
if (t === "response.function_call_arguments.delta") {
|
|
1010
|
-
const callId = resolveCallId(evt);
|
|
1011
|
-
const delta = evt.delta ?? "";
|
|
1012
|
-
if (!callId || !delta) continue;
|
|
1013
|
-
let buf = toolBuffers.get(callId);
|
|
1014
|
-
if (!buf) {
|
|
1015
|
-
buf = { id: callId, name: "", arguments: "", emittedStart: false };
|
|
1016
|
-
toolBuffers.set(callId, buf);
|
|
1017
|
-
}
|
|
1018
|
-
buf.arguments += delta;
|
|
1019
|
-
if (buf.emittedStart) {
|
|
1020
|
-
yield {
|
|
1021
|
-
type: "action:args",
|
|
1022
|
-
id: buf.id,
|
|
1023
|
-
args: buf.arguments
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
continue;
|
|
1027
|
-
}
|
|
1028
|
-
if (t === "response.output_item.done") {
|
|
1029
|
-
const item = evt.item;
|
|
1030
|
-
if (item?.type === "function_call") {
|
|
1031
|
-
const callId = item.call_id ?? item.id ?? "";
|
|
1032
|
-
const buf = toolBuffers.get(callId);
|
|
1033
|
-
const name = buf?.name || item.name || "";
|
|
1034
|
-
const argsStr = buf?.arguments || item.arguments || "{}";
|
|
1035
|
-
if (callId && name) {
|
|
1036
|
-
if (!buf?.emittedStart) {
|
|
1037
|
-
yield { type: "action:start", id: callId, name };
|
|
1038
|
-
}
|
|
1039
|
-
yield {
|
|
1040
|
-
type: "action:args",
|
|
1041
|
-
id: callId,
|
|
1042
|
-
args: argsStr
|
|
1043
|
-
};
|
|
1044
|
-
yield {
|
|
1045
|
-
type: "action:end",
|
|
1046
|
-
id: callId,
|
|
1047
|
-
name
|
|
1048
|
-
};
|
|
1049
|
-
}
|
|
1050
|
-
toolBuffers.delete(callId);
|
|
1051
|
-
}
|
|
1052
|
-
continue;
|
|
1053
|
-
}
|
|
1054
|
-
if (t === "response.completed") {
|
|
1055
|
-
const u = evt.response?.usage;
|
|
1056
|
-
if (u) {
|
|
1057
|
-
usage = {
|
|
1058
|
-
prompt_tokens: u.input_tokens ?? 0,
|
|
1059
|
-
completion_tokens: u.output_tokens ?? 0,
|
|
1060
|
-
total_tokens: u.total_tokens ?? (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
for (const buf of toolBuffers.values()) {
|
|
1064
|
-
if (!buf.id || !buf.name) continue;
|
|
1065
|
-
if (!buf.emittedStart) {
|
|
1066
|
-
yield { type: "action:start", id: buf.id, name: buf.name };
|
|
1067
|
-
}
|
|
1068
|
-
yield {
|
|
1069
|
-
type: "action:args",
|
|
1070
|
-
id: buf.id,
|
|
1071
|
-
args: buf.arguments || "{}"
|
|
1072
|
-
};
|
|
1073
|
-
yield { type: "action:end", id: buf.id, name: buf.name };
|
|
1074
|
-
}
|
|
1075
|
-
toolBuffers.clear();
|
|
1076
|
-
if (reasoningStarted && !textStarted) {
|
|
1077
|
-
yield { type: "thinking:end" };
|
|
1078
|
-
}
|
|
1079
|
-
yield { type: "message:end" };
|
|
1080
|
-
yield { type: "done", usage };
|
|
1081
|
-
finishEmitted = true;
|
|
1082
|
-
continue;
|
|
1083
|
-
}
|
|
1084
|
-
if (t === "response.error" || t === "error") {
|
|
1085
|
-
const msg = evt.error?.message || evt.message || "Responses API error";
|
|
1086
|
-
yield {
|
|
1087
|
-
type: "error",
|
|
1088
|
-
message: msg,
|
|
1089
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
1090
|
-
};
|
|
1091
|
-
return;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
} catch (error) {
|
|
1095
|
-
yield {
|
|
1096
|
-
type: "error",
|
|
1097
|
-
message: error instanceof Error ? error.message : "Unknown error",
|
|
1098
|
-
code: "OPENAI_RESPONSES_ERROR"
|
|
1099
|
-
};
|
|
1100
|
-
return;
|
|
1101
|
-
}
|
|
1102
|
-
if (!finishEmitted) {
|
|
1103
|
-
if (reasoningStarted && !textStarted) {
|
|
1104
|
-
yield { type: "thinking:end" };
|
|
1105
|
-
}
|
|
1106
|
-
yield { type: "message:end" };
|
|
1107
|
-
yield { type: "done", usage };
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
612
|
async completeWithResponses(request) {
|
|
1111
613
|
const client = await this.getClient();
|
|
1112
614
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
615
|
+
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
616
|
+
request.config?.responseFormat
|
|
617
|
+
);
|
|
1113
618
|
const payload = {
|
|
1114
619
|
model: request.config?.model || this.model,
|
|
1115
620
|
instructions: request.systemPrompt,
|
|
@@ -1119,6 +624,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1119
624
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
1120
625
|
temperature: request.config?.temperature ?? this.config.temperature,
|
|
1121
626
|
max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
|
|
627
|
+
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
1122
628
|
stream: false
|
|
1123
629
|
};
|
|
1124
630
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
@@ -1240,37 +746,21 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1240
746
|
name: openaiToolOptions.toolChoice.name
|
|
1241
747
|
}
|
|
1242
748
|
} : openaiToolOptions?.toolChoice;
|
|
1243
|
-
const
|
|
1244
|
-
const activeModel = request.config?.model || this.model;
|
|
1245
|
-
const modelSlug = activeModel.replace("openai/", "");
|
|
1246
|
-
const isOSeries = /^o[1-9]/.test(modelSlug);
|
|
1247
|
-
const isOpenAIOnOpenRouter = isOpenRouter && activeModel.startsWith("openai/");
|
|
1248
|
-
if (!this.config.disableThinking && this.isOpenAIReasoningModelOnOpenRouter(activeModel)) {
|
|
1249
|
-
yield* this.streamWithResponsesAPI(request, activeModel, messageId);
|
|
1250
|
-
return;
|
|
1251
|
-
}
|
|
1252
|
-
const maxTokensValue = request.config?.maxTokens ?? this.config.maxTokens;
|
|
749
|
+
const modelIdForPayload = request.config?.model || this.model;
|
|
1253
750
|
const payload = {
|
|
1254
|
-
model:
|
|
751
|
+
model: modelIdForPayload,
|
|
1255
752
|
messages,
|
|
1256
753
|
tools: tools.length > 0 ? tools : void 0,
|
|
1257
754
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
1258
755
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
756
|
+
...buildOpenAITokenParams(
|
|
757
|
+
modelIdForPayload,
|
|
758
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
759
|
+
request.config?.temperature ?? this.config.temperature
|
|
760
|
+
),
|
|
761
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
1259
762
|
stream: true,
|
|
1260
|
-
stream_options: { include_usage: true }
|
|
1261
|
-
// o-series: use max_completion_tokens + reasoning_effort, no temperature
|
|
1262
|
-
// regular models: use max_tokens + temperature
|
|
1263
|
-
...isOSeries ? {
|
|
1264
|
-
max_completion_tokens: maxTokensValue,
|
|
1265
|
-
reasoning_effort: request.config?.reasoningEffort ?? "medium"
|
|
1266
|
-
} : {
|
|
1267
|
-
temperature: request.config?.temperature ?? this.config.temperature,
|
|
1268
|
-
max_tokens: maxTokensValue
|
|
1269
|
-
},
|
|
1270
|
-
// Non-OpenAI OpenRouter models support OR's reasoning/include_reasoning params.
|
|
1271
|
-
// When disableThinking=true we must explicitly send include_reasoning:false because
|
|
1272
|
-
// models like Qwen3 and DeepSeek-R1 reason by default even without the reasoning param.
|
|
1273
|
-
...isOpenRouter && !isOpenAIOnOpenRouter ? this.config.disableThinking ? { include_reasoning: false } : { reasoning: { max_tokens: 8e3 }, include_reasoning: true } : {}
|
|
763
|
+
stream_options: { include_usage: true }
|
|
1274
764
|
};
|
|
1275
765
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
1276
766
|
const stream = await client.chat.completions.create(payload);
|
|
@@ -1278,7 +768,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1278
768
|
const collectedCitations = [];
|
|
1279
769
|
let citationIndex = 0;
|
|
1280
770
|
let usage;
|
|
1281
|
-
let adapterReasoningStarted = false;
|
|
1282
771
|
for await (const chunk of stream) {
|
|
1283
772
|
logProviderPayload("openai", "stream chunk", chunk, request.debug);
|
|
1284
773
|
if (request.signal?.aborted) {
|
|
@@ -1289,22 +778,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1289
778
|
if (delta?.content) {
|
|
1290
779
|
yield { type: "message:delta", content: delta.content };
|
|
1291
780
|
}
|
|
1292
|
-
if (isOpenRouter) {
|
|
1293
|
-
const rc = delta?.reasoning_content ?? delta?.reasoning ?? null;
|
|
1294
|
-
if (rc) {
|
|
1295
|
-
const rcText = typeof rc === "string" ? rc : Array.isArray(rc) && rc[0]?.text ? rc[0].text : "";
|
|
1296
|
-
if (rcText) {
|
|
1297
|
-
if (!adapterReasoningStarted) {
|
|
1298
|
-
yield { type: "thinking:start" };
|
|
1299
|
-
adapterReasoningStarted = true;
|
|
1300
|
-
}
|
|
1301
|
-
yield { type: "thinking:delta", content: rcText };
|
|
1302
|
-
}
|
|
1303
|
-
} else if (adapterReasoningStarted && (delta?.content || choice?.finish_reason)) {
|
|
1304
|
-
yield { type: "thinking:end" };
|
|
1305
|
-
adapterReasoningStarted = false;
|
|
1306
|
-
}
|
|
1307
|
-
}
|
|
1308
781
|
const annotations = delta?.annotations;
|
|
1309
782
|
if (annotations && annotations.length > 0) {
|
|
1310
783
|
for (const annotation of annotations) {
|
|
@@ -1352,11 +825,6 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1352
825
|
};
|
|
1353
826
|
} else if (currentToolCall && toolCall.function?.arguments) {
|
|
1354
827
|
currentToolCall.arguments += toolCall.function.arguments;
|
|
1355
|
-
yield {
|
|
1356
|
-
type: "action:args",
|
|
1357
|
-
id: currentToolCall.id,
|
|
1358
|
-
args: currentToolCall.arguments
|
|
1359
|
-
};
|
|
1360
828
|
}
|
|
1361
829
|
}
|
|
1362
830
|
}
|
|
@@ -1432,24 +900,20 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1432
900
|
name: openaiToolOptions.toolChoice.name
|
|
1433
901
|
}
|
|
1434
902
|
} : openaiToolOptions?.toolChoice;
|
|
1435
|
-
const
|
|
1436
|
-
const modelSlug2 = activeModel2.replace("openai/", "");
|
|
1437
|
-
const isOSeries2 = /^o[1-9]/.test(modelSlug2);
|
|
1438
|
-
const maxTokensValue2 = request.config?.maxTokens ?? this.config.maxTokens;
|
|
903
|
+
const modelIdForCompletePayload = request.config?.model || this.model;
|
|
1439
904
|
const payload = {
|
|
1440
|
-
model:
|
|
905
|
+
model: modelIdForCompletePayload,
|
|
1441
906
|
messages,
|
|
1442
907
|
tools: tools.length > 0 ? tools : void 0,
|
|
1443
908
|
tool_choice: tools.length > 0 ? toolChoice : void 0,
|
|
1444
909
|
parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
}
|
|
910
|
+
...buildOpenAITokenParams(
|
|
911
|
+
modelIdForCompletePayload,
|
|
912
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
913
|
+
request.config?.temperature ?? this.config.temperature
|
|
914
|
+
),
|
|
915
|
+
response_format: toOpenAIResponseFormat(request.config?.responseFormat),
|
|
916
|
+
stream: false
|
|
1453
917
|
};
|
|
1454
918
|
logProviderPayload("openai", "request payload", payload, request.debug);
|
|
1455
919
|
const response = await client.chat.completions.create(payload);
|
|
@@ -1532,8 +996,7 @@ function createOpenRouter(config = {}) {
|
|
|
1532
996
|
return createOpenAIAdapter({
|
|
1533
997
|
apiKey,
|
|
1534
998
|
model: modelId,
|
|
1535
|
-
baseUrl
|
|
1536
|
-
disableThinking: config.disableThinking
|
|
999
|
+
baseUrl
|
|
1537
1000
|
});
|
|
1538
1001
|
};
|
|
1539
1002
|
const getCapabilities = (modelId) => {
|