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/README.md +10 -0
- package/dist/index.d.mts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +176 -160
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +173 -159
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -136,6 +136,16 @@ const payload: GenericPayload = {
|
|
|
136
136
|
const response = await callWithRetries("image-example", payload);
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
+
How images reach the model depends on the provider. OpenAI, Anthropic, and
|
|
140
|
+
Google get native image blocks. Groq is text-only: images degrade to an inline
|
|
141
|
+
`Image (url)` text reference. OpenRouter sends OpenAI-style `image_url` content
|
|
142
|
+
parts (the remote URL when present, else a `data:` URI) — but if the model has
|
|
143
|
+
no vision-capable endpoints, OpenRouter rejects the request with a
|
|
144
|
+
routing-layer 404, so the retry loop resends the payload with images degraded
|
|
145
|
+
to the same inline text references Groq gets, and remembers the model
|
|
146
|
+
(in-process, until restart) so later calls degrade up front. Messages without
|
|
147
|
+
image attachments serialize identically either way.
|
|
148
|
+
|
|
139
149
|
### With System Messages
|
|
140
150
|
|
|
141
151
|
```typescript
|
package/dist/index.d.mts
CHANGED
|
@@ -352,6 +352,15 @@ interface GenericPayload {
|
|
|
352
352
|
signal?: AbortSignal;
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
/**
|
|
356
|
+
* In-process memory of OpenRouter models that rejected image input (the
|
|
357
|
+
* routing-layer 404 "No endpoints found that support image input"). Payloads
|
|
358
|
+
* for these models degrade image attachments to inline `Image (url)` text
|
|
359
|
+
* references up front — the exact pre-vision serialization — instead of
|
|
360
|
+
* burning a doomed attempt per call. Populated by the retry loop on first
|
|
361
|
+
* rejection; cleared only by process restart (exported so tests can reset it).
|
|
362
|
+
*/
|
|
363
|
+
declare const openRouterImageRejectedModels: Set<string>;
|
|
355
364
|
declare const OPENROUTER_STREAM_TIMEOUT_MS = 600000;
|
|
356
365
|
declare const OPENROUTER_NONSTREAM_TIMEOUT_MS = 180000;
|
|
357
366
|
/**
|
|
@@ -366,4 +375,4 @@ declare function parseModelString(model: string): {
|
|
|
366
375
|
};
|
|
367
376
|
declare function callWithRetries(id: string | string[], aiPayload: GenericPayload, aiConfig?: OpenAIConfig | AnthropicAIConfig, retries?: number, chunkTimeoutMs?: number): Promise<ParsedResponseMessage>;
|
|
368
377
|
|
|
369
|
-
export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, parseModelString };
|
|
378
|
+
export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString };
|
package/dist/index.d.ts
CHANGED
|
@@ -352,6 +352,15 @@ interface GenericPayload {
|
|
|
352
352
|
signal?: AbortSignal;
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
+
/**
|
|
356
|
+
* In-process memory of OpenRouter models that rejected image input (the
|
|
357
|
+
* routing-layer 404 "No endpoints found that support image input"). Payloads
|
|
358
|
+
* for these models degrade image attachments to inline `Image (url)` text
|
|
359
|
+
* references up front — the exact pre-vision serialization — instead of
|
|
360
|
+
* burning a doomed attempt per call. Populated by the retry loop on first
|
|
361
|
+
* rejection; cleared only by process restart (exported so tests can reset it).
|
|
362
|
+
*/
|
|
363
|
+
declare const openRouterImageRejectedModels: Set<string>;
|
|
355
364
|
declare const OPENROUTER_STREAM_TIMEOUT_MS = 600000;
|
|
356
365
|
declare const OPENROUTER_NONSTREAM_TIMEOUT_MS = 180000;
|
|
357
366
|
/**
|
|
@@ -366,4 +375,4 @@ declare function parseModelString(model: string): {
|
|
|
366
375
|
};
|
|
367
376
|
declare function callWithRetries(id: string | string[], aiPayload: GenericPayload, aiConfig?: OpenAIConfig | AnthropicAIConfig, retries?: number, chunkTimeoutMs?: number): Promise<ParsedResponseMessage>;
|
|
368
377
|
|
|
369
|
-
export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, parseModelString };
|
|
378
|
+
export { type AnyModel, ClaudeModel, type FunctionCall, type FunctionDefinition, GPTModel, GeminiModel, type GenericMessage, type GenericPayload, GroqModel, MIN_STREAM_ATTEMPT_MS, OPENROUTER_NONSTREAM_TIMEOUT_MS, OPENROUTER_STREAM_TIMEOUT_MS, type OpenAIConfig, OpenRouterModel, type OpenRouterProviderPreferences, type ParsedResponseMessage, type Provider, type ToolResult, callWithRetries, openRouterImageRejectedModels, parseModelString };
|
package/dist/index.js
CHANGED
|
@@ -28,8 +28,8 @@ 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 index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
33
|
ClaudeModel: () => ClaudeModel,
|
|
34
34
|
GPTModel: () => GPTModel,
|
|
35
35
|
GeminiModel: () => GeminiModel,
|
|
@@ -39,9 +39,10 @@ __export(proof_exports, {
|
|
|
39
39
|
OPENROUTER_STREAM_TIMEOUT_MS: () => OPENROUTER_STREAM_TIMEOUT_MS,
|
|
40
40
|
OpenRouterModel: () => OpenRouterModel,
|
|
41
41
|
callWithRetries: () => callWithRetries,
|
|
42
|
+
openRouterImageRejectedModels: () => openRouterImageRejectedModels,
|
|
42
43
|
parseModelString: () => parseModelString
|
|
43
44
|
});
|
|
44
|
-
module.exports = __toCommonJS(
|
|
45
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
46
|
|
|
46
47
|
// interfaces.ts
|
|
47
48
|
var ClaudeModel = /* @__PURE__ */ ((ClaudeModel2) => {
|
|
@@ -172,8 +173,7 @@ async function withRetries(identifier, apiName, fn, options = {}) {
|
|
|
172
173
|
return await fn();
|
|
173
174
|
} catch (error3) {
|
|
174
175
|
lastError = error3;
|
|
175
|
-
if ((_a = options.signal) == null ? void 0 : _a.aborted)
|
|
176
|
-
throw error3;
|
|
176
|
+
if ((_a = options.signal) == null ? void 0 : _a.aborted) throw error3;
|
|
177
177
|
if (onError) {
|
|
178
178
|
onError(error3, attempt);
|
|
179
179
|
} else {
|
|
@@ -197,8 +197,7 @@ function parseStreamedResponse(identifier, paragraph, toolCallAccumulators, allo
|
|
|
197
197
|
const functionCalls = [];
|
|
198
198
|
for (let i = 0; i < toolCallAccumulators.length; i++) {
|
|
199
199
|
const acc = toolCallAccumulators[i];
|
|
200
|
-
if (!acc.name || !acc.arguments)
|
|
201
|
-
continue;
|
|
200
|
+
if (!acc.name || !acc.arguments) continue;
|
|
202
201
|
if (allowedFunctionNames && !allowedFunctionNames.has(acc.name)) {
|
|
203
202
|
throw new Error(
|
|
204
203
|
`Stream error: received function call with unknown name: ${acc.name}`
|
|
@@ -337,8 +336,7 @@ function buildOpenAIRequestConfig(identifier, model, config) {
|
|
|
337
336
|
};
|
|
338
337
|
}
|
|
339
338
|
function filterOpenAICompatReasoningDetails(details) {
|
|
340
|
-
if (!Array.isArray(details))
|
|
341
|
-
return details || void 0;
|
|
339
|
+
if (!Array.isArray(details)) return details || void 0;
|
|
342
340
|
const blocks = details.filter(
|
|
343
341
|
(block) => typeof (block == null ? void 0 : block.type) === "string" && block.type.startsWith("reasoning.")
|
|
344
342
|
);
|
|
@@ -410,19 +408,17 @@ async function prepareOpenAIPayload(identifier, payload) {
|
|
|
410
408
|
};
|
|
411
409
|
});
|
|
412
410
|
}
|
|
413
|
-
if (message.reasoning)
|
|
414
|
-
outMessage.reasoning = message.reasoning;
|
|
411
|
+
if (message.reasoning) outMessage.reasoning = message.reasoning;
|
|
415
412
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
416
413
|
message.reasoningDetails
|
|
417
414
|
);
|
|
418
|
-
if (reasoningDetails)
|
|
419
|
-
outMessage.reasoning_details = reasoningDetails;
|
|
415
|
+
if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
|
|
420
416
|
preparedPayload.messages.push(outMessage);
|
|
421
417
|
}
|
|
422
418
|
return preparedPayload;
|
|
423
419
|
}
|
|
424
420
|
async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs, requestTimeoutMs = 12e4, signal) {
|
|
425
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
421
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
426
422
|
const functionNames = openAiPayload.tools ? new Set(openAiPayload.tools.map((fn) => fn.function.name)) : null;
|
|
427
423
|
const { endpoint, headers } = buildOpenAIRequestConfig(
|
|
428
424
|
id,
|
|
@@ -440,7 +436,15 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
440
436
|
const response = await fetch(endpoint, {
|
|
441
437
|
method: "POST",
|
|
442
438
|
headers,
|
|
443
|
-
|
|
439
|
+
// include_usage: OpenAI only reports token usage on streams when asked,
|
|
440
|
+
// via a final choices-less chunk — without it every streamed call is
|
|
441
|
+
// invisible to usage accounting. Skipped for Azure, where older
|
|
442
|
+
// api-versions reject stream_options.
|
|
443
|
+
body: JSON.stringify({
|
|
444
|
+
...openAiPayload,
|
|
445
|
+
stream: true,
|
|
446
|
+
...(openAiConfig == null ? void 0 : openAiConfig.service) !== "azure" ? { stream_options: { include_usage: true } } : {}
|
|
447
|
+
}),
|
|
444
448
|
// Merge (don't overwrite) the internal timeout controller with the caller's
|
|
445
449
|
// cancellation signal so both an internal timeout and an external abort stop
|
|
446
450
|
// the stream.
|
|
@@ -451,6 +455,7 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
451
455
|
}
|
|
452
456
|
let paragraph = "";
|
|
453
457
|
let reasoning = "";
|
|
458
|
+
let streamUsage = null;
|
|
454
459
|
const toolCallAccumulators = [];
|
|
455
460
|
const reader = response.body.getReader();
|
|
456
461
|
let partialChunk = "";
|
|
@@ -478,17 +483,18 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
478
483
|
}
|
|
479
484
|
const jsonStrings = chunk.split(/^data: /gm);
|
|
480
485
|
for (const jsonString of jsonStrings) {
|
|
481
|
-
if (!jsonString)
|
|
482
|
-
continue;
|
|
486
|
+
if (!jsonString) continue;
|
|
483
487
|
if (jsonString.includes("[DONE]")) {
|
|
484
488
|
clearTimeout(overallTimeout);
|
|
485
|
-
|
|
489
|
+
const parsed = parseStreamedResponse(
|
|
486
490
|
id,
|
|
487
491
|
paragraph,
|
|
488
492
|
toolCallAccumulators,
|
|
489
493
|
functionNames,
|
|
490
494
|
reasoning
|
|
491
495
|
);
|
|
496
|
+
parsed.usage = streamUsage;
|
|
497
|
+
return parsed;
|
|
492
498
|
}
|
|
493
499
|
let json;
|
|
494
500
|
try {
|
|
@@ -498,6 +504,15 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
498
504
|
continue;
|
|
499
505
|
}
|
|
500
506
|
if (!((_a = json.choices) == null ? void 0 : _a.length)) {
|
|
507
|
+
if (json.usage) {
|
|
508
|
+
streamUsage = {
|
|
509
|
+
prompt_tokens: json.usage.prompt_tokens,
|
|
510
|
+
completion_tokens: json.usage.completion_tokens,
|
|
511
|
+
total_tokens: json.usage.total_tokens,
|
|
512
|
+
cached_tokens: (_c = (_b = json.usage.prompt_tokens_details) == null ? void 0 : _b.cached_tokens) != null ? _c : 0
|
|
513
|
+
};
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
501
516
|
if (json.error) {
|
|
502
517
|
logger_default.error(id, "Stream error from OpenAI:", json.error);
|
|
503
518
|
const error2 = new Error("Stream error: OpenAI error");
|
|
@@ -510,27 +525,24 @@ async function callOpenAIStream(id, openAiPayload, openAiConfig, chunkTimeoutMs,
|
|
|
510
525
|
}
|
|
511
526
|
continue;
|
|
512
527
|
}
|
|
513
|
-
const toolCalls = (
|
|
528
|
+
const toolCalls = (_e = (_d = json.choices[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.tool_calls;
|
|
514
529
|
if (toolCalls) {
|
|
515
530
|
for (const toolCall of toolCalls) {
|
|
516
|
-
const idx = (
|
|
531
|
+
const idx = (_f = toolCall.index) != null ? _f : 0;
|
|
517
532
|
while (toolCallAccumulators.length <= idx) {
|
|
518
533
|
toolCallAccumulators.push({ name: "", arguments: "" });
|
|
519
534
|
}
|
|
520
|
-
if (toolCall.id)
|
|
521
|
-
|
|
522
|
-
if ((_e = toolCall.function) == null ? void 0 : _e.name)
|
|
535
|
+
if (toolCall.id) toolCallAccumulators[idx].id = toolCall.id;
|
|
536
|
+
if ((_g = toolCall.function) == null ? void 0 : _g.name)
|
|
523
537
|
toolCallAccumulators[idx].name += toolCall.function.name;
|
|
524
|
-
if ((
|
|
538
|
+
if ((_h = toolCall.function) == null ? void 0 : _h.arguments)
|
|
525
539
|
toolCallAccumulators[idx].arguments += toolCall.function.arguments;
|
|
526
540
|
}
|
|
527
541
|
}
|
|
528
|
-
const text = (
|
|
529
|
-
if (text)
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if (reasoningDelta)
|
|
533
|
-
reasoning += reasoningDelta;
|
|
542
|
+
const text = (_j = (_i = json.choices[0]) == null ? void 0 : _i.delta) == null ? void 0 : _j.content;
|
|
543
|
+
if (text) paragraph += text;
|
|
544
|
+
const reasoningDelta = (_l = (_k = json.choices[0]) == null ? void 0 : _k.delta) == null ? void 0 : _l.reasoning;
|
|
545
|
+
if (reasoningDelta) reasoning += reasoningDelta;
|
|
534
546
|
}
|
|
535
547
|
}
|
|
536
548
|
}
|
|
@@ -675,8 +687,7 @@ function jigAnthropicMessages(messages) {
|
|
|
675
687
|
];
|
|
676
688
|
}
|
|
677
689
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
678
|
-
if (acc.length === 0)
|
|
679
|
-
return [message];
|
|
690
|
+
if (acc.length === 0) return [message];
|
|
680
691
|
const lastMessage = acc[acc.length - 1];
|
|
681
692
|
if (lastMessage.role === message.role) {
|
|
682
693
|
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [{ type: "text", text: lastMessage.content }];
|
|
@@ -930,8 +941,7 @@ function jigGoogleMessages(messages) {
|
|
|
930
941
|
];
|
|
931
942
|
}
|
|
932
943
|
jiggedMessages = jiggedMessages.reduce((acc, message) => {
|
|
933
|
-
if (acc.length === 0)
|
|
934
|
-
return [message];
|
|
944
|
+
if (acc.length === 0) return [message];
|
|
935
945
|
const lastMessage = acc[acc.length - 1];
|
|
936
946
|
if (lastMessage.role === message.role) {
|
|
937
947
|
lastMessage.parts = [...lastMessage.parts, ...message.parts];
|
|
@@ -970,8 +980,7 @@ async function prepareGoogleAIPayload(_identifier, payload) {
|
|
|
970
980
|
const toolNameById = /* @__PURE__ */ new Map();
|
|
971
981
|
for (const m of payload.messages) {
|
|
972
982
|
for (const fc of m.functionCalls || []) {
|
|
973
|
-
if (fc.id)
|
|
974
|
-
toolNameById.set(fc.id, fc.name);
|
|
983
|
+
if (fc.id) toolNameById.set(fc.id, fc.name);
|
|
975
984
|
}
|
|
976
985
|
}
|
|
977
986
|
for (const message of payload.messages) {
|
|
@@ -1051,8 +1060,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1051
1060
|
...payload.thinkingConfig ? { thinkingConfig: payload.thinkingConfig } : {}
|
|
1052
1061
|
}
|
|
1053
1062
|
};
|
|
1054
|
-
if (payload.tools)
|
|
1055
|
-
requestBody.tools = [payload.tools];
|
|
1063
|
+
if (payload.tools) requestBody.tools = [payload.tools];
|
|
1056
1064
|
if (payload.tools && payload.toolConfig) {
|
|
1057
1065
|
requestBody.toolConfig = payload.toolConfig;
|
|
1058
1066
|
}
|
|
@@ -1110,8 +1118,7 @@ async function callGoogleAI(id, payload, requestTimeoutMs = 12e4, signal) {
|
|
|
1110
1118
|
});
|
|
1111
1119
|
continue;
|
|
1112
1120
|
}
|
|
1113
|
-
if (part.text)
|
|
1114
|
-
text += part.text;
|
|
1121
|
+
if (part.text) text += part.text;
|
|
1115
1122
|
if ((_m = part.inlineData) == null ? void 0 : _m.data) {
|
|
1116
1123
|
files.push({ mimeType: "image/png", data: part.inlineData.data });
|
|
1117
1124
|
}
|
|
@@ -1189,21 +1196,15 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
|
|
|
1189
1196
|
finishReason: error2.finishReason,
|
|
1190
1197
|
modelVersion: error2.modelVersion
|
|
1191
1198
|
};
|
|
1192
|
-
if (error2.safetyRatings)
|
|
1193
|
-
|
|
1194
|
-
if (error2.usageMetadata)
|
|
1195
|
-
errorDetails.usageMetadata = error2.usageMetadata;
|
|
1199
|
+
if (error2.safetyRatings) errorDetails.safetyRatings = error2.safetyRatings;
|
|
1200
|
+
if (error2.usageMetadata) errorDetails.usageMetadata = error2.usageMetadata;
|
|
1196
1201
|
if (error2.promptFeedback)
|
|
1197
1202
|
errorDetails.promptFeedback = error2.promptFeedback;
|
|
1198
|
-
if (error2.status)
|
|
1199
|
-
|
|
1200
|
-
if (error2.
|
|
1201
|
-
errorDetails.errorCode = error2.code;
|
|
1202
|
-
if (error2.details)
|
|
1203
|
-
errorDetails.errorDetails = error2.details;
|
|
1203
|
+
if (error2.status) errorDetails.httpStatus = error2.status;
|
|
1204
|
+
if (error2.code) errorDetails.errorCode = error2.code;
|
|
1205
|
+
if (error2.details) errorDetails.errorDetails = error2.details;
|
|
1204
1206
|
const fileUris = payload.messages.flatMap((m) => m.parts).filter((p) => "fileData" in p).map((p) => p.fileData.fileUri);
|
|
1205
|
-
if (fileUris.length)
|
|
1206
|
-
errorDetails.fileUris = fileUris;
|
|
1207
|
+
if (fileUris.length) errorDetails.fileUris = fileUris;
|
|
1207
1208
|
logger_default.error(
|
|
1208
1209
|
id,
|
|
1209
1210
|
`Retry #${attempt} error: ${error2.message}`,
|
|
@@ -1253,7 +1254,7 @@ async function callGoogleAIWithRetries(id, payload, retries = 5, requestTimeoutM
|
|
|
1253
1254
|
function normalizeMessageContent(content) {
|
|
1254
1255
|
return Array.isArray(content) ? content.map((c) => c.type === "text" ? c.text : `[${c.type}]`).join("\n") : content;
|
|
1255
1256
|
}
|
|
1256
|
-
function prepareOpenAICompatMessages(messages) {
|
|
1257
|
+
function prepareOpenAICompatMessages(messages, opts = {}) {
|
|
1257
1258
|
var _a;
|
|
1258
1259
|
const out = [];
|
|
1259
1260
|
for (const message of messages) {
|
|
@@ -1275,6 +1276,22 @@ function prepareOpenAICompatMessages(messages) {
|
|
|
1275
1276
|
role: message.role,
|
|
1276
1277
|
content
|
|
1277
1278
|
};
|
|
1279
|
+
if (opts.imageParts) {
|
|
1280
|
+
const imageBlocks = (message.files || []).filter(
|
|
1281
|
+
(file) => ALLOWED_IMAGE_MIME_TYPES.includes(file.mimeType) && (file.url || file.data)
|
|
1282
|
+
).map((file) => ({
|
|
1283
|
+
type: "image_url",
|
|
1284
|
+
image_url: {
|
|
1285
|
+
url: file.url || `data:${file.mimeType};base64,${file.data}`
|
|
1286
|
+
}
|
|
1287
|
+
}));
|
|
1288
|
+
if (imageBlocks.length) {
|
|
1289
|
+
outMessage.content = [
|
|
1290
|
+
...content ? [{ type: "text", text: content }] : [],
|
|
1291
|
+
...imageBlocks
|
|
1292
|
+
];
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1278
1295
|
if ((_a = message.functionCalls) == null ? void 0 : _a.length) {
|
|
1279
1296
|
outMessage.tool_calls = message.functionCalls.map((fc, i) => {
|
|
1280
1297
|
var _a2;
|
|
@@ -1287,16 +1304,14 @@ function prepareOpenAICompatMessages(messages) {
|
|
|
1287
1304
|
}
|
|
1288
1305
|
};
|
|
1289
1306
|
});
|
|
1290
|
-
if (!content)
|
|
1307
|
+
if (!content && !Array.isArray(outMessage.content))
|
|
1291
1308
|
outMessage.content = null;
|
|
1292
1309
|
}
|
|
1293
|
-
if (message.reasoning)
|
|
1294
|
-
outMessage.reasoning = message.reasoning;
|
|
1310
|
+
if (message.reasoning) outMessage.reasoning = message.reasoning;
|
|
1295
1311
|
const reasoningDetails = filterOpenAICompatReasoningDetails(
|
|
1296
1312
|
message.reasoningDetails
|
|
1297
1313
|
);
|
|
1298
|
-
if (reasoningDetails)
|
|
1299
|
-
outMessage.reasoning_details = reasoningDetails;
|
|
1314
|
+
if (reasoningDetails) outMessage.reasoning_details = reasoningDetails;
|
|
1300
1315
|
out.push(outMessage);
|
|
1301
1316
|
}
|
|
1302
1317
|
return out;
|
|
@@ -1384,11 +1399,14 @@ async function callGroqWithRetries(id, payload, retries = 5, requestTimeoutMs =
|
|
|
1384
1399
|
signal
|
|
1385
1400
|
});
|
|
1386
1401
|
}
|
|
1402
|
+
var openRouterImageRejectedModels = /* @__PURE__ */ new Set();
|
|
1387
1403
|
function prepareOpenRouterPayload(payload) {
|
|
1388
1404
|
var _a;
|
|
1389
1405
|
return {
|
|
1390
1406
|
model: payload.model,
|
|
1391
|
-
messages: prepareOpenAICompatMessages(payload.messages
|
|
1407
|
+
messages: prepareOpenAICompatMessages(payload.messages, {
|
|
1408
|
+
imageParts: !openRouterImageRejectedModels.has(String(payload.model))
|
|
1409
|
+
}),
|
|
1392
1410
|
tools: (_a = payload.functions) == null ? void 0 : _a.map((fn) => ({
|
|
1393
1411
|
type: "function",
|
|
1394
1412
|
function: fn
|
|
@@ -1439,8 +1457,7 @@ function parseDsmlToolCalls(content) {
|
|
|
1439
1457
|
let last = -1;
|
|
1440
1458
|
let tag;
|
|
1441
1459
|
while ((tag = DSML_ANY_TAG_RE.exec(content)) !== null) {
|
|
1442
|
-
if (first === -1)
|
|
1443
|
-
first = tag.index;
|
|
1460
|
+
if (first === -1) first = tag.index;
|
|
1444
1461
|
last = tag.index + tag[0].length;
|
|
1445
1462
|
}
|
|
1446
1463
|
const remaining = first === -1 ? content : (content.slice(0, first) + content.slice(last)).trim();
|
|
@@ -1456,8 +1473,7 @@ function finalizeOpenRouterMessage(id, raw) {
|
|
|
1456
1473
|
const functionCalls = [];
|
|
1457
1474
|
for (let i = 0; i < raw.toolCalls.length; i++) {
|
|
1458
1475
|
const tc = raw.toolCalls[i];
|
|
1459
|
-
if (!tc.name)
|
|
1460
|
-
continue;
|
|
1476
|
+
if (!tc.name) continue;
|
|
1461
1477
|
functionCalls.push({
|
|
1462
1478
|
id: (_a = tc.id) != null ? _a : `call_${i}`,
|
|
1463
1479
|
name: tc.name,
|
|
@@ -1510,8 +1526,7 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
|
|
|
1510
1526
|
controller.abort();
|
|
1511
1527
|
};
|
|
1512
1528
|
const unref = (t) => {
|
|
1513
|
-
if (typeof t === "object" && "unref" in t)
|
|
1514
|
-
t.unref();
|
|
1529
|
+
if (typeof t === "object" && "unref" in t) t.unref();
|
|
1515
1530
|
return t;
|
|
1516
1531
|
};
|
|
1517
1532
|
const totalTimer = unref(
|
|
@@ -1579,98 +1594,88 @@ async function callOpenRouterStream(id, payload, streamTimeoutMs = OPENROUTER_ST
|
|
|
1579
1594
|
const reader = response.body.getReader();
|
|
1580
1595
|
const decoder = new TextDecoder();
|
|
1581
1596
|
let lineBuffer = "";
|
|
1582
|
-
outer:
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
let newlineIdx;
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1597
|
+
outer: while (true) {
|
|
1598
|
+
const { done, value } = await reader.read();
|
|
1599
|
+
if (done) break;
|
|
1600
|
+
lineBuffer += decoder.decode(value, { stream: true });
|
|
1601
|
+
let newlineIdx;
|
|
1602
|
+
while ((newlineIdx = lineBuffer.indexOf("\n")) !== -1) {
|
|
1603
|
+
let line = lineBuffer.slice(0, newlineIdx);
|
|
1604
|
+
lineBuffer = lineBuffer.slice(newlineIdx + 1);
|
|
1605
|
+
if (line.endsWith("\r")) line = line.slice(0, -1);
|
|
1606
|
+
if (!line) continue;
|
|
1607
|
+
if (line.startsWith(":")) continue;
|
|
1608
|
+
if (!line.startsWith("data:")) continue;
|
|
1609
|
+
const dataStr = line.slice(5).trimStart();
|
|
1610
|
+
if (dataStr === "[DONE]") {
|
|
1611
|
+
sawDone = true;
|
|
1612
|
+
break outer;
|
|
1613
|
+
}
|
|
1614
|
+
let json;
|
|
1615
|
+
try {
|
|
1616
|
+
json = JSON.parse(dataStr);
|
|
1617
|
+
} catch (e) {
|
|
1618
|
+
logger_default.error(
|
|
1619
|
+
id,
|
|
1620
|
+
"OpenRouter stream: unparseable data line:",
|
|
1621
|
+
dataStr.slice(0, 200)
|
|
1622
|
+
);
|
|
1623
|
+
continue;
|
|
1624
|
+
}
|
|
1625
|
+
dataChunks++;
|
|
1626
|
+
if (json.error) {
|
|
1627
|
+
logger_default.error(id, "OpenRouter stream error event:", json.error);
|
|
1628
|
+
const error2 = new Error(
|
|
1629
|
+
`OpenRouter error: ${json.error.message}`
|
|
1630
|
+
);
|
|
1631
|
+
error2.data = json.error;
|
|
1632
|
+
throw error2;
|
|
1633
|
+
}
|
|
1634
|
+
if (json.provider) provider = json.provider;
|
|
1635
|
+
let useful = false;
|
|
1636
|
+
if (json.usage) {
|
|
1637
|
+
usage = json.usage;
|
|
1638
|
+
useful = true;
|
|
1639
|
+
}
|
|
1640
|
+
const choice = (_c = json.choices) == null ? void 0 : _c[0];
|
|
1641
|
+
if (choice) {
|
|
1642
|
+
const delta = (_d = choice.delta) != null ? _d : {};
|
|
1643
|
+
if (delta.content) {
|
|
1644
|
+
paragraph += delta.content;
|
|
1645
|
+
useful = true;
|
|
1615
1646
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
const error2 = new Error(
|
|
1620
|
-
`OpenRouter error: ${json.error.message}`
|
|
1621
|
-
);
|
|
1622
|
-
error2.data = json.error;
|
|
1623
|
-
throw error2;
|
|
1647
|
+
if (delta.reasoning) {
|
|
1648
|
+
reasoning += delta.reasoning;
|
|
1649
|
+
useful = true;
|
|
1624
1650
|
}
|
|
1625
|
-
if (
|
|
1626
|
-
|
|
1627
|
-
let useful = false;
|
|
1628
|
-
if (json.usage) {
|
|
1629
|
-
usage = json.usage;
|
|
1651
|
+
if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
|
|
1652
|
+
reasoningDetails.push(...delta.reasoning_details);
|
|
1630
1653
|
useful = true;
|
|
1631
1654
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
useful = true;
|
|
1638
|
-
}
|
|
1639
|
-
if (delta.reasoning) {
|
|
1640
|
-
reasoning += delta.reasoning;
|
|
1641
|
-
useful = true;
|
|
1642
|
-
}
|
|
1643
|
-
if (Array.isArray(delta.reasoning_details) && delta.reasoning_details.length) {
|
|
1644
|
-
reasoningDetails.push(...delta.reasoning_details);
|
|
1645
|
-
useful = true;
|
|
1646
|
-
}
|
|
1647
|
-
if (Array.isArray(delta.tool_calls)) {
|
|
1648
|
-
for (const toolCall of delta.tool_calls) {
|
|
1649
|
-
const idx = (_e = toolCall.index) != null ? _e : 0;
|
|
1650
|
-
while (toolCalls.length <= idx) {
|
|
1651
|
-
toolCalls.push({ name: "", argumentsJson: "" });
|
|
1652
|
-
}
|
|
1653
|
-
if (toolCall.id)
|
|
1654
|
-
toolCalls[idx].id = toolCall.id;
|
|
1655
|
-
if ((_f = toolCall.function) == null ? void 0 : _f.name)
|
|
1656
|
-
toolCalls[idx].name += toolCall.function.name;
|
|
1657
|
-
if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
|
|
1658
|
-
toolCalls[idx].argumentsJson += toolCall.function.arguments;
|
|
1659
|
-
useful = true;
|
|
1655
|
+
if (Array.isArray(delta.tool_calls)) {
|
|
1656
|
+
for (const toolCall of delta.tool_calls) {
|
|
1657
|
+
const idx = (_e = toolCall.index) != null ? _e : 0;
|
|
1658
|
+
while (toolCalls.length <= idx) {
|
|
1659
|
+
toolCalls.push({ name: "", argumentsJson: "" });
|
|
1660
1660
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1661
|
+
if (toolCall.id) toolCalls[idx].id = toolCall.id;
|
|
1662
|
+
if ((_f = toolCall.function) == null ? void 0 : _f.name)
|
|
1663
|
+
toolCalls[idx].name += toolCall.function.name;
|
|
1664
|
+
if ((_g = toolCall.function) == null ? void 0 : _g.arguments)
|
|
1665
|
+
toolCalls[idx].argumentsJson += toolCall.function.arguments;
|
|
1664
1666
|
useful = true;
|
|
1665
1667
|
}
|
|
1666
1668
|
}
|
|
1667
|
-
if (
|
|
1668
|
-
|
|
1669
|
+
if (choice.finish_reason) {
|
|
1670
|
+
finishReason = choice.finish_reason;
|
|
1671
|
+
useful = true;
|
|
1672
|
+
}
|
|
1669
1673
|
}
|
|
1674
|
+
if (useful) armStallTimer();
|
|
1670
1675
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1676
|
+
}
|
|
1677
|
+
if (sawDone) reader.cancel().catch(() => {
|
|
1678
|
+
});
|
|
1674
1679
|
if (!sawDone && !finishReason) {
|
|
1675
1680
|
logger_default.error(
|
|
1676
1681
|
id,
|
|
@@ -1777,15 +1782,12 @@ var MODERATION_RE = /moderat|inappropriate content|content polic|content managem
|
|
|
1777
1782
|
function moderationEvictionSlug(error2, payload) {
|
|
1778
1783
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
1779
1784
|
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;
|
|
1780
|
-
if (!body)
|
|
1781
|
-
return null;
|
|
1785
|
+
if (!body) return null;
|
|
1782
1786
|
const message = String((_d = body.message) != null ? _d : "");
|
|
1783
1787
|
const isModeration = body.code === 403 || Array.isArray((_e = body.metadata) == null ? void 0 : _e.reasons) || MODERATION_RE.test(message);
|
|
1784
|
-
if (!isModeration)
|
|
1785
|
-
return null;
|
|
1788
|
+
if (!isModeration) return null;
|
|
1786
1789
|
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];
|
|
1787
|
-
if (!display)
|
|
1788
|
-
return null;
|
|
1790
|
+
if (!display) return null;
|
|
1789
1791
|
const key = normalizeProviderKey(display);
|
|
1790
1792
|
const fromOrder = (_j = (_i = payload.provider) == null ? void 0 : _i.order) == null ? void 0 : _j.find(
|
|
1791
1793
|
(entry) => normalizeProviderKey(entry) === key
|
|
@@ -1794,12 +1796,15 @@ function moderationEvictionSlug(error2, payload) {
|
|
|
1794
1796
|
}
|
|
1795
1797
|
var MIN_STREAM_ATTEMPT_MS = 1e4;
|
|
1796
1798
|
var estimateTokens = (text) => Math.round(text.length / 4);
|
|
1799
|
+
function isImageInputRejection(error2) {
|
|
1800
|
+
var _a, _b, _c, _d;
|
|
1801
|
+
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;
|
|
1802
|
+
return /no endpoints found.*image input/i.test(String((_d = body == null ? void 0 : body.message) != null ? _d : ""));
|
|
1803
|
+
}
|
|
1797
1804
|
function streamAttemptBudgetMs(options) {
|
|
1798
|
-
if (options.streamDeadlineAt === void 0)
|
|
1799
|
-
return options.streamTimeoutMs;
|
|
1805
|
+
if (options.streamDeadlineAt === void 0) return options.streamTimeoutMs;
|
|
1800
1806
|
const remaining = options.streamDeadlineAt - Date.now();
|
|
1801
|
-
if (remaining < MIN_STREAM_ATTEMPT_MS)
|
|
1802
|
-
return null;
|
|
1807
|
+
if (remaining < MIN_STREAM_ATTEMPT_MS) return null;
|
|
1803
1808
|
return Math.min(options.streamTimeoutMs, remaining);
|
|
1804
1809
|
}
|
|
1805
1810
|
async function callOpenRouterWithRetries(id, payload, retries = 5, options, signal) {
|
|
@@ -1846,6 +1851,16 @@ async function callOpenRouterWithRetries(id, payload, retries = 5, options, sign
|
|
|
1846
1851
|
`OpenRouter moderation eviction: ignoring provider "${slug}" for remaining attempts`
|
|
1847
1852
|
);
|
|
1848
1853
|
}
|
|
1854
|
+
if (isImageInputRejection(error2) && options.genericMessages) {
|
|
1855
|
+
openRouterImageRejectedModels.add(String(payload.model));
|
|
1856
|
+
payload.messages = prepareOpenAICompatMessages(
|
|
1857
|
+
options.genericMessages
|
|
1858
|
+
);
|
|
1859
|
+
logger_default.log(
|
|
1860
|
+
id,
|
|
1861
|
+
`OpenRouter: ${payload.model} has no image-capable endpoints; retrying with images as text refs`
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1849
1864
|
throw error2;
|
|
1850
1865
|
}),
|
|
1851
1866
|
{ retries, signal }
|
|
@@ -1946,7 +1961,8 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1946
1961
|
streamTimeoutMs: (_c = aiPayload.streamTimeoutMs) != null ? _c : OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1947
1962
|
streamDeadlineAt: aiPayload.streamDeadlineAt,
|
|
1948
1963
|
requestTimeoutMs: (_d = aiPayload.requestTimeoutMs) != null ? _d : OPENROUTER_NONSTREAM_TIMEOUT_MS,
|
|
1949
|
-
chunkTimeoutMs
|
|
1964
|
+
chunkTimeoutMs,
|
|
1965
|
+
genericMessages: routingPayload.messages
|
|
1950
1966
|
},
|
|
1951
1967
|
signal
|
|
1952
1968
|
);
|
|
@@ -1955,8 +1971,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1955
1971
|
(_e = result.provider) != null ? _e : result.provider = provider;
|
|
1956
1972
|
return result;
|
|
1957
1973
|
} catch (error2) {
|
|
1958
|
-
if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted)
|
|
1959
|
-
throw error2;
|
|
1974
|
+
if ((_f = aiPayload.signal) == null ? void 0 : _f.aborted) throw error2;
|
|
1960
1975
|
if (aiPayload.fallbackModel) {
|
|
1961
1976
|
logger_default.error(
|
|
1962
1977
|
id,
|
|
@@ -1992,6 +2007,7 @@ async function callWithRetries(id, aiPayload, aiConfig, retries = 5, chunkTimeou
|
|
|
1992
2007
|
OPENROUTER_STREAM_TIMEOUT_MS,
|
|
1993
2008
|
OpenRouterModel,
|
|
1994
2009
|
callWithRetries,
|
|
2010
|
+
openRouterImageRejectedModels,
|
|
1995
2011
|
parseModelString
|
|
1996
2012
|
});
|
|
1997
2013
|
//# sourceMappingURL=index.js.map
|