@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.js CHANGED
@@ -722,13 +722,22 @@ function endpointFor(baseUrl, apiMode) {
722
722
  }
723
723
 
724
724
  // src/openrouter/headers.ts
725
- function buildHeaders(options) {
725
+ function buildHeaders(options, agentId) {
726
+ const requestAppName = agentId?.trim();
726
727
  return {
727
728
  "content-type": "application/json",
728
729
  authorization: `Bearer ${options.apiKey}`,
729
730
  ...options.appAttribution?.siteUrl ? { "HTTP-Referer": options.appAttribution.siteUrl } : {},
730
- ...options.appAttribution?.appName ? { "X-Title": options.appAttribution.appName } : {},
731
- ...options.defaultHeaders ?? {}
731
+ ...appTitleHeaders(options.appAttribution?.appName),
732
+ ...options.defaultHeaders ?? {},
733
+ ...requestAppName ? appTitleHeaders(requestAppName) : {}
734
+ };
735
+ }
736
+ function appTitleHeaders(name) {
737
+ if (!name) return {};
738
+ return {
739
+ "X-Title": name,
740
+ "X-OpenRouter-Title": name
732
741
  };
733
742
  }
734
743
 
@@ -757,7 +766,7 @@ function cleanParameters(parameters) {
757
766
  function enabled(policy) {
758
767
  return !!policy && policy.mode !== "disabled";
759
768
  }
760
- function buildOpenRouterServerTools(policy) {
769
+ function buildOpenRouterServerTools(policy, fallbackReasoning) {
761
770
  const tools = [];
762
771
  const webSearch = buildWebSearchTool(policy?.webSearch);
763
772
  if (webSearch) tools.push(webSearch);
@@ -769,10 +778,10 @@ function buildOpenRouterServerTools(policy) {
769
778
  if (image) tools.push(image);
770
779
  const patch = buildApplyPatchTool(policy?.applyPatch);
771
780
  if (patch) tools.push(patch);
772
- const fusion = buildFusionTool(policy?.fusion);
781
+ const fusion = buildFusionTool(policy?.fusion, fallbackReasoning);
773
782
  if (fusion) tools.push(fusion);
774
- tools.push(...buildAdvisorTools(policy?.advisor));
775
- const subagent = buildSubagentTool(policy?.subagent);
783
+ tools.push(...buildAdvisorTools(policy?.advisor, fallbackReasoning));
784
+ const subagent = buildSubagentTool(policy?.subagent, fallbackReasoning);
776
785
  if (subagent) tools.push(subagent);
777
786
  return tools;
778
787
  }
@@ -831,7 +840,7 @@ function buildApplyPatchTool(policy) {
831
840
  if (!enabled(policy)) return void 0;
832
841
  return { type: "openrouter:apply_patch" };
833
842
  }
834
- function buildFusionTool(policy) {
843
+ function buildFusionTool(policy, fallbackReasoning) {
835
844
  if (!enabled(policy)) return void 0;
836
845
  return {
837
846
  type: "openrouter:fusion",
@@ -840,12 +849,12 @@ function buildFusionTool(policy) {
840
849
  model: policy?.judgeModel,
841
850
  max_tool_calls: policy?.maxToolCalls ?? 8,
842
851
  max_completion_tokens: policy?.maxCompletionTokens,
843
- reasoning: policy?.reasoning,
852
+ reasoning: policy?.reasoning ?? fallbackReasoning,
844
853
  temperature: policy?.temperature
845
854
  })
846
855
  };
847
856
  }
848
- function buildAdvisorTools(policy) {
857
+ function buildAdvisorTools(policy, fallbackReasoning) {
849
858
  const advisors = Array.isArray(policy) ? policy : policy ? [policy] : [];
850
859
  return advisors.filter(enabled).map((advisor) => {
851
860
  validateNestedTools(advisor.tools);
@@ -860,13 +869,13 @@ function buildAdvisorTools(policy) {
860
869
  stream: advisor.stream,
861
870
  max_tool_calls: advisor.maxToolCalls,
862
871
  max_completion_tokens: advisor.maxCompletionTokens,
863
- reasoning: advisor.reasoning,
872
+ reasoning: advisor.reasoning ?? fallbackReasoning,
864
873
  temperature: advisor.temperature
865
874
  })
866
875
  };
867
876
  });
868
877
  }
869
- function buildSubagentTool(policy) {
878
+ function buildSubagentTool(policy, fallbackReasoning) {
870
879
  if (!policy || policy.mode === "disabled") return void 0;
871
880
  const subagent = policy;
872
881
  validateNestedTools(subagent.tools);
@@ -878,12 +887,86 @@ function buildSubagentTool(policy) {
878
887
  tools: subagent.tools,
879
888
  max_tool_calls: subagent.maxToolCalls,
880
889
  max_completion_tokens: subagent.maxCompletionTokens,
881
- reasoning: subagent.reasoning,
890
+ reasoning: subagent.reasoning ?? fallbackReasoning,
882
891
  temperature: subagent.temperature
883
892
  })
884
893
  };
885
894
  }
886
895
 
896
+ // src/utils/provider-metadata.ts
897
+ var OPENROUTER_METADATA_LIMITS = {
898
+ maxPairs: 16,
899
+ maxKeyLength: 64,
900
+ maxValueLength: 512
901
+ };
902
+ var PROVIDER_RECORD_CHUNK = 256;
903
+ var PROVIDER_RECORD_MAX_CHUNKS = 16;
904
+ function toProviderMetadata(metadata, agentId, _limits, base) {
905
+ return encodeProviderRecord(collectProviderStrings(metadata, agentId, base));
906
+ }
907
+ function decodeProviderMetadata(wire) {
908
+ if (!isRecord2(wire)) return {};
909
+ const parts = [];
910
+ for (let index = 0; ; index += 1) {
911
+ const chunk = wire[`m.${index}`];
912
+ if (typeof chunk !== "string") break;
913
+ parts.push(chunk);
914
+ }
915
+ if (!parts.length) return {};
916
+ const parsed = JSON.parse(Buffer.from(parts.join(""), "base64").toString("utf8"));
917
+ if (!isRecord2(parsed)) return {};
918
+ const record = {};
919
+ for (const [key, value] of Object.entries(parsed)) {
920
+ if (typeof value === "string") record[key] = value;
921
+ }
922
+ return record;
923
+ }
924
+ function encodeProviderRecord(map) {
925
+ const keys = Object.keys(map).sort();
926
+ if (!keys.length) return void 0;
927
+ const ordered = {};
928
+ for (const key of keys) {
929
+ const value = map[key];
930
+ if (value !== void 0) ordered[key] = value;
931
+ }
932
+ const encoded = Buffer.from(JSON.stringify(ordered), "utf8").toString("base64");
933
+ const chunks = Math.ceil(encoded.length / PROVIDER_RECORD_CHUNK);
934
+ if (chunks > PROVIDER_RECORD_MAX_CHUNKS) {
935
+ throw new Error(
936
+ `METADATA_RECORD_TOO_LARGE: provider metadata is ${encoded.length} base64 characters; the maximum is ${PROVIDER_RECORD_CHUNK * PROVIDER_RECORD_MAX_CHUNKS}.`
937
+ );
938
+ }
939
+ const wire = {};
940
+ for (let index = 0; index < chunks; index += 1) {
941
+ wire[`m.${index}`] = encoded.slice(index * PROVIDER_RECORD_CHUNK, (index + 1) * PROVIDER_RECORD_CHUNK);
942
+ }
943
+ return wire;
944
+ }
945
+ function collectProviderStrings(metadata, agentId, base) {
946
+ const map = {};
947
+ appendStrings(map, base);
948
+ appendStrings(map, metadata);
949
+ const trimmedAgentId = agentId?.trim();
950
+ if (trimmedAgentId) map.agentId = trimmedAgentId;
951
+ return map;
952
+ }
953
+ function appendStrings(target, metadata) {
954
+ if (!metadata) return;
955
+ for (const [key, value] of Object.entries(metadata)) {
956
+ const asString = asMetadataString(value);
957
+ if (asString !== void 0) target[key] = asString;
958
+ }
959
+ }
960
+ function asMetadataString(value) {
961
+ if (typeof value === "string") return value;
962
+ if (typeof value === "boolean") return value ? "true" : "false";
963
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
964
+ return void 0;
965
+ }
966
+ function isRecord2(value) {
967
+ return typeof value === "object" && value !== null && !Array.isArray(value);
968
+ }
969
+
887
970
  // src/runtime/runtime.ts
888
971
  function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, context = {}) {
889
972
  const warnings = [];
@@ -895,7 +978,10 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
895
978
  const apiMode = resolveApiMode(request, defaults.apiMode, serverTools);
896
979
  validateRuntimeRequest(request, options, apiMode, normalized.model, serverTools);
897
980
  const tools = [
898
- ...buildOpenRouterServerTools(serverTools),
981
+ ...buildOpenRouterServerTools(
982
+ serverTools,
983
+ effectiveContext.suppressNestedReasoningFallback ? void 0 : request.reasoning
984
+ ),
899
985
  ...(request.functionTools ?? []).map((tool) => ({
900
986
  type: "function",
901
987
  function: {
@@ -905,10 +991,12 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
905
991
  }
906
992
  }))
907
993
  ];
908
- const headers = buildHeaders(options);
994
+ const headers = buildHeaders(options, request.agentId);
909
995
  const baseBody = buildBaseBody(request, normalized.model, defaults, tools, serverTools);
910
- const body = apiMode === "chat" ? buildChatBody(request, baseBody) : buildResponsesBody(request, baseBody);
996
+ const assembled = apiMode === "chat" ? buildChatBody(request, baseBody) : buildResponsesBody(request, baseBody);
997
+ let body = effectiveContext.finalizeBody ? effectiveContext.finalizeBody(assembled) : assembled;
911
998
  enforceStreamingPolicyForRun(body, warnings, effectiveContext);
999
+ body = attachProviderMetadata(body, request);
912
1000
  return {
913
1001
  apiMode,
914
1002
  url: endpointFor(options.baseUrl ?? "https://openrouter.ai/api/v1", apiMode),
@@ -917,12 +1005,24 @@ function compileRuntimeRequest(request, defaults, options = { apiKey: "" }, cont
917
1005
  warnings
918
1006
  };
919
1007
  }
1008
+ function attachProviderMetadata(body, request) {
1009
+ const fromBody = isRecord(body.metadata) ? body.metadata : void 0;
1010
+ const metadata = toProviderMetadata(request.metadata, request.agentId, OPENROUTER_METADATA_LIMITS, fromBody);
1011
+ if (metadata) return { ...body, metadata };
1012
+ if (body.metadata === void 0) return body;
1013
+ const rest = { ...body };
1014
+ delete rest.metadata;
1015
+ return rest;
1016
+ }
920
1017
  function enforceStreamingPolicyForRun(body, warnings, context) {
921
- if (context.streaming) return;
1018
+ if (context.streaming) {
1019
+ body.stream = true;
1020
+ return;
1021
+ }
922
1022
  if (body.stream !== void 0 && body.stream !== false) {
923
1023
  warnings.push({
924
1024
  code: "STREAMING_OVERRIDE_IGNORED_FOR_RUN",
925
- message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() when streaming is implemented.",
1025
+ message: "runtime.run() is non-streaming. Use runtime.executeStreamingChat() for streaming.",
926
1026
  details: { ignoredStreamValue: body.stream }
927
1027
  });
928
1028
  }
@@ -1325,12 +1425,348 @@ function optional6(key, value) {
1325
1425
  return value === void 0 ? {} : { [key]: value };
1326
1426
  }
1327
1427
 
1428
+ // src/openrouter/stream-client.ts
1429
+ async function openOpenRouterStream(compiled, options, timeoutMs) {
1430
+ const controller = new AbortController();
1431
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
1432
+ const cleanup = () => clearTimeout(timeout);
1433
+ try {
1434
+ const response = await options.fetch(compiled.url, {
1435
+ method: "POST",
1436
+ headers: {
1437
+ ...compiled.headers,
1438
+ Accept: "text/event-stream"
1439
+ },
1440
+ body: JSON.stringify(compiled.body),
1441
+ signal: controller.signal
1442
+ });
1443
+ if (!response.ok) {
1444
+ const text = await response.text();
1445
+ cleanup();
1446
+ const body = text ? parseBody2(text) : void 0;
1447
+ const message = extractMessage2(body) ?? `OpenRouter stream failed with status ${response.status}.`;
1448
+ throw new OpenRouterHttpError(
1449
+ response.status,
1450
+ classifyProviderFailure2(response.status, message, body),
1451
+ message,
1452
+ body,
1453
+ isRetryableStatus2(response.status)
1454
+ );
1455
+ }
1456
+ return { response, cleanup };
1457
+ } catch (error) {
1458
+ cleanup();
1459
+ if (error instanceof OpenRouterHttpError) throw error;
1460
+ if (error instanceof Error && error.name === "AbortError") {
1461
+ throw new OpenRouterHttpError(408, "PROVIDER_GATEWAY_UNREACHABLE", "OpenRouter stream timed out.", void 0, true);
1462
+ }
1463
+ throw new OpenRouterHttpError(
1464
+ 503,
1465
+ "PROVIDER_GATEWAY_UNREACHABLE",
1466
+ error instanceof Error ? error.message : "OpenRouter stream failed before receiving a response.",
1467
+ void 0,
1468
+ true
1469
+ );
1470
+ }
1471
+ }
1472
+ async function* parseSseStream(response) {
1473
+ const body = response.body;
1474
+ if (!body) {
1475
+ throw new OpenRouterHttpError(
1476
+ 503,
1477
+ "PROVIDER_GATEWAY_UNREACHABLE",
1478
+ "OpenRouter stream response had no body.",
1479
+ void 0,
1480
+ true
1481
+ );
1482
+ }
1483
+ const reader = body.getReader();
1484
+ const decoder = new TextDecoder();
1485
+ let buffer = "";
1486
+ while (true) {
1487
+ const { done, value } = await reader.read();
1488
+ if (done) break;
1489
+ buffer += decoder.decode(value, { stream: true });
1490
+ const parts = buffer.split(/\r?\n/);
1491
+ buffer = parts.pop() ?? "";
1492
+ for (const part of parts) {
1493
+ const line = part.trim();
1494
+ if (!line || line.startsWith(":")) continue;
1495
+ if (!line.startsWith("data:")) continue;
1496
+ const data = line.slice(5).trim();
1497
+ if (!data) continue;
1498
+ if (data === "[DONE]") return;
1499
+ try {
1500
+ yield JSON.parse(data);
1501
+ } catch {
1502
+ }
1503
+ }
1504
+ }
1505
+ const trailing = buffer.trim();
1506
+ if (trailing.startsWith("data:")) {
1507
+ const data = trailing.slice(5).trim();
1508
+ if (data && data !== "[DONE]") {
1509
+ try {
1510
+ yield JSON.parse(data);
1511
+ } catch {
1512
+ }
1513
+ }
1514
+ }
1515
+ }
1516
+ function parseBody2(text) {
1517
+ try {
1518
+ return JSON.parse(text);
1519
+ } catch {
1520
+ return text;
1521
+ }
1522
+ }
1523
+ function extractMessage2(body) {
1524
+ if (typeof body !== "object" || body === null) return void 0;
1525
+ const record = body;
1526
+ const error = record.error;
1527
+ if (typeof error === "object" && error !== null && typeof error.message === "string") {
1528
+ return error.message;
1529
+ }
1530
+ return typeof record.message === "string" ? record.message : void 0;
1531
+ }
1532
+ function classifyProviderFailure2(status, message, body) {
1533
+ const haystack = `${message} ${JSON.stringify(body ?? "")}`.toLowerCase();
1534
+ if (status === 401 || status === 403) return "PROVIDER_AUTH_FAILED";
1535
+ if (status === 402 || /\b(quota|credit|credits|billing|balance|insufficient funds|insufficient credit)\b/.test(haystack)) {
1536
+ return "PROVIDER_QUOTA_EXCEEDED";
1537
+ }
1538
+ 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)) {
1539
+ return "PROVIDER_MODEL_NOT_FOUND";
1540
+ }
1541
+ if (status === 429) return "PROVIDER_RATE_LIMITED";
1542
+ if (status === 408 || status >= 500) return "PROVIDER_GATEWAY_UNREACHABLE";
1543
+ return "PROVIDER_REQUEST_FAILED";
1544
+ }
1545
+ function isRetryableStatus2(status) {
1546
+ return status === 429 || status === 500 || status === 502 || status === 503 || status === 504;
1547
+ }
1548
+
1328
1549
  // src/runtime/streaming.ts
1329
- async function* executeStreamingChatNotImplemented() {
1330
- throw new RuntimeConfigError(
1331
- "STREAMING_NOT_IMPLEMENTED",
1332
- "executeStreamingChat() is reserved and not implemented yet. Use runtime.run() for non-streaming execution."
1333
- );
1550
+ async function* executeStreamingChat(request, context, call = {}) {
1551
+ const requestId = request.id ?? "unknown";
1552
+ const options = context.options;
1553
+ const defaults = context.defaults;
1554
+ options.logger?.info?.("runtime.executeStreamingChat.started", {
1555
+ requestId,
1556
+ streaming: true,
1557
+ entrypoint: "executeStreamingChat"
1558
+ });
1559
+ try {
1560
+ assertStreamingChatRequest(request, defaults);
1561
+ const streamingRequest = {
1562
+ ...request,
1563
+ apiMode: "chat"
1564
+ };
1565
+ const compiled = compileRuntimeRequest(streamingRequest, defaults, options, {
1566
+ streaming: true,
1567
+ ...call.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
1568
+ ...call.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
1569
+ });
1570
+ if (compiled.body.stream !== true) {
1571
+ throw new RuntimeConfigError(
1572
+ "STREAMING_CHAT_MISCONFIGURED",
1573
+ "executeStreamingChat() requires stream=true on the compiled OpenRouter body."
1574
+ );
1575
+ }
1576
+ for (const warning of compiled.warnings) {
1577
+ yield warningEvent(requestId, warning);
1578
+ }
1579
+ const model = typeof compiled.body.model === "string" ? compiled.body.model : "";
1580
+ yield startEvent(requestId, model);
1581
+ await options.hooks?.beforeOpenRouterRequest?.(compiled);
1582
+ const timeoutMs = request.execution?.timeoutMs ?? defaults.timeoutMs;
1583
+ const session = await openOpenRouterStream(compiled, options, timeoutMs);
1584
+ let text = "";
1585
+ let finishReason;
1586
+ let resolvedModel = model;
1587
+ try {
1588
+ for await (const chunk of parseSseStream(session.response)) {
1589
+ if (!isRecord(chunk)) continue;
1590
+ if (chunk.error) {
1591
+ const message = isRecord(chunk.error) && typeof chunk.error.message === "string" ? chunk.error.message : "OpenRouter stream returned an error chunk.";
1592
+ const error = {
1593
+ code: "PROVIDER_REQUEST_FAILED",
1594
+ message,
1595
+ source: "openrouter",
1596
+ details: chunk.error
1597
+ };
1598
+ yield errorEvent(requestId, error);
1599
+ throw new OpenRouterHttpError(500, "PROVIDER_REQUEST_FAILED", message, chunk, false);
1600
+ }
1601
+ if (typeof chunk.model === "string") resolvedModel = chunk.model;
1602
+ const choice = Array.isArray(chunk.choices) && isRecord(chunk.choices[0]) ? chunk.choices[0] : void 0;
1603
+ const delta = choice && isRecord(choice.delta) ? choice.delta : void 0;
1604
+ if (delta && call.extractStreamReasoning) {
1605
+ const reasoningText = call.extractStreamReasoning(delta);
1606
+ if (reasoningText) yield reasoningDeltaEvent(requestId, reasoningText);
1607
+ }
1608
+ if (delta && typeof delta.content === "string" && delta.content.length > 0) {
1609
+ text += delta.content;
1610
+ yield textDeltaEvent(requestId, delta.content);
1611
+ }
1612
+ if (delta && Array.isArray(delta.tool_calls)) {
1613
+ for (const toolCall of delta.tool_calls) {
1614
+ if (!isRecord(toolCall)) continue;
1615
+ const index = typeof toolCall.index === "number" ? toolCall.index : 0;
1616
+ const fn = isRecord(toolCall.function) ? toolCall.function : {};
1617
+ yield toolCallDeltaEvent(requestId, {
1618
+ index,
1619
+ ...typeof toolCall.id === "string" ? { id: toolCall.id } : {},
1620
+ ...typeof fn.name === "string" ? { name: fn.name } : {},
1621
+ ...typeof fn.arguments === "string" ? { argumentsDelta: fn.arguments } : {}
1622
+ });
1623
+ }
1624
+ }
1625
+ if (choice && typeof choice.finish_reason === "string") {
1626
+ finishReason = choice.finish_reason;
1627
+ }
1628
+ if (chunk.usage) {
1629
+ const usage = normalizeUsage(chunk.usage);
1630
+ if (usage) yield usageEvent(requestId, usage);
1631
+ }
1632
+ }
1633
+ } finally {
1634
+ session.cleanup();
1635
+ }
1636
+ await options.hooks?.afterOpenRouterResponse?.({ streamed: true, text, finishReason, model: resolvedModel });
1637
+ yield doneEvent(requestId, {
1638
+ text,
1639
+ model: resolvedModel,
1640
+ ...finishReason ? { finishReason } : {}
1641
+ });
1642
+ options.logger?.info?.("runtime.executeStreamingChat.completed", {
1643
+ requestId,
1644
+ streaming: true,
1645
+ entrypoint: "executeStreamingChat",
1646
+ finishReason,
1647
+ textLength: text.length
1648
+ });
1649
+ } catch (error) {
1650
+ const runtimeError = toRuntimeError(error);
1651
+ yield errorEvent(requestId, runtimeError);
1652
+ options.logger?.error?.("runtime.executeStreamingChat.failed", {
1653
+ requestId,
1654
+ streaming: true,
1655
+ code: runtimeError.code,
1656
+ message: runtimeError.message
1657
+ });
1658
+ throw error instanceof Error ? error : new Error(runtimeError.message);
1659
+ }
1660
+ }
1661
+ function assertStreamingChatRequest(request, defaults) {
1662
+ if (request.apiMode === "responses") {
1663
+ throw new RuntimeConfigError(
1664
+ "STREAMING_CHAT_REQUIRES_CHAT_API",
1665
+ "executeStreamingChat() only supports Chat Completions. Use runtime.run() for Responses API requests."
1666
+ );
1667
+ }
1668
+ if (request.serverTools?.applyPatch?.mode && request.serverTools.applyPatch.mode !== "disabled") {
1669
+ throw new RuntimeConfigError(
1670
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1671
+ "executeStreamingChat() does not support applyPatch. Use runtime.run() instead."
1672
+ );
1673
+ }
1674
+ if (defaults.serverTools?.applyPatch?.mode && defaults.serverTools.applyPatch.mode !== "disabled") {
1675
+ const requestPatch = request.serverTools?.applyPatch;
1676
+ if (!requestPatch || requestPatch.mode !== "disabled") {
1677
+ throw new RuntimeConfigError(
1678
+ "STREAMING_CHAT_DOES_NOT_SUPPORT_APPLY_PATCH",
1679
+ "executeStreamingChat() does not support applyPatch defaults. Use runtime.run() instead."
1680
+ );
1681
+ }
1682
+ }
1683
+ }
1684
+ function startEvent(requestId, model) {
1685
+ return {
1686
+ type: "stream.start",
1687
+ requestId,
1688
+ data: {
1689
+ model,
1690
+ apiMode: "chat",
1691
+ entrypoint: "executeStreamingChat"
1692
+ }
1693
+ };
1694
+ }
1695
+ function textDeltaEvent(requestId, text) {
1696
+ return {
1697
+ type: "stream.text.delta",
1698
+ requestId,
1699
+ data: { text }
1700
+ };
1701
+ }
1702
+ function reasoningDeltaEvent(requestId, text) {
1703
+ return {
1704
+ type: "stream.reasoning.delta",
1705
+ requestId,
1706
+ data: { text }
1707
+ };
1708
+ }
1709
+ function toolCallDeltaEvent(requestId, data) {
1710
+ return {
1711
+ type: "stream.tool_call.delta",
1712
+ requestId,
1713
+ data
1714
+ };
1715
+ }
1716
+ function usageEvent(requestId, usage) {
1717
+ return {
1718
+ type: "stream.usage",
1719
+ requestId,
1720
+ data: { usage }
1721
+ };
1722
+ }
1723
+ function warningEvent(requestId, warning) {
1724
+ return {
1725
+ type: "stream.warning",
1726
+ requestId,
1727
+ data: { warning }
1728
+ };
1729
+ }
1730
+ function errorEvent(requestId, error) {
1731
+ return {
1732
+ type: "stream.error",
1733
+ requestId,
1734
+ data: { error }
1735
+ };
1736
+ }
1737
+ function doneEvent(requestId, data) {
1738
+ return {
1739
+ type: "stream.done",
1740
+ requestId,
1741
+ data
1742
+ };
1743
+ }
1744
+ function toRuntimeError(error) {
1745
+ if (error instanceof RuntimeConfigError) {
1746
+ return {
1747
+ code: error.code,
1748
+ message: error.message,
1749
+ source: "validation",
1750
+ details: error.details
1751
+ };
1752
+ }
1753
+ if (error instanceof OpenRouterHttpError) {
1754
+ return {
1755
+ code: error.code,
1756
+ message: error.message,
1757
+ source: "openrouter",
1758
+ retryable: error.retryable,
1759
+ details: {
1760
+ providerAttempts: error.providerAttempts,
1761
+ ...error.body === void 0 ? {} : { response: error.body }
1762
+ }
1763
+ };
1764
+ }
1765
+ return {
1766
+ code: "RUNTIME_ERROR",
1767
+ message: error instanceof Error ? error.message : String(error),
1768
+ source: "runtime"
1769
+ };
1334
1770
  }
1335
1771
 
1336
1772
  // src/runtime/create-runtime.ts
@@ -1339,7 +1775,14 @@ function createOpenRouterRuntime(options) {
1339
1775
  const defaults = resolveDefaults(options);
1340
1776
  const context = { options: resolvedOptions, defaults };
1341
1777
  return {
1342
- async run(request) {
1778
+ compile(request, call) {
1779
+ return compileRuntimeRequest(request, defaults, resolvedOptions, {
1780
+ streaming: false,
1781
+ ...call?.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
1782
+ ...call?.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
1783
+ });
1784
+ },
1785
+ async run(request, call) {
1343
1786
  const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
1344
1787
  try {
1345
1788
  resolvedOptions.logger?.info?.("runtime.request.started", {
@@ -1348,7 +1791,11 @@ function createOpenRouterRuntime(options) {
1348
1791
  entrypoint: "run"
1349
1792
  });
1350
1793
  await resolvedOptions.hooks?.beforeCompile?.(requestWithId);
1351
- const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, { streaming: false });
1794
+ const compiled = compileRuntimeRequest(requestWithId, defaults, resolvedOptions, {
1795
+ streaming: false,
1796
+ ...call?.finalizeBody ? { finalizeBody: call.finalizeBody } : {},
1797
+ ...call?.suppressNestedReasoningFallback ? { suppressNestedReasoningFallback: true } : {}
1798
+ });
1352
1799
  await resolvedOptions.hooks?.afterCompile?.(compiled);
1353
1800
  resolvedOptions.logger?.debug?.("runtime.request.compiled", {
1354
1801
  requestId: requestWithId.id,
@@ -1370,14 +1817,9 @@ function createOpenRouterRuntime(options) {
1370
1817
  return errorResponse(requestWithId, error);
1371
1818
  }
1372
1819
  },
1373
- executeStreamingChat(request) {
1374
- resolvedOptions.logger?.warn?.("runtime.executeStreamingChat.called", {
1375
- requestId: request.id,
1376
- streaming: true,
1377
- entrypoint: "executeStreamingChat",
1378
- implemented: false
1379
- });
1380
- return executeStreamingChatNotImplemented();
1820
+ executeStreamingChat(request, call) {
1821
+ const requestWithId = { ...request, id: request.id ?? createRuntimeId() };
1822
+ return executeStreamingChat(requestWithId, context, call);
1381
1823
  }
1382
1824
  };
1383
1825
  function errorResponse(request, error) {
@@ -1466,12 +1908,15 @@ function operatorHintFor(code) {
1466
1908
  }
1467
1909
  }
1468
1910
  export {
1911
+ OPENROUTER_METADATA_LIMITS,
1469
1912
  OpenRouterHttpError,
1470
1913
  RuntimeConfigError,
1471
1914
  buildOpenRouterServerTools,
1472
1915
  compileRuntimeRequest,
1473
1916
  createConsoleLogger,
1474
1917
  createOpenRouterRuntime,
1475
- isRuntimeLoggingEnabled
1918
+ decodeProviderMetadata,
1919
+ isRuntimeLoggingEnabled,
1920
+ toProviderMetadata
1476
1921
  };
1477
1922
  //# sourceMappingURL=index.js.map