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/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") return require.apply(this, arguments);
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) throw error3;
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) continue;
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)) return details || void 0;
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) outMessage.reasoning = 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) outMessage.reasoning_details = 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) continue;
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) toolCallAccumulators[idx].id = 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) paragraph += 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) reasoning += 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) return [message];
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) return [message];
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) toolNameById.set(fc.id, fc.name);
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) requestBody.tools = [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) text += 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) errorDetails.safetyRatings = error2.safetyRatings;
1138
- if (error2.usageMetadata) errorDetails.usageMetadata = error2.usageMetadata;
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) errorDetails.httpStatus = error2.status;
1142
- if (error2.code) errorDetails.errorCode = error2.code;
1143
- if (error2.details) errorDetails.errorDetails = error2.details;
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) errorDetails.fileUris = fileUris;
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) outMessage.content = null;
1246
+ if (!message.content)
1247
+ outMessage.content = null;
1226
1248
  }
1227
- if (message.reasoning) outMessage.reasoning = 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) outMessage.reasoning_details = 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) first = tag.index;
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
- async function callOpenRouter(id, payload, requestTimeoutMs = 12e4, signal) {
1381
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1382
- const response = await withRequestDeadline(
1383
- "OpenRouter",
1384
- requestTimeoutMs,
1385
- signal,
1386
- (mergedSignal) => axios.post(
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
- if ((_c = answer.tool_calls) == null ? void 0 : _c.length) {
1411
- for (let i = 0; i < answer.tool_calls.length; i++) {
1412
- const tc = answer.tool_calls[i];
1413
- functionCalls.push({
1414
- id: (_d = tc.id) != null ? _d : `call_${i}`,
1415
- name: tc.function.name,
1416
- arguments: JSON.parse(tc.function.arguments)
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 = (_e = answer.content) != null ? _e : null;
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: (_f = answer.reasoning) != null ? _f : void 0,
1446
- reasoningDetails: (_g = answer.reasoning_details) != null ? _g : void 0,
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: (_h = response.data.provider) != null ? _h : void 0,
1450
- usage: response.data.usage ? {
1451
- prompt_tokens: response.data.usage.prompt_tokens,
1452
- completion_tokens: response.data.usage.completion_tokens,
1453
- total_tokens: response.data.usage.total_tokens,
1454
- cached_tokens: (_j = (_i = response.data.usage.prompt_tokens_details) == null ? void 0 : _i.cached_tokens) != null ? _j : 0
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 callOpenRouterWithRetries(id, payload, retries = 5, requestTimeoutMs = 12e4, signal) {
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
- () => callOpenRouter(id, payload, requestTimeoutMs, signal),
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
- requestTimeoutMs,
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
- (_b = result.provider) != null ? _b : result.provider = provider;
1861
+ (_e = result.provider) != null ? _e : result.provider = provider;
1562
1862
  return result;
1563
1863
  } catch (error2) {
1564
- if ((_c = aiPayload.signal) == null ? void 0 : _c.aborted) throw error2;
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