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.js
CHANGED
|
@@ -28,17 +28,19 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
29
|
|
|
30
30
|
// index.ts
|
|
31
|
-
var
|
|
32
|
-
__export(
|
|
31
|
+
var proof_exports = {};
|
|
32
|
+
__export(proof_exports, {
|
|
33
33
|
ClaudeModel: () => ClaudeModel,
|
|
34
34
|
GPTModel: () => GPTModel,
|
|
35
35
|
GeminiModel: () => GeminiModel,
|
|
36
36
|
GroqModel: () => GroqModel,
|
|
37
|
+
OPENROUTER_NONSTREAM_TIMEOUT_MS: () => OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
38
|
+
OPENROUTER_STREAM_TIMEOUT_MS: () => OPENROUTER_STREAM_TIMEOUT_MS,
|
|
37
39
|
OpenRouterModel: () => OpenRouterModel,
|
|
38
40
|
callWithRetries: () => callWithRetries,
|
|
39
41
|
parseModelString: () => parseModelString
|
|
40
42
|
});
|
|
41
|
-
module.exports = __toCommonJS(
|
|
43
|
+
module.exports = __toCommonJS(proof_exports);
|
|
42
44
|
|
|
43
45
|
// interfaces.ts
|
|
44
46
|
var ClaudeModel = /* @__PURE__ */ ((ClaudeModel2) => {
|
|
@@ -169,7 +171,8 @@ async function withRetries(identifier, apiName, fn, options = {}) {
|
|
|
169
171
|
return await fn();
|
|
170
172
|
} catch (error3) {
|
|
171
173
|
lastError = error3;
|
|
172
|
-
if ((_a = options.signal) == null ? void 0 : _a.aborted)
|
|
174
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted)
|
|
175
|
+
throw error3;
|
|
173
176
|
if (onError) {
|
|
174
177
|
onError(error3, attempt);
|
|
175
178
|
} else {
|
|
@@ -193,7 +196,8 @@ function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allo
|
|
|
193
196
|
const functionCalls = [];
|
|
194
197
|
for (let i = 0; i < toolCallAccumulators.length; i++) {
|
|
195
198
|
const acc = toolCallAccumulators[i];
|
|
196
|
-
if (!acc.name || !acc.arguments)
|
|
199
|
+
if (!acc.name || !acc.arguments)
|
|
200
|
+
continue;
|
|
197
201
|
if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {
|
|
198
202
|
throw new Error(
|
|
199
203
|
`Stream error: received function call with unknown name: ${acc.name}`
|
|
@@ -332,7 +336,8 @@ function buildOpenAIRequestConfig(identifier, model, config) {
|
|
|
332
336
|
};
|
|
333
337
|
}
|
|
334
338
|
function filterOpenAICompatReasoningDetails(details) {
|
|
335
|
-
if (!Array.isArray(details))
|
|
339
|
+
if (!Array.isArray(details))
|
|
340
|
+
return details || void 0;
|
|
336
341
|
const blocks = details.filter(
|
|
337
342
|
(block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
|
|
338
343
|
);
|
|
@@ -403,11 +408,13 @@ async function prepareOpenAIPayload(identifier, payload) {
|
|
|
403
408
|
};
|
|
404
409
|
});
|
|
405
410
|
}
|
|
406
|
-
if (message.reasoning)
|
|
411
|
+
if (message.reasoning)
|
|
412
|
+
outMessage.reasoning = message.reasoning;
|
|
407
413
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
408
414
|
message.reasoningDetails
|
|
409
415
|
);
|
|
410
|
-
if (reasoningDetails)
|
|
416
|
+
if (reasoningDetails)
|
|
417
|
+
outMessage.reasoning_details = reasoningDetails;
|
|
411
418
|
preparedPayload.messages.push(outMessage);
|
|
412
419
|
}
|
|
413
420
|
return preparedPayload;
|
|
@@ -469,7 +476,8 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
469
476
|
}
|
|
470
477
|
const jsonStrings = chunk.split(/^data: /gm);
|
|
471
478
|
for (const jsonString of jsonStrings) {
|
|
472
|
-
if (!jsonString)
|
|
479
|
+
if (!jsonString)
|
|
480
|
+
continue;
|
|
473
481
|
if (jsonString.includes("[DONE]")) {
|
|
474
482
|
clearTimeout(overallTimeout);
|
|
475
483
|
return parseStreamedResponse(
|
|
@@ -507,7 +515,8 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
507
515
|
while (toolCallAccumulators.length <= idx) {
|
|
508
516
|
toolCallAccumulators.push({ name: "", arguments: "" });
|
|
509
517
|
}
|
|
510
|
-
if (toolCall.id)
|
|
518
|
+
if (toolCall.id)
|
|
519
|
+
toolCallAccumulators[idx].id = toolCall.id;
|
|
511
520
|
if ((_e = toolCall.function) == null ? void 0 : _e.name)
|
|
512
521
|
toolCallAccumulators[idx].name += toolCall.function.name;
|
|
513
522
|
if ((_f = toolCall.function) == null ? void 0 : _f.arguments)
|
|
@@ -515,9 +524,11 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
515
524
|
}
|
|
516
525
|
}
|
|
517
526
|
const text = (_h = (_g = json.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content;
|
|
518
|
-
if (text)
|
|
527
|
+
if (text)
|
|
528
|
+
paragraph += text;
|
|
519
529
|
const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning;
|
|
520
|
-
if (reasoningDelta)
|
|
530
|
+
if (reasoningDelta)
|
|
531
|
+
reasoning += reasoningDelta;
|
|
521
532
|
}
|
|
522
533
|
}
|
|
523
534
|
}
|
|
@@ -662,7 +673,8 @@ function jigAnthropicMessages(messages) {
|
|
|
662
673
|
];
|
|
663
674
|
}
|
|
664
675
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
665
|
-
if (acc.length === 0)
|
|
676
|
+
if (acc.length === 0)
|
|
677
|
+
return [message];
|
|
666
678
|
const lastMessage = acc[acc.length - 1];
|
|
667
679
|
if (lastMessage.role === message.role) {
|
|
668
680
|
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
|
|
@@ -916,7 +928,8 @@ function jigGoogleMessages(messages) {
|
|
|
916
928
|
];
|
|
917
929
|
}
|
|
918
930
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
919
|
-
if (acc.length === 0)
|
|
931
|
+
if (acc.length === 0)
|
|
932
|
+
return [message];
|
|
920
933
|
const lastMessage = acc[acc.length - 1];
|
|
921
934
|
if (lastMessage.role === message.role) {
|
|
922
935
|
lastMessage.parts = [...lastMessage.parts, ...message.parts];
|
|
@@ -954,7 +967,8 @@ async function prepareGoogleAIPayload(_identifier, payload) {
|
|
|
954
967
|
const toolNameById = /* @__PURE__ */ new Map();
|
|
955
968
|
for (const m of payload.messages) {
|
|
956
969
|
for (const fc of m.functionCalls || []) {
|
|
957
|
-
if (fc.id)
|
|
970
|
+
if (fc.id)
|
|
971
|
+
toolNameById.set(fc.id, fc.name);
|
|
958
972
|
}
|
|
959
973
|
}
|
|
960
974
|
for (const message of payload.messages) {
|
|
@@ -1031,7 +1045,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1031
1045
|
contents,
|
|
1032
1046
|
generationConfig: { responseModalities: ["TEXT"] }
|
|
1033
1047
|
};
|
|
1034
|
-
if (payload.tools)
|
|
1048
|
+
if (payload.tools)
|
|
1049
|
+
requestBody.tools = [payload.tools];
|
|
1035
1050
|
if (payload.tools && payload.toolConfig) {
|
|
1036
1051
|
requestBody.toolConfig = payload.toolConfig;
|
|
1037
1052
|
}
|
|
@@ -1089,7 +1104,8 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1089
1104
|
});
|
|
1090
1105
|
continue;
|
|
1091
1106
|
}
|
|
1092
|
-
if (part.text)
|
|
1107
|
+
if (part.text)
|
|
1108
|
+
text += part.text;
|
|
1093
1109
|
if ((_m = part.inlineData) == null ? void 0 : _m.data) {
|
|
1094
1110
|
files.push({ mimeType: "image/png", data: part.inlineData.data });
|
|
1095
1111
|
}
|
|
@@ -1166,15 +1182,21 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
|
|
|
1166
1182
|
finishReason: error2.finishReason,
|
|
1167
1183
|
modelVersion: error2.modelVersion
|
|
1168
1184
|
};
|
|
1169
|
-
if (error2.safetyRatings)
|
|
1170
|
-
|
|
1185
|
+
if (error2.safetyRatings)
|
|
1186
|
+
errorDetails.safetyRatings = error2.safetyRatings;
|
|
1187
|
+
if (error2.usageMetadata)
|
|
1188
|
+
errorDetails.usageMetadata = error2.usageMetadata;
|
|
1171
1189
|
if (error2.promptFeedback)
|
|
1172
1190
|
errorDetails.promptFeedback = error2.promptFeedback;
|
|
1173
|
-
if (error2.status)
|
|
1174
|
-
|
|
1175
|
-
if (error2.
|
|
1191
|
+
if (error2.status)
|
|
1192
|
+
errorDetails.httpStatus = error2.status;
|
|
1193
|
+
if (error2.code)
|
|
1194
|
+
errorDetails.errorCode = error2.code;
|
|
1195
|
+
if (error2.details)
|
|
1196
|
+
errorDetails.errorDetails = error2.details;
|
|
1176
1197
|
const fileUris = payload.messages.flatMap((m) => m.parts).filter((p) => "fileData" in p).map((p) => p.fileData.fileUri);
|
|
1177
|
-
if (fileUris.length)
|
|
1198
|
+
if (fileUris.length)
|
|
1199
|
+
errorDetails.fileUris = fileUris;
|
|
1178
1200
|
logger_default.error(
|
|
1179
1201
|
id,
|
|
1180
1202
|
`Retry #${attempt} error: ${error2.message}`,
|
|
@@ -1254,13 +1276,16 @@ function prepareOpenAICompatMessages(messages) {
|
|
|
1254
1276
|
}
|
|
1255
1277
|
};
|
|
1256
1278
|
});
|
|
1257
|
-
if (!message.content)
|
|
1279
|
+
if (!message.content)
|
|
1280
|
+
outMessage.content = null;
|
|
1258
1281
|
}
|
|
1259
|
-
if (message.reasoning)
|
|
1282
|
+
if (message.reasoning)
|
|
1283
|
+
outMessage.reasoning = message.reasoning;
|
|
1260
1284
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
1261
1285
|
message.reasoningDetails
|
|
1262
1286
|
);
|
|
1263
|
-
if (reasoningDetails)
|
|
1287
|
+
if (reasoningDetails)
|
|
1288
|
+
outMessage.reasoning_details = reasoningDetails;
|
|
1264
1289
|
out.push(outMessage);
|
|
1265
1290
|
}
|
|
1266
1291
|
return out;
|
|
@@ -1403,53 +1428,33 @@ function parseDsmlToolCalls(content) {
|
|
|
1403
1428
|
let last = -1;
|
|
1404
1429
|
let tag;
|
|
1405
1430
|
while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
|
|
1406
|
-
if (first === -1)
|
|
1431
|
+
if (first === -1)
|
|
1432
|
+
first = tag.index;
|
|
1407
1433
|
last = tag.index + tag[0].length;
|
|
1408
1434
|
}
|
|
1409
1435
|
const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
|
|
1410
1436
|
return { calls, remainingContent: remaining.length ? remaining : null };
|
|
1411
1437
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
// Override point for tests (deadline behavior needs a local server).
|
|
1420
|
-
`${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`,
|
|
1421
|
-
payload,
|
|
1422
|
-
{
|
|
1423
|
-
headers: {
|
|
1424
|
-
"content-type": "application/json",
|
|
1425
|
-
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1426
|
-
},
|
|
1427
|
-
timeout: requestTimeoutMs,
|
|
1428
|
-
signal: mergedSignal
|
|
1429
|
-
}
|
|
1430
|
-
)
|
|
1431
|
-
);
|
|
1432
|
-
if (response.data.error) {
|
|
1433
|
-
logger_default.error(id, "OpenRouter error:", response.data.error);
|
|
1434
|
-
throw new Error(`OpenRouter error: ${response.data.error.message}`);
|
|
1435
|
-
}
|
|
1436
|
-
const answer = (_b = (_a = response.data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message;
|
|
1437
|
-
if (!answer) {
|
|
1438
|
-
logger_default.error(id, "Missing answer in OpenRouter API response:", response.data);
|
|
1439
|
-
throw new Error("Missing answer in OpenRouter API");
|
|
1440
|
-
}
|
|
1438
|
+
var OPENROUTER_STREAM_TIMEOUT_MS = 6e5;
|
|
1439
|
+
var OPENROUTER_NONSTREAM_TIMEOUT_MS = 18e4;
|
|
1440
|
+
function openRouterEndpoint() {
|
|
1441
|
+
return `${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`;
|
|
1442
|
+
}
|
|
1443
|
+
function finalizeOpenRouterMessage(id, raw) {
|
|
1444
|
+
var _a, _b, _c, _d, _e;
|
|
1441
1445
|
const functionCalls = [];
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1446
|
+
for (let i = 0; i < raw.toolCalls.length; i++) {
|
|
1447
|
+
const tc = raw.toolCalls[i];
|
|
1448
|
+
if (!tc.name)
|
|
1449
|
+
continue;
|
|
1450
|
+
functionCalls.push({
|
|
1451
|
+
id: (_a = tc.id) != null ? _a : `call_${i}`,
|
|
1452
|
+
name: tc.name,
|
|
1453
|
+
// Streamed no-arg calls can close with an empty fragment; treat as {}.
|
|
1454
|
+
arguments: tc.argumentsJson.trim() ? JSON.parse(tc.argumentsJson) : {}
|
|
1455
|
+
});
|
|
1451
1456
|
}
|
|
1452
|
-
let content =
|
|
1457
|
+
let content = raw.content;
|
|
1453
1458
|
if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {
|
|
1454
1459
|
const { calls, remainingContent } = parseDsmlToolCalls(content);
|
|
1455
1460
|
if (calls.length) {
|
|
@@ -1459,11 +1464,7 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1459
1464
|
}
|
|
1460
1465
|
const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);
|
|
1461
1466
|
if (!functionCalls.length && (!content || hasUnparsedDsml)) {
|
|
1462
|
-
logger_default.error(
|
|
1463
|
-
id,
|
|
1464
|
-
"OpenRouter: empty or unparseable completion:",
|
|
1465
|
-
JSON.stringify(response.data)
|
|
1466
|
-
);
|
|
1467
|
+
logger_default.error(id, "OpenRouter: empty or unparseable completion:", raw.forLog());
|
|
1467
1468
|
throw new Error(
|
|
1468
1469
|
"OpenRouter: received message without usable content or function_call"
|
|
1469
1470
|
);
|
|
@@ -1474,24 +1475,319 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1474
1475
|
function_call: functionCalls[0] || null,
|
|
1475
1476
|
function_calls: functionCalls,
|
|
1476
1477
|
files: [],
|
|
1477
|
-
reasoning:
|
|
1478
|
-
reasoningDetails: (
|
|
1478
|
+
reasoning: raw.reasoning || void 0,
|
|
1479
|
+
reasoningDetails: (_b = raw.reasoningDetails) != null ? _b : void 0,
|
|
1479
1480
|
// The upstream provider OpenRouter routed to (e.g. "Baidu") — finer-grained
|
|
1480
1481
|
// than the "openrouter" stamp callWithRetries would apply.
|
|
1481
|
-
provider: (
|
|
1482
|
-
usage:
|
|
1483
|
-
prompt_tokens:
|
|
1484
|
-
completion_tokens:
|
|
1485
|
-
total_tokens:
|
|
1486
|
-
cached_tokens: (
|
|
1482
|
+
provider: (_c = raw.provider) != null ? _c : void 0,
|
|
1483
|
+
usage: raw.usage ? {
|
|
1484
|
+
prompt_tokens: raw.usage.prompt_tokens,
|
|
1485
|
+
completion_tokens: raw.usage.completion_tokens,
|
|
1486
|
+
total_tokens: raw.usage.total_tokens,
|
|
1487
|
+
cached_tokens: (_e = (_d = raw.usage.prompt_tokens_details) == null ? void 0 : _d.cached_tokens) != null ? _e : 0
|
|
1487
1488
|
} : null
|
|
1488
1489
|
};
|
|
1489
1490
|
}
|
|
1490
|
-
async function
|
|
1491
|
+
async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_STREAM_TIMEOUT_MS, chunkTimeoutMs = 15e3, signal) {
|
|
1492
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1493
|
+
const controller = new AbortController();
|
|
1494
|
+
let abortReason = null;
|
|
1495
|
+
const abortWith = (reason) => {
|
|
1496
|
+
abortReason = reason;
|
|
1497
|
+
controller.abort();
|
|
1498
|
+
};
|
|
1499
|
+
const unref = (t) => {
|
|
1500
|
+
if (typeof t === "object" && "unref" in t)
|
|
1501
|
+
t.unref();
|
|
1502
|
+
return t;
|
|
1503
|
+
};
|
|
1504
|
+
const totalTimer = unref(
|
|
1505
|
+
setTimeout(
|
|
1506
|
+
() => abortWith(
|
|
1507
|
+
`OpenRouter stream exceeded total deadline of ${streamTimeoutMs}ms`
|
|
1508
|
+
),
|
|
1509
|
+
streamTimeoutMs
|
|
1510
|
+
)
|
|
1511
|
+
);
|
|
1512
|
+
let stallTimer;
|
|
1513
|
+
const armStallTimer = () => {
|
|
1514
|
+
clearTimeout(stallTimer);
|
|
1515
|
+
stallTimer = unref(
|
|
1516
|
+
setTimeout(
|
|
1517
|
+
() => abortWith(
|
|
1518
|
+
`OpenRouter stream stalled: no useful chunk for ${chunkTimeoutMs}ms`
|
|
1519
|
+
),
|
|
1520
|
+
chunkTimeoutMs
|
|
1521
|
+
)
|
|
1522
|
+
);
|
|
1523
|
+
};
|
|
1524
|
+
let paragraph = "";
|
|
1525
|
+
let reasoning = "";
|
|
1526
|
+
const reasoningDetails = [];
|
|
1527
|
+
const toolCalls = [];
|
|
1528
|
+
let provider;
|
|
1529
|
+
let usage = null;
|
|
1530
|
+
let finishReason = null;
|
|
1531
|
+
let sawDone = false;
|
|
1532
|
+
let dataChunks = 0;
|
|
1533
|
+
try {
|
|
1534
|
+
armStallTimer();
|
|
1535
|
+
const response = await fetch(openRouterEndpoint(), {
|
|
1536
|
+
method: "POST",
|
|
1537
|
+
headers: {
|
|
1538
|
+
"content-type": "application/json",
|
|
1539
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1540
|
+
},
|
|
1541
|
+
body: JSON.stringify({ ...payload, stream: true, usage: { include: true } }),
|
|
1542
|
+
signal: signal ? anySignal([controller.signal, signal]) : controller.signal
|
|
1543
|
+
});
|
|
1544
|
+
if (!response.ok) {
|
|
1545
|
+
let data;
|
|
1546
|
+
try {
|
|
1547
|
+
data = await response.json();
|
|
1548
|
+
} catch (e) {
|
|
1549
|
+
data = void 0;
|
|
1550
|
+
}
|
|
1551
|
+
logger_default.error(id, `OpenRouter stream HTTP ${response.status}:`, data);
|
|
1552
|
+
const error2 = new Error(
|
|
1553
|
+
`OpenRouter error: ${((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || `HTTP ${response.status}`}`
|
|
1554
|
+
);
|
|
1555
|
+
error2.response = { status: response.status, data };
|
|
1556
|
+
throw error2;
|
|
1557
|
+
}
|
|
1558
|
+
if ((_b = response.headers.get("content-type")) == null ? void 0 : _b.includes("application/json")) {
|
|
1559
|
+
return parseOpenRouterBody(id, await response.json());
|
|
1560
|
+
}
|
|
1561
|
+
if (!response.body) {
|
|
1562
|
+
throw new Error("OpenRouter stream error: no response body");
|
|
1563
|
+
}
|
|
1564
|
+
const reader = response.body.getReader();
|
|
1565
|
+
const decoder = new TextDecoder();
|
|
1566
|
+
let lineBuffer = "";
|
|
1567
|
+
outer:
|
|
1568
|
+
while (true) {
|
|
1569
|
+
const { done, value } = await reader.read();
|
|
1570
|
+
if (done)
|
|
1571
|
+
break;
|
|
1572
|
+
lineBuffer += decoder.decode(value, { stream: true });
|
|
1573
|
+
let newlineIdx;
|
|
1574
|
+
while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
|
|
1575
|
+
let line = lineBuffer.slice(0, newlineIdx);
|
|
1576
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
1577
|
+
if (line.endsWith("\r"))
|
|
1578
|
+
line = line.slice(0, -1);
|
|
1579
|
+
if (!line)
|
|
1580
|
+
continue;
|
|
1581
|
+
if (line.startsWith(":"))
|
|
1582
|
+
continue;
|
|
1583
|
+
if (!line.startsWith("data:"))
|
|
1584
|
+
continue;
|
|
1585
|
+
const dataStr = line.slice(5).trimStart();
|
|
1586
|
+
if (dataStr === "[DONE]") {
|
|
1587
|
+
sawDone = true;
|
|
1588
|
+
break outer;
|
|
1589
|
+
}
|
|
1590
|
+
let json;
|
|
1591
|
+
try {
|
|
1592
|
+
json = JSON.parse(dataStr);
|
|
1593
|
+
} catch (e) {
|
|
1594
|
+
logger_default.error(
|
|
1595
|
+
id,
|
|
1596
|
+
"OpenRouter stream: unparseable data line:",
|
|
1597
|
+
dataStr.slice(0, 200)
|
|
1598
|
+
);
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
dataChunks++;
|
|
1602
|
+
if (json.error) {
|
|
1603
|
+
logger_default.error(id, "OpenRouter stream error event:", json.error);
|
|
1604
|
+
const error2 = new Error(
|
|
1605
|
+
`OpenRouter error: ${json.error.message}`
|
|
1606
|
+
);
|
|
1607
|
+
error2.data = json.error;
|
|
1608
|
+
throw error2;
|
|
1609
|
+
}
|
|
1610
|
+
if (json.provider)
|
|
1611
|
+
provider = json.provider;
|
|
1612
|
+
let useful = false;
|
|
1613
|
+
if (json.usage) {
|
|
1614
|
+
usage = json.usage;
|
|
1615
|
+
useful = true;
|
|
1616
|
+
}
|
|
1617
|
+
const choice = (_c = json.choices) == null ? void 0 : _c[0];
|
|
1618
|
+
if (choice) {
|
|
1619
|
+
const delta = (_d = choice.delta) != null ? _d : {};
|
|
1620
|
+
if (delta.content) {
|
|
1621
|
+
paragraph += delta.content;
|
|
1622
|
+
useful = true;
|
|
1623
|
+
}
|
|
1624
|
+
if (delta.reasoning) {
|
|
1625
|
+
reasoning += delta.reasoning;
|
|
1626
|
+
useful = true;
|
|
1627
|
+
}
|
|
1628
|
+
if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
|
|
1629
|
+
reasoningDetails.push(...delta.reasoning_details);
|
|
1630
|
+
useful = true;
|
|
1631
|
+
}
|
|
1632
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
1633
|
+
for (const toolCall of delta.tool_calls) {
|
|
1634
|
+
const idx = (_e = toolCall.index) != null ? _e : 0;
|
|
1635
|
+
while (toolCalls.length <= idx) {
|
|
1636
|
+
toolCalls.push({ name: "", argumentsJson: "" });
|
|
1637
|
+
}
|
|
1638
|
+
if (toolCall.id)
|
|
1639
|
+
toolCalls[idx].id = toolCall.id;
|
|
1640
|
+
if ((_f = toolCall.function) == null ? void 0 : _f.name)
|
|
1641
|
+
toolCalls[idx].name += toolCall.function.name;
|
|
1642
|
+
if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
|
|
1643
|
+
toolCalls[idx].argumentsJson += toolCall.function.arguments;
|
|
1644
|
+
useful = true;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
if (choice.finish_reason) {
|
|
1648
|
+
finishReason = choice.finish_reason;
|
|
1649
|
+
useful = true;
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
if (useful)
|
|
1653
|
+
armStallTimer();
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
if (sawDone)
|
|
1657
|
+
reader.cancel().catch(() => {
|
|
1658
|
+
});
|
|
1659
|
+
if (!sawDone && !finishReason) {
|
|
1660
|
+
logger_default.error(
|
|
1661
|
+
id,
|
|
1662
|
+
`OpenRouter stream ended prematurely after ${dataChunks} data chunks`
|
|
1663
|
+
);
|
|
1664
|
+
throw new Error("OpenRouter stream error: ended prematurely");
|
|
1665
|
+
}
|
|
1666
|
+
return finalizeOpenRouterMessage(id, {
|
|
1667
|
+
content: paragraph || null,
|
|
1668
|
+
toolCalls,
|
|
1669
|
+
reasoning,
|
|
1670
|
+
reasoningDetails: reasoningDetails.length ? reasoningDetails : void 0,
|
|
1671
|
+
provider,
|
|
1672
|
+
usage,
|
|
1673
|
+
forLog: () => JSON.stringify({
|
|
1674
|
+
finishReason,
|
|
1675
|
+
provider,
|
|
1676
|
+
usage,
|
|
1677
|
+
paragraph: paragraph.slice(0, 500),
|
|
1678
|
+
reasoningChars: reasoning.length,
|
|
1679
|
+
toolCalls
|
|
1680
|
+
})
|
|
1681
|
+
});
|
|
1682
|
+
} catch (error2) {
|
|
1683
|
+
if (abortReason && !(signal == null ? void 0 : signal.aborted)) {
|
|
1684
|
+
logger_default.error(id, abortReason);
|
|
1685
|
+
throw new Error(abortReason);
|
|
1686
|
+
}
|
|
1687
|
+
throw error2;
|
|
1688
|
+
} finally {
|
|
1689
|
+
clearTimeout(totalTimer);
|
|
1690
|
+
clearTimeout(stallTimer);
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
function parseOpenRouterBody(id, data) {
|
|
1694
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1695
|
+
if (data.error) {
|
|
1696
|
+
logger_default.error(id, "OpenRouter error:", data.error);
|
|
1697
|
+
const error2 = new Error(`OpenRouter error: ${data.error.message}`);
|
|
1698
|
+
error2.data = data.error;
|
|
1699
|
+
throw error2;
|
|
1700
|
+
}
|
|
1701
|
+
const answer = (_b = (_a = data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message;
|
|
1702
|
+
if (!answer) {
|
|
1703
|
+
logger_default.error(id, "Missing answer in OpenRouter API response:", data);
|
|
1704
|
+
throw new Error("Missing answer in OpenRouter API");
|
|
1705
|
+
}
|
|
1706
|
+
return finalizeOpenRouterMessage(id, {
|
|
1707
|
+
content: (_c = answer.content) != null ? _c : null,
|
|
1708
|
+
toolCalls: ((_d = answer.tool_calls) != null ? _d : []).map((tc) => ({
|
|
1709
|
+
id: tc.id,
|
|
1710
|
+
name: tc.function.name,
|
|
1711
|
+
argumentsJson: tc.function.arguments
|
|
1712
|
+
})),
|
|
1713
|
+
reasoning: (_e = answer.reasoning) != null ? _e : void 0,
|
|
1714
|
+
reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0,
|
|
1715
|
+
provider: (_g = data.provider) != null ? _g : void 0,
|
|
1716
|
+
usage: (_h = data.usage) != null ? _h : null,
|
|
1717
|
+
forLog: () => JSON.stringify(data)
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
async function callOpenRouterNonStreaming(id, payload, requestTimeoutMs = OPENROUTER_NONSTREAM_TIMEOUT_MS, signal) {
|
|
1721
|
+
const response = await withRequestDeadline(
|
|
1722
|
+
"OpenRouter",
|
|
1723
|
+
requestTimeoutMs,
|
|
1724
|
+
signal,
|
|
1725
|
+
(mergedSignal) => import_axios.default.post(openRouterEndpoint(), payload, {
|
|
1726
|
+
headers: {
|
|
1727
|
+
"content-type": "application/json",
|
|
1728
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1729
|
+
},
|
|
1730
|
+
timeout: requestTimeoutMs,
|
|
1731
|
+
signal: mergedSignal
|
|
1732
|
+
})
|
|
1733
|
+
);
|
|
1734
|
+
return parseOpenRouterBody(id, response.data);
|
|
1735
|
+
}
|
|
1736
|
+
var normalizeProviderKey = (name) => name.split("/")[0].toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1737
|
+
var MODERATION_RE = /moderat|inappropriate content|content polic|content management|flagged/i;
|
|
1738
|
+
function moderationEvictionSlug(error2, payload) {
|
|
1739
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1740
|
+
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;
|
|
1741
|
+
if (!body)
|
|
1742
|
+
return null;
|
|
1743
|
+
const message = String((_d = body.message) != null ? _d : "");
|
|
1744
|
+
const isModeration = body.code === 403 || Array.isArray((_e = body.metadata) == null ? void 0 : _e.reasons) || MODERATION_RE.test(message);
|
|
1745
|
+
if (!isModeration)
|
|
1746
|
+
return null;
|
|
1747
|
+
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];
|
|
1748
|
+
if (!display)
|
|
1749
|
+
return null;
|
|
1750
|
+
const key = normalizeProviderKey(display);
|
|
1751
|
+
const fromOrder = (_j = (_i = payload.provider) == null ? void 0 : _i.order) == null ? void 0 : _j.find(
|
|
1752
|
+
(entry) => normalizeProviderKey(entry) === key
|
|
1753
|
+
);
|
|
1754
|
+
return fromOrder ? fromOrder.split("/")[0] : display.toLowerCase();
|
|
1755
|
+
}
|
|
1756
|
+
async function callOpenRouterWithRetries(id, payload, retries = 5, options, signal) {
|
|
1757
|
+
const evicted = [];
|
|
1491
1758
|
return withRetries(
|
|
1492
1759
|
id,
|
|
1493
1760
|
"OpenRouter",
|
|
1494
|
-
() =>
|
|
1761
|
+
() => (options.streaming ? callOpenRouterStream(
|
|
1762
|
+
id,
|
|
1763
|
+
payload,
|
|
1764
|
+
options.streamTimeoutMs,
|
|
1765
|
+
options.chunkTimeoutMs,
|
|
1766
|
+
signal
|
|
1767
|
+
) : callOpenRouterNonStreaming(
|
|
1768
|
+
id,
|
|
1769
|
+
payload,
|
|
1770
|
+
options.requestTimeoutMs,
|
|
1771
|
+
signal
|
|
1772
|
+
)).catch((error2) => {
|
|
1773
|
+
var _a, _b, _c, _d;
|
|
1774
|
+
const slug = moderationEvictionSlug(error2, payload);
|
|
1775
|
+
if (slug && !evicted.includes(slug)) {
|
|
1776
|
+
evicted.push(slug);
|
|
1777
|
+
payload.provider = {
|
|
1778
|
+
...payload.provider,
|
|
1779
|
+
ignore: [...(_b = (_a = payload.provider) == null ? void 0 : _a.ignore) != null ? _b : [], slug],
|
|
1780
|
+
order: (_d = (_c = payload.provider) == null ? void 0 : _c.order) == null ? void 0 : _d.filter(
|
|
1781
|
+
(entry) => normalizeProviderKey(entry) !== normalizeProviderKey(slug)
|
|
1782
|
+
)
|
|
1783
|
+
};
|
|
1784
|
+
logger_default.log(
|
|
1785
|
+
id,
|
|
1786
|
+
`OpenRouter moderation eviction: ignoring provider "${slug}" for remaining attempts`
|
|
1787
|
+
);
|
|
1788
|
+
}
|
|
1789
|
+
throw error2;
|
|
1790
|
+
}),
|
|
1495
1791
|
{ retries, signal }
|
|
1496
1792
|
);
|
|
1497
1793
|
}
|
|
@@ -1533,7 +1829,7 @@ function parseModelString(model) {
|
|
|
1533
1829
|
);
|
|
1534
1830
|
}
|
|
1535
1831
|
async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
1536
|
-
var _a, _b, _c;
|
|
1832
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1537
1833
|
try {
|
|
1538
1834
|
const { provider, modelId } = parseModelString(aiPayload.model);
|
|
1539
1835
|
const routingPayload = { ...aiPayload, model: modelId };
|
|
@@ -1585,15 +1881,21 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1585
1881
|
id,
|
|
1586
1882
|
prepareOpenRouterPayload(routingPayload),
|
|
1587
1883
|
retries,
|
|
1588
|
-
|
|
1884
|
+
{
|
|
1885
|
+
streaming: (_b = aiPayload.streaming) != null ? _b : true,
|
|
1886
|
+
streamTimeoutMs: (_c = aiPayload.streamTimeoutMs) != null ? _c : OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1887
|
+
requestTimeoutMs: (_d = aiPayload.requestTimeoutMs) != null ? _d : OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1888
|
+
chunkTimeoutMs
|
|
1889
|
+
},
|
|
1589
1890
|
signal
|
|
1590
1891
|
);
|
|
1591
1892
|
break;
|
|
1592
1893
|
}
|
|
1593
|
-
(
|
|
1894
|
+
(_e = result.provider) != null ? _e : result.provider = provider;
|
|
1594
1895
|
return result;
|
|
1595
1896
|
} catch (error2) {
|
|
1596
|
-
if ((
|
|
1897
|
+
if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted)
|
|
1898
|
+
throw error2;
|
|
1597
1899
|
if (aiPayload.fallbackModel) {
|
|
1598
1900
|
logger_default.error(
|
|
1599
1901
|
id,
|
|
@@ -1624,6 +1926,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1624
1926
|
GPTModel,
|
|
1625
1927
|
GeminiModel,
|
|
1626
1928
|
GroqModel,
|
|
1929
|
+
OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1930
|
+
OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1627
1931
|
OpenRouterModel,
|
|
1628
1932
|
callWithRetries,
|
|
1629
1933
|
parseModelString
|