190proof 1.0.115 → 1.0.116

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,8 +1,7 @@
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")
5
- return require.apply(this, arguments);
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
5
  throw Error('Dynamic require of "' + x + '" is not supported');
7
6
  });
8
7
 
@@ -138,8 +137,7 @@ async function withRetries(identifier, apiName, fn, options = {}) {
138
137
  return await fn();
139
138
  } catch (error3) {
140
139
  lastError = error3;
141
- if ((_a = options.signal) == null ? void 0 : _a.aborted)
142
- throw error3;
140
+ if ((_a = options.signal) == null ? void 0 : _a.aborted) throw error3;
143
141
  if (onError) {
144
142
  onError(error3, attempt);
145
143
  } else {
@@ -163,8 +161,7 @@ function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allo
163
161
  const functionCalls = [];
164
162
  for (let i = 0; i < toolCallAccumulators.length; i++) {
165
163
  const acc = toolCallAccumulators[i];
166
- if (!acc.name || !acc.arguments)
167
- continue;
164
+ if (!acc.name || !acc.arguments) continue;
168
165
  if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {
169
166
  throw new Error(
170
167
  `Stream error: received function call with unknown name: ${acc.name}`
@@ -303,8 +300,7 @@ function buildOpenAIRequestConfig(identifier, model, config) {
303
300
  };
304
301
  }
305
302
  function filterOpenAICompatReasoningDetails(details) {
306
- if (!Array.isArray(details))
307
- return details || void 0;
303
+ if (!Array.isArray(details)) return details || void 0;
308
304
  const blocks = details.filter(
309
305
  (block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
310
306
  );
@@ -376,19 +372,17 @@ async function prepareOpenAIPayload(identifier, payload) {
376
372
  };
377
373
  });
378
374
  }
379
- if (message.reasoning)
380
- outMessage.reasoning = message.reasoning;
375
+ if (message.reasoning) outMessage.reasoning = message.reasoning;
381
376
  const reasoningDetails = filterOpenAICompatReasoningDetails(
382
377
  message.reasoningDetails
383
378
  );
384
- if (reasoningDetails)
385
- outMessage.reasoning_details = reasoningDetails;
379
+ if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
386
380
  preparedPayload.messages.push(outMessage);
387
381
  }
388
382
  return preparedPayload;
389
383
  }
390
384
  async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4, signal) {
391
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
385
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
392
386
  const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null;
393
387
  const { endpoint, headers } = buildOpenAIRequestConfig(
394
388
  id,
@@ -406,7 +400,15 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
406
400
  const response = await fetch(endpoint, {
407
401
  method: "POST",
408
402
  headers,
409
- body: JSON.stringify({ ...openAiPayload, stream: true }),
403
+ // include_usage: OpenAI only reports token usage on streams when asked,
404
+ // via a final choices-less chunk — without it every streamed call is
405
+ // invisible to usage accounting. Skipped for Azure, where older
406
+ // api-versions reject stream_options.
407
+ body: JSON.stringify({
408
+ ...openAiPayload,
409
+ stream: true,
410
+ ...(openAiConfig == null ? void 0 : openAiConfig.service) !== "azure" ? { stream_options: { include_usage: true } } : {}
411
+ }),
410
412
  // Merge (don't overwrite) the internal timeout controller with the caller's
411
413
  // cancellation signal so both an internal timeout and an external abort stop
412
414
  // the stream.
@@ -417,6 +419,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
417
419
  }
418
420
  let paragraph = "";
419
421
  let reasoning = "";
422
+ let streamUsage = null;
420
423
  const toolCallAccumulators = [];
421
424
  const reader = response.body.getReader();
422
425
  let partialChunk = "";
@@ -444,17 +447,18 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
444
447
  }
445
448
  const jsonStrings = chunk.split(/^data: /gm);
446
449
  for (const jsonString of jsonStrings) {
447
- if (!jsonString)
448
- continue;
450
+ if (!jsonString) continue;
449
451
  if (jsonString.includes("[DONE]")) {
450
452
  clearTimeout(overallTimeout);
451
- return parseStreamedResponse(
453
+ const parsed = parseStreamedResponse(
452
454
  id,
453
455
  paragraph,
454
456
  toolCallAccumulators,
455
457
  functionNames,
456
458
  reasoning
457
459
  );
460
+ parsed.usage = streamUsage;
461
+ return parsed;
458
462
  }
459
463
  let json;
460
464
  try {
@@ -464,6 +468,15 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
464
468
  continue;
465
469
  }
466
470
  if (!((_a = json.choices) == null ? void 0 : _a.length)) {
471
+ if (json.usage) {
472
+ streamUsage = {
473
+ prompt_tokens: json.usage.prompt_tokens,
474
+ completion_tokens: json.usage.completion_tokens,
475
+ total_tokens: json.usage.total_tokens,
476
+ cached_tokens: (_c = (_b = json.usage.prompt_tokens_details) == null ? void 0 : _b.cached_tokens) != null ? _c : 0
477
+ };
478
+ continue;
479
+ }
467
480
  if (json.error) {
468
481
  logger_default.error(id, "Stream error from OpenAI:", json.error);
469
482
  const error2 = new Error("Stream error: OpenAI error");
@@ -476,27 +489,24 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
476
489
  }
477
490
  continue;
478
491
  }
479
- const toolCalls = (_c = (_b = json.choices[0]) == null ? void 0 : _b.delta) == null ? void 0 : _c.tool_calls;
492
+ const toolCalls = (_e = (_d = json.choices[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.tool_calls;
480
493
  if (toolCalls) {
481
494
  for (const toolCall of toolCalls) {
482
- const idx = (_d = toolCall.index) != null ? _d : 0;
495
+ const idx = (_f = toolCall.index) != null ? _f : 0;
483
496
  while (toolCallAccumulators.length <= idx) {
484
497
  toolCallAccumulators.push({ name: "", arguments: "" });
485
498
  }
486
- if (toolCall.id)
487
- toolCallAccumulators[idx].id = toolCall.id;
488
- if ((_e = toolCall.function) == null ? void 0 : _e.name)
499
+ if (toolCall.id) toolCallAccumulators[idx].id = toolCall.id;
500
+ if ((_g = toolCall.function) == null ? void 0 : _g.name)
489
501
  toolCallAccumulators[idx].name += toolCall.function.name;
490
- if ((_f = toolCall.function) == null ? void 0 : _f.arguments)
502
+ if ((_h = toolCall.function) == null ? void 0 : _h.arguments)
491
503
  toolCallAccumulators[idx].arguments += toolCall.function.arguments;
492
504
  }
493
505
  }
494
- const text = (_h = (_g = json.choices[0]) == null ? void 0 : _g.delta) == null ? void 0 : _h.content;
495
- if (text)
496
- paragraph += text;
497
- const reasoningDelta = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.reasoning;
498
- if (reasoningDelta)
499
- reasoning += reasoningDelta;
506
+ const text = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.content;
507
+ if (text) paragraph += text;
508
+ const reasoningDelta = (_l = (_k = json.choices[0]) == null ? void 0 : _k.delta) == null ? void 0 : _l.reasoning;
509
+ if (reasoningDelta) reasoning += reasoningDelta;
500
510
  }
501
511
  }
502
512
  }
@@ -641,8 +651,7 @@ function jigAnthropicMessages(messages) {
641
651
  ];
642
652
  }
643
653
  jiggedMessages = jiggedMessages.reduce((acc, message) => {
644
- if (acc.length === 0)
645
- return [message];
654
+ if (acc.length === 0) return [message];
646
655
  const lastMessage = acc[acc.length - 1];
647
656
  if (lastMessage.role === message.role) {
648
657
  const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
@@ -896,8 +905,7 @@ function jigGoogleMessages(messages) {
896
905
  ];
897
906
  }
898
907
  jiggedMessages = jiggedMessages.reduce((acc, message) => {
899
- if (acc.length === 0)
900
- return [message];
908
+ if (acc.length === 0) return [message];
901
909
  const lastMessage = acc[acc.length - 1];
902
910
  if (lastMessage.role === message.role) {
903
911
  lastMessage.parts = [...lastMessage.parts, ...message.parts];
@@ -936,8 +944,7 @@ async function prepareGoogleAIPayload(_identifier, payload) {
936
944
  const toolNameById = /* @__PURE__ */ new Map();
937
945
  for (const m of payload.messages) {
938
946
  for (const fc of m.functionCalls || []) {
939
- if (fc.id)
940
- toolNameById.set(fc.id, fc.name);
947
+ if (fc.id) toolNameById.set(fc.id, fc.name);
941
948
  }
942
949
  }
943
950
  for (const message of payload.messages) {
@@ -1017,8 +1024,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
1017
1024
  ...payload.thinkingConfig ? { thinkingConfig: payload.thinkingConfig } : {}
1018
1025
  }
1019
1026
  };
1020
- if (payload.tools)
1021
- requestBody.tools = [payload.tools];
1027
+ if (payload.tools) requestBody.tools = [payload.tools];
1022
1028
  if (payload.tools && payload.toolConfig) {
1023
1029
  requestBody.toolConfig = payload.toolConfig;
1024
1030
  }
@@ -1076,8 +1082,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
1076
1082
  });
1077
1083
  continue;
1078
1084
  }
1079
- if (part.text)
1080
- text += part.text;
1085
+ if (part.text) text += part.text;
1081
1086
  if ((_m = part.inlineData) == null ? void 0 : _m.data) {
1082
1087
  files.push({ mimeType: "image/png", data: part.inlineData.data });
1083
1088
  }
@@ -1155,21 +1160,15 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
1155
1160
  finishReason: error2.finishReason,
1156
1161
  modelVersion: error2.modelVersion
1157
1162
  };
1158
- if (error2.safetyRatings)
1159
- errorDetails.safetyRatings = error2.safetyRatings;
1160
- if (error2.usageMetadata)
1161
- errorDetails.usageMetadata = error2.usageMetadata;
1163
+ if (error2.safetyRatings) errorDetails.safetyRatings = error2.safetyRatings;
1164
+ if (error2.usageMetadata) errorDetails.usageMetadata = error2.usageMetadata;
1162
1165
  if (error2.promptFeedback)
1163
1166
  errorDetails.promptFeedback = error2.promptFeedback;
1164
- if (error2.status)
1165
- errorDetails.httpStatus = error2.status;
1166
- if (error2.code)
1167
- errorDetails.errorCode = error2.code;
1168
- if (error2.details)
1169
- errorDetails.errorDetails = error2.details;
1167
+ if (error2.status) errorDetails.httpStatus = error2.status;
1168
+ if (error2.code) errorDetails.errorCode = error2.code;
1169
+ if (error2.details) errorDetails.errorDetails = error2.details;
1170
1170
  const fileUris = payload.messages.flatMap((m) => m.parts).filter((p) => "fileData" in p).map((p) => p.fileData.fileUri);
1171
- if (fileUris.length)
1172
- errorDetails.fileUris = fileUris;
1171
+ if (fileUris.length) errorDetails.fileUris = fileUris;
1173
1172
  logger_default.error(
1174
1173
  id,
1175
1174
  `Retry #${attempt} error: ${error2.message}`,
@@ -1219,7 +1218,7 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
1219
1218
  function normalizeMessageContent(content) {
1220
1219
  return Array.isArray(content) ? content.map((c) => c.type === "text" ? c.text : `[${c.type}]`).join("\n") : content;
1221
1220
  }
1222
- function prepareOpenAICompatMessages(messages) {
1221
+ function prepareOpenAICompatMessages(messages, opts = {}) {
1223
1222
  var _a;
1224
1223
  const out = [];
1225
1224
  for (const message of messages) {
@@ -1241,6 +1240,22 @@ function prepareOpenAICompatMessages(messages) {
1241
1240
  role: message.role,
1242
1241
  content
1243
1242
  };
1243
+ if (opts.imageParts) {
1244
+ const imageBlocks = (message.files || []).filter(
1245
+ (file) => ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType) && (file.url || file.data)
1246
+ ).map((file) => ({
1247
+ type: "image_url",
1248
+ image_url: {
1249
+ url: file.url || `data:${file.mimeType};base64,${file.data}`
1250
+ }
1251
+ }));
1252
+ if (imageBlocks.length) {
1253
+ outMessage.content = [
1254
+ ...content ? [{ type: "text", text: content }] : [],
1255
+ ...imageBlocks
1256
+ ];
1257
+ }
1258
+ }
1244
1259
  if ((_a = message.functionCalls) == null ? void 0 : _a.length) {
1245
1260
  outMessage.tool_calls = message.functionCalls.map((fc, i) => {
1246
1261
  var _a2;
@@ -1253,16 +1268,14 @@ function prepareOpenAICompatMessages(messages) {
1253
1268
  }
1254
1269
  };
1255
1270
  });
1256
- if (!content)
1271
+ if (!content && !Array.isArray(outMessage.content))
1257
1272
  outMessage.content = null;
1258
1273
  }
1259
- if (message.reasoning)
1260
- outMessage.reasoning = message.reasoning;
1274
+ if (message.reasoning) outMessage.reasoning = message.reasoning;
1261
1275
  const reasoningDetails = filterOpenAICompatReasoningDetails(
1262
1276
  message.reasoningDetails
1263
1277
  );
1264
- if (reasoningDetails)
1265
- outMessage.reasoning_details = reasoningDetails;
1278
+ if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
1266
1279
  out.push(outMessage);
1267
1280
  }
1268
1281
  return out;
@@ -1350,11 +1363,14 @@ async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs =
1350
1363
  signal
1351
1364
  });
1352
1365
  }
1366
+ var openRouterImageRejectedModels = /* @__PURE__ */ new Set();
1353
1367
  function prepareOpenRouterPayload(payload) {
1354
1368
  var _a;
1355
1369
  return {
1356
1370
  model: payload.model,
1357
- messages: prepareOpenAICompatMessages(payload.messages),
1371
+ messages: prepareOpenAICompatMessages(payload.messages, {
1372
+ imageParts: !openRouterImageRejectedModels.has(String(payload.model))
1373
+ }),
1358
1374
  tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({
1359
1375
  type: "function",
1360
1376
  function: fn
@@ -1405,8 +1421,7 @@ function parseDsmlToolCalls(content) {
1405
1421
  let last = -1;
1406
1422
  let tag;
1407
1423
  while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
1408
- if (first === -1)
1409
- first = tag.index;
1424
+ if (first === -1) first = tag.index;
1410
1425
  last = tag.index + tag[0].length;
1411
1426
  }
1412
1427
  const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
@@ -1422,8 +1437,7 @@ function finalizeOpenRouterMessage(id, raw) {
1422
1437
  const functionCalls = [];
1423
1438
  for (let i = 0; i < raw.toolCalls.length; i++) {
1424
1439
  const tc = raw.toolCalls[i];
1425
- if (!tc.name)
1426
- continue;
1440
+ if (!tc.name) continue;
1427
1441
  functionCalls.push({
1428
1442
  id: (_a = tc.id) != null ? _a : `call_${i}`,
1429
1443
  name: tc.name,
@@ -1476,8 +1490,7 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1476
1490
  controller.abort();
1477
1491
  };
1478
1492
  const unref = (t) => {
1479
- if (typeof t === "object" && "unref" in t)
1480
- t.unref();
1493
+ if (typeof t === "object" && "unref" in t) t.unref();
1481
1494
  return t;
1482
1495
  };
1483
1496
  const totalTimer = unref(
@@ -1545,98 +1558,88 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
1545
1558
  const reader = response.body.getReader();
1546
1559
  const decoder = new TextDecoder();
1547
1560
  let lineBuffer = "";
1548
- outer:
1549
- while (true) {
1550
- const { done, value } = await reader.read();
1551
- if (done)
1552
- break;
1553
- lineBuffer += decoder.decode(value, { stream: true });
1554
- let newlineIdx;
1555
- while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
1556
- let line = lineBuffer.slice(0, newlineIdx);
1557
- lineBuffer = lineBuffer.slice(newlineIdx + 1);
1558
- if (line.endsWith("\r"))
1559
- line = line.slice(0, -1);
1560
- if (!line)
1561
- continue;
1562
- if (line.startsWith(":"))
1563
- continue;
1564
- if (!line.startsWith("data:"))
1565
- continue;
1566
- const dataStr = line.slice(5).trimStart();
1567
- if (dataStr === "[DONE]") {
1568
- sawDone = true;
1569
- break outer;
1570
- }
1571
- let json;
1572
- try {
1573
- json = JSON.parse(dataStr);
1574
- } catch (e) {
1575
- logger_default.error(
1576
- id,
1577
- "OpenRouter stream: unparseable data line:",
1578
- dataStr.slice(0, 200)
1579
- );
1580
- continue;
1561
+ outer: while (true) {
1562
+ const { done, value } = await reader.read();
1563
+ if (done) break;
1564
+ lineBuffer += decoder.decode(value, { stream: true });
1565
+ let newlineIdx;
1566
+ while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
1567
+ let line = lineBuffer.slice(0, newlineIdx);
1568
+ lineBuffer = lineBuffer.slice(newlineIdx + 1);
1569
+ if (line.endsWith("\r")) line = line.slice(0, -1);
1570
+ if (!line) continue;
1571
+ if (line.startsWith(":")) continue;
1572
+ if (!line.startsWith("data:")) continue;
1573
+ const dataStr = line.slice(5).trimStart();
1574
+ if (dataStr === "[DONE]") {
1575
+ sawDone = true;
1576
+ break outer;
1577
+ }
1578
+ let json;
1579
+ try {
1580
+ json = JSON.parse(dataStr);
1581
+ } catch (e) {
1582
+ logger_default.error(
1583
+ id,
1584
+ "OpenRouter stream: unparseable data line:",
1585
+ dataStr.slice(0, 200)
1586
+ );
1587
+ continue;
1588
+ }
1589
+ dataChunks++;
1590
+ if (json.error) {
1591
+ logger_default.error(id, "OpenRouter stream error event:", json.error);
1592
+ const error2 = new Error(
1593
+ `OpenRouter error: ${json.error.message}`
1594
+ );
1595
+ error2.data = json.error;
1596
+ throw error2;
1597
+ }
1598
+ if (json.provider) provider = json.provider;
1599
+ let useful = false;
1600
+ if (json.usage) {
1601
+ usage = json.usage;
1602
+ useful = true;
1603
+ }
1604
+ const choice = (_c = json.choices) == null ? void 0 : _c[0];
1605
+ if (choice) {
1606
+ const delta = (_d = choice.delta) != null ? _d : {};
1607
+ if (delta.content) {
1608
+ paragraph += delta.content;
1609
+ useful = true;
1581
1610
  }
1582
- dataChunks++;
1583
- if (json.error) {
1584
- logger_default.error(id, "OpenRouter stream error event:", json.error);
1585
- const error2 = new Error(
1586
- `OpenRouter error: ${json.error.message}`
1587
- );
1588
- error2.data = json.error;
1589
- throw error2;
1611
+ if (delta.reasoning) {
1612
+ reasoning += delta.reasoning;
1613
+ useful = true;
1590
1614
  }
1591
- if (json.provider)
1592
- provider = json.provider;
1593
- let useful = false;
1594
- if (json.usage) {
1595
- usage = json.usage;
1615
+ if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
1616
+ reasoningDetails.push(...delta.reasoning_details);
1596
1617
  useful = true;
1597
1618
  }
1598
- const choice = (_c = json.choices) == null ? void 0 : _c[0];
1599
- if (choice) {
1600
- const delta = (_d = choice.delta) != null ? _d : {};
1601
- if (delta.content) {
1602
- paragraph += delta.content;
1603
- useful = true;
1604
- }
1605
- if (delta.reasoning) {
1606
- reasoning += delta.reasoning;
1607
- useful = true;
1608
- }
1609
- if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
1610
- reasoningDetails.push(...delta.reasoning_details);
1611
- useful = true;
1612
- }
1613
- if (Array.isArray(delta.tool_calls)) {
1614
- for (const toolCall of delta.tool_calls) {
1615
- const idx = (_e = toolCall.index) != null ? _e : 0;
1616
- while (toolCalls.length <= idx) {
1617
- toolCalls.push({ name: "", argumentsJson: "" });
1618
- }
1619
- if (toolCall.id)
1620
- toolCalls[idx].id = toolCall.id;
1621
- if ((_f = toolCall.function) == null ? void 0 : _f.name)
1622
- toolCalls[idx].name += toolCall.function.name;
1623
- if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
1624
- toolCalls[idx].argumentsJson += toolCall.function.arguments;
1625
- useful = true;
1619
+ if (Array.isArray(delta.tool_calls)) {
1620
+ for (const toolCall of delta.tool_calls) {
1621
+ const idx = (_e = toolCall.index) != null ? _e : 0;
1622
+ while (toolCalls.length <= idx) {
1623
+ toolCalls.push({ name: "", argumentsJson: "" });
1626
1624
  }
1627
- }
1628
- if (choice.finish_reason) {
1629
- finishReason = choice.finish_reason;
1625
+ if (toolCall.id) toolCalls[idx].id = toolCall.id;
1626
+ if ((_f = toolCall.function) == null ? void 0 : _f.name)
1627
+ toolCalls[idx].name += toolCall.function.name;
1628
+ if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
1629
+ toolCalls[idx].argumentsJson += toolCall.function.arguments;
1630
1630
  useful = true;
1631
1631
  }
1632
1632
  }
1633
- if (useful)
1634
- armStallTimer();
1633
+ if (choice.finish_reason) {
1634
+ finishReason = choice.finish_reason;
1635
+ useful = true;
1636
+ }
1635
1637
  }
1638
+ if (useful) armStallTimer();
1636
1639
  }
1637
- if (sawDone)
1638
- reader.cancel().catch(() => {
1639
- });
1640
+ }
1641
+ if (sawDone) reader.cancel().catch(() => {
1642
+ });
1640
1643
  if (!sawDone && !finishReason) {
1641
1644
  logger_default.error(
1642
1645
  id,
@@ -1743,15 +1746,12 @@ var MODERATION_RE = /moderat|inappropriate content|content polic|content managem
1743
1746
  function moderationEvictionSlug(error2, payload) {
1744
1747
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1745
1748
  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;
1746
- if (!body)
1747
- return null;
1749
+ if (!body) return null;
1748
1750
  const message = String((_d = body.message) != null ? _d : "");
1749
1751
  const isModeration = body.code === 403 || Array.isArray((_e = body.metadata) == null ? void 0 : _e.reasons) || MODERATION_RE.test(message);
1750
- if (!isModeration)
1751
- return null;
1752
+ if (!isModeration) return null;
1752
1753
  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];
1753
- if (!display)
1754
- return null;
1754
+ if (!display) return null;
1755
1755
  const key = normalizeProviderKey(display);
1756
1756
  const fromOrder = (_j = (_i = payload.provider) == null ? void 0 : _i.order) == null ? void 0 : _j.find(
1757
1757
  (entry) => normalizeProviderKey(entry) === key
@@ -1760,12 +1760,15 @@ function moderationEvictionSlug(error2, payload) {
1760
1760
  }
1761
1761
  var MIN_STREAM_ATTEMPT_MS = 1e4;
1762
1762
  var estimateTokens = (text) => Math.round(text.length / 4);
1763
+ function isImageInputRejection(error2) {
1764
+ var _a, _b, _c, _d;
1765
+ 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;
1766
+ return /no endpoints found.*image input/i.test(String((_d = body == null ? void 0 : body.message) != null ? _d : ""));
1767
+ }
1763
1768
  function streamAttemptBudgetMs(options) {
1764
- if (options.streamDeadlineAt === void 0)
1765
- return options.streamTimeoutMs;
1769
+ if (options.streamDeadlineAt === void 0) return options.streamTimeoutMs;
1766
1770
  const remaining = options.streamDeadlineAt - Date.now();
1767
- if (remaining < MIN_STREAM_ATTEMPT_MS)
1768
- return null;
1771
+ if (remaining < MIN_STREAM_ATTEMPT_MS) return null;
1769
1772
  return Math.min(options.streamTimeoutMs, remaining);
1770
1773
  }
1771
1774
  async function callOpenRouterWithRetries(id, payload, retries = 5, options, signal) {
@@ -1812,6 +1815,16 @@ async function callOpenRouterWithRetries(id, payload, retries = 5, options, sign
1812
1815
  `OpenRouter moderation eviction: ignoring provider "${slug}" for remaining attempts`
1813
1816
  );
1814
1817
  }
1818
+ if (isImageInputRejection(error2) && options.genericMessages) {
1819
+ openRouterImageRejectedModels.add(String(payload.model));
1820
+ payload.messages = prepareOpenAICompatMessages(
1821
+ options.genericMessages
1822
+ );
1823
+ logger_default.log(
1824
+ id,
1825
+ `OpenRouter: ${payload.model} has no image-capable endpoints; retrying with images as text refs`
1826
+ );
1827
+ }
1815
1828
  throw error2;
1816
1829
  }),
1817
1830
  { retries, signal }
@@ -1912,7 +1925,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1912
1925
  streamTimeoutMs: (_c = aiPayload.streamTimeoutMs) != null ? _c : OPENROUTER_STREAM_TIMEOUT_MS,
1913
1926
  streamDeadlineAt: aiPayload.streamDeadlineAt,
1914
1927
  requestTimeoutMs: (_d = aiPayload.requestTimeoutMs) != null ? _d : OPENROUTER_NONSTREAM_TIMEOUT_MS,
1915
- chunkTimeoutMs
1928
+ chunkTimeoutMs,
1929
+ genericMessages: routingPayload.messages
1916
1930
  },
1917
1931
  signal
1918
1932
  );
@@ -1921,8 +1935,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
1921
1935
  (_e = result.provider) != null ? _e : result.provider = provider;
1922
1936
  return result;
1923
1937
  } catch (error2) {
1924
- if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted)
1925
- throw error2;
1938
+ if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted) throw error2;
1926
1939
  if (aiPayload.fallbackModel) {
1927
1940
  logger_default.error(
1928
1941
  id,
@@ -1957,6 +1970,7 @@ export {
1957
1970
  OPENROUTER_STREAM_TIMEOUT_MS,
1958
1971
  OpenRouterModel,
1959
1972
  callWithRetries,
1973
+ openRouterImageRejectedModels,
1960
1974
  parseModelString
1961
1975
  };
1962
1976
  //# sourceMappingURL=index.mjs.map