@standardagents/openrouter 0.43.0 → 0.44.0
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.js +117 -79
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,7 +1,37 @@
|
|
|
1
1
|
// src/OpenRouterProvider.ts
|
|
2
|
-
import { ProviderError, defineTool } from "@standardagents/spec";
|
|
2
|
+
import { ProviderError, defineTool, resolveRequestReasoningLevels } from "@standardagents/spec";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
|
+
// src/responses-transformers.ts
|
|
6
|
+
import { mapReasoningLevel as mapReasoningLevel2 } from "@standardagents/spec";
|
|
7
|
+
|
|
8
|
+
// src/reasoning.ts
|
|
9
|
+
function getOpenRouterReasoningLevels(model) {
|
|
10
|
+
if (/^openai\/o[134](?:[-:]|$)/.test(model)) {
|
|
11
|
+
return { 0: "low", 33: "low", 66: "medium", 100: "high" };
|
|
12
|
+
}
|
|
13
|
+
return { 0: null, 10: "minimal", 33: "low", 66: "medium", 100: "high" };
|
|
14
|
+
}
|
|
15
|
+
function mapOpenRouterReasoningLevels(model, mandatory, supportedEfforts) {
|
|
16
|
+
const efforts = ["minimal", "low", "medium", "high", "xhigh", "max"].filter((effort) => supportedEfforts?.includes(effort));
|
|
17
|
+
if (efforts.length === 0) {
|
|
18
|
+
const fallback = getOpenRouterReasoningLevels(model);
|
|
19
|
+
if (mandatory) return { 0: "low", 33: "low", 66: "medium", 100: "high" };
|
|
20
|
+
return mandatory === false ? { ...fallback, 0: null } : fallback;
|
|
21
|
+
}
|
|
22
|
+
const values = mandatory ? efforts : [null, ...efforts];
|
|
23
|
+
return Object.fromEntries(values.map((effort, index) => [
|
|
24
|
+
Math.round(index * 100 / Math.max(1, values.length - 1)),
|
|
25
|
+
effort
|
|
26
|
+
]));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/responses-transformers.ts
|
|
30
|
+
import { unrecognized } from "@openrouter/sdk/types";
|
|
31
|
+
|
|
32
|
+
// src/chat-completions-transformers.ts
|
|
33
|
+
import { mapReasoningLevel } from "@standardagents/spec";
|
|
34
|
+
|
|
5
35
|
// src/server-tools.ts
|
|
6
36
|
var OPENROUTER_SERVER_TOOL_NAMES = [
|
|
7
37
|
"web_search",
|
|
@@ -235,21 +265,22 @@ function transformChatAssistantMessage(msg) {
|
|
|
235
265
|
return message;
|
|
236
266
|
}
|
|
237
267
|
function transformChatToolMessage(msg) {
|
|
268
|
+
const content = Array.isArray(msg.content) ? msg.content.filter((part) => part.type === "text").map((part) => part.text).join("\n") : msg.content;
|
|
238
269
|
let output;
|
|
239
|
-
if (typeof
|
|
240
|
-
output =
|
|
241
|
-
} else if ("type" in
|
|
242
|
-
if (
|
|
243
|
-
output =
|
|
244
|
-
} else if (
|
|
245
|
-
output = `Error: ${
|
|
270
|
+
if (typeof content === "string") {
|
|
271
|
+
output = content;
|
|
272
|
+
} else if ("type" in content) {
|
|
273
|
+
if (content.type === "text") {
|
|
274
|
+
output = content.text;
|
|
275
|
+
} else if (content.type === "error") {
|
|
276
|
+
output = `Error: ${content.error}`;
|
|
246
277
|
} else {
|
|
247
|
-
output = JSON.stringify(
|
|
278
|
+
output = JSON.stringify(content);
|
|
248
279
|
}
|
|
249
280
|
} else {
|
|
250
|
-
output = JSON.stringify(
|
|
281
|
+
output = JSON.stringify(content);
|
|
251
282
|
}
|
|
252
|
-
const imageAttachments = msg.
|
|
283
|
+
const imageAttachments = Array.isArray(msg.content) ? msg.content.filter((part) => part.type === "image" && Boolean(part.data) || part.type === "image_url") : [];
|
|
253
284
|
const toolMessage = {
|
|
254
285
|
role: "tool",
|
|
255
286
|
tool_call_id: msg.toolCallId,
|
|
@@ -268,15 +299,7 @@ function transformChatToolMessage(msg) {
|
|
|
268
299
|
text: `Here ${verb} ${descriptor} from ${toolName}:`
|
|
269
300
|
});
|
|
270
301
|
for (const attachment of imageAttachments) {
|
|
271
|
-
|
|
272
|
-
const imageData = attachmentData.startsWith("data:") ? attachmentData : `data:${attachment.mediaType || "image/png"};base64,${attachmentData}`;
|
|
273
|
-
imageContent.push({
|
|
274
|
-
type: "image_url",
|
|
275
|
-
image_url: {
|
|
276
|
-
url: imageData,
|
|
277
|
-
detail: "auto"
|
|
278
|
-
}
|
|
279
|
-
});
|
|
302
|
+
imageContent.push(transformChatContentPart(attachment));
|
|
280
303
|
}
|
|
281
304
|
const syntheticUserMessage = {
|
|
282
305
|
role: "user",
|
|
@@ -728,7 +751,7 @@ async function* parseChatSSEStream(response, state) {
|
|
|
728
751
|
reader.releaseLock();
|
|
729
752
|
}
|
|
730
753
|
}
|
|
731
|
-
function buildChatParams(request) {
|
|
754
|
+
function buildChatParams(request, reasoningLevels = getOpenRouterReasoningLevels(request.model)) {
|
|
732
755
|
const messages = transformChatMessages(request.messages);
|
|
733
756
|
const params = {
|
|
734
757
|
model: request.model,
|
|
@@ -757,18 +780,6 @@ function buildChatParams(request) {
|
|
|
757
780
|
if (request.topP !== void 0) {
|
|
758
781
|
params.top_p = request.topP;
|
|
759
782
|
}
|
|
760
|
-
if (request.reasoning?.level !== void 0) {
|
|
761
|
-
const effortMap = {
|
|
762
|
-
10: "minimal",
|
|
763
|
-
33: "low",
|
|
764
|
-
66: "medium",
|
|
765
|
-
100: "high"
|
|
766
|
-
};
|
|
767
|
-
const effort = effortMap[request.reasoning.level];
|
|
768
|
-
if (effort) {
|
|
769
|
-
params.reasoning = { effort };
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
783
|
if (request.responseFormat) {
|
|
773
784
|
if (request.responseFormat.type === "json") {
|
|
774
785
|
if (request.responseFormat.schema) {
|
|
@@ -792,7 +803,27 @@ function buildChatParams(request) {
|
|
|
792
803
|
request.providerOptions
|
|
793
804
|
);
|
|
794
805
|
if (safeOptions) {
|
|
795
|
-
|
|
806
|
+
if (request.reasoning?.level !== void 0) {
|
|
807
|
+
const { effort, reasoning_effort, reasoningEffort, ...otherOptions } = safeOptions;
|
|
808
|
+
Object.assign(params, otherOptions);
|
|
809
|
+
} else {
|
|
810
|
+
Object.assign(params, safeOptions);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
if (request.reasoning?.level !== void 0) {
|
|
814
|
+
if (params.reasoning) {
|
|
815
|
+
params.reasoning = { ...params.reasoning };
|
|
816
|
+
delete params.reasoning.effort;
|
|
817
|
+
}
|
|
818
|
+
const effort = mapReasoningLevel(request.reasoning.level, request.reasoning.levels ?? reasoningLevels);
|
|
819
|
+
if (effort === null || params.reasoning?.enabled !== void 0) {
|
|
820
|
+
params.reasoning = { ...params.reasoning, enabled: effort !== null && effort !== "none" };
|
|
821
|
+
}
|
|
822
|
+
if (effort === "none" || effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max") {
|
|
823
|
+
params.reasoning = { ...params.reasoning, effort };
|
|
824
|
+
} else if (effort === "enabled") {
|
|
825
|
+
params.reasoning = { ...params.reasoning, enabled: true };
|
|
826
|
+
}
|
|
796
827
|
}
|
|
797
828
|
return params;
|
|
798
829
|
}
|
|
@@ -930,21 +961,22 @@ function transformAssistantMessage(msg) {
|
|
|
930
961
|
return items;
|
|
931
962
|
}
|
|
932
963
|
function transformToolMessage(msg) {
|
|
964
|
+
const content = Array.isArray(msg.content) ? msg.content.filter((part) => part.type === "text").map((part) => part.text).join("\n") : msg.content;
|
|
933
965
|
let output;
|
|
934
|
-
if (typeof
|
|
935
|
-
output =
|
|
936
|
-
} else if ("type" in
|
|
937
|
-
if (
|
|
938
|
-
output =
|
|
939
|
-
} else if (
|
|
940
|
-
output = `Error: ${
|
|
966
|
+
if (typeof content === "string") {
|
|
967
|
+
output = content;
|
|
968
|
+
} else if ("type" in content) {
|
|
969
|
+
if (content.type === "text") {
|
|
970
|
+
output = content.text;
|
|
971
|
+
} else if (content.type === "error") {
|
|
972
|
+
output = `Error: ${content.error}`;
|
|
941
973
|
} else {
|
|
942
|
-
output = JSON.stringify(
|
|
974
|
+
output = JSON.stringify(content);
|
|
943
975
|
}
|
|
944
976
|
} else {
|
|
945
|
-
output = JSON.stringify(
|
|
977
|
+
output = JSON.stringify(content);
|
|
946
978
|
}
|
|
947
|
-
const imageAttachments = msg.
|
|
979
|
+
const imageAttachments = Array.isArray(msg.content) ? msg.content.filter((part) => part.type === "image" && Boolean(part.data) || part.type === "image_url") : [];
|
|
948
980
|
const toolOutput = {
|
|
949
981
|
type: "function_call_output",
|
|
950
982
|
call_id: msg.toolCallId,
|
|
@@ -963,13 +995,7 @@ function transformToolMessage(msg) {
|
|
|
963
995
|
text: `Here ${verb} ${descriptor} from ${toolName}:`
|
|
964
996
|
});
|
|
965
997
|
for (const attachment of imageAttachments) {
|
|
966
|
-
|
|
967
|
-
const imageData = attachmentData.startsWith("data:") ? attachmentData : `data:${attachment.mediaType || "image/png"};base64,${attachmentData}`;
|
|
968
|
-
imageContent.push({
|
|
969
|
-
type: "input_image",
|
|
970
|
-
image_url: imageData,
|
|
971
|
-
detail: "auto"
|
|
972
|
-
});
|
|
998
|
+
imageContent.push(transformContentPart(attachment));
|
|
973
999
|
}
|
|
974
1000
|
const syntheticUserMessage = {
|
|
975
1001
|
role: "user",
|
|
@@ -1246,7 +1272,7 @@ function extractReasoningDetails(output, streamedReasoningContent) {
|
|
|
1246
1272
|
}
|
|
1247
1273
|
return details.length > 0 ? details : void 0;
|
|
1248
1274
|
}
|
|
1249
|
-
function buildCreateParams(request) {
|
|
1275
|
+
function buildCreateParams(request, reasoningLevels = getOpenRouterReasoningLevels(request.model)) {
|
|
1250
1276
|
const { input, instructions } = transformMessages(request.messages);
|
|
1251
1277
|
const params = {
|
|
1252
1278
|
model: request.model,
|
|
@@ -1275,24 +1301,6 @@ function buildCreateParams(request) {
|
|
|
1275
1301
|
if (request.topP !== void 0) {
|
|
1276
1302
|
params.topP = request.topP;
|
|
1277
1303
|
}
|
|
1278
|
-
if (request.reasoning?.level !== void 0) {
|
|
1279
|
-
const effortMap = {
|
|
1280
|
-
10: "minimal",
|
|
1281
|
-
// Basic reasoning
|
|
1282
|
-
33: "low",
|
|
1283
|
-
// Light reasoning
|
|
1284
|
-
66: "medium",
|
|
1285
|
-
// Balanced reasoning
|
|
1286
|
-
100: "high"
|
|
1287
|
-
// Deep reasoning
|
|
1288
|
-
};
|
|
1289
|
-
const effort = effortMap[request.reasoning.level];
|
|
1290
|
-
if (effort) {
|
|
1291
|
-
params.reasoning = {
|
|
1292
|
-
effort
|
|
1293
|
-
};
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
1304
|
if (request.responseFormat) {
|
|
1297
1305
|
if (request.responseFormat.type === "json") {
|
|
1298
1306
|
if (request.responseFormat.schema) {
|
|
@@ -1318,7 +1326,27 @@ function buildCreateParams(request) {
|
|
|
1318
1326
|
request.providerOptions
|
|
1319
1327
|
);
|
|
1320
1328
|
if (providerOptions) {
|
|
1321
|
-
|
|
1329
|
+
if (request.reasoning?.level !== void 0) {
|
|
1330
|
+
const { effort, reasoning_effort, reasoningEffort, ...otherOptions } = providerOptions;
|
|
1331
|
+
Object.assign(params, otherOptions);
|
|
1332
|
+
} else {
|
|
1333
|
+
Object.assign(params, providerOptions);
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
if (request.reasoning?.level !== void 0) {
|
|
1337
|
+
if (params.reasoning) {
|
|
1338
|
+
params.reasoning = { ...params.reasoning };
|
|
1339
|
+
delete params.reasoning.effort;
|
|
1340
|
+
}
|
|
1341
|
+
const effort = mapReasoningLevel2(request.reasoning.level, request.reasoning.levels ?? reasoningLevels);
|
|
1342
|
+
if (effort === null || params.reasoning?.enabled !== void 0) {
|
|
1343
|
+
params.reasoning = { ...params.reasoning, enabled: effort !== null && effort !== "none" };
|
|
1344
|
+
}
|
|
1345
|
+
if (effort === "none" || effort === "minimal" || effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max") {
|
|
1346
|
+
params.reasoning = { ...params.reasoning, effort: effort === "max" ? unrecognized(effort) : effort };
|
|
1347
|
+
} else if (effort === "enabled") {
|
|
1348
|
+
params.reasoning = { ...params.reasoning, enabled: true };
|
|
1349
|
+
}
|
|
1322
1350
|
}
|
|
1323
1351
|
return params;
|
|
1324
1352
|
}
|
|
@@ -2205,8 +2233,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2205
2233
|
}
|
|
2206
2234
|
if (!_OpenRouterProvider.modelsFetchPromise) {
|
|
2207
2235
|
_OpenRouterProvider.modelsFetchPromise = (async () => {
|
|
2236
|
+
const controller = new AbortController();
|
|
2237
|
+
const timer = setTimeout(() => controller.abort(), 2500);
|
|
2208
2238
|
try {
|
|
2209
|
-
const response = await fetch("https://openrouter.ai/api/v1/models");
|
|
2239
|
+
const response = await fetch("https://openrouter.ai/api/v1/models", { signal: controller.signal });
|
|
2210
2240
|
if (!response.ok) {
|
|
2211
2241
|
throw new Error(`OpenRouter API error: ${response.status}`);
|
|
2212
2242
|
}
|
|
@@ -2218,6 +2248,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2218
2248
|
_OpenRouterProvider.modelsFetchFailedAt = Date.now();
|
|
2219
2249
|
throw error;
|
|
2220
2250
|
} finally {
|
|
2251
|
+
clearTimeout(timer);
|
|
2221
2252
|
_OpenRouterProvider.modelsFetchPromise = null;
|
|
2222
2253
|
}
|
|
2223
2254
|
})();
|
|
@@ -2243,7 +2274,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2243
2274
|
capabilities.maxOutputTokens = model.top_provider.max_completion_tokens;
|
|
2244
2275
|
}
|
|
2245
2276
|
if (model.id.includes("o1") || model.id.includes("o3") || model.id.includes("o4")) {
|
|
2246
|
-
capabilities.reasoningLevels = { 0:
|
|
2277
|
+
capabilities.reasoningLevels = { 0: "low", 33: "low", 66: "medium", 100: "high" };
|
|
2247
2278
|
if (model.id.includes("o1-preview") || model.id.includes("o1-mini")) {
|
|
2248
2279
|
capabilities.supportsToolCalls = false;
|
|
2249
2280
|
capabilities.supportsJsonMode = false;
|
|
@@ -2251,6 +2282,13 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2251
2282
|
} else if (model.id.includes("claude") && model.id.includes("thinking")) {
|
|
2252
2283
|
capabilities.reasoningLevels = { 0: null, 100: "enabled" };
|
|
2253
2284
|
}
|
|
2285
|
+
if (model.reasoning) {
|
|
2286
|
+
capabilities.reasoningLevels = mapOpenRouterReasoningLevels(
|
|
2287
|
+
model.id,
|
|
2288
|
+
model.reasoning.mandatory,
|
|
2289
|
+
model.reasoning.supported_efforts
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2254
2292
|
return capabilities;
|
|
2255
2293
|
}
|
|
2256
2294
|
/**
|
|
@@ -2303,7 +2341,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2303
2341
|
const apiKey = this.config.apiKey;
|
|
2304
2342
|
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
2305
2343
|
try {
|
|
2306
|
-
const params = buildChatParams(request);
|
|
2344
|
+
const params = buildChatParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2307
2345
|
if (this.config.providers && this.config.providers.length > 0) {
|
|
2308
2346
|
params.provider = { only: this.config.providers };
|
|
2309
2347
|
}
|
|
@@ -2341,7 +2379,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2341
2379
|
const apiKey = this.config.apiKey;
|
|
2342
2380
|
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
2343
2381
|
try {
|
|
2344
|
-
const params = buildCreateParams(request);
|
|
2382
|
+
const params = buildCreateParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2345
2383
|
this.applyConfiguredProvidersToResponses(params);
|
|
2346
2384
|
const pricingPromise = this.getUsagePricing(params.model);
|
|
2347
2385
|
if (this.hasOpenRouterServerTools(params)) {
|
|
@@ -2388,7 +2426,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2388
2426
|
const apiKey = this.config.apiKey;
|
|
2389
2427
|
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
2390
2428
|
try {
|
|
2391
|
-
const params = buildChatParams(request);
|
|
2429
|
+
const params = buildChatParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2392
2430
|
if (this.config.providers && this.config.providers.length > 0) {
|
|
2393
2431
|
params.provider = { only: this.config.providers };
|
|
2394
2432
|
}
|
|
@@ -2464,7 +2502,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2464
2502
|
const apiKey = this.config.apiKey;
|
|
2465
2503
|
const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
|
|
2466
2504
|
try {
|
|
2467
|
-
const params = buildCreateParams(request);
|
|
2505
|
+
const params = buildCreateParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2468
2506
|
this.applyConfiguredProvidersToResponses(params);
|
|
2469
2507
|
const pricingPromise = this.getUsagePricing(params.model);
|
|
2470
2508
|
const response = await fetch(`${baseUrl}/responses`, {
|
|
@@ -2601,7 +2639,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2601
2639
|
async inspectRequest(request) {
|
|
2602
2640
|
const apiMode = this.getApiMode(request);
|
|
2603
2641
|
if (apiMode === "responses") {
|
|
2604
|
-
const params2 = buildCreateParams(request);
|
|
2642
|
+
const params2 = buildCreateParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2605
2643
|
if (this.config.providers && this.config.providers.length > 0) {
|
|
2606
2644
|
params2.provider = { only: this.config.providers };
|
|
2607
2645
|
}
|
|
@@ -2613,7 +2651,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
|
|
|
2613
2651
|
}
|
|
2614
2652
|
};
|
|
2615
2653
|
}
|
|
2616
|
-
const params = buildChatParams(request);
|
|
2654
|
+
const params = buildChatParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
|
|
2617
2655
|
if (this.config.providers && this.config.providers.length > 0) {
|
|
2618
2656
|
params.provider = { only: this.config.providers };
|
|
2619
2657
|
}
|