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