190proof 1.0.108 → 1.0.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -2
- package/dist/index.d.mts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +389 -85
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +386 -83
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
2
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
3
|
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined")
|
|
4
|
+
if (typeof require !== "undefined")
|
|
5
|
+
return require.apply(this, arguments);
|
|
5
6
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
7
|
});
|
|
7
8
|
|
|
@@ -137,7 +138,8 @@ async function withRetries(identifier, apiName, fn, options = {}) {
|
|
|
137
138
|
return await fn();
|
|
138
139
|
} catch (error3) {
|
|
139
140
|
lastError = error3;
|
|
140
|
-
if ((_a = options.signal) == null ? void 0 : _a.aborted)
|
|
141
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted)
|
|
142
|
+
throw error3;
|
|
141
143
|
if (onError) {
|
|
142
144
|
onError(error3, attempt);
|
|
143
145
|
} else {
|
|
@@ -161,7 +163,8 @@ function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allo
|
|
|
161
163
|
const functionCalls = [];
|
|
162
164
|
for (let i = 0; i < toolCallAccumulators.length; i++) {
|
|
163
165
|
const acc = toolCallAccumulators[i];
|
|
164
|
-
if (!acc.name || !acc.arguments)
|
|
166
|
+
if (!acc.name || !acc.arguments)
|
|
167
|
+
continue;
|
|
165
168
|
if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {
|
|
166
169
|
throw new Error(
|
|
167
170
|
`Stream error: received function call with unknown name: ${acc.name}`
|
|
@@ -300,7 +303,8 @@ function buildOpenAIRequestConfig(identifier, model, config) {
|
|
|
300
303
|
};
|
|
301
304
|
}
|
|
302
305
|
function filterOpenAICompatReasoningDetails(details) {
|
|
303
|
-
if (!Array.isArray(details))
|
|
306
|
+
if (!Array.isArray(details))
|
|
307
|
+
return details || void 0;
|
|
304
308
|
const blocks = details.filter(
|
|
305
309
|
(block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
|
|
306
310
|
);
|
|
@@ -371,11 +375,13 @@ async function prepareOpenAIPayload(identifier, payload) {
|
|
|
371
375
|
};
|
|
372
376
|
});
|
|
373
377
|
}
|
|
374
|
-
if (message.reasoning)
|
|
378
|
+
if (message.reasoning)
|
|
379
|
+
outMessage.reasoning = message.reasoning;
|
|
375
380
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
376
381
|
message.reasoningDetails
|
|
377
382
|
);
|
|
378
|
-
if (reasoningDetails)
|
|
383
|
+
if (reasoningDetails)
|
|
384
|
+
outMessage.reasoning_details = reasoningDetails;
|
|
379
385
|
preparedPayload.messages.push(outMessage);
|
|
380
386
|
}
|
|
381
387
|
return preparedPayload;
|
|
@@ -437,7 +443,8 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
437
443
|
}
|
|
438
444
|
const jsonStrings = chunk.split(/^data: /gm);
|
|
439
445
|
for (const jsonString of jsonStrings) {
|
|
440
|
-
if (!jsonString)
|
|
446
|
+
if (!jsonString)
|
|
447
|
+
continue;
|
|
441
448
|
if (jsonString.includes("[DONE]")) {
|
|
442
449
|
clearTimeout(overallTimeout);
|
|
443
450
|
return parseStreamedResponse(
|
|
@@ -475,7 +482,8 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
475
482
|
while (toolCallAccumulators.length <= idx) {
|
|
476
483
|
toolCallAccumulators.push({ name: "", arguments: "" });
|
|
477
484
|
}
|
|
478
|
-
if (toolCall.id)
|
|
485
|
+
if (toolCall.id)
|
|
486
|
+
toolCallAccumulators[idx].id = toolCall.id;
|
|
479
487
|
if ((_e = toolCall.function) == null ? void 0 : _e.name)
|
|
480
488
|
toolCallAccumulators[idx].name += toolCall.function.name;
|
|
481
489
|
if ((_f = toolCall.function) == null ? void 0 : _f.arguments)
|
|
@@ -483,9 +491,11 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
483
491
|
}
|
|
484
492
|
}
|
|
485
493
|
const text = (_h = (_g = json.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content;
|
|
486
|
-
if (text)
|
|
494
|
+
if (text)
|
|
495
|
+
paragraph += text;
|
|
487
496
|
const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning;
|
|
488
|
-
if (reasoningDelta)
|
|
497
|
+
if (reasoningDelta)
|
|
498
|
+
reasoning += reasoningDelta;
|
|
489
499
|
}
|
|
490
500
|
}
|
|
491
501
|
}
|
|
@@ -630,7 +640,8 @@ function jigAnthropicMessages(messages) {
|
|
|
630
640
|
];
|
|
631
641
|
}
|
|
632
642
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
633
|
-
if (acc.length === 0)
|
|
643
|
+
if (acc.length === 0)
|
|
644
|
+
return [message];
|
|
634
645
|
const lastMessage = acc[acc.length - 1];
|
|
635
646
|
if (lastMessage.role === message.role) {
|
|
636
647
|
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
|
|
@@ -884,7 +895,8 @@ function jigGoogleMessages(messages) {
|
|
|
884
895
|
];
|
|
885
896
|
}
|
|
886
897
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
887
|
-
if (acc.length === 0)
|
|
898
|
+
if (acc.length === 0)
|
|
899
|
+
return [message];
|
|
888
900
|
const lastMessage = acc[acc.length - 1];
|
|
889
901
|
if (lastMessage.role === message.role) {
|
|
890
902
|
lastMessage.parts = [...lastMessage.parts, ...message.parts];
|
|
@@ -922,7 +934,8 @@ async function prepareGoogleAIPayload(_identifier, payload) {
|
|
|
922
934
|
const toolNameById = /* @__PURE__ */ new Map();
|
|
923
935
|
for (const m of payload.messages) {
|
|
924
936
|
for (const fc of m.functionCalls || []) {
|
|
925
|
-
if (fc.id)
|
|
937
|
+
if (fc.id)
|
|
938
|
+
toolNameById.set(fc.id, fc.name);
|
|
926
939
|
}
|
|
927
940
|
}
|
|
928
941
|
for (const message of payload.messages) {
|
|
@@ -999,7 +1012,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
999
1012
|
contents,
|
|
1000
1013
|
generationConfig: { responseModalities: ["TEXT"] }
|
|
1001
1014
|
};
|
|
1002
|
-
if (payload.tools)
|
|
1015
|
+
if (payload.tools)
|
|
1016
|
+
requestBody.tools = [payload.tools];
|
|
1003
1017
|
if (payload.tools && payload.toolConfig) {
|
|
1004
1018
|
requestBody.toolConfig = payload.toolConfig;
|
|
1005
1019
|
}
|
|
@@ -1057,7 +1071,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1057
1071
|
});
|
|
1058
1072
|
continue;
|
|
1059
1073
|
}
|
|
1060
|
-
if (part.text)
|
|
1074
|
+
if (part.text)
|
|
1075
|
+
text += part.text;
|
|
1061
1076
|
if ((_m = part.inlineData) == null ? void 0 : _m.data) {
|
|
1062
1077
|
files.push({ mimeType: "image/png", data: part.inlineData.data });
|
|
1063
1078
|
}
|
|
@@ -1134,15 +1149,21 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
|
|
|
1134
1149
|
finishReason: error2.finishReason,
|
|
1135
1150
|
modelVersion: error2.modelVersion
|
|
1136
1151
|
};
|
|
1137
|
-
if (error2.safetyRatings)
|
|
1138
|
-
|
|
1152
|
+
if (error2.safetyRatings)
|
|
1153
|
+
errorDetails.safetyRatings = error2.safetyRatings;
|
|
1154
|
+
if (error2.usageMetadata)
|
|
1155
|
+
errorDetails.usageMetadata = error2.usageMetadata;
|
|
1139
1156
|
if (error2.promptFeedback)
|
|
1140
1157
|
errorDetails.promptFeedback = error2.promptFeedback;
|
|
1141
|
-
if (error2.status)
|
|
1142
|
-
|
|
1143
|
-
if (error2.
|
|
1158
|
+
if (error2.status)
|
|
1159
|
+
errorDetails.httpStatus = error2.status;
|
|
1160
|
+
if (error2.code)
|
|
1161
|
+
errorDetails.errorCode = error2.code;
|
|
1162
|
+
if (error2.details)
|
|
1163
|
+
errorDetails.errorDetails = error2.details;
|
|
1144
1164
|
const fileUris = payload.messages.flatMap((m) => m.parts).filter((p) => "fileData" in p).map((p) => p.fileData.fileUri);
|
|
1145
|
-
if (fileUris.length)
|
|
1165
|
+
if (fileUris.length)
|
|
1166
|
+
errorDetails.fileUris = fileUris;
|
|
1146
1167
|
logger_default.error(
|
|
1147
1168
|
id,
|
|
1148
1169
|
`Retry #${attempt} error: ${error2.message}`,
|
|
@@ -1222,13 +1243,16 @@ function prepareOpenAICompatMessages(messages) {
|
|
|
1222
1243
|
}
|
|
1223
1244
|
};
|
|
1224
1245
|
});
|
|
1225
|
-
if (!message.content)
|
|
1246
|
+
if (!message.content)
|
|
1247
|
+
outMessage.content = null;
|
|
1226
1248
|
}
|
|
1227
|
-
if (message.reasoning)
|
|
1249
|
+
if (message.reasoning)
|
|
1250
|
+
outMessage.reasoning = message.reasoning;
|
|
1228
1251
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
1229
1252
|
message.reasoningDetails
|
|
1230
1253
|
);
|
|
1231
|
-
if (reasoningDetails)
|
|
1254
|
+
if (reasoningDetails)
|
|
1255
|
+
outMessage.reasoning_details = reasoningDetails;
|
|
1232
1256
|
out.push(outMessage);
|
|
1233
1257
|
}
|
|
1234
1258
|
return out;
|
|
@@ -1371,53 +1395,33 @@ function parseDsmlToolCalls(content) {
|
|
|
1371
1395
|
let last = -1;
|
|
1372
1396
|
let tag;
|
|
1373
1397
|
while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
|
|
1374
|
-
if (first === -1)
|
|
1398
|
+
if (first === -1)
|
|
1399
|
+
first = tag.index;
|
|
1375
1400
|
last = tag.index + tag[0].length;
|
|
1376
1401
|
}
|
|
1377
1402
|
const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
|
|
1378
1403
|
return { calls, remainingContent: remaining.length ? remaining : null };
|
|
1379
1404
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
// Override point for tests (deadline behavior needs a local server).
|
|
1388
|
-
`${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`,
|
|
1389
|
-
payload,
|
|
1390
|
-
{
|
|
1391
|
-
headers: {
|
|
1392
|
-
"content-type": "application/json",
|
|
1393
|
-
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1394
|
-
},
|
|
1395
|
-
timeout: requestTimeoutMs,
|
|
1396
|
-
signal: mergedSignal
|
|
1397
|
-
}
|
|
1398
|
-
)
|
|
1399
|
-
);
|
|
1400
|
-
if (response.data.error) {
|
|
1401
|
-
logger_default.error(id, "OpenRouter error:", response.data.error);
|
|
1402
|
-
throw new Error(`OpenRouter error: ${response.data.error.message}`);
|
|
1403
|
-
}
|
|
1404
|
-
const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message;
|
|
1405
|
-
if (!answer) {
|
|
1406
|
-
logger_default.error(id, "Missing answer in OpenRouter API response:", response.data);
|
|
1407
|
-
throw new Error("Missing answer in OpenRouter API");
|
|
1408
|
-
}
|
|
1405
|
+
var OPENROUTER_STREAM_TIMEOUT_MS = 6e5;
|
|
1406
|
+
var OPENROUTER_NONSTREAM_TIMEOUT_MS = 18e4;
|
|
1407
|
+
function openRouterEndpoint() {
|
|
1408
|
+
return `${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`;
|
|
1409
|
+
}
|
|
1410
|
+
function finalizeOpenRouterMessage(id, raw) {
|
|
1411
|
+
var _a, _b, _c, _d, _e;
|
|
1409
1412
|
const functionCalls = [];
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1418
|
-
|
|
1413
|
+
for (let i = 0; i < raw.toolCalls.length; i++) {
|
|
1414
|
+
const tc = raw.toolCalls[i];
|
|
1415
|
+
if (!tc.name)
|
|
1416
|
+
continue;
|
|
1417
|
+
functionCalls.push({
|
|
1418
|
+
id: (_a = tc.id) != null ? _a : `call_${i}`,
|
|
1419
|
+
name: tc.name,
|
|
1420
|
+
// Streamed no-arg calls can close with an empty fragment; treat as {}.
|
|
1421
|
+
arguments: tc.argumentsJson.trim() ? JSON.parse(tc.argumentsJson) : {}
|
|
1422
|
+
});
|
|
1419
1423
|
}
|
|
1420
|
-
let content =
|
|
1424
|
+
let content = raw.content;
|
|
1421
1425
|
if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {
|
|
1422
1426
|
const { calls, remainingContent } = parseDsmlToolCalls(content);
|
|
1423
1427
|
if (calls.length) {
|
|
@@ -1427,11 +1431,7 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1427
1431
|
}
|
|
1428
1432
|
const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);
|
|
1429
1433
|
if (!functionCalls.length && (!content || hasUnparsedDsml)) {
|
|
1430
|
-
logger_default.error(
|
|
1431
|
-
id,
|
|
1432
|
-
"OpenRouter: empty or unparseable completion:",
|
|
1433
|
-
JSON.stringify(response.data)
|
|
1434
|
-
);
|
|
1434
|
+
logger_default.error(id, "OpenRouter: empty or unparseable completion:", raw.forLog());
|
|
1435
1435
|
throw new Error(
|
|
1436
1436
|
"OpenRouter: received message without usable content or function_call"
|
|
1437
1437
|
);
|
|
@@ -1442,24 +1442,319 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1442
1442
|
function_call: functionCalls[0] || null,
|
|
1443
1443
|
function_calls: functionCalls,
|
|
1444
1444
|
files: [],
|
|
1445
|
-
reasoning:
|
|
1446
|
-
reasoningDetails: (
|
|
1445
|
+
reasoning: raw.reasoning || void 0,
|
|
1446
|
+
reasoningDetails: (_b = raw.reasoningDetails) != null ? _b : void 0,
|
|
1447
1447
|
// The upstream provider OpenRouter routed to (e.g. "Baidu") — finer-grained
|
|
1448
1448
|
// than the "openrouter" stamp callWithRetries would apply.
|
|
1449
|
-
provider: (
|
|
1450
|
-
usage:
|
|
1451
|
-
prompt_tokens:
|
|
1452
|
-
completion_tokens:
|
|
1453
|
-
total_tokens:
|
|
1454
|
-
cached_tokens: (
|
|
1449
|
+
provider: (_c = raw.provider) != null ? _c : void 0,
|
|
1450
|
+
usage: raw.usage ? {
|
|
1451
|
+
prompt_tokens: raw.usage.prompt_tokens,
|
|
1452
|
+
completion_tokens: raw.usage.completion_tokens,
|
|
1453
|
+
total_tokens: raw.usage.total_tokens,
|
|
1454
|
+
cached_tokens: (_e = (_d = raw.usage.prompt_tokens_details) == null ? void 0 : _d.cached_tokens) != null ? _e : 0
|
|
1455
1455
|
} : null
|
|
1456
1456
|
};
|
|
1457
1457
|
}
|
|
1458
|
-
async function
|
|
1458
|
+
async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_STREAM_TIMEOUT_MS, chunkTimeoutMs = 15e3, signal) {
|
|
1459
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1460
|
+
const controller = new AbortController();
|
|
1461
|
+
let abortReason = null;
|
|
1462
|
+
const abortWith = (reason) => {
|
|
1463
|
+
abortReason = reason;
|
|
1464
|
+
controller.abort();
|
|
1465
|
+
};
|
|
1466
|
+
const unref = (t) => {
|
|
1467
|
+
if (typeof t === "object" && "unref" in t)
|
|
1468
|
+
t.unref();
|
|
1469
|
+
return t;
|
|
1470
|
+
};
|
|
1471
|
+
const totalTimer = unref(
|
|
1472
|
+
setTimeout(
|
|
1473
|
+
() => abortWith(
|
|
1474
|
+
`OpenRouter stream exceeded total deadline of ${streamTimeoutMs}ms`
|
|
1475
|
+
),
|
|
1476
|
+
streamTimeoutMs
|
|
1477
|
+
)
|
|
1478
|
+
);
|
|
1479
|
+
let stallTimer;
|
|
1480
|
+
const armStallTimer = () => {
|
|
1481
|
+
clearTimeout(stallTimer);
|
|
1482
|
+
stallTimer = unref(
|
|
1483
|
+
setTimeout(
|
|
1484
|
+
() => abortWith(
|
|
1485
|
+
`OpenRouter stream stalled: no useful chunk for ${chunkTimeoutMs}ms`
|
|
1486
|
+
),
|
|
1487
|
+
chunkTimeoutMs
|
|
1488
|
+
)
|
|
1489
|
+
);
|
|
1490
|
+
};
|
|
1491
|
+
let paragraph = "";
|
|
1492
|
+
let reasoning = "";
|
|
1493
|
+
const reasoningDetails = [];
|
|
1494
|
+
const toolCalls = [];
|
|
1495
|
+
let provider;
|
|
1496
|
+
let usage = null;
|
|
1497
|
+
let finishReason = null;
|
|
1498
|
+
let sawDone = false;
|
|
1499
|
+
let dataChunks = 0;
|
|
1500
|
+
try {
|
|
1501
|
+
armStallTimer();
|
|
1502
|
+
const response = await fetch(openRouterEndpoint(), {
|
|
1503
|
+
method: "POST",
|
|
1504
|
+
headers: {
|
|
1505
|
+
"content-type": "application/json",
|
|
1506
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1507
|
+
},
|
|
1508
|
+
body: JSON.stringify({ ...payload, stream: true, usage: { include: true } }),
|
|
1509
|
+
signal: signal ? anySignal([controller.signal, signal]) : controller.signal
|
|
1510
|
+
});
|
|
1511
|
+
if (!response.ok) {
|
|
1512
|
+
let data;
|
|
1513
|
+
try {
|
|
1514
|
+
data = await response.json();
|
|
1515
|
+
} catch (e) {
|
|
1516
|
+
data = void 0;
|
|
1517
|
+
}
|
|
1518
|
+
logger_default.error(id, `OpenRouter stream HTTP ${response.status}:`, data);
|
|
1519
|
+
const error2 = new Error(
|
|
1520
|
+
`OpenRouter error: ${((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || `HTTP ${response.status}`}`
|
|
1521
|
+
);
|
|
1522
|
+
error2.response = { status: response.status, data };
|
|
1523
|
+
throw error2;
|
|
1524
|
+
}
|
|
1525
|
+
if ((_b = response.headers.get("content-type")) == null ? void 0 : _b.includes("application/json")) {
|
|
1526
|
+
return parseOpenRouterBody(id, await response.json());
|
|
1527
|
+
}
|
|
1528
|
+
if (!response.body) {
|
|
1529
|
+
throw new Error("OpenRouter stream error: no response body");
|
|
1530
|
+
}
|
|
1531
|
+
const reader = response.body.getReader();
|
|
1532
|
+
const decoder = new TextDecoder();
|
|
1533
|
+
let lineBuffer = "";
|
|
1534
|
+
outer:
|
|
1535
|
+
while (true) {
|
|
1536
|
+
const { done, value } = await reader.read();
|
|
1537
|
+
if (done)
|
|
1538
|
+
break;
|
|
1539
|
+
lineBuffer += decoder.decode(value, { stream: true });
|
|
1540
|
+
let newlineIdx;
|
|
1541
|
+
while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
|
|
1542
|
+
let line = lineBuffer.slice(0, newlineIdx);
|
|
1543
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
1544
|
+
if (line.endsWith("\r"))
|
|
1545
|
+
line = line.slice(0, -1);
|
|
1546
|
+
if (!line)
|
|
1547
|
+
continue;
|
|
1548
|
+
if (line.startsWith(":"))
|
|
1549
|
+
continue;
|
|
1550
|
+
if (!line.startsWith("data:"))
|
|
1551
|
+
continue;
|
|
1552
|
+
const dataStr = line.slice(5).trimStart();
|
|
1553
|
+
if (dataStr === "[DONE]") {
|
|
1554
|
+
sawDone = true;
|
|
1555
|
+
break outer;
|
|
1556
|
+
}
|
|
1557
|
+
let json;
|
|
1558
|
+
try {
|
|
1559
|
+
json = JSON.parse(dataStr);
|
|
1560
|
+
} catch (e) {
|
|
1561
|
+
logger_default.error(
|
|
1562
|
+
id,
|
|
1563
|
+
"OpenRouter stream: unparseable data line:",
|
|
1564
|
+
dataStr.slice(0, 200)
|
|
1565
|
+
);
|
|
1566
|
+
continue;
|
|
1567
|
+
}
|
|
1568
|
+
dataChunks++;
|
|
1569
|
+
if (json.error) {
|
|
1570
|
+
logger_default.error(id, "OpenRouter stream error event:", json.error);
|
|
1571
|
+
const error2 = new Error(
|
|
1572
|
+
`OpenRouter error: ${json.error.message}`
|
|
1573
|
+
);
|
|
1574
|
+
error2.data = json.error;
|
|
1575
|
+
throw error2;
|
|
1576
|
+
}
|
|
1577
|
+
if (json.provider)
|
|
1578
|
+
provider = json.provider;
|
|
1579
|
+
let useful = false;
|
|
1580
|
+
if (json.usage) {
|
|
1581
|
+
usage = json.usage;
|
|
1582
|
+
useful = true;
|
|
1583
|
+
}
|
|
1584
|
+
const choice = (_c = json.choices) == null ? void 0 : _c[0];
|
|
1585
|
+
if (choice) {
|
|
1586
|
+
const delta = (_d = choice.delta) != null ? _d : {};
|
|
1587
|
+
if (delta.content) {
|
|
1588
|
+
paragraph += delta.content;
|
|
1589
|
+
useful = true;
|
|
1590
|
+
}
|
|
1591
|
+
if (delta.reasoning) {
|
|
1592
|
+
reasoning += delta.reasoning;
|
|
1593
|
+
useful = true;
|
|
1594
|
+
}
|
|
1595
|
+
if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
|
|
1596
|
+
reasoningDetails.push(...delta.reasoning_details);
|
|
1597
|
+
useful = true;
|
|
1598
|
+
}
|
|
1599
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
1600
|
+
for (const toolCall of delta.tool_calls) {
|
|
1601
|
+
const idx = (_e = toolCall.index) != null ? _e : 0;
|
|
1602
|
+
while (toolCalls.length <= idx) {
|
|
1603
|
+
toolCalls.push({ name: "", argumentsJson: "" });
|
|
1604
|
+
}
|
|
1605
|
+
if (toolCall.id)
|
|
1606
|
+
toolCalls[idx].id = toolCall.id;
|
|
1607
|
+
if ((_f = toolCall.function) == null ? void 0 : _f.name)
|
|
1608
|
+
toolCalls[idx].name += toolCall.function.name;
|
|
1609
|
+
if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
|
|
1610
|
+
toolCalls[idx].argumentsJson += toolCall.function.arguments;
|
|
1611
|
+
useful = true;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
if (choice.finish_reason) {
|
|
1615
|
+
finishReason = choice.finish_reason;
|
|
1616
|
+
useful = true;
|
|
1617
|
+
}
|
|
1618
|
+
}
|
|
1619
|
+
if (useful)
|
|
1620
|
+
armStallTimer();
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
if (sawDone)
|
|
1624
|
+
reader.cancel().catch(() => {
|
|
1625
|
+
});
|
|
1626
|
+
if (!sawDone && !finishReason) {
|
|
1627
|
+
logger_default.error(
|
|
1628
|
+
id,
|
|
1629
|
+
`OpenRouter stream ended prematurely after ${dataChunks} data chunks`
|
|
1630
|
+
);
|
|
1631
|
+
throw new Error("OpenRouter stream error: ended prematurely");
|
|
1632
|
+
}
|
|
1633
|
+
return finalizeOpenRouterMessage(id, {
|
|
1634
|
+
content: paragraph || null,
|
|
1635
|
+
toolCalls,
|
|
1636
|
+
reasoning,
|
|
1637
|
+
reasoningDetails: reasoningDetails.length ? reasoningDetails : void 0,
|
|
1638
|
+
provider,
|
|
1639
|
+
usage,
|
|
1640
|
+
forLog: () => JSON.stringify({
|
|
1641
|
+
finishReason,
|
|
1642
|
+
provider,
|
|
1643
|
+
usage,
|
|
1644
|
+
paragraph: paragraph.slice(0, 500),
|
|
1645
|
+
reasoningChars: reasoning.length,
|
|
1646
|
+
toolCalls
|
|
1647
|
+
})
|
|
1648
|
+
});
|
|
1649
|
+
} catch (error2) {
|
|
1650
|
+
if (abortReason && !(signal == null ? void 0 : signal.aborted)) {
|
|
1651
|
+
logger_default.error(id, abortReason);
|
|
1652
|
+
throw new Error(abortReason);
|
|
1653
|
+
}
|
|
1654
|
+
throw error2;
|
|
1655
|
+
} finally {
|
|
1656
|
+
clearTimeout(totalTimer);
|
|
1657
|
+
clearTimeout(stallTimer);
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
function parseOpenRouterBody(id, data) {
|
|
1661
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1662
|
+
if (data.error) {
|
|
1663
|
+
logger_default.error(id, "OpenRouter error:", data.error);
|
|
1664
|
+
const error2 = new Error(`OpenRouter error: ${data.error.message}`);
|
|
1665
|
+
error2.data = data.error;
|
|
1666
|
+
throw error2;
|
|
1667
|
+
}
|
|
1668
|
+
const answer = (_b = (_a = data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message;
|
|
1669
|
+
if (!answer) {
|
|
1670
|
+
logger_default.error(id, "Missing answer in OpenRouter API response:", data);
|
|
1671
|
+
throw new Error("Missing answer in OpenRouter API");
|
|
1672
|
+
}
|
|
1673
|
+
return finalizeOpenRouterMessage(id, {
|
|
1674
|
+
content: (_c = answer.content) != null ? _c : null,
|
|
1675
|
+
toolCalls: ((_d = answer.tool_calls) != null ? _d : []).map((tc) => ({
|
|
1676
|
+
id: tc.id,
|
|
1677
|
+
name: tc.function.name,
|
|
1678
|
+
argumentsJson: tc.function.arguments
|
|
1679
|
+
})),
|
|
1680
|
+
reasoning: (_e = answer.reasoning) != null ? _e : void 0,
|
|
1681
|
+
reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0,
|
|
1682
|
+
provider: (_g = data.provider) != null ? _g : void 0,
|
|
1683
|
+
usage: (_h = data.usage) != null ? _h : null,
|
|
1684
|
+
forLog: () => JSON.stringify(data)
|
|
1685
|
+
});
|
|
1686
|
+
}
|
|
1687
|
+
async function callOpenRouterNonStreaming(id, payload, requestTimeoutMs = OPENROUTER_NONSTREAM_TIMEOUT_MS, signal) {
|
|
1688
|
+
const response = await withRequestDeadline(
|
|
1689
|
+
"OpenRouter",
|
|
1690
|
+
requestTimeoutMs,
|
|
1691
|
+
signal,
|
|
1692
|
+
(mergedSignal) => axios.post(openRouterEndpoint(), payload, {
|
|
1693
|
+
headers: {
|
|
1694
|
+
"content-type": "application/json",
|
|
1695
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1696
|
+
},
|
|
1697
|
+
timeout: requestTimeoutMs,
|
|
1698
|
+
signal: mergedSignal
|
|
1699
|
+
})
|
|
1700
|
+
);
|
|
1701
|
+
return parseOpenRouterBody(id, response.data);
|
|
1702
|
+
}
|
|
1703
|
+
var normalizeProviderKey = (name) => name.split("/")[0].toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1704
|
+
var MODERATION_RE = /moderat|inappropriate content|content polic|content management|flagged/i;
|
|
1705
|
+
function moderationEvictionSlug(error2, payload) {
|
|
1706
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1707
|
+
const body = (_c = error2 == null ? void 0 : error2.data) != null ? _c : (_b = (_a = error2 == null ? void 0 : error2.response) == null ? void 0 : _a.data) == null ? void 0 : _b.error;
|
|
1708
|
+
if (!body)
|
|
1709
|
+
return null;
|
|
1710
|
+
const message = String((_d = body.message) != null ? _d : "");
|
|
1711
|
+
const isModeration = body.code === 403 || Array.isArray((_e = body.metadata) == null ? void 0 : _e.reasons) || MODERATION_RE.test(message);
|
|
1712
|
+
if (!isModeration)
|
|
1713
|
+
return null;
|
|
1714
|
+
const display = (_h = (_f = body.metadata) == null ? void 0 : _f.provider_name) != null ? _h : (_g = /Upstream error from ([^:]+):/.exec(message)) == null ? void 0 : _g[1];
|
|
1715
|
+
if (!display)
|
|
1716
|
+
return null;
|
|
1717
|
+
const key = normalizeProviderKey(display);
|
|
1718
|
+
const fromOrder = (_j = (_i = payload.provider) == null ? void 0 : _i.order) == null ? void 0 : _j.find(
|
|
1719
|
+
(entry) => normalizeProviderKey(entry) === key
|
|
1720
|
+
);
|
|
1721
|
+
return fromOrder ? fromOrder.split("/")[0] : display.toLowerCase();
|
|
1722
|
+
}
|
|
1723
|
+
async function callOpenRouterWithRetries(id, payload, retries = 5, options, signal) {
|
|
1724
|
+
const evicted = [];
|
|
1459
1725
|
return withRetries(
|
|
1460
1726
|
id,
|
|
1461
1727
|
"OpenRouter",
|
|
1462
|
-
() =>
|
|
1728
|
+
() => (options.streaming ? callOpenRouterStream(
|
|
1729
|
+
id,
|
|
1730
|
+
payload,
|
|
1731
|
+
options.streamTimeoutMs,
|
|
1732
|
+
options.chunkTimeoutMs,
|
|
1733
|
+
signal
|
|
1734
|
+
) : callOpenRouterNonStreaming(
|
|
1735
|
+
id,
|
|
1736
|
+
payload,
|
|
1737
|
+
options.requestTimeoutMs,
|
|
1738
|
+
signal
|
|
1739
|
+
)).catch((error2) => {
|
|
1740
|
+
var _a, _b, _c, _d;
|
|
1741
|
+
const slug = moderationEvictionSlug(error2, payload);
|
|
1742
|
+
if (slug && !evicted.includes(slug)) {
|
|
1743
|
+
evicted.push(slug);
|
|
1744
|
+
payload.provider = {
|
|
1745
|
+
...payload.provider,
|
|
1746
|
+
ignore: [...(_b = (_a = payload.provider) == null ? void 0 : _a.ignore) != null ? _b : [], slug],
|
|
1747
|
+
order: (_d = (_c = payload.provider) == null ? void 0 : _c.order) == null ? void 0 : _d.filter(
|
|
1748
|
+
(entry) => normalizeProviderKey(entry) !== normalizeProviderKey(slug)
|
|
1749
|
+
)
|
|
1750
|
+
};
|
|
1751
|
+
logger_default.log(
|
|
1752
|
+
id,
|
|
1753
|
+
`OpenRouter moderation eviction: ignoring provider "${slug}" for remaining attempts`
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1756
|
+
throw error2;
|
|
1757
|
+
}),
|
|
1463
1758
|
{ retries, signal }
|
|
1464
1759
|
);
|
|
1465
1760
|
}
|
|
@@ -1501,7 +1796,7 @@ function parseModelString(model) {
|
|
|
1501
1796
|
);
|
|
1502
1797
|
}
|
|
1503
1798
|
async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
1504
|
-
var _a, _b, _c;
|
|
1799
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1505
1800
|
try {
|
|
1506
1801
|
const { provider, modelId } = parseModelString(aiPayload.model);
|
|
1507
1802
|
const routingPayload = { ...aiPayload, model: modelId };
|
|
@@ -1553,15 +1848,21 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1553
1848
|
id,
|
|
1554
1849
|
prepareOpenRouterPayload(routingPayload),
|
|
1555
1850
|
retries,
|
|
1556
|
-
|
|
1851
|
+
{
|
|
1852
|
+
streaming: (_b = aiPayload.streaming) != null ? _b : true,
|
|
1853
|
+
streamTimeoutMs: (_c = aiPayload.streamTimeoutMs) != null ? _c : OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1854
|
+
requestTimeoutMs: (_d = aiPayload.requestTimeoutMs) != null ? _d : OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1855
|
+
chunkTimeoutMs
|
|
1856
|
+
},
|
|
1557
1857
|
signal
|
|
1558
1858
|
);
|
|
1559
1859
|
break;
|
|
1560
1860
|
}
|
|
1561
|
-
(
|
|
1861
|
+
(_e = result.provider) != null ? _e : result.provider = provider;
|
|
1562
1862
|
return result;
|
|
1563
1863
|
} catch (error2) {
|
|
1564
|
-
if ((
|
|
1864
|
+
if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted)
|
|
1865
|
+
throw error2;
|
|
1565
1866
|
if (aiPayload.fallbackModel) {
|
|
1566
1867
|
logger_default.error(
|
|
1567
1868
|
id,
|
|
@@ -1591,6 +1892,8 @@ export {
|
|
|
1591
1892
|
GPTModel,
|
|
1592
1893
|
GeminiModel,
|
|
1593
1894
|
GroqModel,
|
|
1895
|
+
OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1896
|
+
OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1594
1897
|
OpenRouterModel,
|
|
1595
1898
|
callWithRetries,
|
|
1596
1899
|
parseModelString
|