@x12i/openrouter-runtime 1.1.0 → 1.4.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/LICENSE +21 -21
- package/README.md +160 -145
- package/dist/index.cjs +153 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +60 -5
- package/dist/index.d.ts +60 -5
- package/dist/index.js +149 -23
- package/dist/index.js.map +1 -1
- package/package.json +41 -41
package/dist/index.cjs
CHANGED
|
@@ -20,13 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
OPENROUTER_METADATA_LIMITS: () => OPENROUTER_METADATA_LIMITS,
|
|
23
24
|
OpenRouterHttpError: () => OpenRouterHttpError,
|
|
24
25
|
RuntimeConfigError: () => RuntimeConfigError,
|
|
25
26
|
buildOpenRouterServerTools: () => buildOpenRouterServerTools,
|
|
26
27
|
compileRuntimeRequest: () => compileRuntimeRequest,
|
|
27
28
|
createConsoleLogger: () => createConsoleLogger,
|
|
28
29
|
createOpenRouterRuntime: () => createOpenRouterRuntime,
|
|
29
|
-
|
|
30
|
+
decodeProviderMetadata: () => decodeProviderMetadata,
|
|
31
|
+
isRuntimeLoggingEnabled: () => isRuntimeLoggingEnabled,
|
|
32
|
+
toProviderMetadata: () => toProviderMetadata
|
|
30
33
|
});
|
|
31
34
|
module.exports = __toCommonJS(index_exports);
|
|
32
35
|
|
|
@@ -754,13 +757,22 @@ function endpointFor(baseUrl, apiMode) {
|
|
|
754
757
|
}
|
|
755
758
|
|
|
756
759
|
// src/openrouter/headers.ts
|
|
757
|
-
function buildHeaders(options) {
|
|
760
|
+
function buildHeaders(options, agentId) {
|
|
761
|
+
const requestAppName = agentId?.trim();
|
|
758
762
|
return {
|
|
759
763
|
"content-type": "application/json",
|
|
760
764
|
authorization: `Bearer ${options.apiKey}`,
|
|
761
765
|
...options.appAttribution?.siteUrl ? { "HTTP-Referer": options.appAttribution.siteUrl } : {},
|
|
762
|
-
...options.appAttribution?.appName
|
|
763
|
-
...options.defaultHeaders ?? {}
|
|
766
|
+
...appTitleHeaders(options.appAttribution?.appName),
|
|
767
|
+
...options.defaultHeaders ?? {},
|
|
768
|
+
...requestAppName ? appTitleHeaders(requestAppName) : {}
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function appTitleHeaders(name) {
|
|
772
|
+
if (!name) return {};
|
|
773
|
+
return {
|
|
774
|
+
"X-Title": name,
|
|
775
|
+
"X-OpenRouter-Title": name
|
|
764
776
|
};
|
|
765
777
|
}
|
|
766
778
|
|
|
@@ -789,7 +801,7 @@ function cleanParameters(parameters) {
|
|
|
789
801
|
function enabled(policy) {
|
|
790
802
|
return !!policy && policy.mode !== "disabled";
|
|
791
803
|
}
|
|
792
|
-
function buildOpenRouterServerTools(policy) {
|
|
804
|
+
function buildOpenRouterServerTools(policy, fallbackReasoning) {
|
|
793
805
|
const tools = [];
|
|
794
806
|
const webSearch = buildWebSearchTool(policy?.webSearch);
|
|
795
807
|
if (webSearch) tools.push(webSearch);
|
|
@@ -801,10 +813,10 @@ function buildOpenRouterServerTools(policy) {
|
|
|
801
813
|
if (image) tools.push(image);
|
|
802
814
|
const patch = buildApplyPatchTool(policy?.applyPatch);
|
|
803
815
|
if (patch) tools.push(patch);
|
|
804
|
-
const fusion = buildFusionTool(policy?.fusion);
|
|
816
|
+
const fusion = buildFusionTool(policy?.fusion, fallbackReasoning);
|
|
805
817
|
if (fusion) tools.push(fusion);
|
|
806
|
-
tools.push(...buildAdvisorTools(policy?.advisor));
|
|
807
|
-
const subagent = buildSubagentTool(policy?.subagent);
|
|
818
|
+
tools.push(...buildAdvisorTools(policy?.advisor, fallbackReasoning));
|
|
819
|
+
const subagent = buildSubagentTool(policy?.subagent, fallbackReasoning);
|
|
808
820
|
if (subagent) tools.push(subagent);
|
|
809
821
|
return tools;
|
|
810
822
|
}
|
|
@@ -863,7 +875,7 @@ function buildApplyPatchTool(policy) {
|
|
|
863
875
|
if (!enabled(policy)) return void 0;
|
|
864
876
|
return { type: "openrouter:apply_patch" };
|
|
865
877
|
}
|
|
866
|
-
function buildFusionTool(policy) {
|
|
878
|
+
function buildFusionTool(policy, fallbackReasoning) {
|
|
867
879
|
if (!enabled(policy)) return void 0;
|
|
868
880
|
return {
|
|
869
881
|
type: "openrouter:fusion",
|
|
@@ -872,12 +884,12 @@ function buildFusionTool(policy) {
|
|
|
872
884
|
model: policy?.judgeModel,
|
|
873
885
|
max_tool_calls: policy?.maxToolCalls ?? 8,
|
|
874
886
|
max_completion_tokens: policy?.maxCompletionTokens,
|
|
875
|
-
reasoning: policy?.reasoning,
|
|
887
|
+
reasoning: policy?.reasoning ?? fallbackReasoning,
|
|
876
888
|
temperature: policy?.temperature
|
|
877
889
|
})
|
|
878
890
|
};
|
|
879
891
|
}
|
|
880
|
-
function buildAdvisorTools(policy) {
|
|
892
|
+
function buildAdvisorTools(policy, fallbackReasoning) {
|
|
881
893
|
const advisors = Array.isArray(policy) ? policy : policy ? [policy] : [];
|
|
882
894
|
return advisors.filter(enabled).map((advisor) => {
|
|
883
895
|
validateNestedTools(advisor.tools);
|
|
@@ -892,13 +904,13 @@ function buildAdvisorTools(policy) {
|
|
|
892
904
|
stream: advisor.stream,
|
|
893
905
|
max_tool_calls: advisor.maxToolCalls,
|
|
894
906
|
max_completion_tokens: advisor.maxCompletionTokens,
|
|
895
|
-
reasoning: advisor.reasoning,
|
|
907
|
+
reasoning: advisor.reasoning ?? fallbackReasoning,
|
|
896
908
|
temperature: advisor.temperature
|
|
897
909
|
})
|
|
898
910
|
};
|
|
899
911
|
});
|
|
900
912
|
}
|
|
901
|
-
function buildSubagentTool(policy) {
|
|
913
|
+
function buildSubagentTool(policy, fallbackReasoning) {
|
|
902
914
|
if (!policy || policy.mode === "disabled") return void 0;
|
|
903
915
|
const subagent = policy;
|
|
904
916
|
validateNestedTools(subagent.tools);
|
|
@@ -910,12 +922,86 @@ function buildSubagentTool(policy) {
|
|
|
910
922
|
tools: subagent.tools,
|
|
911
923
|
max_tool_calls: subagent.maxToolCalls,
|
|
912
924
|
max_completion_tokens: subagent.maxCompletionTokens,
|
|
913
|
-
reasoning: subagent.reasoning,
|
|
925
|
+
reasoning: subagent.reasoning ?? fallbackReasoning,
|
|
914
926
|
temperature: subagent.temperature
|
|
915
927
|
})
|
|
916
928
|
};
|
|
917
929
|
}
|
|
918
930
|
|
|
931
|
+
// src/utils/provider-metadata.ts
|
|
932
|
+
var OPENROUTER_METADATA_LIMITS = {
|
|
933
|
+
maxPairs: 16,
|
|
934
|
+
maxKeyLength: 64,
|
|
935
|
+
maxValueLength: 512
|
|
936
|
+
};
|
|
937
|
+
var PROVIDER_RECORD_CHUNK = 256;
|
|
938
|
+
var PROVIDER_RECORD_MAX_CHUNKS = 16;
|
|
939
|
+
function toProviderMetadata(metadata, agentId, _limits, base) {
|
|
940
|
+
return encodeProviderRecord(collectProviderStrings(metadata, agentId, base));
|
|
941
|
+
}
|
|
942
|
+
function decodeProviderMetadata(wire) {
|
|
943
|
+
if (!isRecord2(wire)) return {};
|
|
944
|
+
const parts = [];
|
|
945
|
+
for (let index = 0; ; index += 1) {
|
|
946
|
+
const chunk = wire[`m.${index}`];
|
|
947
|
+
if (typeof chunk !== "string") break;
|
|
948
|
+
parts.push(chunk);
|
|
949
|
+
}
|
|
950
|
+
if (!parts.length) return {};
|
|
951
|
+
const parsed = JSON.parse(Buffer.from(parts.join(""), "base64").toString("utf8"));
|
|
952
|
+
if (!isRecord2(parsed)) return {};
|
|
953
|
+
const record = {};
|
|
954
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
955
|
+
if (typeof value === "string") record[key] = value;
|
|
956
|
+
}
|
|
957
|
+
return record;
|
|
958
|
+
}
|
|
959
|
+
function encodeProviderRecord(map) {
|
|
960
|
+
const keys = Object.keys(map).sort();
|
|
961
|
+
if (!keys.length) return void 0;
|
|
962
|
+
const ordered = {};
|
|
963
|
+
for (const key of keys) {
|
|
964
|
+
const value = map[key];
|
|
965
|
+
if (value !== void 0) ordered[key] = value;
|
|
966
|
+
}
|
|
967
|
+
const encoded = Buffer.from(JSON.stringify(ordered), "utf8").toString("base64");
|
|
968
|
+
const chunks = Math.ceil(encoded.length / PROVIDER_RECORD_CHUNK);
|
|
969
|
+
if (chunks > PROVIDER_RECORD_MAX_CHUNKS) {
|
|
970
|
+
throw new Error(
|
|
971
|
+
`METADATA_RECORD_TOO_LARGE: provider metadata is ${encoded.length} base64 characters; the maximum is ${PROVIDER_RECORD_CHUNK * PROVIDER_RECORD_MAX_CHUNKS}.`
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
const wire = {};
|
|
975
|
+
for (let index = 0; index < chunks; index += 1) {
|
|
976
|
+
wire[`m.${index}`] = encoded.slice(index * PROVIDER_RECORD_CHUNK, (index + 1) * PROVIDER_RECORD_CHUNK);
|
|
977
|
+
}
|
|
978
|
+
return wire;
|
|
979
|
+
}
|
|
980
|
+
function collectProviderStrings(metadata, agentId, base) {
|
|
981
|
+
const map = {};
|
|
982
|
+
appendStrings(map, base);
|
|
983
|
+
appendStrings(map, metadata);
|
|
984
|
+
const trimmedAgentId = agentId?.trim();
|
|
985
|
+
if (trimmedAgentId) map.agentId = trimmedAgentId;
|
|
986
|
+
return map;
|
|
987
|
+
}
|
|
988
|
+
function appendStrings(target, metadata) {
|
|
989
|
+
if (!metadata) return;
|
|
990
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
991
|
+
const asString = asMetadataString(value);
|
|
992
|
+
if (asString !== void 0) target[key] = asString;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
function asMetadataString(value) {
|
|
996
|
+
if (typeof value === "string") return value;
|
|
997
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
998
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
999
|
+
return void 0;
|
|
1000
|
+
}
|
|
1001
|
+
function isRecord2(value) {
|
|
1002
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
919
1005
|
// src/runtime/runtime.ts
|
|
920
1006
|
function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, context = {}) {
|
|
921
1007
|
const warnings = [];
|
|
@@ -927,7 +1013,10 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
|
|
|
927
1013
|
const apiMode = resolveApiMode(request, defaults.apiMode, serverTools);
|
|
928
1014
|
validateRuntimeRequest(request, options, apiMode, normalized.model, serverTools);
|
|
929
1015
|
const tools = [
|
|
930
|
-
...buildOpenRouterServerTools(
|
|
1016
|
+
...buildOpenRouterServerTools(
|
|
1017
|
+
serverTools,
|
|
1018
|
+
effectiveContext.suppressNestedReasoningFallback ? void 0 : request.reasoning
|
|
1019
|
+
),
|
|
931
1020
|
...(request.functionTools ?? []).map((tool) => ({
|
|
932
1021
|
type: "function",
|
|
933
1022
|
function: {
|
|
@@ -937,10 +1026,12 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
|
|
|
937
1026
|
}
|
|
938
1027
|
}))
|
|
939
1028
|
];
|
|
940
|
-
const headers = buildHeaders(options);
|
|
1029
|
+
const headers = buildHeaders(options, request.agentId);
|
|
941
1030
|
const baseBody = buildBaseBody(request, normalized.model, defaults, tools, serverTools);
|
|
942
|
-
const
|
|
1031
|
+
const assembled = apiMode === "chat" ? buildChatBody(request, baseBody) : buildResponsesBody(request, baseBody);
|
|
1032
|
+
let body = effectiveContext.finalizeBody ? effectiveContext.finalizeBody(assembled) : assembled;
|
|
943
1033
|
enforceStreamingPolicyForRun(body, warnings, effectiveContext);
|
|
1034
|
+
body = attachProviderMetadata(body, request);
|
|
944
1035
|
return {
|
|
945
1036
|
apiMode,
|
|
946
1037
|
url: endpointFor(options.baseUrl ?? "https://openrouter.ai/api/v1", apiMode),
|
|
@@ -949,6 +1040,15 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
|
|
|
949
1040
|
warnings
|
|
950
1041
|
};
|
|
951
1042
|
}
|
|
1043
|
+
function attachProviderMetadata(body, request) {
|
|
1044
|
+
const fromBody = isRecord(body.metadata) ? body.metadata : void 0;
|
|
1045
|
+
const metadata = toProviderMetadata(request.metadata, request.agentId, OPENROUTER_METADATA_LIMITS, fromBody);
|
|
1046
|
+
if (metadata) return { ...body, metadata };
|
|
1047
|
+
if (body.metadata === void 0) return body;
|
|
1048
|
+
const rest = { ...body };
|
|
1049
|
+
delete rest.metadata;
|
|
1050
|
+
return rest;
|
|
1051
|
+
}
|
|
952
1052
|
function enforceStreamingPolicyForRun(body, warnings, context) {
|
|
953
1053
|
if (context.streaming) {
|
|
954
1054
|
body.stream = true;
|
|
@@ -1482,7 +1582,7 @@ function isRetryableStatus2(status) {
|
|
|
1482
1582
|
}
|
|
1483
1583
|
|
|
1484
1584
|
// src/runtime/streaming.ts
|
|
1485
|
-
async function* executeStreamingChat(request, context) {
|
|
1585
|
+
async function* executeStreamingChat(request, context, call = {}) {
|
|
1486
1586
|
const requestId = request.id ?? "unknown";
|
|
1487
1587
|
const options = context.options;
|
|
1488
1588
|
const defaults = context.defaults;
|
|
@@ -1497,7 +1597,11 @@ async function* executeStreamingChat(request, context) {
|
|
|
1497
1597
|
...request,
|
|
1498
1598
|
apiMode: "chat"
|
|
1499
1599
|
};
|
|
1500
|
-
const compiled = compileRuntimeRequest(streamingRequest, defaults, options, {
|
|
1600
|
+
const compiled = compileRuntimeRequest(streamingRequest, defaults, options, {
|
|
1601
|
+
streaming: true,
|
|
1602
|
+
...call.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
|
|
1603
|
+
...call.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
|
|
1604
|
+
});
|
|
1501
1605
|
if (compiled.body.stream !== true) {
|
|
1502
1606
|
throw new RuntimeConfigError(
|
|
1503
1607
|
"STREAMING_CHAT_MISCONFIGURED",
|
|
@@ -1532,6 +1636,10 @@ async function* executeStreamingChat(request, context) {
|
|
|
1532
1636
|
if (typeof chunk.model === "string") resolvedModel = chunk.model;
|
|
1533
1637
|
const choice = Array.isArray(chunk.choices) && isRecord(chunk.choices[0]) ? chunk.choices[0] : void 0;
|
|
1534
1638
|
const delta = choice && isRecord(choice.delta) ? choice.delta : void 0;
|
|
1639
|
+
if (delta && call.extractStreamReasoning) {
|
|
1640
|
+
const reasoningText = call.extractStreamReasoning(delta);
|
|
1641
|
+
if (reasoningText) yield reasoningDeltaEvent(requestId, reasoningText);
|
|
1642
|
+
}
|
|
1535
1643
|
if (delta && typeof delta.content === "string" && delta.content.length > 0) {
|
|
1536
1644
|
text += delta.content;
|
|
1537
1645
|
yield textDeltaEvent(requestId, delta.content);
|
|
@@ -1626,6 +1734,13 @@ function textDeltaEvent(requestId, text) {
|
|
|
1626
1734
|
data: { text }
|
|
1627
1735
|
};
|
|
1628
1736
|
}
|
|
1737
|
+
function reasoningDeltaEvent(requestId, text) {
|
|
1738
|
+
return {
|
|
1739
|
+
type: "stream.reasoning.delta",
|
|
1740
|
+
requestId,
|
|
1741
|
+
data: { text }
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1629
1744
|
function toolCallDeltaEvent(requestId, data) {
|
|
1630
1745
|
return {
|
|
1631
1746
|
type: "stream.tool_call.delta",
|
|
@@ -1695,7 +1810,14 @@ function createOpenRouterRuntime(options) {
|
|
|
1695
1810
|
const defaults = resolveDefaults(options);
|
|
1696
1811
|
const context = { options: resolvedOptions, defaults };
|
|
1697
1812
|
return {
|
|
1698
|
-
|
|
1813
|
+
compile(request, call) {
|
|
1814
|
+
return compileRuntimeRequest(request, defaults, resolvedOptions, {
|
|
1815
|
+
streaming: false,
|
|
1816
|
+
...call?.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
|
|
1817
|
+
...call?.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
|
|
1818
|
+
});
|
|
1819
|
+
},
|
|
1820
|
+
async run(request, call) {
|
|
1699
1821
|
const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
|
|
1700
1822
|
try {
|
|
1701
1823
|
resolvedOptions.logger?.info?.("runtime.request.started", {
|
|
@@ -1704,7 +1826,11 @@ function createOpenRouterRuntime(options) {
|
|
|
1704
1826
|
entrypoint: "run"
|
|
1705
1827
|
});
|
|
1706
1828
|
await resolvedOptions.hooks?.beforeCompile?.(requestWithId);
|
|
1707
|
-
const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, {
|
|
1829
|
+
const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, {
|
|
1830
|
+
streaming: false,
|
|
1831
|
+
...call?.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
|
|
1832
|
+
...call?.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
|
|
1833
|
+
});
|
|
1708
1834
|
await resolvedOptions.hooks?.afterCompile?.(compiled);
|
|
1709
1835
|
resolvedOptions.logger?.debug?.("runtime.request.compiled", {
|
|
1710
1836
|
requestId: requestWithId.id,
|
|
@@ -1726,9 +1852,9 @@ function createOpenRouterRuntime(options) {
|
|
|
1726
1852
|
return errorResponse(requestWithId, error);
|
|
1727
1853
|
}
|
|
1728
1854
|
},
|
|
1729
|
-
executeStreamingChat(request) {
|
|
1855
|
+
executeStreamingChat(request, call) {
|
|
1730
1856
|
const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
|
|
1731
|
-
return executeStreamingChat(requestWithId, context);
|
|
1857
|
+
return executeStreamingChat(requestWithId, context, call);
|
|
1732
1858
|
}
|
|
1733
1859
|
};
|
|
1734
1860
|
function errorResponse(request, error) {
|
|
@@ -1818,12 +1944,15 @@ function operatorHintFor(code) {
|
|
|
1818
1944
|
}
|
|
1819
1945
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1820
1946
|
0 && (module.exports = {
|
|
1947
|
+
OPENROUTER_METADATA_LIMITS,
|
|
1821
1948
|
OpenRouterHttpError,
|
|
1822
1949
|
RuntimeConfigError,
|
|
1823
1950
|
buildOpenRouterServerTools,
|
|
1824
1951
|
compileRuntimeRequest,
|
|
1825
1952
|
createConsoleLogger,
|
|
1826
1953
|
createOpenRouterRuntime,
|
|
1827
|
-
|
|
1954
|
+
decodeProviderMetadata,
|
|
1955
|
+
isRuntimeLoggingEnabled,
|
|
1956
|
+
toProviderMetadata
|
|
1828
1957
|
});
|
|
1829
1958
|
//# sourceMappingURL=index.cjs.map
|