@standardagents/openrouter 0.44.1 → 0.45.1

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
@@ -28,6 +28,7 @@ function mapOpenRouterReasoningLevels(model, mandatory, supportedEfforts) {
28
28
 
29
29
  // src/responses-transformers.ts
30
30
  import { unrecognized } from "@openrouter/sdk/types";
31
+ import { OpenResponsesInput$outboundSchema, OpenResponsesReasoningConfig$outboundSchema } from "@openrouter/sdk/models";
31
32
 
32
33
  // src/chat-completions-transformers.ts
33
34
  import { mapReasoningLevel } from "@standardagents/spec";
@@ -73,12 +74,10 @@ function toOpenRouterServerTool(name, parameters) {
73
74
  }
74
75
  function splitOpenRouterProviderOptions(providerOptions) {
75
76
  if (!providerOptions) return void 0;
76
- const {
77
- serverTools: _serverTools,
78
- server_tools: _serverToolsSnake,
79
- _metadata,
80
- ...rest
81
- } = providerOptions;
77
+ const rest = { ...providerOptions };
78
+ delete rest.serverTools;
79
+ delete rest.server_tools;
80
+ delete rest._metadata;
82
81
  return Object.keys(rest).length > 0 ? rest : void 0;
83
82
  }
84
83
  function serverToolNameFromUsageKey(key) {
@@ -250,11 +249,10 @@ function transformChatAssistantMessage(msg) {
250
249
  return typeof detail.data === "string" && detail.data.length > 0;
251
250
  }).map((detail) => {
252
251
  const type = detail.type;
253
- const legacy = detail;
254
252
  if (type === "text" || type === "reasoning.text") {
255
253
  return { type: "reasoning.text", text: detail.text, format: detail.format };
256
254
  } else if (type === "summary" || type === "reasoning.summary") {
257
- return { type: "reasoning.summary", summary: detail.text ?? legacy.summary, format: detail.format };
255
+ return { type: "reasoning.summary", summary: detail.text ?? detail.summary, format: detail.format };
258
256
  }
259
257
  return { type: "reasoning.encrypted", data: detail.data, id: detail.id, format: detail.format };
260
258
  });
@@ -682,7 +680,11 @@ function processChatStreamChunk(chunk, state) {
682
680
  chunk.id
683
681
  ));
684
682
  const actualProvider = chunk.provider || chunk.model?.split("/")[0] || void 0;
685
- const reasoningDetails = state.reasoningDetails.length > 0 ? state.reasoningDetails.map(({ _index, ...d }) => d) : void 0;
683
+ const reasoningDetails = state.reasoningDetails.length > 0 ? state.reasoningDetails.map((detail) => {
684
+ const emittedDetail = { ...detail };
685
+ delete emittedDetail._index;
686
+ return emittedDetail;
687
+ }) : void 0;
686
688
  chunks.push({
687
689
  type: "finish",
688
690
  finishReason: mapChatFinishReason(state.finishReason),
@@ -804,7 +806,10 @@ function buildChatParams(request, reasoningLevels = getOpenRouterReasoningLevels
804
806
  );
805
807
  if (safeOptions) {
806
808
  if (request.reasoning?.level !== void 0) {
807
- const { effort, reasoning_effort, reasoningEffort, ...otherOptions } = safeOptions;
809
+ const otherOptions = { ...safeOptions };
810
+ delete otherOptions.effort;
811
+ delete otherOptions.reasoning_effort;
812
+ delete otherOptions.reasoningEffort;
808
813
  Object.assign(params, otherOptions);
809
814
  } else {
810
815
  Object.assign(params, safeOptions);
@@ -870,6 +875,37 @@ function truncateChatBase64(obj, maxLength = 50) {
870
875
  function isRecord3(value) {
871
876
  return !!value && typeof value === "object" && !Array.isArray(value);
872
877
  }
878
+ function readWireString(record, ...keys) {
879
+ for (const key of keys) {
880
+ const value = record[key];
881
+ if (typeof value === "string" && value) return value;
882
+ }
883
+ return void 0;
884
+ }
885
+ function isResponsesEnvelope(value) {
886
+ return isRecord3(value) && typeof value.id === "string" && Array.isArray(value.output) && (value.model === void 0 || typeof value.model === "string");
887
+ }
888
+ function requireResponsesEnvelope(value) {
889
+ if (!isResponsesEnvelope(value)) throw new Error("Invalid OpenRouter Responses payload.");
890
+ return value;
891
+ }
892
+ function actualProviderOf(response) {
893
+ return typeof response.provider === "string" ? response.provider : response.model?.split("/")[0] || void 0;
894
+ }
895
+ function parseFunctionArguments(value) {
896
+ if (typeof value !== "string" || !value) return {};
897
+ try {
898
+ const parsed = JSON.parse(value);
899
+ return isRecord3(parsed) ? parsed : {};
900
+ } catch {
901
+ return {};
902
+ }
903
+ }
904
+ function generatedImageFromData(data, fields = {}) {
905
+ let mediaType = fields.mediaType ?? "image/png";
906
+ if (data.startsWith("data:")) mediaType = data.match(/^data:([^;,]+)/)?.[1] ?? mediaType;
907
+ return { ...fields, data, mediaType };
908
+ }
873
909
  function transformContentPart(part) {
874
910
  if (part.type === "text") {
875
911
  return { type: "input_text", text: part.text };
@@ -879,7 +915,7 @@ function transformContentPart(part) {
879
915
  const imageUrl = data.startsWith("data:") ? data : `data:${part.mediaType || "image/png"};base64,${data}`;
880
916
  return {
881
917
  type: "input_image",
882
- image_url: imageUrl,
918
+ imageUrl,
883
919
  detail: part.detail || "auto"
884
920
  };
885
921
  }
@@ -888,7 +924,7 @@ function transformContentPart(part) {
888
924
  const detail = part.image_url?.detail || "auto";
889
925
  return {
890
926
  type: "input_image",
891
- image_url: url,
927
+ imageUrl: url,
892
928
  detail
893
929
  };
894
930
  }
@@ -910,28 +946,39 @@ function transformUserMessage(msg) {
910
946
  content: typeof content === "string" ? content : content
911
947
  };
912
948
  }
949
+ function storedReasoningDetail(value) {
950
+ if (!isRecord3(value)) return void 0;
951
+ const type = value.type === "reasoning.text" ? "text" : value.type === "reasoning.encrypted" ? "encrypted" : value.type === "summary" || value.type === "text" || value.type === "encrypted" ? value.type : void 0;
952
+ if (!type) return void 0;
953
+ const data = value.type === "reasoning.encrypted" ? value.text : value.data;
954
+ return {
955
+ type,
956
+ id: typeof value.id === "string" ? value.id : void 0,
957
+ text: typeof value.text === "string" ? value.text : void 0,
958
+ data: typeof data === "string" ? data : void 0
959
+ };
960
+ }
913
961
  function transformAssistantMessage(msg) {
914
962
  const items = [];
915
- const reasoningDetails = msg.reasoningDetails;
916
- if (reasoningDetails && reasoningDetails.length > 0) {
917
- const summaryTexts = [];
918
- let encryptedContent;
919
- for (const detail of reasoningDetails) {
920
- if (detail.type === "reasoning.text") {
921
- summaryTexts.push({ type: "summary_text", text: detail.text });
922
- } else if (detail.type === "reasoning.encrypted") {
923
- encryptedContent = detail.text;
924
- }
925
- }
926
- if (summaryTexts.length > 0) {
927
- const reasoningItem = {
928
- type: "reasoning",
929
- id: "",
930
- summary: summaryTexts,
931
- ...encryptedContent ? { encrypted_content: encryptedContent } : {}
932
- };
933
- items.push(reasoningItem);
934
- }
963
+ const reasoningItems = /* @__PURE__ */ new Map();
964
+ const savedDetails = Array.isArray(msg.reasoningDetails) ? msg.reasoningDetails : [];
965
+ for (const saved of savedDetails) {
966
+ const detail = storedReasoningDetail(saved);
967
+ if (!detail) continue;
968
+ const id = detail.id || "";
969
+ let item = reasoningItems.get(id);
970
+ if (!item) {
971
+ item = { type: "reasoning", id, summary: [] };
972
+ reasoningItems.set(id, item);
973
+ }
974
+ if (detail.type === "encrypted" && detail.data) {
975
+ item.encryptedContent = detail.data;
976
+ } else if ((detail.type === "summary" || detail.type === "text") && typeof detail.text === "string") {
977
+ item.summary.push({ type: "summary_text", text: detail.text });
978
+ }
979
+ }
980
+ for (const item of reasoningItems.values()) {
981
+ if (item.summary.length > 0 || item.encryptedContent && item.id) items.push(item);
935
982
  }
936
983
  if (msg.content) {
937
984
  const outputMessage = {
@@ -949,7 +996,7 @@ function transformAssistantMessage(msg) {
949
996
  type: "function_call",
950
997
  id: `fc_${tc.id}`,
951
998
  // Unique output item ID (prefixed to distinguish from call_id)
952
- call_id: tc.id,
999
+ callId: tc.id,
953
1000
  name: tc.name,
954
1001
  arguments: JSON.stringify(tc.arguments),
955
1002
  status: "completed"
@@ -979,7 +1026,7 @@ function transformToolMessage(msg) {
979
1026
  const imageAttachments = Array.isArray(msg.content) ? msg.content.filter((part) => part.type === "image" && Boolean(part.data) || part.type === "image_url") : [];
980
1027
  const toolOutput = {
981
1028
  type: "function_call_output",
982
- call_id: msg.toolCallId,
1029
+ callId: msg.toolCallId,
983
1030
  output: output || (imageAttachments.length > 0 ? "Success" : "")
984
1031
  };
985
1032
  if (imageAttachments.length === 0) {
@@ -1070,19 +1117,21 @@ function transformToolChoice(choice) {
1070
1117
  return "auto";
1071
1118
  }
1072
1119
  function mapFinishReason(response) {
1120
+ const incomplete = response.incompleteDetails ?? response.incomplete_details;
1121
+ const reason = isRecord3(incomplete) ? incomplete.reason : void 0;
1073
1122
  if (response.status === "failed") {
1074
1123
  return "error";
1075
1124
  }
1076
1125
  if (response.status === "incomplete") {
1077
- if (response.incompleteDetails?.reason === "max_output_tokens") {
1126
+ if (reason === "max_output_tokens") {
1078
1127
  return "length";
1079
1128
  }
1080
- if (response.incompleteDetails?.reason === "content_filter") {
1129
+ if (reason === "content_filter") {
1081
1130
  return "content_filter";
1082
1131
  }
1083
1132
  }
1084
- const hasToolCalls = response.output.some(
1085
- (item) => item.type === "function_call"
1133
+ const hasToolCalls = Array.isArray(response.output) && response.output.some(
1134
+ (item) => isRecord3(item) && item.type === "function_call"
1086
1135
  );
1087
1136
  if (hasToolCalls) {
1088
1137
  return "tool_calls";
@@ -1092,9 +1141,9 @@ function mapFinishReason(response) {
1092
1141
  function extractTextContent(output) {
1093
1142
  const textParts = [];
1094
1143
  for (const item of output) {
1095
- if (item.type === "message" && item.role === "assistant") {
1144
+ if (isRecord3(item) && item.type === "message" && item.role === "assistant" && Array.isArray(item.content)) {
1096
1145
  for (const content of item.content) {
1097
- if (content.type === "output_text") {
1146
+ if (isRecord3(content) && content.type === "output_text" && typeof content.text === "string") {
1098
1147
  textParts.push(content.text);
1099
1148
  }
1100
1149
  }
@@ -1105,7 +1154,7 @@ function extractTextContent(output) {
1105
1154
  function extractResponseWebSearchCitations(output) {
1106
1155
  const citations = [];
1107
1156
  for (const item of output) {
1108
- if (item.type !== "message" || !isRecord3(item) || !Array.isArray(item.content)) {
1157
+ if (!isRecord3(item) || item.type !== "message" || !Array.isArray(item.content)) {
1109
1158
  continue;
1110
1159
  }
1111
1160
  for (const content of item.content) {
@@ -1119,16 +1168,11 @@ function extractResponseWebSearchCitations(output) {
1119
1168
  function extractToolCalls(output) {
1120
1169
  const toolCalls = [];
1121
1170
  for (const item of output) {
1122
- if (item.type === "function_call") {
1123
- let parsedArgs = {};
1124
- try {
1125
- parsedArgs = item.arguments ? JSON.parse(item.arguments) : {};
1126
- } catch {
1127
- }
1171
+ if (isRecord3(item) && item.type === "function_call") {
1128
1172
  toolCalls.push({
1129
- id: item.callId,
1130
- name: item.name,
1131
- arguments: parsedArgs
1173
+ id: readWireString(item, "callId", "call_id") ?? "",
1174
+ name: readWireString(item, "name") ?? "",
1175
+ arguments: parseFunctionArguments(item.arguments)
1132
1176
  });
1133
1177
  }
1134
1178
  }
@@ -1137,75 +1181,55 @@ function extractToolCalls(output) {
1137
1181
  function extractImages(output) {
1138
1182
  const images = [];
1139
1183
  for (const item of output) {
1140
- const itemAny = item;
1141
- if (itemAny.type === "image_generation_call" && itemAny.result) {
1142
- const imageData = itemAny.result;
1143
- const isDataUrl = imageData.startsWith("data:");
1144
- const isHttpUrl = imageData.startsWith("http://") || imageData.startsWith("https://");
1145
- let mediaType = "image/png";
1146
- if (isDataUrl) {
1147
- const match = imageData.match(/^data:([^;,]+)/);
1148
- if (match) {
1149
- mediaType = match[1];
1150
- }
1151
- }
1152
- images.push({
1153
- id: itemAny.id || void 0,
1154
- data: imageData,
1155
- mediaType,
1156
- // Include revised prompt if available
1157
- revisedPrompt: itemAny.revised_prompt || itemAny.revisedPrompt || void 0
1158
- });
1159
- }
1160
- if (itemAny.type === "message" && itemAny.content && Array.isArray(itemAny.content)) {
1161
- for (const content of itemAny.content) {
1162
- if (content.type === "output_image" || content.type === "image") {
1163
- const imageData = content.image || content.data || content.url || content.image_url;
1164
- if (imageData) {
1165
- let mediaType = content.media_type || content.mediaType || "image/png";
1166
- if (typeof imageData === "string" && imageData.startsWith("data:")) {
1167
- const match = imageData.match(/^data:([^;,]+)/);
1168
- if (match) {
1169
- mediaType = match[1];
1170
- }
1171
- }
1172
- images.push({
1173
- id: content.id || void 0,
1174
- data: imageData,
1175
- mediaType
1176
- });
1177
- }
1178
- }
1184
+ if (!isRecord3(item)) continue;
1185
+ if (item.type === "image_generation_call") {
1186
+ const data = readWireString(item, "result");
1187
+ if (data) images.push(generatedImageFromData(data, {
1188
+ id: readWireString(item, "id"),
1189
+ revisedPrompt: readWireString(item, "revised_prompt", "revisedPrompt")
1190
+ }));
1191
+ }
1192
+ if (item.type === "message" && Array.isArray(item.content)) {
1193
+ for (const content of item.content) {
1194
+ if (!isRecord3(content) || content.type !== "output_image" && content.type !== "image") continue;
1195
+ const data = readWireString(content, "image", "data", "url", "image_url");
1196
+ if (data) images.push(generatedImageFromData(data, {
1197
+ id: readWireString(content, "id"),
1198
+ mediaType: readWireString(content, "media_type", "mediaType")
1199
+ }));
1179
1200
  }
1180
1201
  }
1181
1202
  }
1182
1203
  return images.length > 0 ? images : void 0;
1183
1204
  }
1205
+ function numberField(record, key) {
1206
+ const value = record[key];
1207
+ return typeof value === "number" ? value : void 0;
1208
+ }
1209
+ function nestedNumber(record, field, key) {
1210
+ const nested = record[field];
1211
+ return isRecord3(nested) ? numberField(nested, key) : void 0;
1212
+ }
1184
1213
  function transformUsage(usage, actualProvider) {
1185
- if (!usage) {
1186
- return {
1187
- promptTokens: 0,
1188
- completionTokens: 0,
1189
- totalTokens: 0
1190
- };
1191
- }
1192
- const inputTokens = usage.native_tokens_prompt || usage.nativeTokensPrompt || usage.input_tokens || usage.inputTokens || 0;
1193
- const outputTokens = usage.native_tokens_completion || usage.nativeTokensCompletion || usage.output_tokens || usage.outputTokens || 0;
1194
- const totalTokens = usage.total_tokens || usage.totalTokens || 0;
1195
- const reasoningTokens = usage.output_tokens_details?.reasoning_tokens || usage.outputTokensDetails?.reasoningTokens;
1196
- const cachedTokens = usage.input_tokens_details?.cached_tokens || usage.inputTokensDetails?.cachedTokens;
1214
+ if (!isRecord3(usage)) return { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
1215
+ const inputTokens = numberField(usage, "native_tokens_prompt") || numberField(usage, "nativeTokensPrompt") || numberField(usage, "input_tokens") || numberField(usage, "inputTokens") || 0;
1216
+ const outputTokens = numberField(usage, "native_tokens_completion") || numberField(usage, "nativeTokensCompletion") || numberField(usage, "output_tokens") || numberField(usage, "outputTokens") || 0;
1217
+ const totalTokens = numberField(usage, "total_tokens") || numberField(usage, "totalTokens") || 0;
1197
1218
  return {
1198
1219
  promptTokens: inputTokens,
1199
1220
  completionTokens: outputTokens,
1200
1221
  totalTokens: totalTokens || inputTokens + outputTokens,
1201
- reasoningTokens,
1202
- cachedTokens,
1203
- cost: usage.cost,
1222
+ reasoningTokens: nestedNumber(usage, "output_tokens_details", "reasoning_tokens") || nestedNumber(usage, "outputTokensDetails", "reasoningTokens"),
1223
+ cachedTokens: nestedNumber(usage, "input_tokens_details", "cached_tokens") || nestedNumber(usage, "inputTokensDetails", "cachedTokens"),
1224
+ cost: numberField(usage, "cost"),
1204
1225
  provider: actualProvider
1205
1226
  };
1206
1227
  }
1207
- function transformResponse(response) {
1228
+ function transformResponse(value) {
1229
+ const response = requireResponsesEnvelope(value);
1208
1230
  const content = extractTextContent(response.output);
1231
+ const reasoningDetails = extractReasoningDetails(response.output, "");
1232
+ const reasoning = reasoningDetails?.flatMap((detail) => detail.type !== "encrypted" && detail.text !== void 0 ? [detail.text] : []).join("\n") || void 0;
1209
1233
  const toolCalls = extractToolCalls(response.output);
1210
1234
  const images = extractImages(response.output);
1211
1235
  const webSearchCitations = extractResponseWebSearchCitations(response.output);
@@ -1214,9 +1238,11 @@ function transformResponse(response) {
1214
1238
  webSearchCitations,
1215
1239
  response.id
1216
1240
  );
1217
- const actualProvider = typeof response.provider === "string" ? response.provider : response.model?.split("/")[0] || void 0;
1241
+ const actualProvider = actualProviderOf(response);
1218
1242
  return {
1219
1243
  content,
1244
+ reasoning,
1245
+ reasoningDetails,
1220
1246
  toolCalls,
1221
1247
  images,
1222
1248
  providerTools,
@@ -1232,43 +1258,41 @@ function transformResponse(response) {
1232
1258
  }
1233
1259
  function extractReasoningDetails(output, streamedReasoningContent) {
1234
1260
  const details = [];
1235
- if (output && Array.isArray(output)) {
1236
- for (const item of output) {
1237
- const itemAny = item;
1238
- if (itemAny.type === "reasoning") {
1239
- if (itemAny.summary && Array.isArray(itemAny.summary)) {
1240
- for (const step of itemAny.summary) {
1241
- if (typeof step === "string") {
1242
- details.push({ type: "reasoning.text", text: step });
1243
- }
1261
+ if (Array.isArray(output)) {
1262
+ for (const value of output) {
1263
+ if (!isRecord3(value)) continue;
1264
+ const id = typeof value.id === "string" ? value.id : void 0;
1265
+ if (value.type === "reasoning") {
1266
+ if (Array.isArray(value.summary)) {
1267
+ for (const step of value.summary) {
1268
+ const text = typeof step === "string" ? step : isRecord3(step) ? step.text : void 0;
1269
+ if (typeof text === "string") details.push({ type: "summary", id, text });
1244
1270
  }
1245
1271
  }
1246
- if (details.length === 0 && itemAny.encrypted_content) {
1247
- details.push({ type: "reasoning.encrypted", text: itemAny.encrypted_content });
1272
+ const encrypted = value.encrypted_content ?? value.encryptedContent;
1273
+ if (typeof encrypted === "string" && encrypted) {
1274
+ details.push({ type: "encrypted", id, data: encrypted });
1248
1275
  }
1249
- if (itemAny.content) {
1250
- if (typeof itemAny.content === "string") {
1251
- details.push({ type: "reasoning.text", text: itemAny.content });
1252
- } else if (Array.isArray(itemAny.content)) {
1253
- for (const part of itemAny.content) {
1254
- if (part.text) {
1255
- details.push({ type: "reasoning.text", text: part.text });
1256
- }
1276
+ if (typeof value.content === "string") {
1277
+ details.push({ type: "text", id, text: value.content });
1278
+ } else if (Array.isArray(value.content)) {
1279
+ for (const part of value.content) {
1280
+ if (isRecord3(part) && typeof part.text === "string") {
1281
+ details.push({ type: "text", id, text: part.text });
1257
1282
  }
1258
1283
  }
1259
1284
  }
1260
- }
1261
- if (itemAny.type === "message" && itemAny.content && Array.isArray(itemAny.content)) {
1262
- for (const part of itemAny.content) {
1263
- if (part.type === "reasoning" || part.type === "reasoning_text") {
1264
- details.push({ type: "reasoning.text", text: part.text || "" });
1285
+ } else if (value.type === "message" && Array.isArray(value.content)) {
1286
+ for (const part of value.content) {
1287
+ if (isRecord3(part) && (part.type === "reasoning" || part.type === "reasoning_text")) {
1288
+ details.push({ type: "text", text: typeof part.text === "string" ? part.text : "" });
1265
1289
  }
1266
1290
  }
1267
1291
  }
1268
1292
  }
1269
1293
  }
1270
1294
  if (details.length === 0 && streamedReasoningContent) {
1271
- details.push({ type: "reasoning.text", text: streamedReasoningContent });
1295
+ details.push({ type: "text", text: streamedReasoningContent });
1272
1296
  }
1273
1297
  return details.length > 0 ? details : void 0;
1274
1298
  }
@@ -1327,7 +1351,10 @@ function buildCreateParams(request, reasoningLevels = getOpenRouterReasoningLeve
1327
1351
  );
1328
1352
  if (providerOptions) {
1329
1353
  if (request.reasoning?.level !== void 0) {
1330
- const { effort, reasoning_effort, reasoningEffort, ...otherOptions } = providerOptions;
1354
+ const otherOptions = { ...providerOptions };
1355
+ delete otherOptions.effort;
1356
+ delete otherOptions.reasoning_effort;
1357
+ delete otherOptions.reasoningEffort;
1331
1358
  Object.assign(params, otherOptions);
1332
1359
  } else {
1333
1360
  Object.assign(params, providerOptions);
@@ -1350,264 +1377,165 @@ function buildCreateParams(request, reasoningLevels = getOpenRouterReasoningLeve
1350
1377
  }
1351
1378
  return params;
1352
1379
  }
1380
+ function serializeResponsesRequest(params, providerOptions) {
1381
+ const { input, toolChoice, parallelToolCalls, maxOutputTokens, topP, reasoning, ...rest } = params;
1382
+ let reasoningWire = reasoning;
1383
+ if (isRecord3(reasoning)) {
1384
+ const parsed = OpenResponsesReasoningConfig$outboundSchema.safeParse(reasoning);
1385
+ if (parsed.success) {
1386
+ const { effort: _effort, maxTokens: _maxTokens, ...reasoningOptions } = reasoning;
1387
+ reasoningWire = { ...parsed.data, ...reasoningOptions };
1388
+ }
1389
+ }
1390
+ return {
1391
+ input: providerOptions && Object.prototype.propertyIsEnumerable.call(providerOptions, "input") ? providerOptions.input : input === void 0 ? void 0 : OpenResponsesInput$outboundSchema.parse(input),
1392
+ tool_choice: toolChoice,
1393
+ parallel_tool_calls: parallelToolCalls,
1394
+ max_output_tokens: maxOutputTokens,
1395
+ top_p: topP,
1396
+ reasoning: reasoningWire,
1397
+ // Preserve opaque provider options, including explicit wire-field overrides.
1398
+ ...rest
1399
+ };
1400
+ }
1353
1401
  function createStreamState() {
1354
1402
  return {
1355
1403
  toolCalls: /* @__PURE__ */ new Map(),
1356
1404
  reasoningContent: "",
1357
1405
  hasContent: false,
1358
1406
  hasReasoning: false,
1359
- currentItemId: null,
1360
1407
  imageGenerations: /* @__PURE__ */ new Map()
1361
1408
  };
1362
1409
  }
1363
1410
  function processStreamEvent(event, state) {
1364
1411
  const chunks = [];
1412
+ if (!isRecord3(event)) return chunks;
1365
1413
  switch (event.type) {
1366
- // Text content streaming
1367
1414
  case "response.output_text.delta":
1415
+ if (typeof event.delta !== "string") break;
1368
1416
  state.hasContent = true;
1369
1417
  chunks.push({ type: "content-delta", delta: event.delta });
1370
1418
  break;
1371
1419
  case "response.output_text.done":
1420
+ case "response.reasoning_text.done":
1372
1421
  break;
1373
- // Reasoning streaming - OpenRouter uses 'response.reasoning.delta'
1374
- // Note: SDK types may not include reasoning events, so we check dynamically
1375
1422
  case "response.reasoning_text.delta":
1423
+ case "response.reasoning.delta": {
1424
+ const delta = readWireString(event, "delta") ?? "";
1376
1425
  state.hasReasoning = true;
1377
- state.reasoningContent += event.delta;
1378
- chunks.push({ type: "reasoning-delta", delta: event.delta });
1379
- break;
1380
- case "response.reasoning_text.done":
1426
+ state.reasoningContent += delta;
1427
+ chunks.push({ type: "reasoning-delta", delta });
1381
1428
  break;
1382
- // Function call and image generation streaming
1383
- case "response.output_item.added":
1384
- if (event.item.type === "function_call") {
1385
- const callId = event.item.callId || event.item.call_id || "";
1386
- const name = event.item.name || "";
1387
- state.toolCalls.set(callId, {
1388
- id: callId,
1389
- name,
1390
- arguments: ""
1391
- });
1392
- chunks.push({
1393
- type: "tool-call-start",
1394
- id: callId,
1395
- name
1396
- });
1429
+ }
1430
+ case "response.output_item.added": {
1431
+ const item = event.item;
1432
+ if (!isRecord3(item)) break;
1433
+ if (item.type === "function_call") {
1434
+ const callId = readWireString(item, "callId", "call_id") ?? "";
1435
+ const name = readWireString(item, "name") ?? "";
1436
+ state.toolCalls.set(callId, { id: callId, name, arguments: "" });
1437
+ chunks.push({ type: "tool-call-start", id: callId, name });
1397
1438
  }
1398
- if (event.item.type === "image_generation_call") {
1399
- const itemAny = event.item;
1400
- const imageId = itemAny.id || itemAny.call_id || itemAny.callId || `img-${state.imageGenerations.size}`;
1401
- state.imageGenerations.set(imageId, {
1402
- id: imageId,
1403
- data: "",
1404
- status: "in_progress"
1405
- });
1439
+ if (item.type === "image_generation_call") {
1440
+ const id = readWireString(item, "id", "call_id", "callId") ?? `img-${state.imageGenerations.size}`;
1441
+ state.imageGenerations.set(id, { id, data: "", status: "in_progress" });
1406
1442
  }
1407
1443
  break;
1444
+ }
1408
1445
  case "response.output_item.done": {
1409
- const itemAny = event.item;
1410
- if (itemAny.type === "image_generation_call" && itemAny.result) {
1411
- const imageId = itemAny.id || itemAny.call_id || itemAny.callId || "";
1412
- const imageData = itemAny.result;
1413
- let mediaType = "image/png";
1414
- if (imageData.startsWith("data:")) {
1415
- const match = imageData.match(/^data:([^;,]+)/);
1416
- if (match) mediaType = match[1];
1417
- }
1418
- const existing = state.imageGenerations.get(imageId);
1419
- if (existing) {
1420
- existing.data = imageData;
1421
- existing.status = "completed";
1422
- }
1423
- const imageIndex = Array.from(state.imageGenerations.keys()).indexOf(imageId);
1424
- chunks.push({
1425
- type: "image-done",
1426
- index: imageIndex >= 0 ? imageIndex : state.imageGenerations.size - 1,
1427
- image: {
1428
- id: imageId || void 0,
1429
- data: imageData,
1430
- mediaType,
1431
- revisedPrompt: itemAny.revised_prompt || itemAny.revisedPrompt || void 0
1432
- }
1433
- });
1446
+ const item = event.item;
1447
+ if (!isRecord3(item) || item.type !== "image_generation_call") break;
1448
+ const data = readWireString(item, "result");
1449
+ if (!data) break;
1450
+ const id = readWireString(item, "id", "call_id", "callId") ?? "";
1451
+ const existing = state.imageGenerations.get(id);
1452
+ if (existing) {
1453
+ existing.data = data;
1454
+ existing.status = "completed";
1434
1455
  }
1456
+ const index = Array.from(state.imageGenerations.keys()).indexOf(id);
1457
+ chunks.push({
1458
+ type: "image-done",
1459
+ index: index >= 0 ? index : state.imageGenerations.size - 1,
1460
+ image: generatedImageFromData(data, { id: id || void 0, revisedPrompt: readWireString(item, "revised_prompt", "revisedPrompt") })
1461
+ });
1435
1462
  break;
1436
1463
  }
1437
1464
  case "response.function_call_arguments.delta": {
1438
- const itemId = event.itemId || event.item_id || "";
1439
- const deltaToolCall = Array.from(state.toolCalls.values()).find(
1440
- (tc) => tc.id === itemId
1441
- );
1442
- if (deltaToolCall) {
1443
- deltaToolCall.arguments += event.delta;
1444
- chunks.push({
1445
- type: "tool-call-delta",
1446
- id: deltaToolCall.id,
1447
- argumentsDelta: event.delta
1448
- });
1465
+ const itemId = readWireString(event, "itemId", "item_id") ?? "";
1466
+ const call = Array.from(state.toolCalls.values()).find((tool) => tool.id === itemId);
1467
+ if (call && typeof event.delta === "string") {
1468
+ call.arguments += event.delta;
1469
+ chunks.push({ type: "tool-call-delta", id: call.id, argumentsDelta: event.delta });
1449
1470
  }
1450
1471
  break;
1451
1472
  }
1452
1473
  case "response.function_call_arguments.done": {
1453
- const itemId = event.itemId || event.item_id || "";
1454
- const doneToolCall = Array.from(state.toolCalls.values()).find(
1455
- (tc) => tc.id === itemId
1456
- );
1457
- if (doneToolCall) {
1458
- let parsedArgs = {};
1459
- try {
1460
- parsedArgs = doneToolCall.arguments ? JSON.parse(doneToolCall.arguments) : {};
1461
- } catch {
1462
- }
1463
- chunks.push({
1464
- type: "tool-call-done",
1465
- id: doneToolCall.id,
1466
- arguments: parsedArgs
1467
- });
1468
- }
1474
+ const itemId = readWireString(event, "itemId", "item_id") ?? "";
1475
+ const call = Array.from(state.toolCalls.values()).find((tool) => tool.id === itemId);
1476
+ if (call) chunks.push({ type: "tool-call-done", id: call.id, arguments: parseFunctionArguments(call.arguments) });
1469
1477
  break;
1470
1478
  }
1471
- // Response completion
1472
- case "response.completed": {
1473
- if (state.hasContent) {
1474
- chunks.push({ type: "content-done" });
1475
- }
1476
- if (state.hasReasoning) {
1477
- chunks.push({ type: "reasoning-done" });
1478
- }
1479
- const completedProvider = typeof event.response.provider === "string" ? event.response.provider : event.response.model?.split("/")[0] || void 0;
1480
- const reasoningDetails = extractReasoningDetails(event.response.output, state.reasoningContent);
1481
- const generatedImages = extractImages(event.response.output);
1482
- if (generatedImages && generatedImages.length > 0) {
1483
- for (let i = 0; i < generatedImages.length; i++) {
1484
- const img = generatedImages[i];
1485
- const alreadyEmitted = img.id && state.imageGenerations.get(img.id)?.status === "completed";
1486
- if (!alreadyEmitted) {
1487
- chunks.push({
1488
- type: "image-done",
1489
- index: i,
1490
- image: img
1491
- });
1479
+ case "response.completed":
1480
+ case "response.incomplete": {
1481
+ const response = requireResponsesEnvelope(event.response);
1482
+ if (state.hasContent) chunks.push({ type: "content-done" });
1483
+ if (state.hasReasoning) chunks.push({ type: "reasoning-done" });
1484
+ const images = extractImages(response.output);
1485
+ if (images) {
1486
+ for (const [index, image] of images.entries()) {
1487
+ if (!image.id || state.imageGenerations.get(image.id)?.status !== "completed") {
1488
+ chunks.push({ type: "image-done", index, image });
1492
1489
  }
1493
1490
  }
1494
1491
  }
1495
1492
  chunks.push(...providerToolDoneChunksFromServerToolUseOrCitations(
1496
- event.response.usage,
1497
- extractResponseWebSearchCitations(event.response.output),
1498
- event.response.id
1493
+ response.usage,
1494
+ extractResponseWebSearchCitations(response.output),
1495
+ response.id
1499
1496
  ));
1500
- chunks.push({
1497
+ const finish = {
1501
1498
  type: "finish",
1502
- finishReason: mapFinishReason(event.response),
1503
- usage: transformUsage(event.response.usage, completedProvider),
1504
- responseId: event.response.id,
1505
- // Used to fetch generation metadata after stream
1506
- reasoningDetails
1507
- });
1499
+ finishReason: mapFinishReason(response),
1500
+ usage: transformUsage(response.usage, actualProviderOf(response)),
1501
+ responseId: response.id,
1502
+ reasoningDetails: extractReasoningDetails(response.output, state.reasoningContent)
1503
+ };
1504
+ chunks.push(finish);
1508
1505
  break;
1509
1506
  }
1510
- case "response.failed":
1511
- chunks.push({
1512
- type: "error",
1513
- error: event.response.error?.message || "Response generation failed",
1514
- code: event.response.error?.code
1515
- });
1516
- break;
1517
- case "response.incomplete": {
1518
- if (state.hasContent) {
1519
- chunks.push({ type: "content-done" });
1520
- }
1521
- if (state.hasReasoning) {
1522
- chunks.push({ type: "reasoning-done" });
1523
- }
1524
- const incompleteProvider = typeof event.response.provider === "string" ? event.response.provider : event.response.model?.split("/")[0] || void 0;
1525
- const incompleteReasoningDetails = extractReasoningDetails(event.response.output, state.reasoningContent);
1526
- const incompleteImages = extractImages(event.response.output);
1527
- if (incompleteImages && incompleteImages.length > 0) {
1528
- for (let i = 0; i < incompleteImages.length; i++) {
1529
- const img = incompleteImages[i];
1530
- const alreadyEmitted = img.id && state.imageGenerations.get(img.id)?.status === "completed";
1531
- if (!alreadyEmitted) {
1532
- chunks.push({
1533
- type: "image-done",
1534
- index: i,
1535
- image: img
1536
- });
1537
- }
1538
- }
1539
- }
1540
- chunks.push(...providerToolDoneChunksFromServerToolUseOrCitations(
1541
- event.response.usage,
1542
- extractResponseWebSearchCitations(event.response.output),
1543
- event.response.id
1544
- ));
1545
- chunks.push({
1546
- type: "finish",
1547
- finishReason: mapFinishReason(event.response),
1548
- usage: transformUsage(event.response.usage, incompleteProvider),
1549
- responseId: event.response.id,
1550
- // Used to fetch generation metadata after stream
1551
- reasoningDetails: incompleteReasoningDetails
1552
- });
1507
+ case "response.failed": {
1508
+ const response = isRecord3(event.response) ? event.response : {};
1509
+ const error = isRecord3(response.error) ? response.error : {};
1510
+ chunks.push({ type: "error", error: readWireString(error, "message") ?? "Response generation failed", code: readWireString(error, "code") });
1553
1511
  break;
1554
1512
  }
1555
- // Handle reasoning and image events dynamically (SDK types may not include them)
1556
1513
  default: {
1557
- const eventType = event.type;
1558
- const eventAny = event;
1559
- if (eventType === "response.reasoning.delta") {
1560
- state.hasReasoning = true;
1561
- state.reasoningContent += eventAny.delta || "";
1562
- chunks.push({ type: "reasoning-delta", delta: eventAny.delta || "" });
1514
+ if (event.type === "response.image_generation_call.partial_image" || event.type === "response.image_generation.partial") {
1515
+ const id = readWireString(event, "item_id", "itemId", "id") ?? "";
1516
+ const data = readWireString(event, "partial_image_b64", "partial_image", "delta", "data") ?? "";
1517
+ const existing = state.imageGenerations.get(id);
1518
+ if (existing) existing.data += data;
1519
+ else state.imageGenerations.set(id, { id, data, status: "generating" });
1520
+ const index = Array.from(state.imageGenerations.keys()).indexOf(id);
1521
+ chunks.push({ type: "image-delta", index: index >= 0 ? index : state.imageGenerations.size - 1, data });
1563
1522
  }
1564
- if (eventType === "response.image_generation_call.partial_image" || eventType === "response.image_generation.partial") {
1565
- const imageId = eventAny.item_id || eventAny.itemId || eventAny.id || "";
1566
- const partialData = eventAny.partial_image || eventAny.delta || eventAny.data || "";
1567
- const existing = state.imageGenerations.get(imageId);
1523
+ if (event.type === "response.image_generation_call.completed" || event.type === "response.image_generation.done") {
1524
+ const id = readWireString(event, "item_id", "itemId", "id") ?? "";
1525
+ const data = readWireString(event, "result", "image", "data");
1526
+ if (!data) break;
1527
+ const existing = state.imageGenerations.get(id);
1568
1528
  if (existing) {
1569
- existing.data += partialData;
1570
- } else {
1571
- state.imageGenerations.set(imageId, {
1572
- id: imageId,
1573
- data: partialData,
1574
- status: "generating"
1575
- });
1529
+ existing.data = data;
1530
+ existing.status = "completed";
1576
1531
  }
1577
- const imageIndex = Array.from(state.imageGenerations.keys()).indexOf(imageId);
1532
+ const index = Array.from(state.imageGenerations.keys()).indexOf(id);
1578
1533
  chunks.push({
1579
- type: "image-delta",
1580
- index: imageIndex >= 0 ? imageIndex : state.imageGenerations.size - 1,
1581
- data: partialData
1534
+ type: "image-done",
1535
+ index: index >= 0 ? index : state.imageGenerations.size - 1,
1536
+ image: generatedImageFromData(data, { id: id || void 0, revisedPrompt: readWireString(event, "revised_prompt", "revisedPrompt") })
1582
1537
  });
1583
1538
  }
1584
- if (eventType === "response.image_generation_call.completed" || eventType === "response.image_generation.done") {
1585
- const imageId = eventAny.item_id || eventAny.itemId || eventAny.id || "";
1586
- const imageData = eventAny.result || eventAny.image || eventAny.data || "";
1587
- if (imageData) {
1588
- let mediaType = "image/png";
1589
- if (imageData.startsWith("data:")) {
1590
- const match = imageData.match(/^data:([^;,]+)/);
1591
- if (match) mediaType = match[1];
1592
- }
1593
- const existing = state.imageGenerations.get(imageId);
1594
- if (existing) {
1595
- existing.data = imageData;
1596
- existing.status = "completed";
1597
- }
1598
- const imageIndex = Array.from(state.imageGenerations.keys()).indexOf(imageId);
1599
- chunks.push({
1600
- type: "image-done",
1601
- index: imageIndex >= 0 ? imageIndex : state.imageGenerations.size - 1,
1602
- image: {
1603
- id: imageId || void 0,
1604
- data: imageData,
1605
- mediaType,
1606
- revisedPrompt: eventAny.revised_prompt || eventAny.revisedPrompt || void 0
1607
- }
1608
- });
1609
- }
1610
- }
1611
1539
  break;
1612
1540
  }
1613
1541
  }
@@ -1654,7 +1582,7 @@ function truncateBase64(obj, maxLength = 50) {
1654
1582
  function parseRawStreamEvent(jsonStr) {
1655
1583
  try {
1656
1584
  const event = JSON.parse(jsonStr);
1657
- return event;
1585
+ return isRecord3(event) && typeof event.type === "string" ? event : null;
1658
1586
  } catch {
1659
1587
  return null;
1660
1588
  }
@@ -1780,7 +1708,7 @@ var moonshotai_default = 'data:image/svg+xml,<svg fill="currentColor" fill-rule=
1780
1708
  var nvidia_default = 'data:image/svg+xml,<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M10.212 8.976V7.62c.127-.01.256-.017.388-.021 3.596-.117 5.957 3.184 5.957 3.184s-2.548 3.647-5.282 3.647a3.227 3.227 0 01-1.063-.175v-4.109c1.4.174 1.681.812 2.523 2.258l1.873-1.627a4.905 4.905 0 00-3.67-1.846 6.594 6.594 0 00-.729.044m0-4.476v2.025c.13-.01.259-.019.388-.024 5.002-.174 8.261 4.226 8.261 4.226s-3.743 4.69-7.643 4.69c-.338 0-.675-.031-1.007-.092v1.25c.278.038.558.057.838.057 3.629 0 6.253-1.91 8.794-4.169.421.347 2.146 1.193 2.501 1.564-2.416 2.083-8.048 3.763-11.24 3.763-.308 0-.603-.02-.894-.048V19.5H24v-15H10.21zm0 9.756v1.068c-3.356-.616-4.287-4.21-4.287-4.21a7.173 7.173 0 014.287-2.138v1.172h-.005a3.182 3.182 0 00-2.502 1.178s.615 2.276 2.507 2.931m-5.961-3.3c1.436-1.935 3.604-3.148 5.961-3.336V6.523C5.81 6.887 2 10.723 2 10.723s2.158 6.427 8.21 7.015v-1.166C5.77 16 4.25 10.958 4.25 10.958h-.002z" fill="%2374B71B" fill-rule="nonzero"/></svg>%0A';
1781
1709
 
1782
1710
  // src/vendor-icons/openai.svg
1783
- var openai_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" fill="none" viewBox="0 0 128 128"><g clip-path="url(%23clip0_2138_504)"><g clip-path="url(%23clip1_2138_504)"><path fill="%23000" d="M118.824 52.388a31.9 31.9 0 0 0-2.74-26.192 32.25 32.25 0 0 0-34.736-15.472A31.9 31.9 0 0 0 57.296 0C43.28-.032 30.844 8.992 26.532 22.328A31.9 31.9 0 0 0 5.208 37.796C-1.828 49.924-.224 65.212 9.176 75.612a31.9 31.9 0 0 0 2.74 26.192 32.25 32.25 0 0 0 34.736 15.472 31.88 31.88 0 0 0 24.052 10.72c14.024.036 26.464-8.996 30.776-22.344a31.9 31.9 0 0 0 21.324-15.468 32.26 32.26 0 0 0-3.976-37.804zm-48.112 67.244a23.9 23.9 0 0 1-15.356-5.552c.196-.104.536-.292.756-.428L81.6 98.932a4.14 4.14 0 0 0 2.096-3.628V59.372l10.772 6.22a.38.38 0 0 1 .208.296v29.756c-.016 13.232-10.732 23.96-23.964 23.988M19.176 97.62a23.88 23.88 0 0 1-2.86-16.072c.188.112.52.316.756.452L42.56 96.72a4.15 4.15 0 0 0 4.188 0l31.116-17.968v12.44a.4.4 0 0 1-.152.332L51.948 106.4c-11.476 6.608-26.132 2.68-32.768-8.78zm-6.708-55.636a23.9 23.9 0 0 1 12.484-10.516c0 .22-.012.608-.012.88v29.444a4.15 4.15 0 0 0 2.092 3.624L58.148 83.38 47.376 89.6a.38.38 0 0 1-.364.032L21.244 74.744c-11.452-6.632-15.38-21.284-8.78-32.756zm88.504 20.596L69.856 44.612l10.772-6.216a.38.38 0 0 1 .364-.032L106.76 53.24c11.472 6.628 15.404 21.304 8.776 32.776a23.98 23.98 0 0 1-12.48 10.512V66.204a4.14 4.14 0 0 0-2.08-3.624zm10.72-16.136c-.188-.116-.52-.316-.756-.452l-25.488-14.72a4.15 4.15 0 0 0-4.188 0L50.144 49.24V36.8a.4.4 0 0 1 .152-.332L76.06 21.604c11.476-6.62 26.148-2.68 32.764 8.8a23.98 23.98 0 0 1 2.86 16.04zM44.288 68.616l-10.776-6.22a.38.38 0 0 1-.208-.296V32.344C33.312 19.096 44.06 8.36 57.308 8.368a23.98 23.98 0 0 1 15.336 5.552c-.196.104-.532.292-.756.428L46.4 29.068a4.14 4.14 0 0 0-2.096 3.624l-.016 35.916zM50.14 56 64 47.996l13.86 8V72L64 80l-13.86-8z"/></g></g><defs><clipPath id="clip0_2138_504"><path fill="%23fff" d="M0 0h128v128H0z"/></clipPath><clipPath id="clip1_2138_504"><path fill="%23fff" d="M0 0h128v128H0z"/></clipPath></defs></svg>';
1711
+ var openai_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" fill="none" viewBox="0 0 128 128"><rect width="128" height="128" rx="28" fill="%23000"/><path fill="%23fff" transform="translate(18 18) scale(0.71875)" d="M118.824 52.388a31.9 31.9 0 0 0-2.74-26.192 32.25 32.25 0 0 0-34.736-15.472A31.9 31.9 0 0 0 57.296 0C43.28-.032 30.844 8.992 26.532 22.328A31.9 31.9 0 0 0 5.208 37.796C-1.828 49.924-.224 65.212 9.176 75.612a31.9 31.9 0 0 0 2.74 26.192 32.25 32.25 0 0 0 34.736 15.472 31.88 31.88 0 0 0 24.052 10.72c14.024.036 26.464-8.996 30.776-22.344a31.9 31.9 0 0 0 21.324-15.468 32.26 32.26 0 0 0-3.976-37.804zm-48.112 67.244a23.9 23.9 0 0 1-15.356-5.552c.196-.104.536-.292.756-.428L81.6 98.932a4.14 4.14 0 0 0 2.096-3.628V59.372l10.772 6.22a.38.38 0 0 1 .208.296v29.756c-.016 13.232-10.732 23.96-23.964 23.988M19.176 97.62a23.88 23.88 0 0 1-2.86-16.072c.188.112.52.316.756.452L42.56 96.72a4.15 4.15 0 0 0 4.188 0l31.116-17.968v12.44a.4.4 0 0 1-.152.332L51.948 106.4c-11.476 6.608-26.132 2.68-32.768-8.78zm-6.708-55.636a23.9 23.9 0 0 1 12.484-10.516c0 .22-.012.608-.012.88v29.444a4.15 4.15 0 0 0 2.092 3.624L58.148 83.38 47.376 89.6a.38.38 0 0 1-.364.032L21.244 74.744c-11.452-6.632-15.38-21.284-8.78-32.756zm88.504 20.596L69.856 44.612l10.772-6.216a.38.38 0 0 1 .364-.032L106.76 53.24c11.472 6.628 15.404 21.304 8.776 32.776a23.98 23.98 0 0 1-12.48 10.512V66.204a4.14 4.14 0 0 0-2.08-3.624zm10.72-16.136c-.188-.116-.52-.316-.756-.452l-25.488-14.72a4.15 4.15 0 0 0-4.188 0L50.144 49.24V36.8a.4.4 0 0 1 .152-.332L76.06 21.604c11.476-6.62 26.148-2.68 32.764 8.8a23.98 23.98 0 0 1 2.86 16.04zM44.288 68.616l-10.776-6.22a.38.38 0 0 1-.208-.296V32.344C33.312 19.096 44.06 8.36 57.308 8.368a23.98 23.98 0 0 1 15.336 5.552c-.196.104-.532.292-.756.428L46.4 29.068a4.14 4.14 0 0 0-2.096 3.624l-.016 35.916zM50.14 56 64 47.996l13.86 8V72L64 80l-13.86-8z"/></svg>%0A';
1784
1712
 
1785
1713
  // src/vendor-icons/qwen.svg
1786
1714
  var qwen_default = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24"><title>Qwen</title><defs><linearGradient id="lobe-icons-qwen-fill" x1="0%" x2="100%" y1="0%" y2="0%"><stop offset="0%" stop-color="%2300055f" stop-opacity=".84"/><stop offset="100%" stop-color="%236f69f7" stop-opacity=".84"/></linearGradient></defs><path fill="url(%23lobe-icons-qwen-fill)" d="M12.604 1.34q.59 1.035 1.174 2.075a.18.18 0 0 0 .157.091h5.552q.26 0 .446.327l1.454 2.57c.19.337.24.478.024.837q-.39.646-.76 1.3l-.367.658c-.106.196-.223.28-.04.512l2.652 4.637c.172.301.111.494-.043.77q-.656 1.177-1.335 2.34c-.159.272-.352.375-.68.37a43 43 0 0 0-2.327.016.1.1 0 0 0-.081.05 575 575 0 0 1-2.705 4.74c-.169.293-.38.363-.725.364q-1.495.005-3.017.002a.54.54 0 0 1-.465-.271l-1.335-2.323a.09.09 0 0 0-.083-.049H4.982a1.8 1.8 0 0 1-.805-.092l-1.603-2.77a.54.54 0 0 1-.002-.54l1.207-2.12a.2.2 0 0 0 0-.197 551 551 0 0 1-1.875-3.272l-.79-1.395c-.16-.31-.173-.496.095-.965q.697-1.22 1.387-2.436c.132-.234.304-.334.584-.335a338 338 0 0 1 2.589-.001.12.12 0 0 0 .107-.063l2.806-4.895a.49.49 0 0 1 .422-.246c.524-.001 1.053 0 1.583-.006L11.704 1c.341-.003.724.032.9.34m-3.432.403a.06.06 0 0 0-.052.03L6.254 6.788a.16.16 0 0 1-.135.078H3.253q-.084 0-.041.074l5.81 10.156q.037.062-.034.063l-2.795.015a.22.22 0 0 0-.2.116l-1.32 2.31q-.066.117.068.118l5.716.008q.068 0 .104.061l1.403 2.454q.069.122.139 0l5.006-8.76.783-1.382a.055.055 0 0 1 .096 0l1.424 2.53a.12.12 0 0 0 .107.062l2.763-.02a.04.04 0 0 0 .035-.02.04.04 0 0 0 0-.04l-2.9-5.086a.11.11 0 0 1 0-.113l.293-.507 1.12-1.977q.036-.062-.035-.062H9.2q-.088 0-.043-.077l1.434-2.505a.11.11 0 0 0 0-.114L9.225 1.774a.06.06 0 0 0-.053-.031m6.29 8.02q.07 0 .034.06l-.832 1.465-2.613 4.585a.06.06 0 0 1-.05.029.06.06 0 0 1-.05-.029L8.498 9.841q-.03-.051.028-.054l.216-.012 6.722-.012z"/></svg>';
@@ -2390,7 +2318,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
2390
2318
  "Authorization": `Bearer ${apiKey}`
2391
2319
  },
2392
2320
  body: JSON.stringify({
2393
- ...params,
2321
+ ...serializeResponsesRequest(params, request.providerOptions),
2394
2322
  stream: false
2395
2323
  }),
2396
2324
  signal: request.signal
@@ -2422,7 +2350,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
2422
2350
  * Stream using the Chat Completions API (default).
2423
2351
  */
2424
2352
  async streamWithChat(request) {
2425
- const self = this;
2353
+ const toProviderError = this.toProviderError.bind(this);
2426
2354
  const apiKey = this.config.apiKey;
2427
2355
  const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
2428
2356
  try {
@@ -2459,12 +2387,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2459
2387
  async *[Symbol.asyncIterator]() {
2460
2388
  const state = createChatStreamState();
2461
2389
  let finishChunk = null;
2462
- let responseId = null;
2463
2390
  try {
2464
2391
  for await (const chunk of parseChatSSEStream(response, state)) {
2465
2392
  if (chunk.type === "finish") {
2466
2393
  finishChunk = chunk;
2467
- responseId = chunk.responseId || null;
2468
2394
  } else {
2469
2395
  yield chunk;
2470
2396
  }
@@ -2474,18 +2400,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2474
2400
  const pricing = await _OpenRouterProvider.settleUsagePricing(pricingPromise);
2475
2401
  if (pricing) finishChunk.usage.pricing = pricing;
2476
2402
  }
2477
- const finishWithMeta = {
2478
- ...finishChunk,
2479
- _asyncMetadata: responseId ? {
2480
- generationId: responseId,
2481
- apiKey,
2482
- baseUrl
2483
- } : void 0
2484
- };
2485
- yield finishWithMeta;
2403
+ yield finishChunk;
2486
2404
  }
2487
2405
  } catch (error) {
2488
- const providerError = self.toProviderError(error);
2406
+ const providerError = toProviderError(error);
2489
2407
  yield createChatErrorChunk(providerError.message, providerError.code);
2490
2408
  }
2491
2409
  }
@@ -2498,7 +2416,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
2498
2416
  * Stream using the Responses API (beta).
2499
2417
  */
2500
2418
  async streamWithResponses(request) {
2501
- const self = this;
2419
+ const toProviderError = this.toProviderError.bind(this);
2502
2420
  const apiKey = this.config.apiKey;
2503
2421
  const baseUrl = this.config.baseUrl || "https://openrouter.ai/api/v1";
2504
2422
  try {
@@ -2512,7 +2430,7 @@ var OpenRouterProvider = class _OpenRouterProvider {
2512
2430
  "Authorization": `Bearer ${apiKey}`
2513
2431
  },
2514
2432
  body: JSON.stringify({
2515
- ...params,
2433
+ ...serializeResponsesRequest(params, request.providerOptions),
2516
2434
  stream: true
2517
2435
  }),
2518
2436
  signal: request.signal
@@ -2532,12 +2450,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2532
2450
  async *[Symbol.asyncIterator]() {
2533
2451
  const state = createStreamState();
2534
2452
  let finishChunk = null;
2535
- let responseId = null;
2536
2453
  try {
2537
2454
  for await (const chunk of parseSSEStream(response, state)) {
2538
2455
  if (chunk.type === "finish") {
2539
2456
  finishChunk = chunk;
2540
- responseId = chunk.responseId || null;
2541
2457
  } else {
2542
2458
  yield chunk;
2543
2459
  }
@@ -2547,19 +2463,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2547
2463
  const pricing = await _OpenRouterProvider.settleUsagePricing(pricingPromise);
2548
2464
  if (pricing) finishChunk.usage.pricing = pricing;
2549
2465
  }
2550
- const finishWithMeta = {
2551
- ...finishChunk,
2552
- // Include what's needed to fetch metadata later
2553
- _asyncMetadata: responseId ? {
2554
- generationId: responseId,
2555
- apiKey,
2556
- baseUrl
2557
- } : void 0
2558
- };
2559
- yield finishWithMeta;
2466
+ yield finishChunk;
2560
2467
  }
2561
2468
  } catch (error) {
2562
- const providerError = self.toProviderError(error);
2469
+ const providerError = toProviderError(error);
2563
2470
  yield createErrorChunk(providerError.message, providerError.code);
2564
2471
  }
2565
2472
  }
@@ -2607,9 +2514,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2607
2514
  return error;
2608
2515
  }
2609
2516
  if (error instanceof Error) {
2610
- const anyError = error;
2611
- const status = anyError.status || anyError.statusCode;
2612
- const retryAfter = anyError.headers?.["retry-after"] ? parseInt(anyError.headers["retry-after"], 10) : void 0;
2517
+ const status = "status" in error && typeof error.status === "number" && error.status ? error.status : "statusCode" in error && typeof error.statusCode === "number" ? error.statusCode : void 0;
2518
+ const headers = "headers" in error ? error.headers : void 0;
2519
+ const retryHeader = headers instanceof Headers ? headers.get("retry-after") : headers !== null && typeof headers === "object" && "retry-after" in headers ? headers["retry-after"] : void 0;
2520
+ const retryAfter = typeof retryHeader === "string" ? parseInt(retryHeader, 10) : void 0;
2613
2521
  if (status === 429) {
2614
2522
  return new ProviderError(error.message, "rate_limit", status, retryAfter);
2615
2523
  }
@@ -2619,10 +2527,10 @@ var OpenRouterProvider = class _OpenRouterProvider {
2619
2527
  if (status === 400) {
2620
2528
  return new ProviderError(error.message, "invalid_request", status);
2621
2529
  }
2622
- if (status >= 500) {
2530
+ if (status !== void 0 && status >= 500) {
2623
2531
  return new ProviderError(error.message, "server_error", status);
2624
2532
  }
2625
- if (error.name === "AbortError" || anyError.code === "ETIMEDOUT") {
2533
+ if (error.name === "AbortError" || error.name === "RequestTimeoutError" || "code" in error && error.code === "ETIMEDOUT") {
2626
2534
  return new ProviderError(error.message, "timeout");
2627
2535
  }
2628
2536
  return new ProviderError(error.message, "unknown", status);
@@ -2640,11 +2548,9 @@ var OpenRouterProvider = class _OpenRouterProvider {
2640
2548
  const apiMode = this.getApiMode(request);
2641
2549
  if (apiMode === "responses") {
2642
2550
  const params2 = buildCreateParams(request, await resolveRequestReasoningLevels(request, (model) => this.getModelCapabilities(model)));
2643
- if (this.config.providers && this.config.providers.length > 0) {
2644
- params2.provider = { only: this.config.providers };
2645
- }
2551
+ this.applyConfiguredProvidersToResponses(params2);
2646
2552
  return {
2647
- body: truncateBase64(params2),
2553
+ body: truncateBase64(serializeResponsesRequest(params2, request.providerOptions)),
2648
2554
  messagesPath: "input",
2649
2555
  metadata: {
2650
2556
  endpoint: "https://openrouter.ai/api/v1/responses"