@openrouter/ai-sdk-provider 1.5.3 → 6.0.0-alpha.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/index.d.mts +309 -553
- package/dist/index.d.ts +309 -553
- package/dist/index.js +1047 -2805
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1039 -2788
- package/dist/index.mjs.map +1 -1
- package/dist/internal/index.d.mts +315 -361
- package/dist/internal/index.d.ts +315 -361
- package/dist/internal/index.js +372 -2593
- package/dist/internal/index.js.map +1 -1
- package/dist/internal/index.mjs +365 -2582
- package/dist/internal/index.mjs.map +1 -1
- package/package.json +40 -43
package/dist/index.mjs
CHANGED
|
@@ -1,2941 +1,1192 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
-
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
-
var __spreadValues = (a, b) => {
|
|
9
|
-
for (var prop in b || (b = {}))
|
|
10
|
-
if (__hasOwnProp.call(b, prop))
|
|
11
|
-
__defNormalProp(a, prop, b[prop]);
|
|
12
|
-
if (__getOwnPropSymbols)
|
|
13
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
-
if (__propIsEnum.call(b, prop))
|
|
15
|
-
__defNormalProp(a, prop, b[prop]);
|
|
16
|
-
}
|
|
17
|
-
return a;
|
|
18
|
-
};
|
|
19
|
-
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
1
|
+
// src/openrouter-provider.ts
|
|
2
|
+
import { loadApiKey, withoutTrailingSlash } from "@ai-sdk/provider-utils";
|
|
20
3
|
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
var _a;
|
|
25
|
-
var _AISDKError = class _AISDKError2 extends Error {
|
|
26
|
-
/**
|
|
27
|
-
* Creates an AI SDK Error.
|
|
28
|
-
*
|
|
29
|
-
* @param {Object} params - The parameters for creating the error.
|
|
30
|
-
* @param {string} params.name - The name of the error.
|
|
31
|
-
* @param {string} params.message - The error message.
|
|
32
|
-
* @param {unknown} [params.cause] - The underlying cause of the error.
|
|
33
|
-
*/
|
|
34
|
-
constructor({
|
|
35
|
-
name: name14,
|
|
36
|
-
message,
|
|
37
|
-
cause
|
|
38
|
-
}) {
|
|
39
|
-
super(message);
|
|
40
|
-
this[_a] = true;
|
|
41
|
-
this.name = name14;
|
|
42
|
-
this.cause = cause;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Checks if the given error is an AI SDK Error.
|
|
46
|
-
* @param {unknown} error - The error to check.
|
|
47
|
-
* @returns {boolean} True if the error is an AI SDK Error, false otherwise.
|
|
48
|
-
*/
|
|
49
|
-
static isInstance(error) {
|
|
50
|
-
return _AISDKError2.hasMarker(error, marker);
|
|
51
|
-
}
|
|
52
|
-
static hasMarker(error, marker15) {
|
|
53
|
-
const markerSymbol = Symbol.for(marker15);
|
|
54
|
-
return error != null && typeof error === "object" && markerSymbol in error && typeof error[markerSymbol] === "boolean" && error[markerSymbol] === true;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
_a = symbol;
|
|
58
|
-
var AISDKError = _AISDKError;
|
|
59
|
-
var name = "AI_APICallError";
|
|
60
|
-
var marker2 = `vercel.ai.error.${name}`;
|
|
61
|
-
var symbol2 = Symbol.for(marker2);
|
|
62
|
-
var _a2;
|
|
63
|
-
var APICallError = class extends AISDKError {
|
|
64
|
-
constructor({
|
|
65
|
-
message,
|
|
66
|
-
url,
|
|
67
|
-
requestBodyValues,
|
|
68
|
-
statusCode,
|
|
69
|
-
responseHeaders,
|
|
70
|
-
responseBody,
|
|
71
|
-
cause,
|
|
72
|
-
isRetryable = statusCode != null && (statusCode === 408 || // request timeout
|
|
73
|
-
statusCode === 409 || // conflict
|
|
74
|
-
statusCode === 429 || // too many requests
|
|
75
|
-
statusCode >= 500),
|
|
76
|
-
// server error
|
|
77
|
-
data
|
|
78
|
-
}) {
|
|
79
|
-
super({ name, message, cause });
|
|
80
|
-
this[_a2] = true;
|
|
81
|
-
this.url = url;
|
|
82
|
-
this.requestBodyValues = requestBodyValues;
|
|
83
|
-
this.statusCode = statusCode;
|
|
84
|
-
this.responseHeaders = responseHeaders;
|
|
85
|
-
this.responseBody = responseBody;
|
|
86
|
-
this.isRetryable = isRetryable;
|
|
87
|
-
this.data = data;
|
|
88
|
-
}
|
|
89
|
-
static isInstance(error) {
|
|
90
|
-
return AISDKError.hasMarker(error, marker2);
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
_a2 = symbol2;
|
|
94
|
-
var name2 = "AI_EmptyResponseBodyError";
|
|
95
|
-
var marker3 = `vercel.ai.error.${name2}`;
|
|
96
|
-
var symbol3 = Symbol.for(marker3);
|
|
97
|
-
var _a3;
|
|
98
|
-
var EmptyResponseBodyError = class extends AISDKError {
|
|
99
|
-
// used in isInstance
|
|
100
|
-
constructor({ message = "Empty response body" } = {}) {
|
|
101
|
-
super({ name: name2, message });
|
|
102
|
-
this[_a3] = true;
|
|
103
|
-
}
|
|
104
|
-
static isInstance(error) {
|
|
105
|
-
return AISDKError.hasMarker(error, marker3);
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
_a3 = symbol3;
|
|
109
|
-
function getErrorMessage(error) {
|
|
110
|
-
if (error == null) {
|
|
111
|
-
return "unknown error";
|
|
112
|
-
}
|
|
113
|
-
if (typeof error === "string") {
|
|
114
|
-
return error;
|
|
115
|
-
}
|
|
116
|
-
if (error instanceof Error) {
|
|
117
|
-
return error.message;
|
|
118
|
-
}
|
|
119
|
-
return JSON.stringify(error);
|
|
120
|
-
}
|
|
121
|
-
var name3 = "AI_InvalidArgumentError";
|
|
122
|
-
var marker4 = `vercel.ai.error.${name3}`;
|
|
123
|
-
var symbol4 = Symbol.for(marker4);
|
|
124
|
-
var _a4;
|
|
125
|
-
var InvalidArgumentError = class extends AISDKError {
|
|
126
|
-
constructor({
|
|
127
|
-
message,
|
|
128
|
-
cause,
|
|
129
|
-
argument
|
|
130
|
-
}) {
|
|
131
|
-
super({ name: name3, message, cause });
|
|
132
|
-
this[_a4] = true;
|
|
133
|
-
this.argument = argument;
|
|
134
|
-
}
|
|
135
|
-
static isInstance(error) {
|
|
136
|
-
return AISDKError.hasMarker(error, marker4);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
_a4 = symbol4;
|
|
140
|
-
var name4 = "AI_InvalidPromptError";
|
|
141
|
-
var marker5 = `vercel.ai.error.${name4}`;
|
|
142
|
-
var symbol5 = Symbol.for(marker5);
|
|
143
|
-
var _a5;
|
|
144
|
-
var InvalidPromptError = class extends AISDKError {
|
|
145
|
-
constructor({
|
|
146
|
-
prompt,
|
|
147
|
-
message,
|
|
148
|
-
cause
|
|
149
|
-
}) {
|
|
150
|
-
super({ name: name4, message: `Invalid prompt: ${message}`, cause });
|
|
151
|
-
this[_a5] = true;
|
|
152
|
-
this.prompt = prompt;
|
|
153
|
-
}
|
|
154
|
-
static isInstance(error) {
|
|
155
|
-
return AISDKError.hasMarker(error, marker5);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
_a5 = symbol5;
|
|
159
|
-
var name5 = "AI_InvalidResponseDataError";
|
|
160
|
-
var marker6 = `vercel.ai.error.${name5}`;
|
|
161
|
-
var symbol6 = Symbol.for(marker6);
|
|
162
|
-
var _a6;
|
|
163
|
-
var InvalidResponseDataError = class extends AISDKError {
|
|
164
|
-
constructor({
|
|
165
|
-
data,
|
|
166
|
-
message = `Invalid response data: ${JSON.stringify(data)}.`
|
|
167
|
-
}) {
|
|
168
|
-
super({ name: name5, message });
|
|
169
|
-
this[_a6] = true;
|
|
170
|
-
this.data = data;
|
|
171
|
-
}
|
|
172
|
-
static isInstance(error) {
|
|
173
|
-
return AISDKError.hasMarker(error, marker6);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
_a6 = symbol6;
|
|
177
|
-
var name6 = "AI_JSONParseError";
|
|
178
|
-
var marker7 = `vercel.ai.error.${name6}`;
|
|
179
|
-
var symbol7 = Symbol.for(marker7);
|
|
180
|
-
var _a7;
|
|
181
|
-
var JSONParseError = class extends AISDKError {
|
|
182
|
-
constructor({ text, cause }) {
|
|
183
|
-
super({
|
|
184
|
-
name: name6,
|
|
185
|
-
message: `JSON parsing failed: Text: ${text}.
|
|
186
|
-
Error message: ${getErrorMessage(cause)}`,
|
|
187
|
-
cause
|
|
188
|
-
});
|
|
189
|
-
this[_a7] = true;
|
|
190
|
-
this.text = text;
|
|
191
|
-
}
|
|
192
|
-
static isInstance(error) {
|
|
193
|
-
return AISDKError.hasMarker(error, marker7);
|
|
194
|
-
}
|
|
195
|
-
};
|
|
196
|
-
_a7 = symbol7;
|
|
197
|
-
var name7 = "AI_LoadAPIKeyError";
|
|
198
|
-
var marker8 = `vercel.ai.error.${name7}`;
|
|
199
|
-
var symbol8 = Symbol.for(marker8);
|
|
200
|
-
var _a8;
|
|
201
|
-
var LoadAPIKeyError = class extends AISDKError {
|
|
202
|
-
// used in isInstance
|
|
203
|
-
constructor({ message }) {
|
|
204
|
-
super({ name: name7, message });
|
|
205
|
-
this[_a8] = true;
|
|
206
|
-
}
|
|
207
|
-
static isInstance(error) {
|
|
208
|
-
return AISDKError.hasMarker(error, marker8);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
_a8 = symbol8;
|
|
212
|
-
var name8 = "AI_LoadSettingError";
|
|
213
|
-
var marker9 = `vercel.ai.error.${name8}`;
|
|
214
|
-
var symbol9 = Symbol.for(marker9);
|
|
215
|
-
var _a9;
|
|
216
|
-
_a9 = symbol9;
|
|
217
|
-
var name9 = "AI_NoContentGeneratedError";
|
|
218
|
-
var marker10 = `vercel.ai.error.${name9}`;
|
|
219
|
-
var symbol10 = Symbol.for(marker10);
|
|
220
|
-
var _a10;
|
|
221
|
-
var NoContentGeneratedError = class extends AISDKError {
|
|
222
|
-
// used in isInstance
|
|
223
|
-
constructor({
|
|
224
|
-
message = "No content generated."
|
|
225
|
-
} = {}) {
|
|
226
|
-
super({ name: name9, message });
|
|
227
|
-
this[_a10] = true;
|
|
228
|
-
}
|
|
229
|
-
static isInstance(error) {
|
|
230
|
-
return AISDKError.hasMarker(error, marker10);
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
_a10 = symbol10;
|
|
234
|
-
var name10 = "AI_NoSuchModelError";
|
|
235
|
-
var marker11 = `vercel.ai.error.${name10}`;
|
|
236
|
-
var symbol11 = Symbol.for(marker11);
|
|
237
|
-
var _a11;
|
|
238
|
-
_a11 = symbol11;
|
|
239
|
-
var name11 = "AI_TooManyEmbeddingValuesForCallError";
|
|
240
|
-
var marker12 = `vercel.ai.error.${name11}`;
|
|
241
|
-
var symbol12 = Symbol.for(marker12);
|
|
242
|
-
var _a12;
|
|
243
|
-
_a12 = symbol12;
|
|
244
|
-
var name12 = "AI_TypeValidationError";
|
|
245
|
-
var marker13 = `vercel.ai.error.${name12}`;
|
|
246
|
-
var symbol13 = Symbol.for(marker13);
|
|
247
|
-
var _a13;
|
|
248
|
-
var _TypeValidationError = class _TypeValidationError2 extends AISDKError {
|
|
249
|
-
constructor({ value, cause }) {
|
|
250
|
-
super({
|
|
251
|
-
name: name12,
|
|
252
|
-
message: `Type validation failed: Value: ${JSON.stringify(value)}.
|
|
253
|
-
Error message: ${getErrorMessage(cause)}`,
|
|
254
|
-
cause
|
|
255
|
-
});
|
|
256
|
-
this[_a13] = true;
|
|
257
|
-
this.value = value;
|
|
258
|
-
}
|
|
259
|
-
static isInstance(error) {
|
|
260
|
-
return AISDKError.hasMarker(error, marker13);
|
|
261
|
-
}
|
|
262
|
-
/**
|
|
263
|
-
* Wraps an error into a TypeValidationError.
|
|
264
|
-
* If the cause is already a TypeValidationError with the same value, it returns the cause.
|
|
265
|
-
* Otherwise, it creates a new TypeValidationError.
|
|
266
|
-
*
|
|
267
|
-
* @param {Object} params - The parameters for wrapping the error.
|
|
268
|
-
* @param {unknown} params.value - The value that failed validation.
|
|
269
|
-
* @param {unknown} params.cause - The original error or cause of the validation failure.
|
|
270
|
-
* @returns {TypeValidationError} A TypeValidationError instance.
|
|
271
|
-
*/
|
|
272
|
-
static wrap({
|
|
273
|
-
value,
|
|
274
|
-
cause
|
|
275
|
-
}) {
|
|
276
|
-
return _TypeValidationError2.isInstance(cause) && cause.value === value ? cause : new _TypeValidationError2({ value, cause });
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
_a13 = symbol13;
|
|
280
|
-
var TypeValidationError = _TypeValidationError;
|
|
281
|
-
var name13 = "AI_UnsupportedFunctionalityError";
|
|
282
|
-
var marker14 = `vercel.ai.error.${name13}`;
|
|
283
|
-
var symbol14 = Symbol.for(marker14);
|
|
284
|
-
var _a14;
|
|
285
|
-
var UnsupportedFunctionalityError = class extends AISDKError {
|
|
286
|
-
constructor({
|
|
287
|
-
functionality,
|
|
288
|
-
message = `'${functionality}' functionality not supported.`
|
|
289
|
-
}) {
|
|
290
|
-
super({ name: name13, message });
|
|
291
|
-
this[_a14] = true;
|
|
292
|
-
this.functionality = functionality;
|
|
293
|
-
}
|
|
294
|
-
static isInstance(error) {
|
|
295
|
-
return AISDKError.hasMarker(error, marker14);
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
_a14 = symbol14;
|
|
4
|
+
// src/chat/openrouter-chat-language-model.ts
|
|
5
|
+
import { combineHeaders, normalizeHeaders } from "@ai-sdk/provider-utils";
|
|
6
|
+
import { OpenRouter } from "@openrouter/sdk";
|
|
299
7
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
};
|
|
306
|
-
function noop(_arg) {
|
|
307
|
-
}
|
|
308
|
-
function createParser(callbacks) {
|
|
309
|
-
if (typeof callbacks == "function")
|
|
310
|
-
throw new TypeError(
|
|
311
|
-
"`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
|
|
312
|
-
);
|
|
313
|
-
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
|
|
314
|
-
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
|
|
315
|
-
function feed(newChunk) {
|
|
316
|
-
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`);
|
|
317
|
-
for (const line of complete)
|
|
318
|
-
parseLine(line);
|
|
319
|
-
incompleteLine = incomplete, isFirstChunk = false;
|
|
320
|
-
}
|
|
321
|
-
function parseLine(line) {
|
|
322
|
-
if (line === "") {
|
|
323
|
-
dispatchEvent();
|
|
324
|
-
return;
|
|
325
|
-
}
|
|
326
|
-
if (line.startsWith(":")) {
|
|
327
|
-
onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1));
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
const fieldSeparatorIndex = line.indexOf(":");
|
|
331
|
-
if (fieldSeparatorIndex !== -1) {
|
|
332
|
-
const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
333
|
-
processField(field, value, line);
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
processField(line, "", line);
|
|
337
|
-
}
|
|
338
|
-
function processField(field, value, line) {
|
|
339
|
-
switch (field) {
|
|
340
|
-
case "event":
|
|
341
|
-
eventType = value;
|
|
342
|
-
break;
|
|
343
|
-
case "data":
|
|
344
|
-
data = `${data}${value}
|
|
345
|
-
`;
|
|
346
|
-
break;
|
|
347
|
-
case "id":
|
|
348
|
-
id = value.includes("\0") ? void 0 : value;
|
|
349
|
-
break;
|
|
350
|
-
case "retry":
|
|
351
|
-
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
|
|
352
|
-
new ParseError(`Invalid \`retry\` value: "${value}"`, {
|
|
353
|
-
type: "invalid-retry",
|
|
354
|
-
value,
|
|
355
|
-
line
|
|
356
|
-
})
|
|
357
|
-
);
|
|
358
|
-
break;
|
|
359
|
-
default:
|
|
360
|
-
onError(
|
|
361
|
-
new ParseError(
|
|
362
|
-
`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
|
|
363
|
-
{ type: "unknown-field", field, value, line }
|
|
364
|
-
)
|
|
365
|
-
);
|
|
366
|
-
break;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
function dispatchEvent() {
|
|
370
|
-
data.length > 0 && onEvent({
|
|
371
|
-
id,
|
|
372
|
-
event: eventType || void 0,
|
|
373
|
-
// If the data buffer's last character is a U+000A LINE FEED (LF) character,
|
|
374
|
-
// then remove the last character from the data buffer.
|
|
375
|
-
data: data.endsWith(`
|
|
376
|
-
`) ? data.slice(0, -1) : data
|
|
377
|
-
}), id = void 0, data = "", eventType = "";
|
|
378
|
-
}
|
|
379
|
-
function reset(options = {}) {
|
|
380
|
-
incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = true, id = void 0, data = "", eventType = "", incompleteLine = "";
|
|
381
|
-
}
|
|
382
|
-
return { feed, reset };
|
|
8
|
+
// src/utils/build-provider-metadata.ts
|
|
9
|
+
function filterUndefined(obj) {
|
|
10
|
+
return Object.fromEntries(
|
|
11
|
+
Object.entries(obj).filter(([_, v]) => v !== void 0)
|
|
12
|
+
);
|
|
383
13
|
}
|
|
384
|
-
function
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
14
|
+
function buildProviderMetadata(response) {
|
|
15
|
+
if (!response) {
|
|
16
|
+
return void 0;
|
|
17
|
+
}
|
|
18
|
+
const usage = response.usage;
|
|
19
|
+
const usageMetadata = usage ? filterUndefined({
|
|
20
|
+
promptTokens: usage.promptTokens,
|
|
21
|
+
completionTokens: usage.completionTokens,
|
|
22
|
+
totalTokens: usage.totalTokens,
|
|
23
|
+
...usage.promptTokensDetails && {
|
|
24
|
+
promptTokensDetails: filterUndefined({
|
|
25
|
+
cachedTokens: usage.promptTokensDetails.cachedTokens ?? void 0,
|
|
26
|
+
cacheWriteTokens: usage.promptTokensDetails.cacheWriteTokens ?? void 0,
|
|
27
|
+
audioTokens: usage.promptTokensDetails.audioTokens ?? void 0,
|
|
28
|
+
videoTokens: usage.promptTokensDetails.videoTokens ?? void 0
|
|
29
|
+
})
|
|
30
|
+
},
|
|
31
|
+
...usage.completionTokensDetails && {
|
|
32
|
+
completionTokensDetails: filterUndefined({
|
|
33
|
+
reasoningTokens: usage.completionTokensDetails.reasoningTokens ?? void 0,
|
|
34
|
+
imageTokens: usage.completionTokensDetails.imageTokens ?? void 0
|
|
35
|
+
})
|
|
36
|
+
},
|
|
37
|
+
cost: usage.cost,
|
|
38
|
+
isByok: usage.isByok,
|
|
39
|
+
costDetails: usage.costDetails
|
|
40
|
+
}) : void 0;
|
|
41
|
+
const metadata = filterUndefined({
|
|
42
|
+
responseId: response.id,
|
|
43
|
+
provider: response.provider,
|
|
44
|
+
usage: usageMetadata
|
|
45
|
+
});
|
|
46
|
+
return {
|
|
47
|
+
openrouter: metadata
|
|
48
|
+
};
|
|
401
49
|
}
|
|
402
50
|
|
|
403
|
-
//
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
},
|
|
413
|
-
onError(error) {
|
|
414
|
-
onError === "terminate" ? controller.error(error) : typeof onError == "function" && onError(error);
|
|
415
|
-
},
|
|
416
|
-
onRetry,
|
|
417
|
-
onComment
|
|
418
|
-
});
|
|
51
|
+
// src/utils/build-usage.ts
|
|
52
|
+
function buildUsage(usage) {
|
|
53
|
+
if (!usage) {
|
|
54
|
+
return {
|
|
55
|
+
inputTokens: {
|
|
56
|
+
total: 0,
|
|
57
|
+
noCache: void 0,
|
|
58
|
+
cacheRead: void 0,
|
|
59
|
+
cacheWrite: void 0
|
|
419
60
|
},
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
61
|
+
outputTokens: {
|
|
62
|
+
total: 0,
|
|
63
|
+
text: void 0,
|
|
64
|
+
reasoning: void 0
|
|
65
|
+
},
|
|
66
|
+
raw: void 0
|
|
67
|
+
};
|
|
424
68
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
69
|
+
const rawUsage = {
|
|
70
|
+
inputTokens: usage.inputTokens ?? null,
|
|
71
|
+
outputTokens: usage.outputTokens ?? null,
|
|
72
|
+
...usage.inputTokensDetails && {
|
|
73
|
+
inputTokensDetails: {
|
|
74
|
+
cachedTokens: usage.inputTokensDetails.cachedTokens ?? null
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
...usage.outputTokensDetails && {
|
|
78
|
+
outputTokensDetails: {
|
|
79
|
+
reasoningTokens: usage.outputTokensDetails.reasoningTokens ?? null
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
inputTokens: {
|
|
85
|
+
total: usage.inputTokens ?? 0,
|
|
86
|
+
noCache: void 0,
|
|
87
|
+
cacheRead: usage.inputTokensDetails?.cachedTokens,
|
|
88
|
+
cacheWrite: void 0
|
|
89
|
+
},
|
|
90
|
+
outputTokens: {
|
|
91
|
+
total: usage.outputTokens ?? 0,
|
|
92
|
+
text: void 0,
|
|
93
|
+
reasoning: usage.outputTokensDetails?.reasoningTokens
|
|
94
|
+
},
|
|
95
|
+
raw: rawUsage
|
|
96
|
+
};
|
|
451
97
|
}
|
|
452
|
-
|
|
453
|
-
|
|
98
|
+
|
|
99
|
+
// src/chat/convert-to-openrouter-messages.ts
|
|
100
|
+
function convertToOpenRouterMessages(prompt) {
|
|
101
|
+
const result = [];
|
|
102
|
+
for (const message of prompt) {
|
|
103
|
+
const converted = convertMessage(message);
|
|
104
|
+
result.push(...converted);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
454
107
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
108
|
+
function convertMessage(message) {
|
|
109
|
+
const messageWithOptions = message;
|
|
110
|
+
const providerOptions = messageWithOptions.providerOptions;
|
|
111
|
+
const providerMetadata = messageWithOptions.providerMetadata;
|
|
112
|
+
switch (message.role) {
|
|
113
|
+
case "system":
|
|
114
|
+
return [{ role: "system", content: message.content }];
|
|
115
|
+
case "user":
|
|
116
|
+
return [convertUserMessage(message.content)];
|
|
117
|
+
case "assistant":
|
|
118
|
+
return convertAssistantMessage(message.content, providerMetadata, providerOptions);
|
|
119
|
+
case "tool":
|
|
120
|
+
return convertToolMessage(message.content);
|
|
121
|
+
default: {
|
|
122
|
+
const _exhaustive = message;
|
|
123
|
+
throw new Error(`Unknown message role: ${_exhaustive.role}`);
|
|
466
124
|
}
|
|
467
|
-
return chars.join("");
|
|
468
|
-
};
|
|
469
|
-
if (prefix == null) {
|
|
470
|
-
return generator;
|
|
471
|
-
}
|
|
472
|
-
if (alphabet.includes(separator)) {
|
|
473
|
-
throw new InvalidArgumentError({
|
|
474
|
-
argument: "separator",
|
|
475
|
-
message: `The separator "${separator}" must not be part of the alphabet "${alphabet}".`
|
|
476
|
-
});
|
|
477
125
|
}
|
|
478
|
-
return () => `${prefix}${separator}${generator()}`;
|
|
479
|
-
};
|
|
480
|
-
var generateId = createIdGenerator();
|
|
481
|
-
function isAbortError(error) {
|
|
482
|
-
return (error instanceof Error || error instanceof DOMException) && (error.name === "AbortError" || error.name === "ResponseAborted" || // Next.js
|
|
483
|
-
error.name === "TimeoutError");
|
|
484
126
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
url,
|
|
501
|
-
requestBodyValues,
|
|
502
|
-
isRetryable: true
|
|
503
|
-
// retry when network error
|
|
504
|
-
});
|
|
127
|
+
function convertUserMessage(content) {
|
|
128
|
+
const convertedContent = [];
|
|
129
|
+
for (const part of content) {
|
|
130
|
+
switch (part.type) {
|
|
131
|
+
case "text": {
|
|
132
|
+
convertedContent.push({ type: "input_text", text: part.text });
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case "file":
|
|
136
|
+
convertedContent.push(convertFilePart(part));
|
|
137
|
+
break;
|
|
138
|
+
default: {
|
|
139
|
+
const _exhaustive = part;
|
|
140
|
+
throw new Error(`Unknown user content type: ${_exhaustive.type}`);
|
|
141
|
+
}
|
|
505
142
|
}
|
|
506
143
|
}
|
|
507
|
-
return
|
|
144
|
+
return { role: "user", content: convertedContent };
|
|
508
145
|
}
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
apiKeyParameterName = "apiKey",
|
|
518
|
-
description
|
|
519
|
-
}) {
|
|
520
|
-
if (typeof apiKey === "string") {
|
|
521
|
-
return apiKey;
|
|
146
|
+
function convertFilePart(part) {
|
|
147
|
+
const url = convertDataContent(part.data, part.mediaType);
|
|
148
|
+
if (part.mediaType.startsWith("image/")) {
|
|
149
|
+
return {
|
|
150
|
+
type: "input_image",
|
|
151
|
+
imageUrl: url,
|
|
152
|
+
detail: "auto"
|
|
153
|
+
};
|
|
522
154
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
155
|
+
return {
|
|
156
|
+
type: "input_file",
|
|
157
|
+
fileUrl: url
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function convertDataContent(data, mediaType) {
|
|
161
|
+
if (data instanceof URL) {
|
|
162
|
+
return data.toString();
|
|
527
163
|
}
|
|
528
|
-
if (
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
});
|
|
164
|
+
if (data instanceof Uint8Array) {
|
|
165
|
+
const base64 = uint8ArrayToBase64(data);
|
|
166
|
+
return `data:${mediaType};base64,${base64}`;
|
|
532
167
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
throw new LoadAPIKeyError({
|
|
536
|
-
message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or the ${environmentVariableName} environment variable.`
|
|
537
|
-
});
|
|
168
|
+
if (data.startsWith("http://") || data.startsWith("https://") || data.startsWith("data:")) {
|
|
169
|
+
return data;
|
|
538
170
|
}
|
|
539
|
-
|
|
540
|
-
throw new LoadAPIKeyError({
|
|
541
|
-
message: `${description} API key must be a string. The value of the ${environmentVariableName} environment variable is not a string.`
|
|
542
|
-
});
|
|
543
|
-
}
|
|
544
|
-
return apiKey;
|
|
171
|
+
return `data:${mediaType};base64,${data}`;
|
|
545
172
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
if (obj === null || typeof obj !== "object") {
|
|
551
|
-
return obj;
|
|
552
|
-
}
|
|
553
|
-
if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) {
|
|
554
|
-
return obj;
|
|
173
|
+
function uint8ArrayToBase64(bytes) {
|
|
174
|
+
let binary = "";
|
|
175
|
+
for (const byte of bytes) {
|
|
176
|
+
binary += String.fromCharCode(byte);
|
|
555
177
|
}
|
|
556
|
-
return
|
|
178
|
+
return btoa(binary);
|
|
557
179
|
}
|
|
558
|
-
function
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (
|
|
568
|
-
|
|
569
|
-
}
|
|
570
|
-
for (const key in node) {
|
|
571
|
-
const value = node[key];
|
|
572
|
-
if (value && typeof value === "object") {
|
|
573
|
-
next.push(value);
|
|
574
|
-
}
|
|
180
|
+
function extractReasoningDetails(content, providerMetadata, providerOptions) {
|
|
181
|
+
const messageLevel = providerOptions?.openrouter?.reasoning_details ?? providerMetadata?.openrouter?.reasoning_details;
|
|
182
|
+
if (messageLevel && Array.isArray(messageLevel) && messageLevel.length > 0) {
|
|
183
|
+
return messageLevel;
|
|
184
|
+
}
|
|
185
|
+
for (const part of content) {
|
|
186
|
+
if (part.type === "reasoning") {
|
|
187
|
+
const partWithMeta = part;
|
|
188
|
+
const partLevel = partWithMeta.providerOptions?.openrouter?.reasoning_details ?? partWithMeta.providerMetadata?.openrouter?.reasoning_details;
|
|
189
|
+
if (partLevel && Array.isArray(partLevel) && partLevel.length > 0) {
|
|
190
|
+
return partLevel;
|
|
575
191
|
}
|
|
576
192
|
}
|
|
577
193
|
}
|
|
578
|
-
return
|
|
194
|
+
return void 0;
|
|
579
195
|
}
|
|
580
|
-
function
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
} finally {
|
|
586
|
-
Error.stackTraceLimit = stackTraceLimit;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
var validatorSymbol = Symbol.for("vercel.ai.validator");
|
|
590
|
-
function validator(validate) {
|
|
591
|
-
return { [validatorSymbol]: true, validate };
|
|
592
|
-
}
|
|
593
|
-
function isValidator(value) {
|
|
594
|
-
return typeof value === "object" && value !== null && validatorSymbol in value && value[validatorSymbol] === true && "validate" in value;
|
|
595
|
-
}
|
|
596
|
-
function asValidator(value) {
|
|
597
|
-
return isValidator(value) ? value : standardSchemaValidator(value);
|
|
598
|
-
}
|
|
599
|
-
function standardSchemaValidator(standardSchema) {
|
|
600
|
-
return validator(async (value) => {
|
|
601
|
-
const result = await standardSchema["~standard"].validate(value);
|
|
602
|
-
return result.issues == null ? { success: true, value: result.value } : {
|
|
603
|
-
success: false,
|
|
604
|
-
error: new TypeValidationError({
|
|
605
|
-
value,
|
|
606
|
-
cause: result.issues
|
|
607
|
-
})
|
|
608
|
-
};
|
|
609
|
-
});
|
|
610
|
-
}
|
|
611
|
-
async function validateTypes({
|
|
612
|
-
value,
|
|
613
|
-
schema
|
|
614
|
-
}) {
|
|
615
|
-
const result = await safeValidateTypes({ value, schema });
|
|
616
|
-
if (!result.success) {
|
|
617
|
-
throw TypeValidationError.wrap({ value, cause: result.error });
|
|
618
|
-
}
|
|
619
|
-
return result.value;
|
|
620
|
-
}
|
|
621
|
-
async function safeValidateTypes({
|
|
622
|
-
value,
|
|
623
|
-
schema
|
|
624
|
-
}) {
|
|
625
|
-
const validator2 = asValidator(schema);
|
|
626
|
-
try {
|
|
627
|
-
if (validator2.validate == null) {
|
|
628
|
-
return { success: true, value, rawValue: value };
|
|
196
|
+
function transformReasoningToApiFormat(sdkItems) {
|
|
197
|
+
const apiItems = [];
|
|
198
|
+
for (const rawItem of sdkItems) {
|
|
199
|
+
if (typeof rawItem !== "object" || rawItem === null) {
|
|
200
|
+
continue;
|
|
629
201
|
}
|
|
630
|
-
const
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
return {
|
|
635
|
-
success: false,
|
|
636
|
-
error: TypeValidationError.wrap({ value, cause: result.error }),
|
|
637
|
-
rawValue: value
|
|
202
|
+
const item = rawItem;
|
|
203
|
+
const baseProps = {
|
|
204
|
+
id: item.id,
|
|
205
|
+
format: item.format ?? null
|
|
638
206
|
};
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
schema
|
|
650
|
-
}) {
|
|
651
|
-
try {
|
|
652
|
-
const value = secureJsonParse(text);
|
|
653
|
-
if (schema == null) {
|
|
654
|
-
return value;
|
|
207
|
+
let index = item.index ?? 0;
|
|
208
|
+
if (item.type === "reasoning.text" && item.text !== void 0) {
|
|
209
|
+
apiItems.push({
|
|
210
|
+
type: "reasoning.text",
|
|
211
|
+
text: item.text,
|
|
212
|
+
signature: item.signature ?? null,
|
|
213
|
+
index,
|
|
214
|
+
...baseProps
|
|
215
|
+
});
|
|
216
|
+
continue;
|
|
655
217
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
218
|
+
if (item.type === "reasoning.summary" && item.summary !== void 0) {
|
|
219
|
+
apiItems.push({
|
|
220
|
+
type: "reasoning.summary",
|
|
221
|
+
summary: typeof item.summary === "string" ? item.summary : "",
|
|
222
|
+
index,
|
|
223
|
+
...baseProps
|
|
224
|
+
});
|
|
225
|
+
continue;
|
|
660
226
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
})
|
|
668
|
-
|
|
669
|
-
const value = secureJsonParse(text);
|
|
670
|
-
if (schema == null) {
|
|
671
|
-
return { success: true, value, rawValue: value };
|
|
227
|
+
if (item.type === "reasoning.encrypted" && item.data !== void 0) {
|
|
228
|
+
apiItems.push({
|
|
229
|
+
type: "reasoning.encrypted",
|
|
230
|
+
data: item.data,
|
|
231
|
+
index,
|
|
232
|
+
...baseProps
|
|
233
|
+
});
|
|
234
|
+
continue;
|
|
672
235
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
return true;
|
|
686
|
-
} catch (e) {
|
|
687
|
-
return false;
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
function parseJsonEventStream({
|
|
691
|
-
stream,
|
|
692
|
-
schema
|
|
693
|
-
}) {
|
|
694
|
-
return stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream()).pipeThrough(
|
|
695
|
-
new TransformStream({
|
|
696
|
-
async transform({ data }, controller) {
|
|
697
|
-
if (data === "[DONE]") {
|
|
698
|
-
return;
|
|
236
|
+
if (item.type === "reasoning" || item.content || item.summary || item.encryptedContent) {
|
|
237
|
+
if (item.content && Array.isArray(item.content)) {
|
|
238
|
+
for (const contentItem of item.content) {
|
|
239
|
+
if (contentItem.type === "reasoning_text" && contentItem.text) {
|
|
240
|
+
apiItems.push({
|
|
241
|
+
type: "reasoning.text",
|
|
242
|
+
text: contentItem.text,
|
|
243
|
+
signature: item.signature ?? null,
|
|
244
|
+
index: index++,
|
|
245
|
+
...baseProps
|
|
246
|
+
});
|
|
247
|
+
}
|
|
699
248
|
}
|
|
700
|
-
controller.enqueue(await safeParseJSON({ text: data, schema }));
|
|
701
249
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
abortSignal,
|
|
713
|
-
fetch
|
|
714
|
-
}) => postToApi({
|
|
715
|
-
url,
|
|
716
|
-
headers: __spreadValues({
|
|
717
|
-
"Content-Type": "application/json"
|
|
718
|
-
}, headers),
|
|
719
|
-
body: {
|
|
720
|
-
content: JSON.stringify(body),
|
|
721
|
-
values: body
|
|
722
|
-
},
|
|
723
|
-
failedResponseHandler,
|
|
724
|
-
successfulResponseHandler,
|
|
725
|
-
abortSignal,
|
|
726
|
-
fetch
|
|
727
|
-
});
|
|
728
|
-
var postToApi = async ({
|
|
729
|
-
url,
|
|
730
|
-
headers = {},
|
|
731
|
-
body,
|
|
732
|
-
successfulResponseHandler,
|
|
733
|
-
failedResponseHandler,
|
|
734
|
-
abortSignal,
|
|
735
|
-
fetch = getOriginalFetch2()
|
|
736
|
-
}) => {
|
|
737
|
-
try {
|
|
738
|
-
const response = await fetch(url, {
|
|
739
|
-
method: "POST",
|
|
740
|
-
headers: removeUndefinedEntries(headers),
|
|
741
|
-
body: body.content,
|
|
742
|
-
signal: abortSignal
|
|
743
|
-
});
|
|
744
|
-
const responseHeaders = extractResponseHeaders(response);
|
|
745
|
-
if (!response.ok) {
|
|
746
|
-
let errorInformation;
|
|
747
|
-
try {
|
|
748
|
-
errorInformation = await failedResponseHandler({
|
|
749
|
-
response,
|
|
750
|
-
url,
|
|
751
|
-
requestBodyValues: body.values
|
|
752
|
-
});
|
|
753
|
-
} catch (error) {
|
|
754
|
-
if (isAbortError(error) || APICallError.isInstance(error)) {
|
|
755
|
-
throw error;
|
|
250
|
+
if (item.summary && Array.isArray(item.summary)) {
|
|
251
|
+
for (const summaryItem of item.summary) {
|
|
252
|
+
if (summaryItem.type === "summary_text" && summaryItem.text) {
|
|
253
|
+
apiItems.push({
|
|
254
|
+
type: "reasoning.summary",
|
|
255
|
+
summary: summaryItem.text,
|
|
256
|
+
index: index++,
|
|
257
|
+
...baseProps
|
|
258
|
+
});
|
|
259
|
+
}
|
|
756
260
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
261
|
+
}
|
|
262
|
+
if (item.encryptedContent) {
|
|
263
|
+
apiItems.push({
|
|
264
|
+
type: "reasoning.encrypted",
|
|
265
|
+
data: item.encryptedContent,
|
|
266
|
+
index: index++,
|
|
267
|
+
...baseProps
|
|
764
268
|
});
|
|
765
269
|
}
|
|
766
|
-
throw errorInformation.value;
|
|
767
270
|
}
|
|
768
|
-
try {
|
|
769
|
-
return await successfulResponseHandler({
|
|
770
|
-
response,
|
|
771
|
-
url,
|
|
772
|
-
requestBodyValues: body.values
|
|
773
|
-
});
|
|
774
|
-
} catch (error) {
|
|
775
|
-
if (error instanceof Error) {
|
|
776
|
-
if (isAbortError(error) || APICallError.isInstance(error)) {
|
|
777
|
-
throw error;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
throw new APICallError({
|
|
781
|
-
message: "Failed to process successful response",
|
|
782
|
-
cause: error,
|
|
783
|
-
statusCode: response.status,
|
|
784
|
-
url,
|
|
785
|
-
responseHeaders,
|
|
786
|
-
requestBodyValues: body.values
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
} catch (error) {
|
|
790
|
-
throw handleFetchError({ error, url, requestBodyValues: body.values });
|
|
791
|
-
}
|
|
792
|
-
};
|
|
793
|
-
var createJsonErrorResponseHandler = ({
|
|
794
|
-
errorSchema,
|
|
795
|
-
errorToMessage,
|
|
796
|
-
isRetryable
|
|
797
|
-
}) => async ({ response, url, requestBodyValues }) => {
|
|
798
|
-
const responseBody = await response.text();
|
|
799
|
-
const responseHeaders = extractResponseHeaders(response);
|
|
800
|
-
if (responseBody.trim() === "") {
|
|
801
|
-
return {
|
|
802
|
-
responseHeaders,
|
|
803
|
-
value: new APICallError({
|
|
804
|
-
message: response.statusText,
|
|
805
|
-
url,
|
|
806
|
-
requestBodyValues,
|
|
807
|
-
statusCode: response.status,
|
|
808
|
-
responseHeaders,
|
|
809
|
-
responseBody,
|
|
810
|
-
isRetryable: isRetryable == null ? void 0 : isRetryable(response)
|
|
811
|
-
})
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
try {
|
|
815
|
-
const parsedError = await parseJSON({
|
|
816
|
-
text: responseBody,
|
|
817
|
-
schema: errorSchema
|
|
818
|
-
});
|
|
819
|
-
return {
|
|
820
|
-
responseHeaders,
|
|
821
|
-
value: new APICallError({
|
|
822
|
-
message: errorToMessage(parsedError),
|
|
823
|
-
url,
|
|
824
|
-
requestBodyValues,
|
|
825
|
-
statusCode: response.status,
|
|
826
|
-
responseHeaders,
|
|
827
|
-
responseBody,
|
|
828
|
-
data: parsedError,
|
|
829
|
-
isRetryable: isRetryable == null ? void 0 : isRetryable(response, parsedError)
|
|
830
|
-
})
|
|
831
|
-
};
|
|
832
|
-
} catch (parseError) {
|
|
833
|
-
return {
|
|
834
|
-
responseHeaders,
|
|
835
|
-
value: new APICallError({
|
|
836
|
-
message: response.statusText,
|
|
837
|
-
url,
|
|
838
|
-
requestBodyValues,
|
|
839
|
-
statusCode: response.status,
|
|
840
|
-
responseHeaders,
|
|
841
|
-
responseBody,
|
|
842
|
-
isRetryable: isRetryable == null ? void 0 : isRetryable(response)
|
|
843
|
-
})
|
|
844
|
-
};
|
|
845
|
-
}
|
|
846
|
-
};
|
|
847
|
-
var createEventSourceResponseHandler = (chunkSchema) => async ({ response }) => {
|
|
848
|
-
const responseHeaders = extractResponseHeaders(response);
|
|
849
|
-
if (response.body == null) {
|
|
850
|
-
throw new EmptyResponseBodyError({});
|
|
851
|
-
}
|
|
852
|
-
return {
|
|
853
|
-
responseHeaders,
|
|
854
|
-
value: parseJsonEventStream({
|
|
855
|
-
stream: response.body,
|
|
856
|
-
schema: chunkSchema
|
|
857
|
-
})
|
|
858
|
-
};
|
|
859
|
-
};
|
|
860
|
-
var createJsonResponseHandler = (responseSchema) => async ({ response, url, requestBodyValues }) => {
|
|
861
|
-
const responseBody = await response.text();
|
|
862
|
-
const parsedResult = await safeParseJSON({
|
|
863
|
-
text: responseBody,
|
|
864
|
-
schema: responseSchema
|
|
865
|
-
});
|
|
866
|
-
const responseHeaders = extractResponseHeaders(response);
|
|
867
|
-
if (!parsedResult.success) {
|
|
868
|
-
throw new APICallError({
|
|
869
|
-
message: "Invalid JSON response",
|
|
870
|
-
cause: parsedResult.error,
|
|
871
|
-
statusCode: response.status,
|
|
872
|
-
responseHeaders,
|
|
873
|
-
responseBody,
|
|
874
|
-
url,
|
|
875
|
-
requestBodyValues
|
|
876
|
-
});
|
|
877
|
-
}
|
|
878
|
-
return {
|
|
879
|
-
responseHeaders,
|
|
880
|
-
value: parsedResult.value,
|
|
881
|
-
rawValue: parsedResult.rawValue
|
|
882
|
-
};
|
|
883
|
-
};
|
|
884
|
-
var schemaSymbol = Symbol.for("vercel.ai.schema");
|
|
885
|
-
var { btoa, atob } = globalThis;
|
|
886
|
-
function convertUint8ArrayToBase64(array) {
|
|
887
|
-
let latin1string = "";
|
|
888
|
-
for (let i = 0; i < array.length; i++) {
|
|
889
|
-
latin1string += String.fromCodePoint(array[i]);
|
|
890
271
|
}
|
|
891
|
-
return
|
|
272
|
+
return apiItems;
|
|
892
273
|
}
|
|
893
|
-
function
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
// src/schemas/reasoning-details.ts
|
|
898
|
-
import { z } from "zod/v4";
|
|
899
|
-
|
|
900
|
-
// src/utils/type-guards.ts
|
|
901
|
-
function isDefinedOrNotNull(value) {
|
|
902
|
-
return value !== null && value !== void 0;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
// src/schemas/format.ts
|
|
906
|
-
var ReasoningFormat = /* @__PURE__ */ ((ReasoningFormat2) => {
|
|
907
|
-
ReasoningFormat2["Unknown"] = "unknown";
|
|
908
|
-
ReasoningFormat2["OpenAIResponsesV1"] = "openai-responses-v1";
|
|
909
|
-
ReasoningFormat2["XAIResponsesV1"] = "xai-responses-v1";
|
|
910
|
-
ReasoningFormat2["AnthropicClaudeV1"] = "anthropic-claude-v1";
|
|
911
|
-
ReasoningFormat2["GoogleGeminiV1"] = "google-gemini-v1";
|
|
912
|
-
return ReasoningFormat2;
|
|
913
|
-
})(ReasoningFormat || {});
|
|
914
|
-
|
|
915
|
-
// src/schemas/reasoning-details.ts
|
|
916
|
-
var CommonReasoningDetailSchema = z.object({
|
|
917
|
-
id: z.string().nullish(),
|
|
918
|
-
format: z.enum(ReasoningFormat).nullish(),
|
|
919
|
-
index: z.number().optional()
|
|
920
|
-
}).loose();
|
|
921
|
-
var ReasoningDetailSummarySchema = z.object({
|
|
922
|
-
type: z.literal("reasoning.summary" /* Summary */),
|
|
923
|
-
summary: z.string()
|
|
924
|
-
}).extend(CommonReasoningDetailSchema.shape);
|
|
925
|
-
var ReasoningDetailEncryptedSchema = z.object({
|
|
926
|
-
type: z.literal("reasoning.encrypted" /* Encrypted */),
|
|
927
|
-
data: z.string()
|
|
928
|
-
}).extend(CommonReasoningDetailSchema.shape);
|
|
929
|
-
var ReasoningDetailTextSchema = z.object({
|
|
930
|
-
type: z.literal("reasoning.text" /* Text */),
|
|
931
|
-
text: z.string().nullish(),
|
|
932
|
-
signature: z.string().nullish()
|
|
933
|
-
}).extend(CommonReasoningDetailSchema.shape);
|
|
934
|
-
var ReasoningDetailUnionSchema = z.union([
|
|
935
|
-
ReasoningDetailSummarySchema,
|
|
936
|
-
ReasoningDetailEncryptedSchema,
|
|
937
|
-
ReasoningDetailTextSchema
|
|
938
|
-
]);
|
|
939
|
-
var ReasoningDetailsWithUnknownSchema = z.union([
|
|
940
|
-
ReasoningDetailUnionSchema,
|
|
941
|
-
z.unknown().transform(() => null)
|
|
942
|
-
]);
|
|
943
|
-
var ReasoningDetailArraySchema = z.array(ReasoningDetailsWithUnknownSchema).transform((d) => d.filter((d2) => !!d2));
|
|
944
|
-
var OutputUnionToReasoningDetailsSchema = z.union([
|
|
945
|
-
z.object({
|
|
946
|
-
delta: z.object({
|
|
947
|
-
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
|
|
948
|
-
})
|
|
949
|
-
}).transform(
|
|
950
|
-
(data) => data.delta.reasoning_details.filter(isDefinedOrNotNull)
|
|
951
|
-
),
|
|
952
|
-
z.object({
|
|
953
|
-
message: z.object({
|
|
954
|
-
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
|
|
955
|
-
})
|
|
956
|
-
}).transform(
|
|
957
|
-
(data) => data.message.reasoning_details.filter(isDefinedOrNotNull)
|
|
958
|
-
),
|
|
959
|
-
z.object({
|
|
960
|
-
text: z.string(),
|
|
961
|
-
reasoning_details: z.array(ReasoningDetailsWithUnknownSchema)
|
|
962
|
-
}).transform((data) => data.reasoning_details.filter(isDefinedOrNotNull))
|
|
963
|
-
]);
|
|
964
|
-
|
|
965
|
-
// src/schemas/error-response.ts
|
|
966
|
-
import { z as z2 } from "zod/v4";
|
|
967
|
-
var OpenRouterErrorResponseSchema = z2.object({
|
|
968
|
-
error: z2.object({
|
|
969
|
-
code: z2.union([z2.string(), z2.number()]).nullable().optional().default(null),
|
|
970
|
-
message: z2.string(),
|
|
971
|
-
type: z2.string().nullable().optional().default(null),
|
|
972
|
-
param: z2.any().nullable().optional().default(null)
|
|
973
|
-
}).passthrough()
|
|
974
|
-
}).passthrough();
|
|
975
|
-
var openrouterFailedResponseHandler = createJsonErrorResponseHandler({
|
|
976
|
-
errorSchema: OpenRouterErrorResponseSchema,
|
|
977
|
-
errorToMessage: (data) => data.error.message
|
|
978
|
-
});
|
|
979
|
-
|
|
980
|
-
// src/schemas/provider-metadata.ts
|
|
981
|
-
import { z as z3 } from "zod/v4";
|
|
982
|
-
var FileAnnotationSchema = z3.object({
|
|
983
|
-
type: z3.literal("file"),
|
|
984
|
-
file: z3.object({
|
|
985
|
-
hash: z3.string(),
|
|
986
|
-
name: z3.string(),
|
|
987
|
-
content: z3.array(
|
|
988
|
-
z3.object({
|
|
989
|
-
type: z3.string(),
|
|
990
|
-
text: z3.string().optional()
|
|
991
|
-
}).catchall(z3.any())
|
|
992
|
-
).optional()
|
|
993
|
-
}).catchall(z3.any())
|
|
994
|
-
}).catchall(z3.any());
|
|
995
|
-
var OpenRouterProviderMetadataSchema = z3.object({
|
|
996
|
-
provider: z3.string(),
|
|
997
|
-
reasoning_details: z3.array(ReasoningDetailUnionSchema).optional(),
|
|
998
|
-
annotations: z3.array(FileAnnotationSchema).optional(),
|
|
999
|
-
usage: z3.object({
|
|
1000
|
-
promptTokens: z3.number(),
|
|
1001
|
-
promptTokensDetails: z3.object({
|
|
1002
|
-
cachedTokens: z3.number()
|
|
1003
|
-
}).catchall(z3.any()).optional(),
|
|
1004
|
-
completionTokens: z3.number(),
|
|
1005
|
-
completionTokensDetails: z3.object({
|
|
1006
|
-
reasoningTokens: z3.number()
|
|
1007
|
-
}).catchall(z3.any()).optional(),
|
|
1008
|
-
totalTokens: z3.number(),
|
|
1009
|
-
cost: z3.number().optional(),
|
|
1010
|
-
costDetails: z3.object({
|
|
1011
|
-
upstreamInferenceCost: z3.number()
|
|
1012
|
-
}).catchall(z3.any()).optional()
|
|
1013
|
-
}).catchall(z3.any())
|
|
1014
|
-
}).catchall(z3.any());
|
|
1015
|
-
var OpenRouterProviderOptionsSchema = z3.object({
|
|
1016
|
-
openrouter: z3.object({
|
|
1017
|
-
reasoning_details: z3.array(ReasoningDetailUnionSchema).optional(),
|
|
1018
|
-
annotations: z3.array(FileAnnotationSchema).optional()
|
|
1019
|
-
}).optional()
|
|
1020
|
-
}).optional();
|
|
1021
|
-
|
|
1022
|
-
// src/utils/map-finish-reason.ts
|
|
1023
|
-
function mapOpenRouterFinishReason(finishReason) {
|
|
1024
|
-
switch (finishReason) {
|
|
1025
|
-
case "stop":
|
|
1026
|
-
return "stop";
|
|
1027
|
-
case "length":
|
|
1028
|
-
return "length";
|
|
1029
|
-
case "content_filter":
|
|
1030
|
-
return "content-filter";
|
|
1031
|
-
case "function_call":
|
|
1032
|
-
case "tool_calls":
|
|
1033
|
-
return "tool-calls";
|
|
1034
|
-
default:
|
|
1035
|
-
return "unknown";
|
|
274
|
+
function buildReasoningFromDetails(items) {
|
|
275
|
+
if (items.length === 0) {
|
|
276
|
+
return void 0;
|
|
1036
277
|
}
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
"wav",
|
|
1042
|
-
"mp3",
|
|
1043
|
-
"aiff",
|
|
1044
|
-
"aac",
|
|
1045
|
-
"ogg",
|
|
1046
|
-
"flac",
|
|
1047
|
-
"m4a",
|
|
1048
|
-
"pcm16",
|
|
1049
|
-
"pcm24"
|
|
1050
|
-
];
|
|
1051
|
-
|
|
1052
|
-
// src/chat/is-url.ts
|
|
1053
|
-
function isUrl({
|
|
1054
|
-
url,
|
|
1055
|
-
protocols
|
|
1056
|
-
}) {
|
|
1057
|
-
try {
|
|
1058
|
-
const urlObj = new URL(url);
|
|
1059
|
-
return protocols.has(urlObj.protocol);
|
|
1060
|
-
} catch (_) {
|
|
1061
|
-
return false;
|
|
278
|
+
const reasoning = {};
|
|
279
|
+
const textItems = items.filter((i) => i.type === "reasoning.text" && i.text);
|
|
280
|
+
if (textItems.length > 0) {
|
|
281
|
+
reasoning.text = textItems.map((i) => i.text).join("");
|
|
1062
282
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
defaultMediaType
|
|
1069
|
-
}) {
|
|
1070
|
-
var _a15, _b;
|
|
1071
|
-
if (part.data instanceof Uint8Array) {
|
|
1072
|
-
const base64 = convertUint8ArrayToBase64(part.data);
|
|
1073
|
-
return `data:${(_a15 = part.mediaType) != null ? _a15 : defaultMediaType};base64,${base64}`;
|
|
1074
|
-
}
|
|
1075
|
-
const stringUrl = part.data.toString();
|
|
1076
|
-
if (isUrl({
|
|
1077
|
-
url: stringUrl,
|
|
1078
|
-
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
|
|
1079
|
-
})) {
|
|
1080
|
-
return stringUrl;
|
|
283
|
+
const summaryItems = items.filter(
|
|
284
|
+
(i) => i.type === "reasoning.summary" && i.summary
|
|
285
|
+
);
|
|
286
|
+
if (summaryItems.length > 0) {
|
|
287
|
+
reasoning.summary = summaryItems.map((i) => i.summary).join("");
|
|
1081
288
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
return match ? (_a15 = match[1]) != null ? _a15 : defaultMediaType : defaultMediaType;
|
|
1088
|
-
}
|
|
1089
|
-
function getBase64FromDataUrl(dataUrl) {
|
|
1090
|
-
const match = dataUrl.match(/^data:[^;]*;base64,(.+)$/);
|
|
1091
|
-
return match ? match[1] : dataUrl;
|
|
1092
|
-
}
|
|
1093
|
-
var MIME_TO_FORMAT = {
|
|
1094
|
-
// MP3 variants
|
|
1095
|
-
mpeg: "mp3",
|
|
1096
|
-
mp3: "mp3",
|
|
1097
|
-
// WAV variants
|
|
1098
|
-
"x-wav": "wav",
|
|
1099
|
-
wave: "wav",
|
|
1100
|
-
wav: "wav",
|
|
1101
|
-
// OGG variants
|
|
1102
|
-
ogg: "ogg",
|
|
1103
|
-
vorbis: "ogg",
|
|
1104
|
-
// AAC variants
|
|
1105
|
-
aac: "aac",
|
|
1106
|
-
"x-aac": "aac",
|
|
1107
|
-
// M4A variants
|
|
1108
|
-
m4a: "m4a",
|
|
1109
|
-
"x-m4a": "m4a",
|
|
1110
|
-
mp4: "m4a",
|
|
1111
|
-
// AIFF variants
|
|
1112
|
-
aiff: "aiff",
|
|
1113
|
-
"x-aiff": "aiff",
|
|
1114
|
-
// FLAC
|
|
1115
|
-
flac: "flac",
|
|
1116
|
-
"x-flac": "flac",
|
|
1117
|
-
// PCM variants
|
|
1118
|
-
pcm16: "pcm16",
|
|
1119
|
-
pcm24: "pcm24"
|
|
1120
|
-
};
|
|
1121
|
-
function getInputAudioData(part) {
|
|
1122
|
-
const fileData = getFileUrl({
|
|
1123
|
-
part,
|
|
1124
|
-
defaultMediaType: "audio/mpeg"
|
|
1125
|
-
});
|
|
1126
|
-
if (isUrl({
|
|
1127
|
-
url: fileData,
|
|
1128
|
-
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
|
|
1129
|
-
})) {
|
|
1130
|
-
throw new Error(
|
|
1131
|
-
`Audio files cannot be provided as URLs.
|
|
1132
|
-
|
|
1133
|
-
OpenRouter requires audio to be base64-encoded. Please:
|
|
1134
|
-
1. Download the audio file locally
|
|
1135
|
-
2. Read it as a Buffer or Uint8Array
|
|
1136
|
-
3. Pass it as the data parameter
|
|
1137
|
-
|
|
1138
|
-
The AI SDK will automatically handle base64 encoding.
|
|
1139
|
-
|
|
1140
|
-
Learn more: https://openrouter.ai/docs/features/multimodal/audio`
|
|
1141
|
-
);
|
|
289
|
+
const encryptedItem = items.find(
|
|
290
|
+
(i) => i.type === "reasoning.encrypted" && i.data
|
|
291
|
+
);
|
|
292
|
+
if (encryptedItem?.data) {
|
|
293
|
+
reasoning.encrypted = encryptedItem.data;
|
|
1142
294
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
const rawFormat = mediaType.replace("audio/", "");
|
|
1146
|
-
const format = MIME_TO_FORMAT[rawFormat];
|
|
1147
|
-
if (format === void 0) {
|
|
1148
|
-
const supportedList = OPENROUTER_AUDIO_FORMATS.join(", ");
|
|
1149
|
-
throw new Error(
|
|
1150
|
-
`Unsupported audio format: "${mediaType}"
|
|
1151
|
-
|
|
1152
|
-
OpenRouter supports the following audio formats: ${supportedList}
|
|
1153
|
-
|
|
1154
|
-
Learn more: https://openrouter.ai/docs/features/multimodal/audio`
|
|
1155
|
-
);
|
|
295
|
+
if (!reasoning.text && !reasoning.summary && !reasoning.encrypted) {
|
|
296
|
+
return void 0;
|
|
1156
297
|
}
|
|
1157
|
-
return
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
// src/chat/convert-to-openrouter-chat-messages.ts
|
|
1161
|
-
function getCacheControl(providerMetadata) {
|
|
1162
|
-
var _a15, _b, _c;
|
|
1163
|
-
const anthropic = providerMetadata == null ? void 0 : providerMetadata.anthropic;
|
|
1164
|
-
const openrouter2 = providerMetadata == null ? void 0 : providerMetadata.openrouter;
|
|
1165
|
-
return (_c = (_b = (_a15 = openrouter2 == null ? void 0 : openrouter2.cacheControl) != null ? _a15 : openrouter2 == null ? void 0 : openrouter2.cache_control) != null ? _b : anthropic == null ? void 0 : anthropic.cacheControl) != null ? _c : anthropic == null ? void 0 : anthropic.cache_control;
|
|
298
|
+
return reasoning;
|
|
1166
299
|
}
|
|
1167
|
-
function
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
300
|
+
function convertAssistantMessage(content, providerMetadata, providerOptions) {
|
|
301
|
+
const result = [];
|
|
302
|
+
let textContent = "";
|
|
303
|
+
const sdkReasoningDetails = extractReasoningDetails(
|
|
304
|
+
content,
|
|
305
|
+
providerMetadata,
|
|
306
|
+
providerOptions
|
|
307
|
+
);
|
|
308
|
+
const reasoningItems = sdkReasoningDetails ? transformReasoningToApiFormat(sdkReasoningDetails) : [];
|
|
309
|
+
const reasoning = buildReasoningFromDetails(reasoningItems);
|
|
310
|
+
for (const part of content) {
|
|
311
|
+
switch (part.type) {
|
|
312
|
+
case "text":
|
|
313
|
+
textContent += part.text;
|
|
1178
314
|
break;
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
if (content.length === 1 && ((_a15 = content[0]) == null ? void 0 : _a15.type) === "text") {
|
|
1182
|
-
const cacheControl = (_b = getCacheControl(providerOptions)) != null ? _b : getCacheControl(content[0].providerOptions);
|
|
1183
|
-
const contentWithCacheControl = cacheControl ? [
|
|
1184
|
-
{
|
|
1185
|
-
type: "text",
|
|
1186
|
-
text: content[0].text,
|
|
1187
|
-
cache_control: cacheControl
|
|
1188
|
-
}
|
|
1189
|
-
] : content[0].text;
|
|
1190
|
-
messages.push({
|
|
1191
|
-
role: "user",
|
|
1192
|
-
content: contentWithCacheControl
|
|
1193
|
-
});
|
|
1194
|
-
break;
|
|
1195
|
-
}
|
|
1196
|
-
const messageCacheControl = getCacheControl(providerOptions);
|
|
1197
|
-
const contentParts = content.map(
|
|
1198
|
-
(part) => {
|
|
1199
|
-
var _a16, _b2, _c2, _d2, _e2, _f2, _g2;
|
|
1200
|
-
const cacheControl = (_a16 = getCacheControl(part.providerOptions)) != null ? _a16 : messageCacheControl;
|
|
1201
|
-
switch (part.type) {
|
|
1202
|
-
case "text":
|
|
1203
|
-
return {
|
|
1204
|
-
type: "text",
|
|
1205
|
-
text: part.text,
|
|
1206
|
-
// For text parts, only use part-specific cache control
|
|
1207
|
-
cache_control: cacheControl
|
|
1208
|
-
};
|
|
1209
|
-
case "file": {
|
|
1210
|
-
if ((_b2 = part.mediaType) == null ? void 0 : _b2.startsWith("image/")) {
|
|
1211
|
-
const url = getFileUrl({
|
|
1212
|
-
part,
|
|
1213
|
-
defaultMediaType: "image/jpeg"
|
|
1214
|
-
});
|
|
1215
|
-
return {
|
|
1216
|
-
type: "image_url",
|
|
1217
|
-
image_url: {
|
|
1218
|
-
url
|
|
1219
|
-
},
|
|
1220
|
-
// For image parts, use part-specific or message-level cache control
|
|
1221
|
-
cache_control: cacheControl
|
|
1222
|
-
};
|
|
1223
|
-
}
|
|
1224
|
-
if ((_c2 = part.mediaType) == null ? void 0 : _c2.startsWith("audio/")) {
|
|
1225
|
-
return {
|
|
1226
|
-
type: "input_audio",
|
|
1227
|
-
input_audio: getInputAudioData(part),
|
|
1228
|
-
cache_control: cacheControl
|
|
1229
|
-
};
|
|
1230
|
-
}
|
|
1231
|
-
const fileName = String(
|
|
1232
|
-
(_g2 = (_f2 = (_e2 = (_d2 = part.providerOptions) == null ? void 0 : _d2.openrouter) == null ? void 0 : _e2.filename) != null ? _f2 : part.filename) != null ? _g2 : ""
|
|
1233
|
-
);
|
|
1234
|
-
const fileData = getFileUrl({
|
|
1235
|
-
part,
|
|
1236
|
-
defaultMediaType: "application/pdf"
|
|
1237
|
-
});
|
|
1238
|
-
if (isUrl({
|
|
1239
|
-
url: fileData,
|
|
1240
|
-
protocols: /* @__PURE__ */ new Set(["http:", "https:"])
|
|
1241
|
-
})) {
|
|
1242
|
-
return {
|
|
1243
|
-
type: "file",
|
|
1244
|
-
file: {
|
|
1245
|
-
filename: fileName,
|
|
1246
|
-
file_data: fileData
|
|
1247
|
-
}
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
return {
|
|
1251
|
-
type: "file",
|
|
1252
|
-
file: {
|
|
1253
|
-
filename: fileName,
|
|
1254
|
-
file_data: fileData
|
|
1255
|
-
},
|
|
1256
|
-
cache_control: cacheControl
|
|
1257
|
-
};
|
|
1258
|
-
}
|
|
1259
|
-
default: {
|
|
1260
|
-
return {
|
|
1261
|
-
type: "text",
|
|
1262
|
-
text: "",
|
|
1263
|
-
cache_control: cacheControl
|
|
1264
|
-
};
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
);
|
|
1269
|
-
messages.push({
|
|
1270
|
-
role: "user",
|
|
1271
|
-
content: contentParts
|
|
1272
|
-
});
|
|
315
|
+
case "reasoning":
|
|
316
|
+
textContent += part.text;
|
|
1273
317
|
break;
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
for (const part of content) {
|
|
1281
|
-
switch (part.type) {
|
|
1282
|
-
case "text": {
|
|
1283
|
-
text += part.text;
|
|
1284
|
-
break;
|
|
1285
|
-
}
|
|
1286
|
-
case "tool-call": {
|
|
1287
|
-
const partReasoningDetails = (_c = part.providerOptions) == null ? void 0 : _c.openrouter;
|
|
1288
|
-
if ((partReasoningDetails == null ? void 0 : partReasoningDetails.reasoning_details) && Array.isArray(partReasoningDetails.reasoning_details)) {
|
|
1289
|
-
accumulatedReasoningDetails.push(
|
|
1290
|
-
...partReasoningDetails.reasoning_details
|
|
1291
|
-
);
|
|
1292
|
-
}
|
|
1293
|
-
toolCalls.push({
|
|
1294
|
-
id: part.toolCallId,
|
|
1295
|
-
type: "function",
|
|
1296
|
-
function: {
|
|
1297
|
-
name: part.toolName,
|
|
1298
|
-
arguments: JSON.stringify(part.input)
|
|
1299
|
-
}
|
|
1300
|
-
});
|
|
1301
|
-
break;
|
|
1302
|
-
}
|
|
1303
|
-
case "reasoning": {
|
|
1304
|
-
reasoning += part.text;
|
|
1305
|
-
const parsedPartProviderOptions = OpenRouterProviderOptionsSchema.safeParse(part.providerOptions);
|
|
1306
|
-
if (parsedPartProviderOptions.success && ((_e = (_d = parsedPartProviderOptions.data) == null ? void 0 : _d.openrouter) == null ? void 0 : _e.reasoning_details)) {
|
|
1307
|
-
accumulatedReasoningDetails.push(
|
|
1308
|
-
...parsedPartProviderOptions.data.openrouter.reasoning_details
|
|
1309
|
-
);
|
|
1310
|
-
}
|
|
1311
|
-
break;
|
|
1312
|
-
}
|
|
1313
|
-
case "file":
|
|
1314
|
-
break;
|
|
1315
|
-
default: {
|
|
1316
|
-
break;
|
|
1317
|
-
}
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
const parsedProviderOptions = OpenRouterProviderOptionsSchema.safeParse(providerOptions);
|
|
1321
|
-
const messageReasoningDetails = parsedProviderOptions.success ? (_g = (_f = parsedProviderOptions.data) == null ? void 0 : _f.openrouter) == null ? void 0 : _g.reasoning_details : void 0;
|
|
1322
|
-
const messageAnnotations = parsedProviderOptions.success ? (_i = (_h = parsedProviderOptions.data) == null ? void 0 : _h.openrouter) == null ? void 0 : _i.annotations : void 0;
|
|
1323
|
-
const finalReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) && messageReasoningDetails.length > 0 ? messageReasoningDetails : accumulatedReasoningDetails.length > 0 ? accumulatedReasoningDetails : void 0;
|
|
1324
|
-
messages.push({
|
|
1325
|
-
role: "assistant",
|
|
1326
|
-
content: text,
|
|
1327
|
-
tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
|
|
1328
|
-
reasoning: reasoning || void 0,
|
|
1329
|
-
reasoning_details: finalReasoningDetails,
|
|
1330
|
-
annotations: messageAnnotations,
|
|
1331
|
-
cache_control: getCacheControl(providerOptions)
|
|
318
|
+
case "tool-call":
|
|
319
|
+
result.push({
|
|
320
|
+
type: "function_call",
|
|
321
|
+
callId: part.toolCallId,
|
|
322
|
+
name: part.toolName,
|
|
323
|
+
arguments: typeof part.input === "string" ? part.input : JSON.stringify(part.input)
|
|
1332
324
|
});
|
|
1333
325
|
break;
|
|
1334
|
-
|
|
1335
|
-
case "tool": {
|
|
1336
|
-
for (const toolResponse of content) {
|
|
1337
|
-
const content2 = getToolResultContent(toolResponse);
|
|
1338
|
-
messages.push({
|
|
1339
|
-
role: "tool",
|
|
1340
|
-
tool_call_id: toolResponse.toolCallId,
|
|
1341
|
-
content: content2,
|
|
1342
|
-
cache_control: (_j = getCacheControl(providerOptions)) != null ? _j : getCacheControl(toolResponse.providerOptions)
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
326
|
+
case "file":
|
|
1345
327
|
break;
|
|
1346
|
-
|
|
1347
|
-
|
|
328
|
+
case "tool-result":
|
|
329
|
+
result.push(convertToolResult(part));
|
|
1348
330
|
break;
|
|
331
|
+
default: {
|
|
332
|
+
const _exhaustive = part;
|
|
333
|
+
throw new Error(
|
|
334
|
+
`Unknown assistant content type: ${_exhaustive.type}`
|
|
335
|
+
);
|
|
1349
336
|
}
|
|
1350
337
|
}
|
|
1351
338
|
}
|
|
1352
|
-
|
|
339
|
+
if (textContent) {
|
|
340
|
+
const assistantMessage = {
|
|
341
|
+
role: "assistant",
|
|
342
|
+
content: textContent
|
|
343
|
+
};
|
|
344
|
+
if (reasoning) {
|
|
345
|
+
assistantMessage.reasoning = reasoning;
|
|
346
|
+
}
|
|
347
|
+
result.unshift(assistantMessage);
|
|
348
|
+
} else if (reasoning) {
|
|
349
|
+
const assistantMessage = {
|
|
350
|
+
role: "assistant",
|
|
351
|
+
content: ""
|
|
352
|
+
};
|
|
353
|
+
assistantMessage.reasoning = reasoning;
|
|
354
|
+
result.unshift(assistantMessage);
|
|
355
|
+
}
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
function convertToolMessage(content) {
|
|
359
|
+
const result = [];
|
|
360
|
+
for (const part of content) {
|
|
361
|
+
if (part.type === "tool-result") {
|
|
362
|
+
result.push(convertToolResult(part));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return result;
|
|
1353
366
|
}
|
|
1354
|
-
function
|
|
1355
|
-
|
|
367
|
+
function convertToolResult(part) {
|
|
368
|
+
const output = convertToolResultOutput(part.output);
|
|
369
|
+
return {
|
|
370
|
+
type: "function_call_output",
|
|
371
|
+
callId: part.toolCallId,
|
|
372
|
+
output: output.value,
|
|
373
|
+
status: output.isError ? "incomplete" : "completed"
|
|
374
|
+
};
|
|
1356
375
|
}
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
z5.object({
|
|
1365
|
-
type: z5.literal("function"),
|
|
1366
|
-
function: z5.object({
|
|
1367
|
-
name: z5.string()
|
|
1368
|
-
})
|
|
1369
|
-
})
|
|
1370
|
-
]);
|
|
1371
|
-
function getChatCompletionToolChoice(toolChoice) {
|
|
1372
|
-
switch (toolChoice.type) {
|
|
1373
|
-
case "auto":
|
|
1374
|
-
case "none":
|
|
1375
|
-
case "required":
|
|
1376
|
-
return toolChoice.type;
|
|
1377
|
-
case "tool": {
|
|
376
|
+
function convertToolResultOutput(output) {
|
|
377
|
+
switch (output.type) {
|
|
378
|
+
case "text":
|
|
379
|
+
return { value: output.value, isError: false };
|
|
380
|
+
case "json":
|
|
381
|
+
return { value: JSON.stringify(output.value), isError: false };
|
|
382
|
+
case "execution-denied":
|
|
1378
383
|
return {
|
|
1379
|
-
|
|
1380
|
-
|
|
384
|
+
value: `Execution denied: ${output.reason ?? "No reason provided"}`,
|
|
385
|
+
isError: true
|
|
1381
386
|
};
|
|
387
|
+
case "error-text":
|
|
388
|
+
return { value: output.value, isError: true };
|
|
389
|
+
case "error-json":
|
|
390
|
+
return { value: JSON.stringify(output.value), isError: true };
|
|
391
|
+
case "content": {
|
|
392
|
+
const textParts = output.value.filter((item) => item.type === "text").map((item) => item.text);
|
|
393
|
+
return { value: textParts.join("\n"), isError: false };
|
|
1382
394
|
}
|
|
1383
395
|
default: {
|
|
1384
|
-
|
|
1385
|
-
throw new
|
|
1386
|
-
argument: "toolChoice",
|
|
1387
|
-
message: `Invalid tool choice type: ${JSON.stringify(toolChoice)}`
|
|
1388
|
-
});
|
|
396
|
+
const _exhaustive = output;
|
|
397
|
+
throw new Error(`Unknown tool result output type: ${_exhaustive.type}`);
|
|
1389
398
|
}
|
|
1390
399
|
}
|
|
1391
400
|
}
|
|
1392
401
|
|
|
1393
|
-
// src/chat/
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
402
|
+
// src/chat/extract-reasoning-details.ts
|
|
403
|
+
function extractReasoningDetails2(response) {
|
|
404
|
+
const extractedDetails = [];
|
|
405
|
+
for (const outputItem of response.output) {
|
|
406
|
+
if ("type" in outputItem && outputItem.type === "reasoning") {
|
|
407
|
+
const reasoningItem = outputItem;
|
|
408
|
+
extractedDetails.push({
|
|
409
|
+
type: "reasoning",
|
|
410
|
+
id: reasoningItem.id,
|
|
411
|
+
content: reasoningItem.content,
|
|
412
|
+
summary: reasoningItem.summary,
|
|
413
|
+
encryptedContent: reasoningItem.encryptedContent,
|
|
414
|
+
signature: reasoningItem.signature,
|
|
415
|
+
format: reasoningItem.format
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return extractedDetails.length > 0 ? extractedDetails : void 0;
|
|
420
|
+
}
|
|
421
|
+
function hasEncryptedReasoning(reasoningDetails) {
|
|
422
|
+
if (!reasoningDetails) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
return reasoningDetails.some((d) => {
|
|
426
|
+
if (typeof d === "object" && d !== null) {
|
|
427
|
+
const obj = d;
|
|
428
|
+
return obj.encryptedContent != null || obj.type === "reasoning.encrypted";
|
|
429
|
+
}
|
|
430
|
+
return false;
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
function buildReasoningProviderMetadata(reasoningDetails) {
|
|
434
|
+
if (!reasoningDetails || reasoningDetails.length === 0) {
|
|
435
|
+
return void 0;
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
openrouter: {
|
|
439
|
+
reasoning_details: reasoningDetails
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
1409
443
|
|
|
1410
|
-
// src/chat/
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
choices: z7.array(
|
|
1435
|
-
z7.object({
|
|
1436
|
-
message: z7.object({
|
|
1437
|
-
role: z7.literal("assistant"),
|
|
1438
|
-
content: z7.string().nullable().optional(),
|
|
1439
|
-
reasoning: z7.string().nullable().optional(),
|
|
1440
|
-
reasoning_details: ReasoningDetailArraySchema.nullish(),
|
|
1441
|
-
images: ImageResponseArraySchema.nullish(),
|
|
1442
|
-
tool_calls: z7.array(
|
|
1443
|
-
z7.object({
|
|
1444
|
-
id: z7.string().optional().nullable(),
|
|
1445
|
-
type: z7.literal("function"),
|
|
1446
|
-
function: z7.object({
|
|
1447
|
-
name: z7.string(),
|
|
1448
|
-
arguments: z7.string()
|
|
1449
|
-
}).passthrough()
|
|
1450
|
-
}).passthrough()
|
|
1451
|
-
).optional(),
|
|
1452
|
-
annotations: z7.array(
|
|
1453
|
-
z7.union([
|
|
1454
|
-
// URL citation from web search
|
|
1455
|
-
z7.object({
|
|
1456
|
-
type: z7.literal("url_citation"),
|
|
1457
|
-
url_citation: z7.object({
|
|
1458
|
-
end_index: z7.number(),
|
|
1459
|
-
start_index: z7.number(),
|
|
1460
|
-
title: z7.string(),
|
|
1461
|
-
url: z7.string(),
|
|
1462
|
-
content: z7.string().optional()
|
|
1463
|
-
}).passthrough()
|
|
1464
|
-
}).passthrough(),
|
|
1465
|
-
// File annotation from FileParserPlugin (old format)
|
|
1466
|
-
z7.object({
|
|
1467
|
-
type: z7.literal("file_annotation"),
|
|
1468
|
-
file_annotation: z7.object({
|
|
1469
|
-
file_id: z7.string(),
|
|
1470
|
-
quote: z7.string().optional()
|
|
1471
|
-
}).passthrough()
|
|
1472
|
-
}).passthrough(),
|
|
1473
|
-
// File annotation from FileParserPlugin (new format)
|
|
1474
|
-
z7.object({
|
|
1475
|
-
type: z7.literal("file"),
|
|
1476
|
-
file: z7.object({
|
|
1477
|
-
hash: z7.string(),
|
|
1478
|
-
name: z7.string(),
|
|
1479
|
-
content: z7.array(
|
|
1480
|
-
z7.object({
|
|
1481
|
-
type: z7.string(),
|
|
1482
|
-
text: z7.string().optional()
|
|
1483
|
-
}).passthrough()
|
|
1484
|
-
).optional()
|
|
1485
|
-
}).passthrough()
|
|
1486
|
-
}).passthrough()
|
|
1487
|
-
])
|
|
1488
|
-
).nullish()
|
|
1489
|
-
}).passthrough(),
|
|
1490
|
-
index: z7.number().nullish(),
|
|
1491
|
-
logprobs: z7.object({
|
|
1492
|
-
content: z7.array(
|
|
1493
|
-
z7.object({
|
|
1494
|
-
token: z7.string(),
|
|
1495
|
-
logprob: z7.number(),
|
|
1496
|
-
top_logprobs: z7.array(
|
|
1497
|
-
z7.object({
|
|
1498
|
-
token: z7.string(),
|
|
1499
|
-
logprob: z7.number()
|
|
1500
|
-
}).passthrough()
|
|
1501
|
-
)
|
|
1502
|
-
}).passthrough()
|
|
1503
|
-
).nullable()
|
|
1504
|
-
}).passthrough().nullable().optional(),
|
|
1505
|
-
finish_reason: z7.string().optional().nullable()
|
|
1506
|
-
}).passthrough()
|
|
1507
|
-
)
|
|
1508
|
-
}),
|
|
1509
|
-
// Error response (HTTP 200 with error payload)
|
|
1510
|
-
OpenRouterErrorResponseSchema.extend({
|
|
1511
|
-
user_id: z7.string().optional()
|
|
1512
|
-
})
|
|
1513
|
-
]);
|
|
1514
|
-
var OpenRouterStreamChatCompletionChunkSchema = z7.union([
|
|
1515
|
-
OpenRouterChatCompletionBaseResponseSchema.extend({
|
|
1516
|
-
choices: z7.array(
|
|
1517
|
-
z7.object({
|
|
1518
|
-
delta: z7.object({
|
|
1519
|
-
role: z7.enum(["assistant"]).optional(),
|
|
1520
|
-
content: z7.string().nullish(),
|
|
1521
|
-
reasoning: z7.string().nullish().optional(),
|
|
1522
|
-
reasoning_details: ReasoningDetailArraySchema.nullish(),
|
|
1523
|
-
images: ImageResponseArraySchema.nullish(),
|
|
1524
|
-
tool_calls: z7.array(
|
|
1525
|
-
z7.object({
|
|
1526
|
-
index: z7.number().nullish(),
|
|
1527
|
-
id: z7.string().nullish(),
|
|
1528
|
-
type: z7.literal("function").optional(),
|
|
1529
|
-
function: z7.object({
|
|
1530
|
-
name: z7.string().nullish(),
|
|
1531
|
-
arguments: z7.string().nullish()
|
|
1532
|
-
}).passthrough()
|
|
1533
|
-
}).passthrough()
|
|
1534
|
-
).nullish(),
|
|
1535
|
-
annotations: z7.array(
|
|
1536
|
-
z7.union([
|
|
1537
|
-
// URL citation from web search
|
|
1538
|
-
z7.object({
|
|
1539
|
-
type: z7.literal("url_citation"),
|
|
1540
|
-
url_citation: z7.object({
|
|
1541
|
-
end_index: z7.number(),
|
|
1542
|
-
start_index: z7.number(),
|
|
1543
|
-
title: z7.string(),
|
|
1544
|
-
url: z7.string(),
|
|
1545
|
-
content: z7.string().optional()
|
|
1546
|
-
}).passthrough()
|
|
1547
|
-
}).passthrough(),
|
|
1548
|
-
// File annotation from FileParserPlugin (old format)
|
|
1549
|
-
z7.object({
|
|
1550
|
-
type: z7.literal("file_annotation"),
|
|
1551
|
-
file_annotation: z7.object({
|
|
1552
|
-
file_id: z7.string(),
|
|
1553
|
-
quote: z7.string().optional()
|
|
1554
|
-
}).passthrough()
|
|
1555
|
-
}).passthrough(),
|
|
1556
|
-
// File annotation from FileParserPlugin (new format)
|
|
1557
|
-
z7.object({
|
|
1558
|
-
type: z7.literal("file"),
|
|
1559
|
-
file: z7.object({
|
|
1560
|
-
hash: z7.string(),
|
|
1561
|
-
name: z7.string(),
|
|
1562
|
-
content: z7.array(
|
|
1563
|
-
z7.object({
|
|
1564
|
-
type: z7.string(),
|
|
1565
|
-
text: z7.string().optional()
|
|
1566
|
-
}).passthrough()
|
|
1567
|
-
).optional()
|
|
1568
|
-
}).passthrough()
|
|
1569
|
-
}).passthrough()
|
|
1570
|
-
])
|
|
1571
|
-
).nullish()
|
|
1572
|
-
}).passthrough().nullish(),
|
|
1573
|
-
logprobs: z7.object({
|
|
1574
|
-
content: z7.array(
|
|
1575
|
-
z7.object({
|
|
1576
|
-
token: z7.string(),
|
|
1577
|
-
logprob: z7.number(),
|
|
1578
|
-
top_logprobs: z7.array(
|
|
1579
|
-
z7.object({
|
|
1580
|
-
token: z7.string(),
|
|
1581
|
-
logprob: z7.number()
|
|
1582
|
-
}).passthrough()
|
|
1583
|
-
)
|
|
1584
|
-
}).passthrough()
|
|
1585
|
-
).nullable()
|
|
1586
|
-
}).passthrough().nullish(),
|
|
1587
|
-
finish_reason: z7.string().nullable().optional(),
|
|
1588
|
-
index: z7.number().nullish()
|
|
1589
|
-
}).passthrough()
|
|
1590
|
-
)
|
|
1591
|
-
}),
|
|
1592
|
-
OpenRouterErrorResponseSchema
|
|
1593
|
-
]);
|
|
444
|
+
// src/chat/map-openrouter-finish-reason.ts
|
|
445
|
+
function mapOpenRouterFinishReason(finishReason) {
|
|
446
|
+
if (finishReason == null) {
|
|
447
|
+
return { unified: "other", raw: void 0 };
|
|
448
|
+
}
|
|
449
|
+
switch (finishReason) {
|
|
450
|
+
case "end_turn":
|
|
451
|
+
case "stop":
|
|
452
|
+
case "stop_sequence":
|
|
453
|
+
return { unified: "stop", raw: finishReason };
|
|
454
|
+
case "max_tokens":
|
|
455
|
+
case "length":
|
|
456
|
+
return { unified: "length", raw: finishReason };
|
|
457
|
+
case "tool_use":
|
|
458
|
+
case "tool_calls":
|
|
459
|
+
return { unified: "tool-calls", raw: finishReason };
|
|
460
|
+
case "content_filter":
|
|
461
|
+
return { unified: "content-filter", raw: finishReason };
|
|
462
|
+
case "error":
|
|
463
|
+
return { unified: "error", raw: finishReason };
|
|
464
|
+
default:
|
|
465
|
+
return { unified: "other", raw: finishReason };
|
|
466
|
+
}
|
|
467
|
+
}
|
|
1594
468
|
|
|
1595
|
-
// src/chat/
|
|
469
|
+
// src/chat/openrouter-chat-language-model.ts
|
|
1596
470
|
var OpenRouterChatLanguageModel = class {
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
471
|
+
specificationVersion = "v3";
|
|
472
|
+
provider = "openrouter";
|
|
473
|
+
modelId;
|
|
474
|
+
settings;
|
|
475
|
+
/**
|
|
476
|
+
* Supported URL patterns by media type.
|
|
477
|
+
* OpenRouter Chat API only supports image URLs natively.
|
|
478
|
+
* PDF URLs are not supported - use PDF data URIs or the Responses API instead.
|
|
479
|
+
*/
|
|
480
|
+
supportedUrls = {
|
|
481
|
+
"image/*": [/^https?:\/\/.*$/]
|
|
482
|
+
};
|
|
483
|
+
constructor(modelId, settings) {
|
|
1610
484
|
this.modelId = modelId;
|
|
1611
485
|
this.settings = settings;
|
|
1612
|
-
this.config = config;
|
|
1613
|
-
}
|
|
1614
|
-
getArgs({
|
|
1615
|
-
prompt,
|
|
1616
|
-
maxOutputTokens,
|
|
1617
|
-
temperature,
|
|
1618
|
-
topP,
|
|
1619
|
-
frequencyPenalty,
|
|
1620
|
-
presencePenalty,
|
|
1621
|
-
seed,
|
|
1622
|
-
stopSequences,
|
|
1623
|
-
responseFormat,
|
|
1624
|
-
topK,
|
|
1625
|
-
tools,
|
|
1626
|
-
toolChoice
|
|
1627
|
-
}) {
|
|
1628
|
-
var _a15;
|
|
1629
|
-
const baseArgs = __spreadValues(__spreadValues({
|
|
1630
|
-
// model id:
|
|
1631
|
-
model: this.modelId,
|
|
1632
|
-
models: this.settings.models,
|
|
1633
|
-
// model specific settings:
|
|
1634
|
-
logit_bias: this.settings.logitBias,
|
|
1635
|
-
logprobs: this.settings.logprobs === true || typeof this.settings.logprobs === "number" ? true : void 0,
|
|
1636
|
-
top_logprobs: typeof this.settings.logprobs === "number" ? this.settings.logprobs : typeof this.settings.logprobs === "boolean" ? this.settings.logprobs ? 0 : void 0 : void 0,
|
|
1637
|
-
user: this.settings.user,
|
|
1638
|
-
parallel_tool_calls: this.settings.parallelToolCalls,
|
|
1639
|
-
// standardized settings:
|
|
1640
|
-
max_tokens: maxOutputTokens,
|
|
1641
|
-
temperature,
|
|
1642
|
-
top_p: topP,
|
|
1643
|
-
frequency_penalty: frequencyPenalty,
|
|
1644
|
-
presence_penalty: presencePenalty,
|
|
1645
|
-
seed,
|
|
1646
|
-
stop: stopSequences,
|
|
1647
|
-
response_format: (responseFormat == null ? void 0 : responseFormat.type) === "json" ? responseFormat.schema != null ? {
|
|
1648
|
-
type: "json_schema",
|
|
1649
|
-
json_schema: __spreadValues({
|
|
1650
|
-
schema: responseFormat.schema,
|
|
1651
|
-
strict: true,
|
|
1652
|
-
name: (_a15 = responseFormat.name) != null ? _a15 : "response"
|
|
1653
|
-
}, responseFormat.description && {
|
|
1654
|
-
description: responseFormat.description
|
|
1655
|
-
})
|
|
1656
|
-
} : { type: "json_object" } : void 0,
|
|
1657
|
-
top_k: topK,
|
|
1658
|
-
// messages:
|
|
1659
|
-
messages: convertToOpenRouterChatMessages(prompt),
|
|
1660
|
-
// OpenRouter specific settings:
|
|
1661
|
-
include_reasoning: this.settings.includeReasoning,
|
|
1662
|
-
reasoning: this.settings.reasoning,
|
|
1663
|
-
usage: this.settings.usage,
|
|
1664
|
-
// Web search settings:
|
|
1665
|
-
plugins: this.settings.plugins,
|
|
1666
|
-
web_search_options: this.settings.web_search_options,
|
|
1667
|
-
// Provider routing settings:
|
|
1668
|
-
provider: this.settings.provider,
|
|
1669
|
-
// Debug settings:
|
|
1670
|
-
debug: this.settings.debug
|
|
1671
|
-
}, this.config.extraBody), this.settings.extraBody);
|
|
1672
|
-
if (tools && tools.length > 0) {
|
|
1673
|
-
const mappedTools = tools.filter(
|
|
1674
|
-
(tool) => tool.type === "function"
|
|
1675
|
-
).map((tool) => ({
|
|
1676
|
-
type: "function",
|
|
1677
|
-
function: {
|
|
1678
|
-
name: tool.name,
|
|
1679
|
-
description: tool.description,
|
|
1680
|
-
parameters: tool.inputSchema
|
|
1681
|
-
}
|
|
1682
|
-
}));
|
|
1683
|
-
return __spreadProps(__spreadValues({}, baseArgs), {
|
|
1684
|
-
tools: mappedTools,
|
|
1685
|
-
tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
|
|
1686
|
-
});
|
|
1687
|
-
}
|
|
1688
|
-
return baseArgs;
|
|
1689
486
|
}
|
|
1690
487
|
async doGenerate(options) {
|
|
1691
|
-
|
|
1692
|
-
const
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
const { value: responseValue, responseHeaders } = await postJsonToApi({
|
|
1696
|
-
url: this.config.url({
|
|
1697
|
-
path: "/chat/completions",
|
|
1698
|
-
modelId: this.modelId
|
|
1699
|
-
}),
|
|
1700
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
1701
|
-
body: args,
|
|
1702
|
-
failedResponseHandler: openrouterFailedResponseHandler,
|
|
1703
|
-
successfulResponseHandler: createJsonResponseHandler(
|
|
1704
|
-
OpenRouterNonStreamChatCompletionResponseSchema
|
|
1705
|
-
),
|
|
1706
|
-
abortSignal: options.abortSignal,
|
|
1707
|
-
fetch: this.config.fetch
|
|
488
|
+
const warnings = [];
|
|
489
|
+
const client = new OpenRouter({
|
|
490
|
+
apiKey: this.settings.apiKey,
|
|
491
|
+
serverURL: this.settings.baseURL
|
|
1708
492
|
});
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
message: "No choice in response"
|
|
1728
|
-
});
|
|
1729
|
-
}
|
|
1730
|
-
const usageInfo = response.usage ? {
|
|
1731
|
-
inputTokens: (_a15 = response.usage.prompt_tokens) != null ? _a15 : 0,
|
|
1732
|
-
outputTokens: (_b = response.usage.completion_tokens) != null ? _b : 0,
|
|
1733
|
-
totalTokens: ((_c = response.usage.prompt_tokens) != null ? _c : 0) + ((_d = response.usage.completion_tokens) != null ? _d : 0),
|
|
1734
|
-
reasoningTokens: (_f = (_e = response.usage.completion_tokens_details) == null ? void 0 : _e.reasoning_tokens) != null ? _f : 0,
|
|
1735
|
-
cachedInputTokens: (_h = (_g = response.usage.prompt_tokens_details) == null ? void 0 : _g.cached_tokens) != null ? _h : 0
|
|
1736
|
-
} : {
|
|
1737
|
-
inputTokens: 0,
|
|
1738
|
-
outputTokens: 0,
|
|
1739
|
-
totalTokens: 0,
|
|
1740
|
-
reasoningTokens: 0,
|
|
1741
|
-
cachedInputTokens: 0
|
|
493
|
+
const openRouterInput = convertToOpenRouterMessages(options.prompt);
|
|
494
|
+
const tools = convertToolsToResponsesFormat(options.tools, warnings);
|
|
495
|
+
const toolChoice = convertToolChoiceToResponsesFormat(options.toolChoice);
|
|
496
|
+
const text = convertResponseFormatToText(options.responseFormat);
|
|
497
|
+
const requestParams = {
|
|
498
|
+
model: this.modelId,
|
|
499
|
+
input: openRouterInput,
|
|
500
|
+
stream: false,
|
|
501
|
+
...options.maxOutputTokens !== void 0 && {
|
|
502
|
+
maxOutputTokens: options.maxOutputTokens
|
|
503
|
+
},
|
|
504
|
+
...options.temperature !== void 0 && {
|
|
505
|
+
temperature: options.temperature
|
|
506
|
+
},
|
|
507
|
+
...options.topP !== void 0 && { topP: options.topP },
|
|
508
|
+
...tools.length > 0 && { tools },
|
|
509
|
+
...toolChoice !== void 0 && { toolChoice },
|
|
510
|
+
...text !== void 0 && { text }
|
|
1742
511
|
};
|
|
1743
|
-
const
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
providerMetadata: {
|
|
1766
|
-
openrouter: {
|
|
1767
|
-
reasoning_details: [detail]
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
};
|
|
1771
|
-
}
|
|
1772
|
-
break;
|
|
512
|
+
const combinedHeaders = normalizeHeaders(
|
|
513
|
+
combineHeaders(this.settings.headers, options.headers)
|
|
514
|
+
);
|
|
515
|
+
const response = await client.beta.responses.send(requestParams, {
|
|
516
|
+
fetchOptions: {
|
|
517
|
+
signal: options.abortSignal,
|
|
518
|
+
headers: combinedHeaders
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
const content = [];
|
|
522
|
+
const reasoningDetails = extractReasoningDetails2(response);
|
|
523
|
+
const reasoningMetadata = buildReasoningProviderMetadata(reasoningDetails);
|
|
524
|
+
for (const outputItem of response.output) {
|
|
525
|
+
if (outputItem.type === "reasoning") {
|
|
526
|
+
const reasoningItem = outputItem;
|
|
527
|
+
const reasoningText = reasoningItem.content?.filter((c) => c.type === "reasoning_text").map((c) => c.text).join("") || reasoningItem.summary?.filter((c) => c.type === "summary_text").map((c) => c.text).join("") || "";
|
|
528
|
+
if (reasoningText) {
|
|
529
|
+
content.push({
|
|
530
|
+
type: "reasoning",
|
|
531
|
+
text: reasoningText,
|
|
532
|
+
...reasoningMetadata && { providerMetadata: reasoningMetadata }
|
|
533
|
+
});
|
|
1773
534
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
}
|
|
1783
|
-
}
|
|
1784
|
-
};
|
|
535
|
+
} else if (outputItem.type === "message") {
|
|
536
|
+
const messageItem = outputItem;
|
|
537
|
+
for (const contentItem of messageItem.content) {
|
|
538
|
+
if (contentItem.type === "output_text" && contentItem.text) {
|
|
539
|
+
content.push({
|
|
540
|
+
type: "text",
|
|
541
|
+
text: contentItem.text
|
|
542
|
+
});
|
|
1785
543
|
}
|
|
1786
|
-
break;
|
|
1787
|
-
}
|
|
1788
|
-
default: {
|
|
1789
|
-
detail;
|
|
1790
544
|
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
}).filter((p) => p !== null) : choice.message.reasoning ? [
|
|
1794
|
-
{
|
|
1795
|
-
type: "reasoning",
|
|
1796
|
-
text: choice.message.reasoning
|
|
1797
|
-
}
|
|
1798
|
-
] : [];
|
|
1799
|
-
const content = [];
|
|
1800
|
-
content.push(...reasoning);
|
|
1801
|
-
if (choice.message.content) {
|
|
1802
|
-
content.push({
|
|
1803
|
-
type: "text",
|
|
1804
|
-
text: choice.message.content
|
|
1805
|
-
});
|
|
1806
|
-
}
|
|
1807
|
-
if (choice.message.tool_calls) {
|
|
1808
|
-
for (const toolCall of choice.message.tool_calls) {
|
|
545
|
+
} else if (outputItem.type === "function_call") {
|
|
546
|
+
const functionCallItem = outputItem;
|
|
1809
547
|
content.push({
|
|
1810
548
|
type: "tool-call",
|
|
1811
|
-
toolCallId:
|
|
1812
|
-
toolName:
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
});
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1822
|
-
if (choice.message.images) {
|
|
1823
|
-
for (const image of choice.message.images) {
|
|
1824
|
-
content.push({
|
|
1825
|
-
type: "file",
|
|
1826
|
-
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
|
|
1827
|
-
data: getBase64FromDataUrl(image.image_url.url)
|
|
549
|
+
toolCallId: functionCallItem.callId,
|
|
550
|
+
toolName: functionCallItem.name,
|
|
551
|
+
// Default to empty object when arguments is undefined/empty
|
|
552
|
+
// (some providers omit arguments for tools with no parameters)
|
|
553
|
+
input: functionCallItem.arguments || "{}",
|
|
554
|
+
...reasoningMetadata && { providerMetadata: reasoningMetadata }
|
|
1828
555
|
});
|
|
1829
556
|
}
|
|
1830
557
|
}
|
|
1831
|
-
if (
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
sourceType: "url",
|
|
1837
|
-
id: annotation.url_citation.url,
|
|
1838
|
-
url: annotation.url_citation.url,
|
|
1839
|
-
title: annotation.url_citation.title,
|
|
1840
|
-
providerMetadata: {
|
|
1841
|
-
openrouter: {
|
|
1842
|
-
content: annotation.url_citation.content || ""
|
|
1843
|
-
}
|
|
1844
|
-
}
|
|
1845
|
-
});
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
558
|
+
if (response.outputText && !content.some((c) => c.type === "text")) {
|
|
559
|
+
content.push({
|
|
560
|
+
type: "text",
|
|
561
|
+
text: response.outputText
|
|
562
|
+
});
|
|
1848
563
|
}
|
|
1849
|
-
|
|
1850
|
-
|
|
564
|
+
let finishReason = mapOpenRouterFinishReason(
|
|
565
|
+
response.status === "completed" ? "stop" : response.status ?? "stop"
|
|
1851
566
|
);
|
|
1852
|
-
const hasToolCalls =
|
|
1853
|
-
|
|
1854
|
-
|
|
567
|
+
const hasToolCalls = content.some((c) => c.type === "tool-call");
|
|
568
|
+
if (hasToolCalls && hasEncryptedReasoning(reasoningDetails) && finishReason.unified === "stop") {
|
|
569
|
+
finishReason = { unified: "tool-calls", raw: finishReason.raw };
|
|
570
|
+
}
|
|
571
|
+
const usage = buildUsage(
|
|
572
|
+
response.usage ? {
|
|
573
|
+
inputTokens: response.usage.inputTokens,
|
|
574
|
+
outputTokens: response.usage.outputTokens
|
|
575
|
+
} : void 0
|
|
1855
576
|
);
|
|
1856
|
-
const
|
|
1857
|
-
|
|
577
|
+
const providerMetadata = buildProviderMetadata({
|
|
578
|
+
id: response.id,
|
|
579
|
+
provider: void 0,
|
|
580
|
+
// Responses API doesn't expose provider in response
|
|
581
|
+
usage: response.usage ? {
|
|
582
|
+
promptTokens: response.usage.inputTokens,
|
|
583
|
+
completionTokens: response.usage.outputTokens,
|
|
584
|
+
totalTokens: response.usage.totalTokens,
|
|
585
|
+
cost: response.usage.cost ?? void 0,
|
|
586
|
+
// Map inputTokensDetails -> promptTokensDetails
|
|
587
|
+
promptTokensDetails: response.usage.inputTokensDetails ? {
|
|
588
|
+
cachedTokens: response.usage.inputTokensDetails.cachedTokens
|
|
589
|
+
} : void 0,
|
|
590
|
+
// Map outputTokensDetails -> completionTokensDetails
|
|
591
|
+
completionTokensDetails: response.usage.outputTokensDetails ? {
|
|
592
|
+
reasoningTokens: response.usage.outputTokensDetails.reasoningTokens
|
|
593
|
+
} : void 0
|
|
594
|
+
} : void 0
|
|
595
|
+
});
|
|
1858
596
|
return {
|
|
1859
597
|
content,
|
|
1860
|
-
finishReason
|
|
1861
|
-
usage
|
|
1862
|
-
warnings
|
|
1863
|
-
providerMetadata
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
reasoning_details: (_m = choice.message.reasoning_details) != null ? _m : [],
|
|
1867
|
-
annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
|
|
1868
|
-
usage: __spreadValues(__spreadValues(__spreadValues({
|
|
1869
|
-
promptTokens: (_n = usageInfo.inputTokens) != null ? _n : 0,
|
|
1870
|
-
completionTokens: (_o = usageInfo.outputTokens) != null ? _o : 0,
|
|
1871
|
-
totalTokens: (_p = usageInfo.totalTokens) != null ? _p : 0,
|
|
1872
|
-
cost: (_q = response.usage) == null ? void 0 : _q.cost
|
|
1873
|
-
}, ((_s = (_r = response.usage) == null ? void 0 : _r.prompt_tokens_details) == null ? void 0 : _s.cached_tokens) != null ? {
|
|
1874
|
-
promptTokensDetails: {
|
|
1875
|
-
cachedTokens: response.usage.prompt_tokens_details.cached_tokens
|
|
1876
|
-
}
|
|
1877
|
-
} : {}), ((_u = (_t = response.usage) == null ? void 0 : _t.completion_tokens_details) == null ? void 0 : _u.reasoning_tokens) != null ? {
|
|
1878
|
-
completionTokensDetails: {
|
|
1879
|
-
reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
|
|
1880
|
-
}
|
|
1881
|
-
} : {}), ((_w = (_v = response.usage) == null ? void 0 : _v.cost_details) == null ? void 0 : _w.upstream_inference_cost) != null ? {
|
|
1882
|
-
costDetails: {
|
|
1883
|
-
upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
|
|
1884
|
-
}
|
|
1885
|
-
} : {})
|
|
1886
|
-
})
|
|
598
|
+
finishReason,
|
|
599
|
+
usage,
|
|
600
|
+
warnings,
|
|
601
|
+
providerMetadata,
|
|
602
|
+
request: {
|
|
603
|
+
body: requestParams
|
|
1887
604
|
},
|
|
1888
|
-
request: { body: args },
|
|
1889
605
|
response: {
|
|
1890
606
|
id: response.id,
|
|
1891
|
-
|
|
1892
|
-
|
|
607
|
+
timestamp: new Date(response.createdAt * 1e3),
|
|
608
|
+
modelId: response.model
|
|
1893
609
|
}
|
|
1894
610
|
};
|
|
1895
611
|
}
|
|
1896
612
|
async doStream(options) {
|
|
1897
|
-
|
|
1898
|
-
const
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
const { value: response, responseHeaders } = await postJsonToApi({
|
|
1902
|
-
url: this.config.url({
|
|
1903
|
-
path: "/chat/completions",
|
|
1904
|
-
modelId: this.modelId
|
|
1905
|
-
}),
|
|
1906
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
1907
|
-
body: __spreadProps(__spreadValues({}, args), {
|
|
1908
|
-
stream: true,
|
|
1909
|
-
// only include stream_options when in strict compatibility mode:
|
|
1910
|
-
stream_options: this.config.compatibility === "strict" ? __spreadValues({
|
|
1911
|
-
include_usage: true
|
|
1912
|
-
}, ((_a15 = this.settings.usage) == null ? void 0 : _a15.include) ? { include_usage: true } : {}) : void 0
|
|
1913
|
-
}),
|
|
1914
|
-
failedResponseHandler: openrouterFailedResponseHandler,
|
|
1915
|
-
successfulResponseHandler: createEventSourceResponseHandler(
|
|
1916
|
-
OpenRouterStreamChatCompletionChunkSchema
|
|
1917
|
-
),
|
|
1918
|
-
abortSignal: options.abortSignal,
|
|
1919
|
-
fetch: this.config.fetch
|
|
613
|
+
const warnings = [];
|
|
614
|
+
const client = new OpenRouter({
|
|
615
|
+
apiKey: this.settings.apiKey,
|
|
616
|
+
serverURL: this.settings.baseURL
|
|
1920
617
|
});
|
|
1921
|
-
const
|
|
1922
|
-
|
|
1923
|
-
const
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
618
|
+
const openRouterInput = convertToOpenRouterMessages(options.prompt);
|
|
619
|
+
const tools = convertToolsToResponsesFormat(options.tools, warnings);
|
|
620
|
+
const toolChoice = convertToolChoiceToResponsesFormat(options.toolChoice);
|
|
621
|
+
const text = convertResponseFormatToText(options.responseFormat);
|
|
622
|
+
const requestParams = {
|
|
623
|
+
model: this.modelId,
|
|
624
|
+
input: openRouterInput,
|
|
625
|
+
stream: true,
|
|
626
|
+
...options.maxOutputTokens !== void 0 && {
|
|
627
|
+
maxOutputTokens: options.maxOutputTokens
|
|
628
|
+
},
|
|
629
|
+
...options.temperature !== void 0 && {
|
|
630
|
+
temperature: options.temperature
|
|
631
|
+
},
|
|
632
|
+
...options.topP !== void 0 && { topP: options.topP },
|
|
633
|
+
...tools.length > 0 && { tools },
|
|
634
|
+
...toolChoice !== void 0 && { toolChoice },
|
|
635
|
+
...text !== void 0 && { text }
|
|
1929
636
|
};
|
|
1930
|
-
const
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
const
|
|
1950
|
-
|
|
1951
|
-
finishReason = "error";
|
|
1952
|
-
controller.enqueue({ type: "error", error: value.error });
|
|
1953
|
-
return;
|
|
1954
|
-
}
|
|
1955
|
-
if (value.provider) {
|
|
1956
|
-
provider = value.provider;
|
|
1957
|
-
}
|
|
1958
|
-
if (value.id) {
|
|
1959
|
-
openrouterResponseId = value.id;
|
|
1960
|
-
controller.enqueue({
|
|
1961
|
-
type: "response-metadata",
|
|
1962
|
-
id: value.id
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
if (value.model) {
|
|
1966
|
-
controller.enqueue({
|
|
1967
|
-
type: "response-metadata",
|
|
1968
|
-
modelId: value.model
|
|
1969
|
-
});
|
|
1970
|
-
}
|
|
1971
|
-
if (value.usage != null) {
|
|
1972
|
-
usage.inputTokens = value.usage.prompt_tokens;
|
|
1973
|
-
usage.outputTokens = value.usage.completion_tokens;
|
|
1974
|
-
usage.totalTokens = value.usage.prompt_tokens + value.usage.completion_tokens;
|
|
1975
|
-
openrouterUsage.promptTokens = value.usage.prompt_tokens;
|
|
1976
|
-
if (value.usage.prompt_tokens_details) {
|
|
1977
|
-
const cachedInputTokens = (_a16 = value.usage.prompt_tokens_details.cached_tokens) != null ? _a16 : 0;
|
|
1978
|
-
usage.cachedInputTokens = cachedInputTokens;
|
|
1979
|
-
openrouterUsage.promptTokensDetails = {
|
|
1980
|
-
cachedTokens: cachedInputTokens
|
|
1981
|
-
};
|
|
1982
|
-
}
|
|
1983
|
-
openrouterUsage.completionTokens = value.usage.completion_tokens;
|
|
1984
|
-
if (value.usage.completion_tokens_details) {
|
|
1985
|
-
const reasoningTokens = (_b = value.usage.completion_tokens_details.reasoning_tokens) != null ? _b : 0;
|
|
1986
|
-
usage.reasoningTokens = reasoningTokens;
|
|
1987
|
-
openrouterUsage.completionTokensDetails = {
|
|
1988
|
-
reasoningTokens
|
|
1989
|
-
};
|
|
1990
|
-
}
|
|
1991
|
-
openrouterUsage.cost = value.usage.cost;
|
|
1992
|
-
openrouterUsage.totalTokens = value.usage.total_tokens;
|
|
1993
|
-
const upstreamInferenceCost = (_c = value.usage.cost_details) == null ? void 0 : _c.upstream_inference_cost;
|
|
1994
|
-
if (upstreamInferenceCost != null) {
|
|
1995
|
-
openrouterUsage.costDetails = {
|
|
1996
|
-
upstreamInferenceCost
|
|
1997
|
-
};
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
const choice = value.choices[0];
|
|
2001
|
-
if ((choice == null ? void 0 : choice.finish_reason) != null) {
|
|
2002
|
-
finishReason = mapOpenRouterFinishReason(choice.finish_reason);
|
|
2003
|
-
}
|
|
2004
|
-
if ((choice == null ? void 0 : choice.delta) == null) {
|
|
2005
|
-
return;
|
|
2006
|
-
}
|
|
2007
|
-
const delta = choice.delta;
|
|
2008
|
-
const emitReasoningChunk = (chunkText, providerMetadata) => {
|
|
2009
|
-
if (!reasoningStarted) {
|
|
2010
|
-
reasoningId = openrouterResponseId || generateId();
|
|
2011
|
-
controller.enqueue({
|
|
2012
|
-
providerMetadata,
|
|
2013
|
-
type: "reasoning-start",
|
|
2014
|
-
id: reasoningId
|
|
2015
|
-
});
|
|
2016
|
-
reasoningStarted = true;
|
|
2017
|
-
}
|
|
2018
|
-
controller.enqueue({
|
|
2019
|
-
providerMetadata,
|
|
2020
|
-
type: "reasoning-delta",
|
|
2021
|
-
delta: chunkText,
|
|
2022
|
-
id: reasoningId || generateId()
|
|
2023
|
-
});
|
|
2024
|
-
};
|
|
2025
|
-
if (delta.reasoning_details && delta.reasoning_details.length > 0) {
|
|
2026
|
-
for (const detail of delta.reasoning_details) {
|
|
2027
|
-
if (detail.type === "reasoning.text" /* Text */) {
|
|
2028
|
-
const lastDetail = accumulatedReasoningDetails[accumulatedReasoningDetails.length - 1];
|
|
2029
|
-
if ((lastDetail == null ? void 0 : lastDetail.type) === "reasoning.text" /* Text */) {
|
|
2030
|
-
lastDetail.text = (lastDetail.text || "") + (detail.text || "");
|
|
2031
|
-
lastDetail.signature = lastDetail.signature || detail.signature;
|
|
2032
|
-
lastDetail.format = lastDetail.format || detail.format;
|
|
2033
|
-
} else {
|
|
2034
|
-
accumulatedReasoningDetails.push(__spreadValues({}, detail));
|
|
2035
|
-
}
|
|
2036
|
-
} else {
|
|
2037
|
-
accumulatedReasoningDetails.push(detail);
|
|
2038
|
-
}
|
|
2039
|
-
}
|
|
2040
|
-
const reasoningMetadata = {
|
|
2041
|
-
openrouter: {
|
|
2042
|
-
reasoning_details: delta.reasoning_details
|
|
2043
|
-
}
|
|
2044
|
-
};
|
|
2045
|
-
for (const detail of delta.reasoning_details) {
|
|
2046
|
-
switch (detail.type) {
|
|
2047
|
-
case "reasoning.text" /* Text */: {
|
|
2048
|
-
if (detail.text) {
|
|
2049
|
-
emitReasoningChunk(detail.text, reasoningMetadata);
|
|
2050
|
-
}
|
|
2051
|
-
break;
|
|
2052
|
-
}
|
|
2053
|
-
case "reasoning.encrypted" /* Encrypted */: {
|
|
2054
|
-
if (detail.data) {
|
|
2055
|
-
emitReasoningChunk("[REDACTED]", reasoningMetadata);
|
|
2056
|
-
}
|
|
2057
|
-
break;
|
|
2058
|
-
}
|
|
2059
|
-
case "reasoning.summary" /* Summary */: {
|
|
2060
|
-
if (detail.summary) {
|
|
2061
|
-
emitReasoningChunk(detail.summary, reasoningMetadata);
|
|
2062
|
-
}
|
|
2063
|
-
break;
|
|
2064
|
-
}
|
|
2065
|
-
default: {
|
|
2066
|
-
detail;
|
|
2067
|
-
break;
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
} else if (delta.reasoning) {
|
|
2072
|
-
emitReasoningChunk(delta.reasoning);
|
|
2073
|
-
}
|
|
2074
|
-
if (delta.content) {
|
|
2075
|
-
if (reasoningStarted && !textStarted) {
|
|
2076
|
-
controller.enqueue({
|
|
2077
|
-
type: "reasoning-end",
|
|
2078
|
-
id: reasoningId || generateId()
|
|
2079
|
-
});
|
|
2080
|
-
reasoningStarted = false;
|
|
2081
|
-
}
|
|
2082
|
-
if (!textStarted) {
|
|
2083
|
-
textId = openrouterResponseId || generateId();
|
|
2084
|
-
controller.enqueue({
|
|
2085
|
-
type: "text-start",
|
|
2086
|
-
id: textId
|
|
2087
|
-
});
|
|
2088
|
-
textStarted = true;
|
|
2089
|
-
}
|
|
2090
|
-
controller.enqueue({
|
|
2091
|
-
type: "text-delta",
|
|
2092
|
-
delta: delta.content,
|
|
2093
|
-
id: textId || generateId()
|
|
2094
|
-
});
|
|
2095
|
-
}
|
|
2096
|
-
if (delta.annotations) {
|
|
2097
|
-
for (const annotation of delta.annotations) {
|
|
2098
|
-
if (annotation.type === "url_citation") {
|
|
2099
|
-
controller.enqueue({
|
|
2100
|
-
type: "source",
|
|
2101
|
-
sourceType: "url",
|
|
2102
|
-
id: annotation.url_citation.url,
|
|
2103
|
-
url: annotation.url_citation.url,
|
|
2104
|
-
title: annotation.url_citation.title,
|
|
2105
|
-
providerMetadata: {
|
|
2106
|
-
openrouter: {
|
|
2107
|
-
content: annotation.url_citation.content || ""
|
|
2108
|
-
}
|
|
2109
|
-
}
|
|
2110
|
-
});
|
|
2111
|
-
} else if (annotation.type === "file") {
|
|
2112
|
-
const file = annotation.file;
|
|
2113
|
-
if (file && typeof file === "object" && "hash" in file && "name" in file) {
|
|
2114
|
-
accumulatedFileAnnotations.push(
|
|
2115
|
-
annotation
|
|
2116
|
-
);
|
|
2117
|
-
}
|
|
2118
|
-
}
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
if (delta.tool_calls != null) {
|
|
2122
|
-
for (const toolCallDelta of delta.tool_calls) {
|
|
2123
|
-
const index = (_d = toolCallDelta.index) != null ? _d : toolCalls.length - 1;
|
|
2124
|
-
if (toolCalls[index] == null) {
|
|
2125
|
-
if (toolCallDelta.type !== "function") {
|
|
2126
|
-
throw new InvalidResponseDataError({
|
|
2127
|
-
data: toolCallDelta,
|
|
2128
|
-
message: `Expected 'function' type.`
|
|
2129
|
-
});
|
|
2130
|
-
}
|
|
2131
|
-
if (toolCallDelta.id == null) {
|
|
2132
|
-
throw new InvalidResponseDataError({
|
|
2133
|
-
data: toolCallDelta,
|
|
2134
|
-
message: `Expected 'id' to be a string.`
|
|
2135
|
-
});
|
|
2136
|
-
}
|
|
2137
|
-
if (((_e = toolCallDelta.function) == null ? void 0 : _e.name) == null) {
|
|
2138
|
-
throw new InvalidResponseDataError({
|
|
2139
|
-
data: toolCallDelta,
|
|
2140
|
-
message: `Expected 'function.name' to be a string.`
|
|
2141
|
-
});
|
|
2142
|
-
}
|
|
2143
|
-
toolCalls[index] = {
|
|
2144
|
-
id: toolCallDelta.id,
|
|
2145
|
-
type: "function",
|
|
2146
|
-
function: {
|
|
2147
|
-
name: toolCallDelta.function.name,
|
|
2148
|
-
arguments: (_f = toolCallDelta.function.arguments) != null ? _f : ""
|
|
2149
|
-
},
|
|
2150
|
-
inputStarted: false,
|
|
2151
|
-
sent: false
|
|
2152
|
-
};
|
|
2153
|
-
const toolCall2 = toolCalls[index];
|
|
2154
|
-
if (toolCall2 == null) {
|
|
2155
|
-
throw new InvalidResponseDataError({
|
|
2156
|
-
data: { index, toolCallsLength: toolCalls.length },
|
|
2157
|
-
message: `Tool call at index ${index} is missing after creation.`
|
|
2158
|
-
});
|
|
2159
|
-
}
|
|
2160
|
-
if (((_g = toolCall2.function) == null ? void 0 : _g.name) != null && ((_h = toolCall2.function) == null ? void 0 : _h.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
|
|
2161
|
-
toolCall2.inputStarted = true;
|
|
2162
|
-
controller.enqueue({
|
|
2163
|
-
type: "tool-input-start",
|
|
2164
|
-
id: toolCall2.id,
|
|
2165
|
-
toolName: toolCall2.function.name
|
|
2166
|
-
});
|
|
2167
|
-
controller.enqueue({
|
|
2168
|
-
type: "tool-input-delta",
|
|
2169
|
-
id: toolCall2.id,
|
|
2170
|
-
delta: toolCall2.function.arguments
|
|
2171
|
-
});
|
|
2172
|
-
controller.enqueue({
|
|
2173
|
-
type: "tool-input-end",
|
|
2174
|
-
id: toolCall2.id
|
|
2175
|
-
});
|
|
2176
|
-
controller.enqueue({
|
|
2177
|
-
type: "tool-call",
|
|
2178
|
-
toolCallId: toolCall2.id,
|
|
2179
|
-
toolName: toolCall2.function.name,
|
|
2180
|
-
input: toolCall2.function.arguments,
|
|
2181
|
-
providerMetadata: {
|
|
2182
|
-
openrouter: {
|
|
2183
|
-
reasoning_details: accumulatedReasoningDetails
|
|
2184
|
-
}
|
|
2185
|
-
}
|
|
2186
|
-
});
|
|
2187
|
-
toolCall2.sent = true;
|
|
2188
|
-
}
|
|
2189
|
-
continue;
|
|
2190
|
-
}
|
|
2191
|
-
const toolCall = toolCalls[index];
|
|
2192
|
-
if (toolCall == null) {
|
|
2193
|
-
throw new InvalidResponseDataError({
|
|
2194
|
-
data: {
|
|
2195
|
-
index,
|
|
2196
|
-
toolCallsLength: toolCalls.length,
|
|
2197
|
-
toolCallDelta
|
|
2198
|
-
},
|
|
2199
|
-
message: `Tool call at index ${index} is missing during merge.`
|
|
2200
|
-
});
|
|
2201
|
-
}
|
|
2202
|
-
if (!toolCall.inputStarted) {
|
|
2203
|
-
toolCall.inputStarted = true;
|
|
2204
|
-
controller.enqueue({
|
|
2205
|
-
type: "tool-input-start",
|
|
2206
|
-
id: toolCall.id,
|
|
2207
|
-
toolName: toolCall.function.name
|
|
2208
|
-
});
|
|
2209
|
-
}
|
|
2210
|
-
if (((_i = toolCallDelta.function) == null ? void 0 : _i.arguments) != null) {
|
|
2211
|
-
toolCall.function.arguments += (_k = (_j = toolCallDelta.function) == null ? void 0 : _j.arguments) != null ? _k : "";
|
|
2212
|
-
}
|
|
2213
|
-
controller.enqueue({
|
|
2214
|
-
type: "tool-input-delta",
|
|
2215
|
-
id: toolCall.id,
|
|
2216
|
-
delta: (_l = toolCallDelta.function.arguments) != null ? _l : ""
|
|
2217
|
-
});
|
|
2218
|
-
if (((_m = toolCall.function) == null ? void 0 : _m.name) != null && ((_n = toolCall.function) == null ? void 0 : _n.arguments) != null && isParsableJson(toolCall.function.arguments)) {
|
|
2219
|
-
controller.enqueue({
|
|
2220
|
-
type: "tool-call",
|
|
2221
|
-
toolCallId: (_o = toolCall.id) != null ? _o : generateId(),
|
|
2222
|
-
toolName: toolCall.function.name,
|
|
2223
|
-
input: toolCall.function.arguments,
|
|
2224
|
-
providerMetadata: {
|
|
2225
|
-
openrouter: {
|
|
2226
|
-
reasoning_details: accumulatedReasoningDetails
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
});
|
|
2230
|
-
toolCall.sent = true;
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
}
|
|
2234
|
-
if (delta.images != null) {
|
|
2235
|
-
for (const image of delta.images) {
|
|
2236
|
-
controller.enqueue({
|
|
2237
|
-
type: "file",
|
|
2238
|
-
mediaType: getMediaType(image.image_url.url, "image/jpeg"),
|
|
2239
|
-
data: getBase64FromDataUrl(image.image_url.url)
|
|
2240
|
-
});
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
},
|
|
2244
|
-
flush(controller) {
|
|
2245
|
-
var _a16;
|
|
2246
|
-
const hasToolCalls = toolCalls.length > 0;
|
|
2247
|
-
const hasEncryptedReasoning = accumulatedReasoningDetails.some(
|
|
2248
|
-
(d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
|
|
2249
|
-
);
|
|
2250
|
-
if (hasToolCalls && hasEncryptedReasoning && finishReason === "stop") {
|
|
2251
|
-
finishReason = "tool-calls";
|
|
2252
|
-
}
|
|
2253
|
-
if (finishReason === "tool-calls") {
|
|
2254
|
-
for (const toolCall of toolCalls) {
|
|
2255
|
-
if (toolCall && !toolCall.sent) {
|
|
2256
|
-
controller.enqueue({
|
|
2257
|
-
type: "tool-call",
|
|
2258
|
-
toolCallId: (_a16 = toolCall.id) != null ? _a16 : generateId(),
|
|
2259
|
-
toolName: toolCall.function.name,
|
|
2260
|
-
// Coerce invalid arguments to an empty JSON object
|
|
2261
|
-
input: isParsableJson(toolCall.function.arguments) ? toolCall.function.arguments : "{}",
|
|
2262
|
-
providerMetadata: {
|
|
2263
|
-
openrouter: {
|
|
2264
|
-
reasoning_details: accumulatedReasoningDetails
|
|
2265
|
-
}
|
|
2266
|
-
}
|
|
2267
|
-
});
|
|
2268
|
-
toolCall.sent = true;
|
|
2269
|
-
}
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
if (reasoningStarted) {
|
|
2273
|
-
controller.enqueue({
|
|
2274
|
-
type: "reasoning-end",
|
|
2275
|
-
id: reasoningId || generateId()
|
|
2276
|
-
});
|
|
2277
|
-
}
|
|
2278
|
-
if (textStarted) {
|
|
2279
|
-
controller.enqueue({
|
|
2280
|
-
type: "text-end",
|
|
2281
|
-
id: textId || generateId()
|
|
2282
|
-
});
|
|
2283
|
-
}
|
|
2284
|
-
const openrouterMetadata = {
|
|
2285
|
-
usage: openrouterUsage
|
|
2286
|
-
};
|
|
2287
|
-
if (provider !== void 0) {
|
|
2288
|
-
openrouterMetadata.provider = provider;
|
|
2289
|
-
}
|
|
2290
|
-
if (accumulatedReasoningDetails.length > 0) {
|
|
2291
|
-
openrouterMetadata.reasoning_details = accumulatedReasoningDetails;
|
|
2292
|
-
}
|
|
2293
|
-
if (accumulatedFileAnnotations.length > 0) {
|
|
2294
|
-
openrouterMetadata.annotations = accumulatedFileAnnotations;
|
|
637
|
+
const combinedHeaders = normalizeHeaders(
|
|
638
|
+
combineHeaders(this.settings.headers, options.headers)
|
|
639
|
+
);
|
|
640
|
+
const eventStream = await client.beta.responses.send(requestParams, {
|
|
641
|
+
fetchOptions: {
|
|
642
|
+
signal: options.abortSignal,
|
|
643
|
+
headers: combinedHeaders
|
|
644
|
+
}
|
|
645
|
+
});
|
|
646
|
+
const state = createStreamState();
|
|
647
|
+
const transformedStream = new ReadableStream({
|
|
648
|
+
async start(controller) {
|
|
649
|
+
controller.enqueue({
|
|
650
|
+
type: "stream-start",
|
|
651
|
+
warnings
|
|
652
|
+
});
|
|
653
|
+
try {
|
|
654
|
+
for await (const event of eventStream) {
|
|
655
|
+
const parts = transformResponsesEvent(event, state);
|
|
656
|
+
for (const part of parts) {
|
|
657
|
+
controller.enqueue(part);
|
|
2295
658
|
}
|
|
2296
|
-
controller.enqueue({
|
|
2297
|
-
type: "finish",
|
|
2298
|
-
finishReason,
|
|
2299
|
-
usage,
|
|
2300
|
-
providerMetadata: {
|
|
2301
|
-
openrouter: openrouterMetadata
|
|
2302
|
-
}
|
|
2303
|
-
});
|
|
2304
659
|
}
|
|
2305
|
-
})
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
660
|
+
} catch (error) {
|
|
661
|
+
controller.enqueue({
|
|
662
|
+
type: "error",
|
|
663
|
+
error
|
|
664
|
+
});
|
|
665
|
+
} finally {
|
|
666
|
+
controller.close();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
return {
|
|
671
|
+
stream: transformedStream,
|
|
672
|
+
request: {
|
|
673
|
+
body: requestParams
|
|
674
|
+
}
|
|
2310
675
|
};
|
|
2311
676
|
}
|
|
2312
677
|
};
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
678
|
+
function createStreamState() {
|
|
679
|
+
return {
|
|
680
|
+
responseId: void 0,
|
|
681
|
+
responseModel: void 0,
|
|
682
|
+
responseCreated: void 0,
|
|
683
|
+
textStarted: false,
|
|
684
|
+
textId: "text-0",
|
|
685
|
+
reasoningStarted: false,
|
|
686
|
+
reasoningId: "reasoning-0",
|
|
687
|
+
textEnded: false,
|
|
688
|
+
reasoningEnded: false,
|
|
689
|
+
sourceIds: [],
|
|
690
|
+
toolCalls: /* @__PURE__ */ new Map()
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function transformResponsesEvent(event, state) {
|
|
694
|
+
const parts = [];
|
|
695
|
+
switch (event.type) {
|
|
696
|
+
// Response lifecycle events
|
|
697
|
+
case "response.created":
|
|
698
|
+
case "response.in_progress": {
|
|
699
|
+
if (event.response) {
|
|
700
|
+
state.responseId = event.response.id;
|
|
701
|
+
state.responseModel = event.response.model;
|
|
702
|
+
state.responseCreated = event.response.createdAt;
|
|
703
|
+
}
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
// Text streaming
|
|
707
|
+
case "response.output_text.delta": {
|
|
708
|
+
if (!state.textStarted) {
|
|
709
|
+
state.textStarted = true;
|
|
710
|
+
parts.push({
|
|
711
|
+
type: "text-start",
|
|
712
|
+
id: state.textId
|
|
2337
713
|
});
|
|
2338
714
|
}
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
case "file": {
|
|
2346
|
-
throw new UnsupportedFunctionalityError({
|
|
2347
|
-
functionality: "file attachments"
|
|
2348
|
-
});
|
|
2349
|
-
}
|
|
2350
|
-
default: {
|
|
2351
|
-
return "";
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
}).join("");
|
|
2355
|
-
text += `${user}:
|
|
2356
|
-
${userMessage}
|
|
2357
|
-
|
|
2358
|
-
`;
|
|
2359
|
-
break;
|
|
715
|
+
if (event.delta && event.delta.length > 0) {
|
|
716
|
+
parts.push({
|
|
717
|
+
type: "text-delta",
|
|
718
|
+
id: state.textId,
|
|
719
|
+
delta: event.delta
|
|
720
|
+
});
|
|
2360
721
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
});
|
|
2382
|
-
}
|
|
2383
|
-
case "file": {
|
|
2384
|
-
throw new UnsupportedFunctionalityError({
|
|
2385
|
-
functionality: "file attachments"
|
|
2386
|
-
});
|
|
2387
|
-
}
|
|
2388
|
-
default: {
|
|
2389
|
-
return "";
|
|
2390
|
-
}
|
|
2391
|
-
}
|
|
2392
|
-
}
|
|
2393
|
-
).join("");
|
|
2394
|
-
text += `${assistant}:
|
|
2395
|
-
${assistantMessage}
|
|
2396
|
-
|
|
2397
|
-
`;
|
|
2398
|
-
break;
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
case "response.output_text.done": {
|
|
725
|
+
if (state.textStarted && !state.textEnded) {
|
|
726
|
+
state.textEnded = true;
|
|
727
|
+
parts.push({
|
|
728
|
+
type: "text-end",
|
|
729
|
+
id: state.textId
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
break;
|
|
733
|
+
}
|
|
734
|
+
// Reasoning streaming
|
|
735
|
+
case "response.reasoning_text.delta": {
|
|
736
|
+
if (!state.reasoningStarted) {
|
|
737
|
+
state.reasoningStarted = true;
|
|
738
|
+
parts.push({
|
|
739
|
+
type: "reasoning-start",
|
|
740
|
+
id: state.reasoningId
|
|
741
|
+
});
|
|
2399
742
|
}
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
743
|
+
if (event.delta && event.delta.length > 0) {
|
|
744
|
+
parts.push({
|
|
745
|
+
type: "reasoning-delta",
|
|
746
|
+
id: state.reasoningId,
|
|
747
|
+
delta: event.delta
|
|
2403
748
|
});
|
|
2404
749
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
// Function call arguments streaming
|
|
753
|
+
case "response.function_call_arguments.delta": {
|
|
754
|
+
const toolCallId = event.itemId;
|
|
755
|
+
let toolState = state.toolCalls.get(toolCallId);
|
|
756
|
+
if (!toolState) {
|
|
757
|
+
toolState = { argumentsStarted: false };
|
|
758
|
+
state.toolCalls.set(toolCallId, toolState);
|
|
759
|
+
}
|
|
760
|
+
if (!toolState.argumentsStarted) {
|
|
761
|
+
toolState.argumentsStarted = true;
|
|
762
|
+
parts.push({
|
|
763
|
+
type: "tool-input-start",
|
|
764
|
+
id: toolCallId,
|
|
765
|
+
toolName: toolState.name ?? ""
|
|
766
|
+
// Will be filled in by output_item.added
|
|
767
|
+
});
|
|
2407
768
|
}
|
|
769
|
+
if (event.delta && event.delta.length > 0) {
|
|
770
|
+
parts.push({
|
|
771
|
+
type: "tool-input-delta",
|
|
772
|
+
id: toolCallId,
|
|
773
|
+
delta: event.delta
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
break;
|
|
2408
777
|
}
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
778
|
+
case "response.function_call_arguments.done": {
|
|
779
|
+
const toolCallId = event.itemId;
|
|
780
|
+
const toolState = state.toolCalls.get(toolCallId);
|
|
781
|
+
if (!toolState?.argumentsStarted) {
|
|
782
|
+
parts.push({
|
|
783
|
+
type: "tool-input-start",
|
|
784
|
+
id: toolCallId,
|
|
785
|
+
toolName: event.name
|
|
786
|
+
});
|
|
787
|
+
const args = event.arguments || "{}";
|
|
788
|
+
parts.push({
|
|
789
|
+
type: "tool-input-delta",
|
|
790
|
+
id: toolCallId,
|
|
791
|
+
delta: args
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
parts.push({
|
|
795
|
+
type: "tool-input-end",
|
|
796
|
+
id: toolCallId
|
|
797
|
+
});
|
|
798
|
+
parts.push({
|
|
799
|
+
type: "tool-call",
|
|
800
|
+
toolCallId,
|
|
801
|
+
toolName: event.name,
|
|
802
|
+
input: event.arguments || "{}"
|
|
803
|
+
});
|
|
804
|
+
break;
|
|
805
|
+
}
|
|
806
|
+
// Output item events (for function call metadata)
|
|
807
|
+
case "response.output_item.added": {
|
|
808
|
+
if (event.item.type === "function_call") {
|
|
809
|
+
const funcItem = event.item;
|
|
810
|
+
const toolCallId = funcItem.callId ?? `tool-${event.outputIndex}`;
|
|
811
|
+
const toolState = state.toolCalls.get(toolCallId) ?? {
|
|
812
|
+
argumentsStarted: false
|
|
813
|
+
};
|
|
814
|
+
toolState.name = funcItem.name;
|
|
815
|
+
state.toolCalls.set(toolCallId, toolState);
|
|
816
|
+
}
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
// Annotation events (web search sources)
|
|
820
|
+
case "response.output_text.annotation.added": {
|
|
821
|
+
const annotation = event.annotation;
|
|
822
|
+
if (annotation.type === "url_citation") {
|
|
823
|
+
const urlAnnotation = annotation;
|
|
824
|
+
const sourceId = `source-${state.sourceIds.length}`;
|
|
825
|
+
state.sourceIds.push(sourceId);
|
|
826
|
+
parts.push({
|
|
827
|
+
type: "source",
|
|
828
|
+
sourceType: "url",
|
|
829
|
+
id: sourceId,
|
|
830
|
+
url: urlAnnotation.url,
|
|
831
|
+
title: urlAnnotation.title
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
break;
|
|
835
|
+
}
|
|
836
|
+
// Response completed - extract final usage data
|
|
837
|
+
case "response.completed": {
|
|
838
|
+
if (state.textStarted && !state.textEnded) {
|
|
839
|
+
state.textEnded = true;
|
|
840
|
+
parts.push({
|
|
841
|
+
type: "text-end",
|
|
842
|
+
id: state.textId
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
if (state.reasoningStarted && !state.reasoningEnded) {
|
|
846
|
+
state.reasoningEnded = true;
|
|
847
|
+
parts.push({
|
|
848
|
+
type: "reasoning-end",
|
|
849
|
+
id: state.reasoningId
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
const response = event.response;
|
|
853
|
+
parts.push({
|
|
854
|
+
type: "response-metadata",
|
|
855
|
+
id: response.id,
|
|
856
|
+
timestamp: response.createdAt ? new Date(response.createdAt * 1e3) : void 0,
|
|
857
|
+
modelId: response.model
|
|
858
|
+
});
|
|
859
|
+
const finishReason = mapOpenRouterFinishReason(
|
|
860
|
+
response.status === "completed" ? "stop" : response.status ?? "stop"
|
|
861
|
+
);
|
|
862
|
+
const usage = buildUsage(
|
|
863
|
+
response.usage ? {
|
|
864
|
+
inputTokens: response.usage.inputTokens,
|
|
865
|
+
outputTokens: response.usage.outputTokens
|
|
866
|
+
} : void 0
|
|
867
|
+
);
|
|
868
|
+
const providerMetadata = buildProviderMetadata({
|
|
869
|
+
id: response.id,
|
|
870
|
+
provider: void 0,
|
|
871
|
+
// Responses API doesn't expose provider
|
|
872
|
+
usage: response.usage ? {
|
|
873
|
+
promptTokens: response.usage.inputTokens,
|
|
874
|
+
completionTokens: response.usage.outputTokens,
|
|
875
|
+
totalTokens: response.usage.totalTokens,
|
|
876
|
+
cost: response.usage.cost ?? void 0,
|
|
877
|
+
// Map inputTokensDetails -> promptTokensDetails
|
|
878
|
+
promptTokensDetails: response.usage.inputTokensDetails ? {
|
|
879
|
+
cachedTokens: response.usage.inputTokensDetails.cachedTokens
|
|
880
|
+
} : void 0,
|
|
881
|
+
// Map outputTokensDetails -> completionTokensDetails
|
|
882
|
+
completionTokensDetails: response.usage.outputTokensDetails ? {
|
|
883
|
+
reasoningTokens: response.usage.outputTokensDetails.reasoningTokens
|
|
884
|
+
} : void 0
|
|
885
|
+
} : void 0
|
|
886
|
+
});
|
|
887
|
+
parts.push({
|
|
888
|
+
type: "finish",
|
|
889
|
+
finishReason,
|
|
890
|
+
usage,
|
|
891
|
+
providerMetadata
|
|
2496
892
|
});
|
|
893
|
+
break;
|
|
2497
894
|
}
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
895
|
+
// Response incomplete or failed
|
|
896
|
+
case "response.incomplete":
|
|
897
|
+
case "response.failed": {
|
|
898
|
+
if (state.textStarted && !state.textEnded) {
|
|
899
|
+
state.textEnded = true;
|
|
900
|
+
parts.push({
|
|
901
|
+
type: "text-end",
|
|
902
|
+
id: state.textId
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
if (state.reasoningStarted && !state.reasoningEnded) {
|
|
906
|
+
state.reasoningEnded = true;
|
|
907
|
+
parts.push({
|
|
908
|
+
type: "reasoning-end",
|
|
909
|
+
id: state.reasoningId
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
const response = event.response;
|
|
913
|
+
parts.push({
|
|
914
|
+
type: "response-metadata",
|
|
915
|
+
id: response.id,
|
|
916
|
+
timestamp: response.createdAt ? new Date(response.createdAt * 1e3) : void 0,
|
|
917
|
+
modelId: response.model
|
|
2501
918
|
});
|
|
919
|
+
const finishReason = event.type === "response.failed" ? mapOpenRouterFinishReason("error") : mapOpenRouterFinishReason(response.status ?? "incomplete");
|
|
920
|
+
const usage = buildUsage(
|
|
921
|
+
response.usage ? {
|
|
922
|
+
inputTokens: response.usage.inputTokens,
|
|
923
|
+
outputTokens: response.usage.outputTokens
|
|
924
|
+
} : void 0
|
|
925
|
+
);
|
|
926
|
+
const providerMetadata = buildProviderMetadata({
|
|
927
|
+
id: response.id,
|
|
928
|
+
provider: void 0,
|
|
929
|
+
usage: response.usage ? {
|
|
930
|
+
promptTokens: response.usage.inputTokens,
|
|
931
|
+
completionTokens: response.usage.outputTokens,
|
|
932
|
+
totalTokens: response.usage.totalTokens,
|
|
933
|
+
cost: response.usage.cost ?? void 0,
|
|
934
|
+
// Map inputTokensDetails -> promptTokensDetails
|
|
935
|
+
promptTokensDetails: response.usage.inputTokensDetails ? {
|
|
936
|
+
cachedTokens: response.usage.inputTokensDetails.cachedTokens
|
|
937
|
+
} : void 0,
|
|
938
|
+
// Map outputTokensDetails -> completionTokensDetails
|
|
939
|
+
completionTokensDetails: response.usage.outputTokensDetails ? {
|
|
940
|
+
reasoningTokens: response.usage.outputTokensDetails.reasoningTokens
|
|
941
|
+
} : void 0
|
|
942
|
+
} : void 0
|
|
943
|
+
});
|
|
944
|
+
parts.push({
|
|
945
|
+
type: "finish",
|
|
946
|
+
finishReason,
|
|
947
|
+
usage,
|
|
948
|
+
providerMetadata
|
|
949
|
+
});
|
|
950
|
+
break;
|
|
2502
951
|
}
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
user: this.settings.user,
|
|
2512
|
-
// standardized settings:
|
|
2513
|
-
max_tokens: maxOutputTokens,
|
|
2514
|
-
temperature,
|
|
2515
|
-
top_p: topP,
|
|
2516
|
-
frequency_penalty: frequencyPenalty,
|
|
2517
|
-
presence_penalty: presencePenalty,
|
|
2518
|
-
seed,
|
|
2519
|
-
stop: stopSequences,
|
|
2520
|
-
response_format: responseFormat,
|
|
2521
|
-
top_k: topK,
|
|
2522
|
-
// prompt:
|
|
2523
|
-
prompt: completionPrompt,
|
|
2524
|
-
// OpenRouter specific settings:
|
|
2525
|
-
include_reasoning: this.settings.includeReasoning,
|
|
2526
|
-
reasoning: this.settings.reasoning
|
|
2527
|
-
}, this.config.extraBody), this.settings.extraBody);
|
|
2528
|
-
}
|
|
2529
|
-
async doGenerate(options) {
|
|
2530
|
-
var _a15, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
2531
|
-
const providerOptions = options.providerOptions || {};
|
|
2532
|
-
const openrouterOptions = providerOptions.openrouter || {};
|
|
2533
|
-
const args = __spreadValues(__spreadValues({}, this.getArgs(options)), openrouterOptions);
|
|
2534
|
-
const { value: response, responseHeaders } = await postJsonToApi({
|
|
2535
|
-
url: this.config.url({
|
|
2536
|
-
path: "/completions",
|
|
2537
|
-
modelId: this.modelId
|
|
2538
|
-
}),
|
|
2539
|
-
headers: combineHeaders(this.config.headers(), options.headers),
|
|
2540
|
-
body: args,
|
|
2541
|
-
failedResponseHandler: openrouterFailedResponseHandler,
|
|
2542
|
-
successfulResponseHandler: createJsonResponseHandler(
|
|
2543
|
-
OpenRouterCompletionChunkSchema
|
|
2544
|
-
),
|
|
2545
|
-
abortSignal: options.abortSignal,
|
|
2546
|
-
fetch: this.config.fetch
|
|
2547
|
-
});
|
|
2548
|
-
if ("error" in response) {
|
|
2549
|
-
const errorData = response.error;
|
|
2550
|
-
throw new APICallError({
|
|
2551
|
-
message: errorData.message,
|
|
2552
|
-
url: this.config.url({
|
|
2553
|
-
path: "/completions",
|
|
2554
|
-
modelId: this.modelId
|
|
2555
|
-
}),
|
|
2556
|
-
requestBodyValues: args,
|
|
2557
|
-
statusCode: 200,
|
|
2558
|
-
responseHeaders,
|
|
2559
|
-
data: errorData
|
|
952
|
+
// Error event
|
|
953
|
+
case "error": {
|
|
954
|
+
const errorEvent = event;
|
|
955
|
+
parts.push({
|
|
956
|
+
type: "error",
|
|
957
|
+
error: new Error(
|
|
958
|
+
errorEvent.error?.message ?? "Unknown streaming error"
|
|
959
|
+
)
|
|
2560
960
|
});
|
|
961
|
+
break;
|
|
2561
962
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
963
|
+
// Ignored events (handled implicitly or not needed)
|
|
964
|
+
case "response.output_item.done":
|
|
965
|
+
case "response.content_part.added":
|
|
966
|
+
case "response.content_part.done":
|
|
967
|
+
case "response.refusal.delta":
|
|
968
|
+
case "response.refusal.done":
|
|
969
|
+
case "response.reasoning_text.done":
|
|
970
|
+
case "response.reasoning_summary_part.added":
|
|
971
|
+
case "response.reasoning_summary_part.done":
|
|
972
|
+
case "response.reasoning_summary_text.delta":
|
|
973
|
+
case "response.reasoning_summary_text.done":
|
|
974
|
+
case "response.image_generation_call.in_progress":
|
|
975
|
+
case "response.image_generation_call.generating":
|
|
976
|
+
case "response.image_generation_call.partial_image":
|
|
977
|
+
case "response.image_generation_call.completed":
|
|
978
|
+
break;
|
|
979
|
+
}
|
|
980
|
+
return parts;
|
|
981
|
+
}
|
|
982
|
+
function convertToolsToResponsesFormat(tools, warnings) {
|
|
983
|
+
if (!tools || tools.length === 0) {
|
|
984
|
+
return [];
|
|
985
|
+
}
|
|
986
|
+
return tools.map((tool) => {
|
|
987
|
+
if (tool.type !== "function") {
|
|
988
|
+
warnings.push({
|
|
989
|
+
type: "unsupported",
|
|
990
|
+
feature: `tool type '${tool.type}'`,
|
|
991
|
+
details: `Only 'function' type tools are supported. Tool '${tool.name ?? "unknown"}' has type '${tool.type}'.`
|
|
2566
992
|
});
|
|
993
|
+
return null;
|
|
2567
994
|
}
|
|
995
|
+
const functionTool = tool;
|
|
2568
996
|
return {
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
}
|
|
2574
|
-
],
|
|
2575
|
-
finishReason: mapOpenRouterFinishReason(choice.finish_reason),
|
|
2576
|
-
usage: {
|
|
2577
|
-
inputTokens: (_c = (_b = response.usage) == null ? void 0 : _b.prompt_tokens) != null ? _c : 0,
|
|
2578
|
-
outputTokens: (_e = (_d = response.usage) == null ? void 0 : _d.completion_tokens) != null ? _e : 0,
|
|
2579
|
-
totalTokens: ((_g = (_f = response.usage) == null ? void 0 : _f.prompt_tokens) != null ? _g : 0) + ((_i = (_h = response.usage) == null ? void 0 : _h.completion_tokens) != null ? _i : 0),
|
|
2580
|
-
reasoningTokens: (_l = (_k = (_j = response.usage) == null ? void 0 : _j.completion_tokens_details) == null ? void 0 : _k.reasoning_tokens) != null ? _l : 0,
|
|
2581
|
-
cachedInputTokens: (_o = (_n = (_m = response.usage) == null ? void 0 : _m.prompt_tokens_details) == null ? void 0 : _n.cached_tokens) != null ? _o : 0
|
|
2582
|
-
},
|
|
2583
|
-
warnings: [],
|
|
2584
|
-
response: {
|
|
2585
|
-
headers: responseHeaders
|
|
2586
|
-
}
|
|
997
|
+
type: "function",
|
|
998
|
+
name: functionTool.name,
|
|
999
|
+
description: functionTool.description ?? null,
|
|
1000
|
+
parameters: functionTool.inputSchema
|
|
2587
1001
|
};
|
|
1002
|
+
}).filter((tool) => tool !== null);
|
|
1003
|
+
}
|
|
1004
|
+
function convertToolChoiceToResponsesFormat(toolChoice) {
|
|
1005
|
+
if (!toolChoice) {
|
|
1006
|
+
return void 0;
|
|
2588
1007
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
const usage = {
|
|
2613
|
-
inputTokens: Number.NaN,
|
|
2614
|
-
outputTokens: Number.NaN,
|
|
2615
|
-
totalTokens: Number.NaN,
|
|
2616
|
-
reasoningTokens: Number.NaN,
|
|
2617
|
-
cachedInputTokens: Number.NaN
|
|
1008
|
+
switch (toolChoice.type) {
|
|
1009
|
+
case "auto":
|
|
1010
|
+
return "auto";
|
|
1011
|
+
case "none":
|
|
1012
|
+
return "none";
|
|
1013
|
+
case "required":
|
|
1014
|
+
return "required";
|
|
1015
|
+
case "tool":
|
|
1016
|
+
return {
|
|
1017
|
+
type: "function",
|
|
1018
|
+
name: toolChoice.toolName
|
|
1019
|
+
};
|
|
1020
|
+
default:
|
|
1021
|
+
return void 0;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
function convertResponseFormatToText(responseFormat) {
|
|
1025
|
+
if (!responseFormat) {
|
|
1026
|
+
return void 0;
|
|
1027
|
+
}
|
|
1028
|
+
if (responseFormat.type === "text") {
|
|
1029
|
+
return {
|
|
1030
|
+
format: { type: "text" }
|
|
2618
1031
|
};
|
|
2619
|
-
|
|
1032
|
+
}
|
|
1033
|
+
if (responseFormat.type === "json") {
|
|
1034
|
+
if (responseFormat.schema) {
|
|
1035
|
+
return {
|
|
1036
|
+
format: {
|
|
1037
|
+
type: "json_schema",
|
|
1038
|
+
name: responseFormat.name ?? "response",
|
|
1039
|
+
description: responseFormat.description,
|
|
1040
|
+
schema: responseFormat.schema
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
2620
1044
|
return {
|
|
2621
|
-
|
|
2622
|
-
new TransformStream({
|
|
2623
|
-
transform(chunk, controller) {
|
|
2624
|
-
var _a15, _b, _c;
|
|
2625
|
-
if (!chunk.success) {
|
|
2626
|
-
finishReason = "error";
|
|
2627
|
-
controller.enqueue({ type: "error", error: chunk.error });
|
|
2628
|
-
return;
|
|
2629
|
-
}
|
|
2630
|
-
const value = chunk.value;
|
|
2631
|
-
if ("error" in value) {
|
|
2632
|
-
finishReason = "error";
|
|
2633
|
-
controller.enqueue({ type: "error", error: value.error });
|
|
2634
|
-
return;
|
|
2635
|
-
}
|
|
2636
|
-
if (value.usage != null) {
|
|
2637
|
-
usage.inputTokens = value.usage.prompt_tokens;
|
|
2638
|
-
usage.outputTokens = value.usage.completion_tokens;
|
|
2639
|
-
usage.totalTokens = value.usage.prompt_tokens + value.usage.completion_tokens;
|
|
2640
|
-
openrouterUsage.promptTokens = value.usage.prompt_tokens;
|
|
2641
|
-
if (value.usage.prompt_tokens_details) {
|
|
2642
|
-
const cachedInputTokens = (_a15 = value.usage.prompt_tokens_details.cached_tokens) != null ? _a15 : 0;
|
|
2643
|
-
usage.cachedInputTokens = cachedInputTokens;
|
|
2644
|
-
openrouterUsage.promptTokensDetails = {
|
|
2645
|
-
cachedTokens: cachedInputTokens
|
|
2646
|
-
};
|
|
2647
|
-
}
|
|
2648
|
-
openrouterUsage.completionTokens = value.usage.completion_tokens;
|
|
2649
|
-
if (value.usage.completion_tokens_details) {
|
|
2650
|
-
const reasoningTokens = (_b = value.usage.completion_tokens_details.reasoning_tokens) != null ? _b : 0;
|
|
2651
|
-
usage.reasoningTokens = reasoningTokens;
|
|
2652
|
-
openrouterUsage.completionTokensDetails = {
|
|
2653
|
-
reasoningTokens
|
|
2654
|
-
};
|
|
2655
|
-
}
|
|
2656
|
-
openrouterUsage.cost = value.usage.cost;
|
|
2657
|
-
openrouterUsage.totalTokens = value.usage.total_tokens;
|
|
2658
|
-
const upstreamInferenceCost = (_c = value.usage.cost_details) == null ? void 0 : _c.upstream_inference_cost;
|
|
2659
|
-
if (upstreamInferenceCost != null) {
|
|
2660
|
-
openrouterUsage.costDetails = {
|
|
2661
|
-
upstreamInferenceCost
|
|
2662
|
-
};
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
|
-
const choice = value.choices[0];
|
|
2666
|
-
if ((choice == null ? void 0 : choice.finish_reason) != null) {
|
|
2667
|
-
finishReason = mapOpenRouterFinishReason(choice.finish_reason);
|
|
2668
|
-
}
|
|
2669
|
-
if ((choice == null ? void 0 : choice.text) != null) {
|
|
2670
|
-
controller.enqueue({
|
|
2671
|
-
type: "text-delta",
|
|
2672
|
-
delta: choice.text,
|
|
2673
|
-
id: generateId()
|
|
2674
|
-
});
|
|
2675
|
-
}
|
|
2676
|
-
},
|
|
2677
|
-
flush(controller) {
|
|
2678
|
-
controller.enqueue({
|
|
2679
|
-
type: "finish",
|
|
2680
|
-
finishReason,
|
|
2681
|
-
usage,
|
|
2682
|
-
providerMetadata: {
|
|
2683
|
-
openrouter: {
|
|
2684
|
-
usage: openrouterUsage
|
|
2685
|
-
}
|
|
2686
|
-
}
|
|
2687
|
-
});
|
|
2688
|
-
}
|
|
2689
|
-
})
|
|
2690
|
-
),
|
|
2691
|
-
response: {
|
|
2692
|
-
headers: responseHeaders
|
|
2693
|
-
}
|
|
1045
|
+
format: { type: "json_object" }
|
|
2694
1046
|
};
|
|
2695
1047
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
// src/embedding/schemas.ts
|
|
2699
|
-
import { z as z9 } from "zod/v4";
|
|
2700
|
-
var openrouterEmbeddingUsageSchema = z9.object({
|
|
2701
|
-
prompt_tokens: z9.number(),
|
|
2702
|
-
total_tokens: z9.number(),
|
|
2703
|
-
cost: z9.number().optional()
|
|
2704
|
-
});
|
|
2705
|
-
var openrouterEmbeddingDataSchema = z9.object({
|
|
2706
|
-
object: z9.literal("embedding"),
|
|
2707
|
-
embedding: z9.array(z9.number()),
|
|
2708
|
-
index: z9.number().optional()
|
|
2709
|
-
});
|
|
2710
|
-
var OpenRouterEmbeddingResponseSchema = z9.object({
|
|
2711
|
-
id: z9.string().optional(),
|
|
2712
|
-
object: z9.literal("list"),
|
|
2713
|
-
data: z9.array(openrouterEmbeddingDataSchema),
|
|
2714
|
-
model: z9.string(),
|
|
2715
|
-
usage: openrouterEmbeddingUsageSchema.optional()
|
|
2716
|
-
});
|
|
1048
|
+
return void 0;
|
|
1049
|
+
}
|
|
2717
1050
|
|
|
2718
|
-
// src/embedding/
|
|
1051
|
+
// src/embedding/openrouter-embedding-model.ts
|
|
1052
|
+
import { combineHeaders as combineHeaders2, normalizeHeaders as normalizeHeaders2 } from "@ai-sdk/provider-utils";
|
|
1053
|
+
import { OpenRouter as OpenRouter2 } from "@openrouter/sdk";
|
|
2719
1054
|
var OpenRouterEmbeddingModel = class {
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
1055
|
+
specificationVersion = "v3";
|
|
1056
|
+
provider = "openrouter";
|
|
1057
|
+
modelId;
|
|
1058
|
+
settings;
|
|
1059
|
+
/**
|
|
1060
|
+
* Maximum number of embeddings that can be generated in a single API call.
|
|
1061
|
+
* Set to 2048 as a reasonable default for most embedding models.
|
|
1062
|
+
*/
|
|
1063
|
+
maxEmbeddingsPerCall = 2048;
|
|
1064
|
+
/**
|
|
1065
|
+
* Whether the model supports parallel calls.
|
|
1066
|
+
*/
|
|
1067
|
+
supportsParallelCalls = true;
|
|
1068
|
+
constructor(modelId, settings) {
|
|
2725
1069
|
this.modelId = modelId;
|
|
2726
1070
|
this.settings = settings;
|
|
2727
|
-
this.config = config;
|
|
2728
1071
|
}
|
|
2729
1072
|
async doEmbed(options) {
|
|
2730
|
-
|
|
2731
|
-
const
|
|
2732
|
-
|
|
1073
|
+
const warnings = [];
|
|
1074
|
+
const client = new OpenRouter2({
|
|
1075
|
+
apiKey: this.settings.apiKey,
|
|
1076
|
+
serverURL: this.settings.baseURL
|
|
1077
|
+
});
|
|
1078
|
+
const requestParams = {
|
|
2733
1079
|
model: this.modelId,
|
|
2734
|
-
input: values
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
1080
|
+
input: options.values
|
|
1081
|
+
};
|
|
1082
|
+
const modelOptions = this.settings.modelOptions;
|
|
1083
|
+
if (modelOptions?.user) {
|
|
1084
|
+
requestParams.user = modelOptions.user;
|
|
1085
|
+
}
|
|
1086
|
+
if (modelOptions?.provider) {
|
|
1087
|
+
requestParams.provider = modelOptions.provider;
|
|
1088
|
+
}
|
|
1089
|
+
const combinedHeaders = normalizeHeaders2(
|
|
1090
|
+
combineHeaders2(this.settings.headers, options.headers)
|
|
1091
|
+
);
|
|
1092
|
+
const response = await client.embeddings.generate(requestParams, {
|
|
1093
|
+
fetchOptions: {
|
|
1094
|
+
signal: options.abortSignal,
|
|
1095
|
+
headers: combinedHeaders
|
|
1096
|
+
}
|
|
2751
1097
|
});
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
}
|
|
2761
|
-
} : void 0,
|
|
2762
|
-
response: {
|
|
2763
|
-
headers: responseHeaders,
|
|
2764
|
-
body: responseValue
|
|
1098
|
+
if (typeof response === "string") {
|
|
1099
|
+
throw new Error(`Unexpected string response from embeddings API: ${response}`);
|
|
1100
|
+
}
|
|
1101
|
+
const responseBody = response;
|
|
1102
|
+
const sortedData = [...responseBody.data].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
1103
|
+
const embeddings = sortedData.map((item) => {
|
|
1104
|
+
if (typeof item.embedding === "string") {
|
|
1105
|
+
throw new Error("Base64 encoded embeddings are not supported");
|
|
2765
1106
|
}
|
|
1107
|
+
return item.embedding;
|
|
1108
|
+
});
|
|
1109
|
+
return {
|
|
1110
|
+
embeddings,
|
|
1111
|
+
usage: responseBody.usage ? { tokens: responseBody.usage.promptTokens } : void 0,
|
|
1112
|
+
warnings
|
|
2766
1113
|
};
|
|
2767
1114
|
}
|
|
2768
1115
|
};
|
|
2769
1116
|
|
|
2770
|
-
// src/
|
|
2771
|
-
var
|
|
1117
|
+
// src/image/openrouter-image-model.ts
|
|
1118
|
+
var OpenRouterImageModel = class {
|
|
1119
|
+
specificationVersion = "v3";
|
|
1120
|
+
provider = "openrouter";
|
|
1121
|
+
modelId;
|
|
2772
1122
|
/**
|
|
2773
|
-
*
|
|
1123
|
+
* Maximum number of images that can be generated in a single API call.
|
|
2774
1124
|
*/
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
this.
|
|
2778
|
-
this.apiKey = options.apiKey;
|
|
2779
|
-
this.headers = options.headers;
|
|
2780
|
-
this.api_keys = options.api_keys;
|
|
2781
|
-
}
|
|
2782
|
-
get baseConfig() {
|
|
2783
|
-
return {
|
|
2784
|
-
baseURL: this.baseURL,
|
|
2785
|
-
headers: () => __spreadValues(__spreadValues({
|
|
2786
|
-
Authorization: `Bearer ${loadApiKey({
|
|
2787
|
-
apiKey: this.apiKey,
|
|
2788
|
-
environmentVariableName: "OPENROUTER_API_KEY",
|
|
2789
|
-
description: "OpenRouter"
|
|
2790
|
-
})}`
|
|
2791
|
-
}, this.headers), this.api_keys && Object.keys(this.api_keys).length > 0 && {
|
|
2792
|
-
"X-Provider-API-Keys": JSON.stringify(this.api_keys)
|
|
2793
|
-
})
|
|
2794
|
-
};
|
|
2795
|
-
}
|
|
2796
|
-
chat(modelId, settings = {}) {
|
|
2797
|
-
return new OpenRouterChatLanguageModel(modelId, settings, __spreadProps(__spreadValues({
|
|
2798
|
-
provider: "openrouter.chat"
|
|
2799
|
-
}, this.baseConfig), {
|
|
2800
|
-
compatibility: "strict",
|
|
2801
|
-
url: ({ path }) => `${this.baseURL}${path}`
|
|
2802
|
-
}));
|
|
2803
|
-
}
|
|
2804
|
-
completion(modelId, settings = {}) {
|
|
2805
|
-
return new OpenRouterCompletionLanguageModel(modelId, settings, __spreadProps(__spreadValues({
|
|
2806
|
-
provider: "openrouter.completion"
|
|
2807
|
-
}, this.baseConfig), {
|
|
2808
|
-
compatibility: "strict",
|
|
2809
|
-
url: ({ path }) => `${this.baseURL}${path}`
|
|
2810
|
-
}));
|
|
2811
|
-
}
|
|
2812
|
-
textEmbeddingModel(modelId, settings = {}) {
|
|
2813
|
-
return new OpenRouterEmbeddingModel(modelId, settings, __spreadProps(__spreadValues({
|
|
2814
|
-
provider: "openrouter.embedding"
|
|
2815
|
-
}, this.baseConfig), {
|
|
2816
|
-
url: ({ path }) => `${this.baseURL}${path}`
|
|
2817
|
-
}));
|
|
1125
|
+
maxImagesPerCall = 1;
|
|
1126
|
+
constructor(modelId, _settings) {
|
|
1127
|
+
this.modelId = modelId;
|
|
2818
1128
|
}
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
return this.textEmbeddingModel(modelId, settings);
|
|
1129
|
+
async doGenerate(_options) {
|
|
1130
|
+
throw new Error(
|
|
1131
|
+
"Image generation not yet supported. See: https://github.com/OpenRouterTeam/ai-sdk-provider/issues/new?title=Image+generation+support"
|
|
1132
|
+
);
|
|
2824
1133
|
}
|
|
2825
1134
|
};
|
|
2826
1135
|
|
|
2827
|
-
// src/
|
|
2828
|
-
function removeUndefinedEntries2(record) {
|
|
2829
|
-
return Object.fromEntries(
|
|
2830
|
-
Object.entries(record).filter(([, value]) => value !== null)
|
|
2831
|
-
);
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
|
-
// src/utils/with-user-agent-suffix.ts
|
|
2835
|
-
function withUserAgentSuffix(headers, ...userAgentSuffixParts) {
|
|
2836
|
-
const cleanedHeaders = removeUndefinedEntries2(
|
|
2837
|
-
headers != null ? headers : {}
|
|
2838
|
-
);
|
|
2839
|
-
const currentUserAgentHeader = cleanedHeaders["user-agent"] || "";
|
|
2840
|
-
const newUserAgent = [currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(" ");
|
|
2841
|
-
return __spreadProps(__spreadValues({}, cleanedHeaders), {
|
|
2842
|
-
"user-agent": newUserAgent
|
|
2843
|
-
});
|
|
2844
|
-
}
|
|
2845
|
-
|
|
2846
|
-
// src/version.ts
|
|
2847
|
-
var VERSION = false ? "0.0.0-test" : "1.5.3";
|
|
2848
|
-
|
|
2849
|
-
// src/provider.ts
|
|
1136
|
+
// src/openrouter-provider.ts
|
|
2850
1137
|
function createOpenRouter(options = {}) {
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
const compatibility = (_c = options.compatibility) != null ? _c : "compatible";
|
|
2854
|
-
const getHeaders = () => withUserAgentSuffix(
|
|
2855
|
-
__spreadValues(__spreadValues({
|
|
2856
|
-
Authorization: `Bearer ${loadApiKey({
|
|
2857
|
-
apiKey: options.apiKey,
|
|
2858
|
-
environmentVariableName: "OPENROUTER_API_KEY",
|
|
2859
|
-
description: "OpenRouter"
|
|
2860
|
-
})}`
|
|
2861
|
-
}, options.headers), options.api_keys && Object.keys(options.api_keys).length > 0 && {
|
|
2862
|
-
"X-Provider-API-Keys": JSON.stringify(options.api_keys)
|
|
2863
|
-
}),
|
|
2864
|
-
`ai-sdk/openrouter/${VERSION}`
|
|
1138
|
+
const baseURL = withoutTrailingSlash(
|
|
1139
|
+
options.baseURL ?? options.baseUrl ?? "https://openrouter.ai/api/v1"
|
|
2865
1140
|
);
|
|
2866
|
-
const
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
provider: "openrouter.embedding",
|
|
2884
|
-
url: ({ path }) => `${baseURL}${path}`,
|
|
2885
|
-
headers: getHeaders,
|
|
2886
|
-
fetch: options.fetch,
|
|
2887
|
-
extraBody: options.extraBody
|
|
2888
|
-
});
|
|
2889
|
-
const createLanguageModel = (modelId, settings) => {
|
|
2890
|
-
if (new.target) {
|
|
2891
|
-
throw new Error(
|
|
2892
|
-
"The OpenRouter model function cannot be called with the new keyword."
|
|
2893
|
-
);
|
|
2894
|
-
}
|
|
2895
|
-
if (modelId === "openai/gpt-3.5-turbo-instruct") {
|
|
2896
|
-
return createCompletionModel(
|
|
2897
|
-
modelId,
|
|
2898
|
-
settings
|
|
2899
|
-
);
|
|
2900
|
-
}
|
|
2901
|
-
return createChatModel(modelId, settings);
|
|
1141
|
+
const getModelSettings = (modelOptions) => {
|
|
1142
|
+
const apiKey = loadApiKey({
|
|
1143
|
+
apiKey: options.apiKey,
|
|
1144
|
+
environmentVariableName: "OPENROUTER_API_KEY",
|
|
1145
|
+
description: "OpenRouter"
|
|
1146
|
+
});
|
|
1147
|
+
return {
|
|
1148
|
+
apiKey,
|
|
1149
|
+
baseURL,
|
|
1150
|
+
headers: options.headers,
|
|
1151
|
+
fetch: options.fetch,
|
|
1152
|
+
extraBody: options.extraBody,
|
|
1153
|
+
modelOptions
|
|
1154
|
+
};
|
|
1155
|
+
};
|
|
1156
|
+
const languageModel = (modelId, modelOptions) => {
|
|
1157
|
+
return new OpenRouterChatLanguageModel(modelId, getModelSettings(modelOptions));
|
|
2902
1158
|
};
|
|
2903
|
-
const
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
1159
|
+
const embeddingModel = (modelId, modelOptions) => {
|
|
1160
|
+
return new OpenRouterEmbeddingModel(modelId, getModelSettings(modelOptions));
|
|
1161
|
+
};
|
|
1162
|
+
const imageModel = (modelId, modelOptions) => {
|
|
1163
|
+
return new OpenRouterImageModel(modelId, getModelSettings(modelOptions));
|
|
1164
|
+
};
|
|
1165
|
+
const provider = Object.assign(
|
|
1166
|
+
// Make provider callable - calling it directly creates a language model
|
|
1167
|
+
(modelId, modelOptions) => languageModel(modelId, modelOptions),
|
|
1168
|
+
{
|
|
1169
|
+
specificationVersion: "v3",
|
|
1170
|
+
languageModel,
|
|
1171
|
+
chat: languageModel,
|
|
1172
|
+
embeddingModel,
|
|
1173
|
+
textEmbeddingModel: embeddingModel,
|
|
1174
|
+
imageModel,
|
|
1175
|
+
image: imageModel,
|
|
1176
|
+
embedding: embeddingModel
|
|
1177
|
+
}
|
|
1178
|
+
);
|
|
2909
1179
|
return provider;
|
|
2910
1180
|
}
|
|
2911
|
-
var openrouter = createOpenRouter({
|
|
2912
|
-
compatibility: "strict"
|
|
2913
|
-
// strict for OpenRouter API
|
|
2914
|
-
});
|
|
2915
1181
|
|
|
2916
|
-
// src/
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
throw new Error(
|
|
2922
|
-
"The @toon-format/toon package is required for TOON encoding/decoding. Install it with: npm install @toon-format/toon"
|
|
2923
|
-
);
|
|
2924
|
-
}
|
|
2925
|
-
}
|
|
2926
|
-
async function encodeToon(value, options) {
|
|
2927
|
-
const toon = await getToonModule();
|
|
2928
|
-
return toon.encode(value, options);
|
|
2929
|
-
}
|
|
2930
|
-
async function decodeToon(input, options) {
|
|
2931
|
-
const toon = await getToonModule();
|
|
2932
|
-
return toon.decode(input, options);
|
|
2933
|
-
}
|
|
1182
|
+
// src/version.ts
|
|
1183
|
+
var VERSION = "6.0.0-alpha.0";
|
|
1184
|
+
|
|
1185
|
+
// src/index.ts
|
|
1186
|
+
var openrouter = createOpenRouter();
|
|
2934
1187
|
export {
|
|
2935
|
-
|
|
1188
|
+
VERSION,
|
|
2936
1189
|
createOpenRouter,
|
|
2937
|
-
decodeToon,
|
|
2938
|
-
encodeToon,
|
|
2939
1190
|
openrouter
|
|
2940
1191
|
};
|
|
2941
1192
|
//# sourceMappingURL=index.mjs.map
|