190proof 1.0.108 → 1.0.109
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 +4 -2
- package/dist/index.d.mts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +284 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +282 -58
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1377,47 +1377,25 @@ function parseDsmlToolCalls(content) {
|
|
|
1377
1377
|
const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
|
|
1378
1378
|
return { calls, remainingContent: remaining.length ? remaining : null };
|
|
1379
1379
|
}
|
|
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
|
-
}
|
|
1380
|
+
var OPENROUTER_STREAM_TIMEOUT_MS = 6e5;
|
|
1381
|
+
var OPENROUTER_NONSTREAM_TIMEOUT_MS = 18e4;
|
|
1382
|
+
function openRouterEndpoint() {
|
|
1383
|
+
return `${process.env.OPENROUTER_BASE_URL || "https://openrouter.ai"}/api/v1/chat/completions`;
|
|
1384
|
+
}
|
|
1385
|
+
function finalizeOpenRouterMessage(id, raw) {
|
|
1386
|
+
var _a, _b, _c, _d, _e;
|
|
1409
1387
|
const functionCalls = [];
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1388
|
+
for (let i = 0; i < raw.toolCalls.length; i++) {
|
|
1389
|
+
const tc = raw.toolCalls[i];
|
|
1390
|
+
if (!tc.name) continue;
|
|
1391
|
+
functionCalls.push({
|
|
1392
|
+
id: (_a = tc.id) != null ? _a : `call_${i}`,
|
|
1393
|
+
name: tc.name,
|
|
1394
|
+
// Streamed no-arg calls can close with an empty fragment; treat as {}.
|
|
1395
|
+
arguments: tc.argumentsJson.trim() ? JSON.parse(tc.argumentsJson) : {}
|
|
1396
|
+
});
|
|
1419
1397
|
}
|
|
1420
|
-
let content =
|
|
1398
|
+
let content = raw.content;
|
|
1421
1399
|
if (!functionCalls.length && content && DSML_ENVELOPE_RE.test(content)) {
|
|
1422
1400
|
const { calls, remainingContent } = parseDsmlToolCalls(content);
|
|
1423
1401
|
if (calls.length) {
|
|
@@ -1427,11 +1405,7 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1427
1405
|
}
|
|
1428
1406
|
const hasUnparsedDsml = !!content && DSML_DELIMITER_RE.test(content);
|
|
1429
1407
|
if (!functionCalls.length && (!content || hasUnparsedDsml)) {
|
|
1430
|
-
logger_default.error(
|
|
1431
|
-
id,
|
|
1432
|
-
"OpenRouter: empty or unparseable completion:",
|
|
1433
|
-
JSON.stringify(response.data)
|
|
1434
|
-
);
|
|
1408
|
+
logger_default.error(id, "OpenRouter: empty or unparseable completion:", raw.forLog());
|
|
1435
1409
|
throw new Error(
|
|
1436
1410
|
"OpenRouter: received message without usable content or function_call"
|
|
1437
1411
|
);
|
|
@@ -1442,24 +1416,267 @@ async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1442
1416
|
function_call: functionCalls[0] || null,
|
|
1443
1417
|
function_calls: functionCalls,
|
|
1444
1418
|
files: [],
|
|
1445
|
-
reasoning:
|
|
1446
|
-
reasoningDetails: (
|
|
1419
|
+
reasoning: raw.reasoning || void 0,
|
|
1420
|
+
reasoningDetails: (_b = raw.reasoningDetails) != null ? _b : void 0,
|
|
1447
1421
|
// The upstream provider OpenRouter routed to (e.g. "Baidu") — finer-grained
|
|
1448
1422
|
// than the "openrouter" stamp callWithRetries would apply.
|
|
1449
|
-
provider: (
|
|
1450
|
-
usage:
|
|
1451
|
-
prompt_tokens:
|
|
1452
|
-
completion_tokens:
|
|
1453
|
-
total_tokens:
|
|
1454
|
-
cached_tokens: (
|
|
1423
|
+
provider: (_c = raw.provider) != null ? _c : void 0,
|
|
1424
|
+
usage: raw.usage ? {
|
|
1425
|
+
prompt_tokens: raw.usage.prompt_tokens,
|
|
1426
|
+
completion_tokens: raw.usage.completion_tokens,
|
|
1427
|
+
total_tokens: raw.usage.total_tokens,
|
|
1428
|
+
cached_tokens: (_e = (_d = raw.usage.prompt_tokens_details) == null ? void 0 : _d.cached_tokens) != null ? _e : 0
|
|
1455
1429
|
} : null
|
|
1456
1430
|
};
|
|
1457
1431
|
}
|
|
1458
|
-
async function
|
|
1432
|
+
async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_STREAM_TIMEOUT_MS, chunkTimeoutMs = 15e3, signal) {
|
|
1433
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1434
|
+
const controller = new AbortController();
|
|
1435
|
+
let abortReason = null;
|
|
1436
|
+
const abortWith = (reason) => {
|
|
1437
|
+
abortReason = reason;
|
|
1438
|
+
controller.abort();
|
|
1439
|
+
};
|
|
1440
|
+
const unref = (t) => {
|
|
1441
|
+
if (typeof t === "object" && "unref" in t) t.unref();
|
|
1442
|
+
return t;
|
|
1443
|
+
};
|
|
1444
|
+
const totalTimer = unref(
|
|
1445
|
+
setTimeout(
|
|
1446
|
+
() => abortWith(
|
|
1447
|
+
`OpenRouter stream exceeded total deadline of ${streamTimeoutMs}ms`
|
|
1448
|
+
),
|
|
1449
|
+
streamTimeoutMs
|
|
1450
|
+
)
|
|
1451
|
+
);
|
|
1452
|
+
let stallTimer;
|
|
1453
|
+
const armStallTimer = () => {
|
|
1454
|
+
clearTimeout(stallTimer);
|
|
1455
|
+
stallTimer = unref(
|
|
1456
|
+
setTimeout(
|
|
1457
|
+
() => abortWith(
|
|
1458
|
+
`OpenRouter stream stalled: no useful chunk for ${chunkTimeoutMs}ms`
|
|
1459
|
+
),
|
|
1460
|
+
chunkTimeoutMs
|
|
1461
|
+
)
|
|
1462
|
+
);
|
|
1463
|
+
};
|
|
1464
|
+
let paragraph = "";
|
|
1465
|
+
let reasoning = "";
|
|
1466
|
+
const reasoningDetails = [];
|
|
1467
|
+
const toolCalls = [];
|
|
1468
|
+
let provider;
|
|
1469
|
+
let usage = null;
|
|
1470
|
+
let finishReason = null;
|
|
1471
|
+
let sawDone = false;
|
|
1472
|
+
let dataChunks = 0;
|
|
1473
|
+
try {
|
|
1474
|
+
armStallTimer();
|
|
1475
|
+
const response = await fetch(openRouterEndpoint(), {
|
|
1476
|
+
method: "POST",
|
|
1477
|
+
headers: {
|
|
1478
|
+
"content-type": "application/json",
|
|
1479
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1480
|
+
},
|
|
1481
|
+
body: JSON.stringify({ ...payload, stream: true, usage: { include: true } }),
|
|
1482
|
+
signal: signal ? anySignal([controller.signal, signal]) : controller.signal
|
|
1483
|
+
});
|
|
1484
|
+
if (!response.ok) {
|
|
1485
|
+
let data;
|
|
1486
|
+
try {
|
|
1487
|
+
data = await response.json();
|
|
1488
|
+
} catch (e) {
|
|
1489
|
+
data = void 0;
|
|
1490
|
+
}
|
|
1491
|
+
logger_default.error(id, `OpenRouter stream HTTP ${response.status}:`, data);
|
|
1492
|
+
const error2 = new Error(
|
|
1493
|
+
`OpenRouter error: ${((_a = data == null ? void 0 : data.error) == null ? void 0 : _a.message) || `HTTP ${response.status}`}`
|
|
1494
|
+
);
|
|
1495
|
+
error2.response = { status: response.status, data };
|
|
1496
|
+
throw error2;
|
|
1497
|
+
}
|
|
1498
|
+
if ((_b = response.headers.get("content-type")) == null ? void 0 : _b.includes("application/json")) {
|
|
1499
|
+
return parseOpenRouterBody(id, await response.json());
|
|
1500
|
+
}
|
|
1501
|
+
if (!response.body) {
|
|
1502
|
+
throw new Error("OpenRouter stream error: no response body");
|
|
1503
|
+
}
|
|
1504
|
+
const reader = response.body.getReader();
|
|
1505
|
+
const decoder = new TextDecoder();
|
|
1506
|
+
let lineBuffer = "";
|
|
1507
|
+
outer: while (true) {
|
|
1508
|
+
const { done, value } = await reader.read();
|
|
1509
|
+
if (done) break;
|
|
1510
|
+
lineBuffer += decoder.decode(value, { stream: true });
|
|
1511
|
+
let newlineIdx;
|
|
1512
|
+
while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
|
|
1513
|
+
let line = lineBuffer.slice(0, newlineIdx);
|
|
1514
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
1515
|
+
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
1516
|
+
if (!line) continue;
|
|
1517
|
+
if (line.startsWith(":")) continue;
|
|
1518
|
+
if (!line.startsWith("data:")) continue;
|
|
1519
|
+
const dataStr = line.slice(5).trimStart();
|
|
1520
|
+
if (dataStr === "[DONE]") {
|
|
1521
|
+
sawDone = true;
|
|
1522
|
+
break outer;
|
|
1523
|
+
}
|
|
1524
|
+
let json;
|
|
1525
|
+
try {
|
|
1526
|
+
json = JSON.parse(dataStr);
|
|
1527
|
+
} catch (e) {
|
|
1528
|
+
logger_default.error(
|
|
1529
|
+
id,
|
|
1530
|
+
"OpenRouter stream: unparseable data line:",
|
|
1531
|
+
dataStr.slice(0, 200)
|
|
1532
|
+
);
|
|
1533
|
+
continue;
|
|
1534
|
+
}
|
|
1535
|
+
dataChunks++;
|
|
1536
|
+
if (json.error) {
|
|
1537
|
+
logger_default.error(id, "OpenRouter stream error event:", json.error);
|
|
1538
|
+
const error2 = new Error(
|
|
1539
|
+
`OpenRouter error: ${json.error.message}`
|
|
1540
|
+
);
|
|
1541
|
+
error2.data = json.error;
|
|
1542
|
+
throw error2;
|
|
1543
|
+
}
|
|
1544
|
+
if (json.provider) provider = json.provider;
|
|
1545
|
+
let useful = false;
|
|
1546
|
+
if (json.usage) {
|
|
1547
|
+
usage = json.usage;
|
|
1548
|
+
useful = true;
|
|
1549
|
+
}
|
|
1550
|
+
const choice = (_c = json.choices) == null ? void 0 : _c[0];
|
|
1551
|
+
if (choice) {
|
|
1552
|
+
const delta = (_d = choice.delta) != null ? _d : {};
|
|
1553
|
+
if (delta.content) {
|
|
1554
|
+
paragraph += delta.content;
|
|
1555
|
+
useful = true;
|
|
1556
|
+
}
|
|
1557
|
+
if (delta.reasoning) {
|
|
1558
|
+
reasoning += delta.reasoning;
|
|
1559
|
+
useful = true;
|
|
1560
|
+
}
|
|
1561
|
+
if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
|
|
1562
|
+
reasoningDetails.push(...delta.reasoning_details);
|
|
1563
|
+
useful = true;
|
|
1564
|
+
}
|
|
1565
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
1566
|
+
for (const toolCall of delta.tool_calls) {
|
|
1567
|
+
const idx = (_e = toolCall.index) != null ? _e : 0;
|
|
1568
|
+
while (toolCalls.length <= idx) {
|
|
1569
|
+
toolCalls.push({ name: "", argumentsJson: "" });
|
|
1570
|
+
}
|
|
1571
|
+
if (toolCall.id) toolCalls[idx].id = toolCall.id;
|
|
1572
|
+
if ((_f = toolCall.function) == null ? void 0 : _f.name)
|
|
1573
|
+
toolCalls[idx].name += toolCall.function.name;
|
|
1574
|
+
if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
|
|
1575
|
+
toolCalls[idx].argumentsJson += toolCall.function.arguments;
|
|
1576
|
+
useful = true;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
if (choice.finish_reason) {
|
|
1580
|
+
finishReason = choice.finish_reason;
|
|
1581
|
+
useful = true;
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
if (useful) armStallTimer();
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
if (sawDone) reader.cancel().catch(() => {
|
|
1588
|
+
});
|
|
1589
|
+
if (!sawDone && !finishReason) {
|
|
1590
|
+
logger_default.error(
|
|
1591
|
+
id,
|
|
1592
|
+
`OpenRouter stream ended prematurely after ${dataChunks} data chunks`
|
|
1593
|
+
);
|
|
1594
|
+
throw new Error("OpenRouter stream error: ended prematurely");
|
|
1595
|
+
}
|
|
1596
|
+
return finalizeOpenRouterMessage(id, {
|
|
1597
|
+
content: paragraph || null,
|
|
1598
|
+
toolCalls,
|
|
1599
|
+
reasoning,
|
|
1600
|
+
reasoningDetails: reasoningDetails.length ? reasoningDetails : void 0,
|
|
1601
|
+
provider,
|
|
1602
|
+
usage,
|
|
1603
|
+
forLog: () => JSON.stringify({
|
|
1604
|
+
finishReason,
|
|
1605
|
+
provider,
|
|
1606
|
+
usage,
|
|
1607
|
+
paragraph: paragraph.slice(0, 500),
|
|
1608
|
+
reasoningChars: reasoning.length,
|
|
1609
|
+
toolCalls
|
|
1610
|
+
})
|
|
1611
|
+
});
|
|
1612
|
+
} catch (error2) {
|
|
1613
|
+
if (abortReason && !(signal == null ? void 0 : signal.aborted)) {
|
|
1614
|
+
logger_default.error(id, abortReason);
|
|
1615
|
+
throw new Error(abortReason);
|
|
1616
|
+
}
|
|
1617
|
+
throw error2;
|
|
1618
|
+
} finally {
|
|
1619
|
+
clearTimeout(totalTimer);
|
|
1620
|
+
clearTimeout(stallTimer);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
function parseOpenRouterBody(id, data) {
|
|
1624
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1625
|
+
if (data.error) {
|
|
1626
|
+
logger_default.error(id, "OpenRouter error:", data.error);
|
|
1627
|
+
throw new Error(`OpenRouter error: ${data.error.message}`);
|
|
1628
|
+
}
|
|
1629
|
+
const answer = (_b = (_a = data.choices) == null ? void 0 : _a[0]) == null ? void 0 : _b.message;
|
|
1630
|
+
if (!answer) {
|
|
1631
|
+
logger_default.error(id, "Missing answer in OpenRouter API response:", data);
|
|
1632
|
+
throw new Error("Missing answer in OpenRouter API");
|
|
1633
|
+
}
|
|
1634
|
+
return finalizeOpenRouterMessage(id, {
|
|
1635
|
+
content: (_c = answer.content) != null ? _c : null,
|
|
1636
|
+
toolCalls: ((_d = answer.tool_calls) != null ? _d : []).map((tc) => ({
|
|
1637
|
+
id: tc.id,
|
|
1638
|
+
name: tc.function.name,
|
|
1639
|
+
argumentsJson: tc.function.arguments
|
|
1640
|
+
})),
|
|
1641
|
+
reasoning: (_e = answer.reasoning) != null ? _e : void 0,
|
|
1642
|
+
reasoningDetails: (_f = answer.reasoning_details) != null ? _f : void 0,
|
|
1643
|
+
provider: (_g = data.provider) != null ? _g : void 0,
|
|
1644
|
+
usage: (_h = data.usage) != null ? _h : null,
|
|
1645
|
+
forLog: () => JSON.stringify(data)
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
async function callOpenRouterNonStreaming(id, payload, requestTimeoutMs = OPENROUTER_NONSTREAM_TIMEOUT_MS, signal) {
|
|
1649
|
+
const response = await withRequestDeadline(
|
|
1650
|
+
"OpenRouter",
|
|
1651
|
+
requestTimeoutMs,
|
|
1652
|
+
signal,
|
|
1653
|
+
(mergedSignal) => axios.post(openRouterEndpoint(), payload, {
|
|
1654
|
+
headers: {
|
|
1655
|
+
"content-type": "application/json",
|
|
1656
|
+
Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`
|
|
1657
|
+
},
|
|
1658
|
+
timeout: requestTimeoutMs,
|
|
1659
|
+
signal: mergedSignal
|
|
1660
|
+
})
|
|
1661
|
+
);
|
|
1662
|
+
return parseOpenRouterBody(id, response.data);
|
|
1663
|
+
}
|
|
1664
|
+
async function callOpenRouterWithRetries(id, payload, retries = 5, options, signal) {
|
|
1459
1665
|
return withRetries(
|
|
1460
1666
|
id,
|
|
1461
1667
|
"OpenRouter",
|
|
1462
|
-
() =>
|
|
1668
|
+
() => options.streaming ? callOpenRouterStream(
|
|
1669
|
+
id,
|
|
1670
|
+
payload,
|
|
1671
|
+
options.streamTimeoutMs,
|
|
1672
|
+
options.chunkTimeoutMs,
|
|
1673
|
+
signal
|
|
1674
|
+
) : callOpenRouterNonStreaming(
|
|
1675
|
+
id,
|
|
1676
|
+
payload,
|
|
1677
|
+
options.requestTimeoutMs,
|
|
1678
|
+
signal
|
|
1679
|
+
),
|
|
1463
1680
|
{ retries, signal }
|
|
1464
1681
|
);
|
|
1465
1682
|
}
|
|
@@ -1501,7 +1718,7 @@ function parseModelString(model) {
|
|
|
1501
1718
|
);
|
|
1502
1719
|
}
|
|
1503
1720
|
async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeoutMs = 15e3) {
|
|
1504
|
-
var _a, _b, _c;
|
|
1721
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1505
1722
|
try {
|
|
1506
1723
|
const { provider, modelId } = parseModelString(aiPayload.model);
|
|
1507
1724
|
const routingPayload = { ...aiPayload, model: modelId };
|
|
@@ -1553,15 +1770,20 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1553
1770
|
id,
|
|
1554
1771
|
prepareOpenRouterPayload(routingPayload),
|
|
1555
1772
|
retries,
|
|
1556
|
-
|
|
1773
|
+
{
|
|
1774
|
+
streaming: (_b = aiPayload.streaming) != null ? _b : true,
|
|
1775
|
+
streamTimeoutMs: (_c = aiPayload.streamTimeoutMs) != null ? _c : OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1776
|
+
requestTimeoutMs: (_d = aiPayload.requestTimeoutMs) != null ? _d : OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1777
|
+
chunkTimeoutMs
|
|
1778
|
+
},
|
|
1557
1779
|
signal
|
|
1558
1780
|
);
|
|
1559
1781
|
break;
|
|
1560
1782
|
}
|
|
1561
|
-
(
|
|
1783
|
+
(_e = result.provider) != null ? _e : result.provider = provider;
|
|
1562
1784
|
return result;
|
|
1563
1785
|
} catch (error2) {
|
|
1564
|
-
if ((
|
|
1786
|
+
if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted) throw error2;
|
|
1565
1787
|
if (aiPayload.fallbackModel) {
|
|
1566
1788
|
logger_default.error(
|
|
1567
1789
|
id,
|
|
@@ -1591,6 +1813,8 @@ export {
|
|
|
1591
1813
|
GPTModel,
|
|
1592
1814
|
GeminiModel,
|
|
1593
1815
|
GroqModel,
|
|
1816
|
+
OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1817
|
+
OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1594
1818
|
OpenRouterModel,
|
|
1595
1819
|
callWithRetries,
|
|
1596
1820
|
parseModelString
|