@x12i/openrouter-runtime 1.0.6 → 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/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
- isRuntimeLoggingEnabled: () => isRuntimeLoggingEnabled
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 ? { "X-Title": 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(serverTools),
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 body = apiMode === "chat" ? buildChatBody(request, baseBody) : buildResponsesBody(request, baseBody);
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,12 +1040,24 @@ 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
- if (context.streaming) return;
1053
+ if (context.streaming) {
1054
+ body.stream = true;
1055
+ return;
1056
+ }
954
1057
  if (body.stream !== void 0 && body.stream !== false) {
955
1058
  warnings.push({
956
1059
  code: "STREAMING_OVERRIDE_IGNORED_FOR_RUN",
957
- message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() when streaming is implemented.",
1060
+ message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() for streaming.",
958
1061
  details: { ignoredStreamValue: body.stream }
959
1062
  });
960
1063
  }
@@ -1357,12 +1460,348 @@ function optional6(key, value) {
1357
1460
  return value === void 0 ? {} : { [key]: value };
1358
1461
  }
1359
1462
 
1463
+ // src/openrouter/stream-client.ts
1464
+ async function openOpenRouterStream(compiled, options, timeoutMs) {
1465
+ const controller = new AbortController();
1466
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
1467
+ const cleanup = () => clearTimeout(timeout);
1468
+ try {
1469
+ const response = await options.fetch(compiled.url, {
1470
+ method: "POST",
1471
+ headers: {
1472
+ ...compiled.headers,
1473
+ Accept: "text/event-stream"
1474
+ },
1475
+ body: JSON.stringify(compiled.body),
1476
+ signal: controller.signal
1477
+ });
1478
+ if (!response.ok) {
1479
+ const text = await response.text();
1480
+ cleanup();
1481
+ const body = text ? parseBody2(text) : void 0;
1482
+ const message = extractMessage2(body) ?? `OpenRouter stream failed with status ${response.status}.`;
1483
+ throw new OpenRouterHttpError(
1484
+ response.status,
1485
+ classifyProviderFailure2(response.status, message, body),
1486
+ message,
1487
+ body,
1488
+ isRetryableStatus2(response.status)
1489
+ );
1490
+ }
1491
+ return { response, cleanup };
1492
+ } catch (error) {
1493
+ cleanup();
1494
+ if (error instanceof OpenRouterHttpError) throw error;
1495
+ if (error instanceof Error && error.name === "AbortError") {
1496
+ throw new OpenRouterHttpError(408, "PROVIDER_GATEWAY_UNREACHABLE", "OpenRouter stream timed out.", void 0, true);
1497
+ }
1498
+ throw new OpenRouterHttpError(
1499
+ 503,
1500
+ "PROVIDER_GATEWAY_UNREACHABLE",
1501
+ error instanceof Error ? error.message : "OpenRouter stream failed before receiving a response.",
1502
+ void 0,
1503
+ true
1504
+ );
1505
+ }
1506
+ }
1507
+ async function* parseSseStream(response) {
1508
+ const body = response.body;
1509
+ if (!body) {
1510
+ throw new OpenRouterHttpError(
1511
+ 503,
1512
+ "PROVIDER_GATEWAY_UNREACHABLE",
1513
+ "OpenRouter stream response had no body.",
1514
+ void 0,
1515
+ true
1516
+ );
1517
+ }
1518
+ const reader = body.getReader();
1519
+ const decoder = new TextDecoder();
1520
+ let buffer = "";
1521
+ while (true) {
1522
+ const { done, value } = await reader.read();
1523
+ if (done) break;
1524
+ buffer += decoder.decode(value, { stream: true });
1525
+ const parts = buffer.split(/\r?\n/);
1526
+ buffer = parts.pop() ?? "";
1527
+ for (const part of parts) {
1528
+ const line = part.trim();
1529
+ if (!line || line.startsWith(":")) continue;
1530
+ if (!line.startsWith("data:")) continue;
1531
+ const data = line.slice(5).trim();
1532
+ if (!data) continue;
1533
+ if (data === "[DONE]") return;
1534
+ try {
1535
+ yield JSON.parse(data);
1536
+ } catch {
1537
+ }
1538
+ }
1539
+ }
1540
+ const trailing = buffer.trim();
1541
+ if (trailing.startsWith("data:")) {
1542
+ const data = trailing.slice(5).trim();
1543
+ if (data && data !== "[DONE]") {
1544
+ try {
1545
+ yield JSON.parse(data);
1546
+ } catch {
1547
+ }
1548
+ }
1549
+ }
1550
+ }
1551
+ function parseBody2(text) {
1552
+ try {
1553
+ return JSON.parse(text);
1554
+ } catch {
1555
+ return text;
1556
+ }
1557
+ }
1558
+ function extractMessage2(body) {
1559
+ if (typeof body !== "object" || body === null) return void 0;
1560
+ const record = body;
1561
+ const error = record.error;
1562
+ if (typeof error === "object" && error !== null && typeof error.message === "string") {
1563
+ return error.message;
1564
+ }
1565
+ return typeof record.message === "string" ? record.message : void 0;
1566
+ }
1567
+ function classifyProviderFailure2(status, message, body) {
1568
+ const haystack = `${message} ${JSON.stringify(body ?? "")}`.toLowerCase();
1569
+ if (status === 401 || status === 403) return "PROVIDER_AUTH_FAILED";
1570
+ if (status === 402 || /\b(quota|credit|credits|billing|balance|insufficient funds|insufficient credit)\b/.test(haystack)) {
1571
+ return "PROVIDER_QUOTA_EXCEEDED";
1572
+ }
1573
+ if (status === 404 || /\bmodel\b.*\b(not found|not a valid|invalid|unavailable)\b/.test(haystack) || /\b(no endpoints found|not a valid model id)\b/.test(haystack)) {
1574
+ return "PROVIDER_MODEL_NOT_FOUND";
1575
+ }
1576
+ if (status === 429) return "PROVIDER_RATE_LIMITED";
1577
+ if (status === 408 || status >= 500) return "PROVIDER_GATEWAY_UNREACHABLE";
1578
+ return "PROVIDER_REQUEST_FAILED";
1579
+ }
1580
+ function isRetryableStatus2(status) {
1581
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
1582
+ }
1583
+
1360
1584
  // src/runtime/streaming.ts
1361
- async function* executeStreamingChatNotImplemented() {
1362
- throw new RuntimeConfigError(
1363
- "STREAMING_NOT_IMPLEMENTED",
1364
- "executeStreamingChat() is reserved and not implemented yet. Use runtime.run() for non-streaming execution."
1365
- );
1585
+ async function* executeStreamingChat(request, context, call = {}) {
1586
+ const requestId = request.id ?? "unknown";
1587
+ const options = context.options;
1588
+ const defaults = context.defaults;
1589
+ options.logger?.info?.("runtime.executeStreamingChat.started", {
1590
+ requestId,
1591
+ streaming: true,
1592
+ entrypoint: "executeStreamingChat"
1593
+ });
1594
+ try {
1595
+ assertStreamingChatRequest(request, defaults);
1596
+ const streamingRequest = {
1597
+ ...request,
1598
+ apiMode: "chat"
1599
+ };
1600
+ const compiled = compileRuntimeRequest(streamingRequest, defaults, options, {
1601
+ streaming: true,
1602
+ ...call.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
1603
+ ...call.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
1604
+ });
1605
+ if (compiled.body.stream !== true) {
1606
+ throw new RuntimeConfigError(
1607
+ "STREAMING_CHAT_MISCONFIGURED",
1608
+ "executeStreamingChat() requires stream=true on the compiled OpenRouter body."
1609
+ );
1610
+ }
1611
+ for (const warning of compiled.warnings) {
1612
+ yield warningEvent(requestId, warning);
1613
+ }
1614
+ const model = typeof compiled.body.model === "string" ? compiled.body.model : "";
1615
+ yield startEvent(requestId, model);
1616
+ await options.hooks?.beforeOpenRouterRequest?.(compiled);
1617
+ const timeoutMs = request.execution?.timeoutMs ?? defaults.timeoutMs;
1618
+ const session = await openOpenRouterStream(compiled, options, timeoutMs);
1619
+ let text = "";
1620
+ let finishReason;
1621
+ let resolvedModel = model;
1622
+ try {
1623
+ for await (const chunk of parseSseStream(session.response)) {
1624
+ if (!isRecord(chunk)) continue;
1625
+ if (chunk.error) {
1626
+ const message = isRecord(chunk.error) && typeof chunk.error.message === "string" ? chunk.error.message : "OpenRouter stream returned an error chunk.";
1627
+ const error = {
1628
+ code: "PROVIDER_REQUEST_FAILED",
1629
+ message,
1630
+ source: "openrouter",
1631
+ details: chunk.error
1632
+ };
1633
+ yield errorEvent(requestId, error);
1634
+ throw new OpenRouterHttpError(500, "PROVIDER_REQUEST_FAILED", message, chunk, false);
1635
+ }
1636
+ if (typeof chunk.model === "string") resolvedModel = chunk.model;
1637
+ const choice = Array.isArray(chunk.choices) && isRecord(chunk.choices[0]) ? chunk.choices[0] : void 0;
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
+ }
1643
+ if (delta && typeof delta.content === "string" && delta.content.length > 0) {
1644
+ text += delta.content;
1645
+ yield textDeltaEvent(requestId, delta.content);
1646
+ }
1647
+ if (delta && Array.isArray(delta.tool_calls)) {
1648
+ for (const toolCall of delta.tool_calls) {
1649
+ if (!isRecord(toolCall)) continue;
1650
+ const index = typeof toolCall.index === "number" ? toolCall.index : 0;
1651
+ const fn = isRecord(toolCall.function) ? toolCall.function : {};
1652
+ yield toolCallDeltaEvent(requestId, {
1653
+ index,
1654
+ ...typeof toolCall.id === "string" ? { id: toolCall.id } : {},
1655
+ ...typeof fn.name === "string" ? { name: fn.name } : {},
1656
+ ...typeof fn.arguments === "string" ? { argumentsDelta: fn.arguments } : {}
1657
+ });
1658
+ }
1659
+ }
1660
+ if (choice && typeof choice.finish_reason === "string") {
1661
+ finishReason = choice.finish_reason;
1662
+ }
1663
+ if (chunk.usage) {
1664
+ const usage = normalizeUsage(chunk.usage);
1665
+ if (usage) yield usageEvent(requestId, usage);
1666
+ }
1667
+ }
1668
+ } finally {
1669
+ session.cleanup();
1670
+ }
1671
+ await options.hooks?.afterOpenRouterResponse?.({ streamed: true, text, finishReason, model: resolvedModel });
1672
+ yield doneEvent(requestId, {
1673
+ text,
1674
+ model: resolvedModel,
1675
+ ...finishReason ? { finishReason } : {}
1676
+ });
1677
+ options.logger?.info?.("runtime.executeStreamingChat.completed", {
1678
+ requestId,
1679
+ streaming: true,
1680
+ entrypoint: "executeStreamingChat",
1681
+ finishReason,
1682
+ textLength: text.length
1683
+ });
1684
+ } catch (error) {
1685
+ const runtimeError = toRuntimeError(error);
1686
+ yield errorEvent(requestId, runtimeError);
1687
+ options.logger?.error?.("runtime.executeStreamingChat.failed", {
1688
+ requestId,
1689
+ streaming: true,
1690
+ code: runtimeError.code,
1691
+ message: runtimeError.message
1692
+ });
1693
+ throw error instanceof Error ? error : new Error(runtimeError.message);
1694
+ }
1695
+ }
1696
+ function assertStreamingChatRequest(request, defaults) {
1697
+ if (request.apiMode === "responses") {
1698
+ throw new RuntimeConfigError(
1699
+ "STREAMING_CHAT_REQUIRES_CHAT_API",
1700
+ "executeStreamingChat() only supports Chat Completions. Use runtime.run() for Responses API requests."
1701
+ );
1702
+ }
1703
+ if (request.serverTools?.applyPatch?.mode && request.serverTools.applyPatch.mode !== "disabled") {
1704
+ throw new RuntimeConfigError(
1705
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1706
+ "executeStreamingChat() does not support applyPatch. Use runtime.run() instead."
1707
+ );
1708
+ }
1709
+ if (defaults.serverTools?.applyPatch?.mode && defaults.serverTools.applyPatch.mode !== "disabled") {
1710
+ const requestPatch = request.serverTools?.applyPatch;
1711
+ if (!requestPatch || requestPatch.mode !== "disabled") {
1712
+ throw new RuntimeConfigError(
1713
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1714
+ "executeStreamingChat() does not support applyPatch defaults. Use runtime.run() instead."
1715
+ );
1716
+ }
1717
+ }
1718
+ }
1719
+ function startEvent(requestId, model) {
1720
+ return {
1721
+ type: "stream.start",
1722
+ requestId,
1723
+ data: {
1724
+ model,
1725
+ apiMode: "chat",
1726
+ entrypoint: "executeStreamingChat"
1727
+ }
1728
+ };
1729
+ }
1730
+ function textDeltaEvent(requestId, text) {
1731
+ return {
1732
+ type: "stream.text.delta",
1733
+ requestId,
1734
+ data: { text }
1735
+ };
1736
+ }
1737
+ function reasoningDeltaEvent(requestId, text) {
1738
+ return {
1739
+ type: "stream.reasoning.delta",
1740
+ requestId,
1741
+ data: { text }
1742
+ };
1743
+ }
1744
+ function toolCallDeltaEvent(requestId, data) {
1745
+ return {
1746
+ type: "stream.tool_call.delta",
1747
+ requestId,
1748
+ data
1749
+ };
1750
+ }
1751
+ function usageEvent(requestId, usage) {
1752
+ return {
1753
+ type: "stream.usage",
1754
+ requestId,
1755
+ data: { usage }
1756
+ };
1757
+ }
1758
+ function warningEvent(requestId, warning) {
1759
+ return {
1760
+ type: "stream.warning",
1761
+ requestId,
1762
+ data: { warning }
1763
+ };
1764
+ }
1765
+ function errorEvent(requestId, error) {
1766
+ return {
1767
+ type: "stream.error",
1768
+ requestId,
1769
+ data: { error }
1770
+ };
1771
+ }
1772
+ function doneEvent(requestId, data) {
1773
+ return {
1774
+ type: "stream.done",
1775
+ requestId,
1776
+ data
1777
+ };
1778
+ }
1779
+ function toRuntimeError(error) {
1780
+ if (error instanceof RuntimeConfigError) {
1781
+ return {
1782
+ code: error.code,
1783
+ message: error.message,
1784
+ source: "validation",
1785
+ details: error.details
1786
+ };
1787
+ }
1788
+ if (error instanceof OpenRouterHttpError) {
1789
+ return {
1790
+ code: error.code,
1791
+ message: error.message,
1792
+ source: "openrouter",
1793
+ retryable: error.retryable,
1794
+ details: {
1795
+ providerAttempts: error.providerAttempts,
1796
+ ...error.body === void 0 ? {} : { response: error.body }
1797
+ }
1798
+ };
1799
+ }
1800
+ return {
1801
+ code: "RUNTIME_ERROR",
1802
+ message: error instanceof Error ? error.message : String(error),
1803
+ source: "runtime"
1804
+ };
1366
1805
  }
1367
1806
 
1368
1807
  // src/runtime/create-runtime.ts
@@ -1371,7 +1810,14 @@ function createOpenRouterRuntime(options) {
1371
1810
  const defaults = resolveDefaults(options);
1372
1811
  const context = { options: resolvedOptions, defaults };
1373
1812
  return {
1374
- async run(request) {
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) {
1375
1821
  const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
1376
1822
  try {
1377
1823
  resolvedOptions.logger?.info?.("runtime.request.started", {
@@ -1380,7 +1826,11 @@ function createOpenRouterRuntime(options) {
1380
1826
  entrypoint: "run"
1381
1827
  });
1382
1828
  await resolvedOptions.hooks?.beforeCompile?.(requestWithId);
1383
- const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, { streaming: false });
1829
+ const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, {
1830
+ streaming: false,
1831
+ ...call?.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
1832
+ ...call?.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
1833
+ });
1384
1834
  await resolvedOptions.hooks?.afterCompile?.(compiled);
1385
1835
  resolvedOptions.logger?.debug?.("runtime.request.compiled", {
1386
1836
  requestId: requestWithId.id,
@@ -1402,14 +1852,9 @@ function createOpenRouterRuntime(options) {
1402
1852
  return errorResponse(requestWithId, error);
1403
1853
  }
1404
1854
  },
1405
- executeStreamingChat(request) {
1406
- resolvedOptions.logger?.warn?.("runtime.executeStreamingChat.called", {
1407
- requestId: request.id,
1408
- streaming: true,
1409
- entrypoint: "executeStreamingChat",
1410
- implemented: false
1411
- });
1412
- return executeStreamingChatNotImplemented();
1855
+ executeStreamingChat(request, call) {
1856
+ const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
1857
+ return executeStreamingChat(requestWithId, context, call);
1413
1858
  }
1414
1859
  };
1415
1860
  function errorResponse(request, error) {
@@ -1499,12 +1944,15 @@ function operatorHintFor(code) {
1499
1944
  }
1500
1945
  // Annotate the CommonJS export names for ESM import in node:
1501
1946
  0 && (module.exports = {
1947
+ OPENROUTER_METADATA_LIMITS,
1502
1948
  OpenRouterHttpError,
1503
1949
  RuntimeConfigError,
1504
1950
  buildOpenRouterServerTools,
1505
1951
  compileRuntimeRequest,
1506
1952
  createConsoleLogger,
1507
1953
  createOpenRouterRuntime,
1508
- isRuntimeLoggingEnabled
1954
+ decodeProviderMetadata,
1955
+ isRuntimeLoggingEnabled,
1956
+ toProviderMetadata
1509
1957
  });
1510
1958
  //# sourceMappingURL=index.cjs.map