@absolutejs/ai 0.0.50 → 0.0.52

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.
Files changed (36) hide show
  1. package/README.md +84 -15
  2. package/dist/ai/client/index.js +30 -1
  3. package/dist/ai/client/index.js.map +5 -5
  4. package/dist/ai/index.js +753 -62
  5. package/dist/ai/index.js.map +15 -15
  6. package/dist/ai/providers/anthropic.js +100 -25
  7. package/dist/ai/providers/anthropic.js.map +5 -5
  8. package/dist/ai/providers/gemini.js +5 -2
  9. package/dist/ai/providers/gemini.js.map +4 -4
  10. package/dist/ai/providers/ollama.js +5 -2
  11. package/dist/ai/providers/ollama.js.map +4 -4
  12. package/dist/ai/providers/openai.js +56 -10
  13. package/dist/ai/providers/openai.js.map +5 -5
  14. package/dist/ai/providers/openaiCompatible.js +56 -10
  15. package/dist/ai/providers/openaiCompatible.js.map +5 -5
  16. package/dist/ai/providers/openaiResponses.js +100 -16
  17. package/dist/ai/providers/openaiResponses.js.map +5 -5
  18. package/dist/ai/providers/openrouter.js +1111 -45
  19. package/dist/ai/providers/openrouter.js.map +10 -9
  20. package/dist/angular/ai/index.js +30 -1
  21. package/dist/angular/ai/index.js.map +5 -5
  22. package/dist/react/ai/index.js +30 -1
  23. package/dist/react/ai/index.js.map +5 -5
  24. package/dist/src/ai/client/actions.d.ts +53 -0
  25. package/dist/src/ai/errors/providerError.d.ts +3 -0
  26. package/dist/src/ai/index.d.ts +2 -2
  27. package/dist/src/ai/providers/openrouter.d.ts +56 -3
  28. package/dist/src/ai/providers/openrouterClient.d.ts +495 -9
  29. package/dist/src/ai/streamAIWithTools.d.ts +6 -0
  30. package/dist/svelte/ai/index.js +30 -1
  31. package/dist/svelte/ai/index.js.map +5 -5
  32. package/dist/types/ai.d.ts +54 -3
  33. package/dist/types/anthropic.d.ts +13 -5
  34. package/dist/vue/ai/index.js +30 -1
  35. package/dist/vue/ai/index.js.map +5 -5
  36. package/package.json +1 -1
@@ -43,6 +43,7 @@ class ProviderError extends Error {
43
43
  status;
44
44
  type;
45
45
  retryable;
46
+ metadata;
46
47
  statusPageUrl;
47
48
  constructor(init) {
48
49
  super(init.message, init.cause === undefined ? undefined : { cause: init.cause });
@@ -51,6 +52,7 @@ class ProviderError extends Error {
51
52
  this.status = init.status ?? null;
52
53
  this.type = init.type ?? null;
53
54
  this.retryable = init.retryable;
55
+ this.metadata = init.metadata;
54
56
  this.statusPageUrl = providerStatusPage(init.provider);
55
57
  }
56
58
  static fromResponse(provider, status, body, type) {
@@ -223,7 +225,8 @@ var withResilience = (provider, providerName = "unknown") => {
223
225
  yield* attempt(params, attemptNo + 1);
224
226
  return;
225
227
  }
226
- noteFailure(providerName, providerError);
228
+ if (providerError.retryable)
229
+ noteFailure(providerName, providerError);
227
230
  throw providerError;
228
231
  }
229
232
  };
@@ -505,6 +508,9 @@ var buildRequestBody = (params, capabilityModel = params.model) => {
505
508
  content: mapOpenAIContent(msg),
506
509
  role: msg.role
507
510
  })), params);
511
+ if (params.systemPrompt) {
512
+ messages.unshift({ content: params.systemPrompt, role: "system" });
513
+ }
508
514
  const body = {
509
515
  messages,
510
516
  model: params.model,
@@ -648,6 +654,18 @@ var processDelta = function* (delta, pendingToolCalls) {
648
654
  if (typeof delta.content === "string") {
649
655
  yield { content: delta.content, type: "text" };
650
656
  }
657
+ if (isRecord(delta.audio)) {
658
+ const audio = delta.audio;
659
+ if (typeof audio.data === "string" || typeof audio.transcript === "string") {
660
+ yield {
661
+ audioId: typeof audio.id === "string" ? audio.id : undefined,
662
+ data: typeof audio.data === "string" ? audio.data : "",
663
+ format: typeof audio.format === "string" ? audio.format : "pcm16",
664
+ transcript: typeof audio.transcript === "string" ? audio.transcript : undefined,
665
+ type: "audio"
666
+ };
667
+ }
668
+ }
651
669
  if (isRecordArray(delta.tool_calls)) {
652
670
  processToolCallDeltas(delta.tool_calls, pendingToolCalls);
653
671
  }
@@ -716,7 +734,7 @@ var narrowUsageRecord = (parsed) => {
716
734
  }
717
735
  return normalized;
718
736
  };
719
- var processSSELine = function* (line, pendingToolCalls) {
737
+ var processSSELine = function* (line, pendingToolCalls, providerName) {
720
738
  const trimmed = line.trim();
721
739
  if (!trimmed || !trimmed.startsWith("data: ")) {
722
740
  return;
@@ -732,6 +750,20 @@ var processSSELine = function* (line, pendingToolCalls) {
732
750
  } catch {
733
751
  return;
734
752
  }
753
+ if (isRecord(parsed.error)) {
754
+ const error = parsed.error;
755
+ const metadata2 = isRecord(error.metadata) ? error.metadata : undefined;
756
+ const status = typeof error.code === "number" ? error.code : null;
757
+ const type = metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : typeof error.error_type === "string" ? error.error_type : null;
758
+ throw new ProviderError({
759
+ message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
760
+ metadata: metadata2,
761
+ provider: providerName,
762
+ retryable: status === 408 || status === 409 || status === 425 || status === 429 || status !== null && status >= 500,
763
+ status,
764
+ type
765
+ });
766
+ }
735
767
  const usageUpdate = narrowUsageRecord(parsed);
736
768
  if (usageUpdate) {
737
769
  yield { type: "usage_update", usage: usageUpdate };
@@ -748,11 +780,24 @@ var processSSELine = function* (line, pendingToolCalls) {
748
780
  if (!firstChoice) {
749
781
  return;
750
782
  }
783
+ if (isRecord(firstChoice.error)) {
784
+ const error = firstChoice.error;
785
+ const metadata2 = isRecord(error.metadata) ? error.metadata : undefined;
786
+ const status = typeof error.code === "number" ? error.code : null;
787
+ throw new ProviderError({
788
+ message: typeof error.message === "string" ? error.message : "OpenRouter stream failed",
789
+ metadata: metadata2,
790
+ provider: providerName,
791
+ retryable: status === 429 || status !== null && status >= 500,
792
+ status,
793
+ type: metadata2 && typeof metadata2.error_type === "string" ? metadata2.error_type : null
794
+ });
795
+ }
751
796
  yield* processChoice(firstChoice, pendingToolCalls);
752
797
  };
753
798
  var isUsageUpdate = (chunk) => chunk.type === "usage_update";
754
- var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef) => {
755
- const allChunks = Array.from(processSSELine(line, pendingToolCalls));
799
+ var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef, providerName) => {
800
+ const allChunks = Array.from(processSSELine(line, pendingToolCalls, providerName));
756
801
  const usageChunks = allChunks.filter(isUsageUpdate);
757
802
  const lastUsage = usageChunks.at(NOT_FOUND);
758
803
  if (lastUsage) {
@@ -772,9 +817,9 @@ var collectYieldableChunks = (line, pendingToolCalls, usageRef, metadataRef) =>
772
817
  }
773
818
  return allChunks.filter((chunk) => !isUsageUpdate(chunk) && chunk.type !== "response_metadata");
774
819
  };
775
- var processSSELines = function* (lines, pendingToolCalls, usageRef, metadataRef) {
820
+ var processSSELines = function* (lines, pendingToolCalls, usageRef, metadataRef, providerName) {
776
821
  for (const line of lines) {
777
- yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef);
822
+ yield* collectYieldableChunks(line, pendingToolCalls, usageRef, metadataRef, providerName);
778
823
  }
779
824
  };
780
825
  var processStreamValue = (value, decoder, state) => {
@@ -787,16 +832,17 @@ var processStreamValue = (value, decoder, state) => {
787
832
  var drainReader = async function* (reader, decoder, state, signal) {
788
833
  for (let result = await reader.read();!result.done && !signal?.aborted; result = await reader.read()) {
789
834
  const lines = processStreamValue(result.value, decoder, state);
790
- yield* processSSELines(lines, state.pendingToolCalls, state.usageRef, state.metadataRef);
835
+ yield* processSSELines(lines, state.pendingToolCalls, state.usageRef, state.metadataRef, state.providerName);
791
836
  }
792
837
  };
793
- var parseSSEStream = async function* (body, initialMetadata, signal) {
838
+ var parseSSEStream = async function* (body, initialMetadata, providerName = "openai", signal) {
794
839
  const reader = body.getReader();
795
840
  const decoder = new TextDecoder;
796
841
  const state = {
797
842
  buffer: "",
798
843
  metadataRef: { current: initialMetadata },
799
844
  pendingToolCalls: new Map,
845
+ providerName,
800
846
  usageRef: { current: undefined }
801
847
  };
802
848
  try {
@@ -841,7 +887,7 @@ var fetchOpenAIStream = async function* (baseUrl, apiKey, body, fetchImpl, heade
841
887
  cacheStatus: response.headers.get("X-OpenRouter-Cache-Status") ?? undefined,
842
888
  cacheTtl: response.headers.get("X-OpenRouter-Cache-TTL") ?? undefined
843
889
  }
844
- }, signal);
890
+ }, providerName, signal);
845
891
  };
846
892
  var openai = (config2) => {
847
893
  const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL;
@@ -923,7 +969,12 @@ var mapContentToResponsesFormat = (content) => {
923
969
  };
924
970
  var hasToolBlocks = (content) => content.some((block) => block.type === "tool_use" || block.type === "tool_result");
925
971
  var convertToolBlock = (block) => {
972
+ if (block.type === "provider_data" && block.provider === "openrouter") {
973
+ return { ...block.data };
974
+ }
926
975
  if (block.type === "tool_use") {
976
+ if (block.providerData)
977
+ return { ...block.providerData };
927
978
  return {
928
979
  arguments: typeof block.input === "string" ? block.input : JSON.stringify(block.input),
929
980
  call_id: block.id,
@@ -1059,11 +1110,32 @@ var extractUsage2 = (response) => {
1059
1110
  const { usage } = response;
1060
1111
  const input = typeof usage.input_tokens === "number" ? usage.input_tokens : 0;
1061
1112
  const cached = isRecord2(usage.input_tokens_details) && typeof usage.input_tokens_details.cached_tokens === "number" ? usage.input_tokens_details.cached_tokens : 0;
1062
- return {
1113
+ const outputDetails = isRecord2(usage.output_tokens_details) ? usage.output_tokens_details : undefined;
1114
+ const inputDetails = isRecord2(usage.input_tokens_details) ? usage.input_tokens_details : undefined;
1115
+ const costDetails = isRecord2(usage.cost_details) ? usage.cost_details : undefined;
1116
+ const normalized = {
1063
1117
  cacheReadInputTokens: cached,
1118
+ cacheWriteInputTokens: inputDetails && typeof inputDetails.cache_write_tokens === "number" ? inputDetails.cache_write_tokens : undefined,
1119
+ costCredits: typeof usage.cost === "number" ? usage.cost : undefined,
1064
1120
  inputTokens: Math.max(0, input - cached),
1065
- outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0
1121
+ outputTokens: typeof usage.output_tokens === "number" ? usage.output_tokens : 0,
1122
+ reasoningTokens: outputDetails && typeof outputDetails.reasoning_tokens === "number" ? outputDetails.reasoning_tokens : undefined,
1123
+ upstreamInferenceCostCredits: costDetails && typeof costDetails.upstream_inference_cost === "number" ? costDetails.upstream_inference_cost : undefined
1066
1124
  };
1125
+ if (isRecord2(usage.server_tool_use)) {
1126
+ normalized.serverToolUse = Object.fromEntries(Object.entries(usage.server_tool_use).filter((entry) => typeof entry[1] === "number"));
1127
+ }
1128
+ return normalized;
1129
+ };
1130
+ var extractResponseMetadata = (response) => {
1131
+ const providerMetadata = isRecord2(response.openrouter_metadata) ? response.openrouter_metadata : undefined;
1132
+ const generationId = typeof response.id === "string" ? response.id : undefined;
1133
+ const model = typeof response.model === "string" ? response.model : undefined;
1134
+ const provider = typeof response.provider === "string" ? response.provider : undefined;
1135
+ const serviceTier = typeof response.service_tier === "string" ? response.service_tier : undefined;
1136
+ if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
1137
+ return;
1138
+ return { generationId, model, provider, providerMetadata, serviceTier };
1067
1139
  };
1068
1140
  var extractMimeFormat = (mimeType) => {
1069
1141
  if (typeof mimeType !== "string") {
@@ -1120,6 +1192,7 @@ var processFunctionCallArgumentsDone = function* (parsed, pendingCalls) {
1120
1192
  id: callId || pending?.callId || itemId,
1121
1193
  input: parseToolInput2(args),
1122
1194
  name,
1195
+ providerData: pending?.providerData ? { ...pending.providerData, arguments: args } : undefined,
1123
1196
  type: "tool_use"
1124
1197
  };
1125
1198
  };
@@ -1138,9 +1211,21 @@ var processOutputItemAdded = (parsed, pendingCalls) => {
1138
1211
  pendingCalls.set(itemId, {
1139
1212
  arguments: "",
1140
1213
  callId,
1141
- name
1214
+ name,
1215
+ providerData: { ...item }
1142
1216
  });
1143
1217
  };
1218
+ var processOutputItemDone = function* (parsed) {
1219
+ if (!isRecord2(parsed.item) || typeof parsed.item.type !== "string")
1220
+ return;
1221
+ if (!parsed.item.type.startsWith("openrouter:"))
1222
+ return;
1223
+ yield {
1224
+ data: { ...parsed.item },
1225
+ provider: "openrouter",
1226
+ type: "provider_event"
1227
+ };
1228
+ };
1144
1229
  var isCompletedImageGeneration = (item) => item.type === "image_generation_call" && item.status === "completed" && typeof item.result === "string" && item.result !== "";
1145
1230
  var buildImageChunk = (item) => ({
1146
1231
  data: typeof item.result === "string" ? item.result : "",
@@ -1156,6 +1241,30 @@ var extractImageFromOutput = function* (output) {
1156
1241
  yield buildImageChunk(item);
1157
1242
  }
1158
1243
  };
1244
+ var extractCitationsFromOutput = function* (output) {
1245
+ for (const item of output) {
1246
+ if (!isRecordArray2(item.content))
1247
+ continue;
1248
+ for (const content of item.content) {
1249
+ if (!Array.isArray(content.annotations))
1250
+ continue;
1251
+ for (const annotation of content.annotations) {
1252
+ if (!isRecord2(annotation) || annotation.type !== "url_citation")
1253
+ continue;
1254
+ if (typeof annotation.url !== "string")
1255
+ continue;
1256
+ yield {
1257
+ content: typeof annotation.content === "string" ? annotation.content : undefined,
1258
+ endIndex: typeof annotation.end_index === "number" ? annotation.end_index : undefined,
1259
+ startIndex: typeof annotation.start_index === "number" ? annotation.start_index : undefined,
1260
+ title: typeof annotation.title === "string" ? annotation.title : undefined,
1261
+ type: "citation",
1262
+ url: annotation.url
1263
+ };
1264
+ }
1265
+ }
1266
+ }
1267
+ };
1159
1268
  var processCompleted = function* (parsed) {
1160
1269
  if (!isRecord2(parsed.response)) {
1161
1270
  yield { type: "done", usage: undefined };
@@ -1163,12 +1272,26 @@ var processCompleted = function* (parsed) {
1163
1272
  }
1164
1273
  const { response } = parsed;
1165
1274
  const usage = extractUsage2(response);
1275
+ const metadata = extractResponseMetadata(response);
1166
1276
  if (isRecordArray2(response.output)) {
1277
+ yield* extractCitationsFromOutput(response.output);
1167
1278
  yield* extractImageFromOutput(response.output);
1168
1279
  }
1169
- yield { type: "done", usage };
1280
+ yield { metadata, type: "done", usage };
1281
+ };
1282
+ var responseFailure = (eventType, parsed, providerName) => {
1283
+ const response = isRecord2(parsed.response) ? parsed.response : parsed;
1284
+ const error = isRecord2(response.error) ? response.error : undefined;
1285
+ const type = typeof response.error_type === "string" ? response.error_type : error && typeof error.code === "string" ? error.code : eventType;
1286
+ return new ProviderError({
1287
+ message: error && typeof error.message === "string" ? error.message : `OpenRouter Responses API: ${eventType}`,
1288
+ metadata: response,
1289
+ provider: providerName,
1290
+ retryable: type === "rate_limit_exceeded" || type === "provider_overloaded" || type === "provider_unavailable" || type === "server",
1291
+ type
1292
+ });
1170
1293
  };
1171
- var processSSEEvent = function* (eventType, parsed, pendingCalls) {
1294
+ var processSSEEvent = function* (eventType, parsed, pendingCalls, providerName) {
1172
1295
  switch (eventType) {
1173
1296
  case "response.reasoning_summary_text.delta": {
1174
1297
  const delta = typeof parsed.delta === "string" ? parsed.delta : "";
@@ -1189,6 +1312,9 @@ var processSSEEvent = function* (eventType, parsed, pendingCalls) {
1189
1312
  case "response.output_item.added":
1190
1313
  processOutputItemAdded(parsed, pendingCalls);
1191
1314
  break;
1315
+ case "response.output_item.done":
1316
+ yield* processOutputItemDone(parsed);
1317
+ break;
1192
1318
  case "response.function_call_arguments.delta":
1193
1319
  processFunctionCallArgumentsDelta(parsed, pendingCalls);
1194
1320
  break;
@@ -1199,11 +1325,10 @@ var processSSEEvent = function* (eventType, parsed, pendingCalls) {
1199
1325
  yield* processCompleted(parsed);
1200
1326
  break;
1201
1327
  case "response.failed":
1202
- case "response.incomplete": {
1203
- const respObj = isRecord2(parsed.response) ? parsed.response : parsed;
1204
- const errMsg = isRecord2(respObj.error) && typeof respObj.error.message === "string" ? respObj.error.message : `OpenAI Responses API: ${eventType}`;
1205
- throw new Error(errMsg);
1206
- }
1328
+ case "response.incomplete":
1329
+ case "response.error":
1330
+ case "error":
1331
+ throw responseFailure(eventType, parsed, providerName);
1207
1332
  }
1208
1333
  };
1209
1334
  var flushSSEBuffer = function* (state) {
@@ -1212,7 +1337,7 @@ var flushSSEBuffer = function* (state) {
1212
1337
  }
1213
1338
  const parsed = parseJSON(state.buffer);
1214
1339
  if (parsed) {
1215
- yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls);
1340
+ yield* processSSEEvent(state.currentEvent, parsed, state.pendingCalls, state.providerName);
1216
1341
  }
1217
1342
  state.currentEvent = "";
1218
1343
  state.buffer = "";
@@ -1250,17 +1375,19 @@ var drainReader2 = async function* (reader, decoder, state, signal) {
1250
1375
  yield* processSSELines2([textBuffer, ""], state);
1251
1376
  }
1252
1377
  };
1253
- var parseSSEStream2 = async function* (body, signal) {
1378
+ var parseSSEStream2 = async function* (body, providerName, signal) {
1254
1379
  const reader = body.getReader();
1255
1380
  const decoder = new TextDecoder;
1256
1381
  const state = {
1257
1382
  buffer: "",
1258
1383
  currentEvent: "",
1259
1384
  pendingCalls: new Map,
1260
- usage: undefined
1385
+ usage: undefined,
1386
+ providerName
1261
1387
  };
1262
1388
  try {
1263
1389
  yield* drainReader2(reader, decoder, state, signal);
1390
+ yield* flushSSEBuffer(state);
1264
1391
  } finally {
1265
1392
  reader.releaseLock();
1266
1393
  }
@@ -1288,7 +1415,7 @@ var fetchResponsesStream = async function* (baseUrl, apiKey, body, fetchImpl, he
1288
1415
  retryable: true
1289
1416
  });
1290
1417
  }
1291
- yield* parseSSEStream2(response.body, signal);
1418
+ yield* parseSSEStream2(response.body, providerName, signal);
1292
1419
  };
1293
1420
  var resolveImageModels = (imageModels) => {
1294
1421
  if (!imageModels) {
@@ -1324,8 +1451,585 @@ var openaiResponses = (config2) => {
1324
1451
  }, providerName);
1325
1452
  };
1326
1453
 
1454
+ // src/ai/providers/anthropic.ts
1455
+ var h2IfHttps3 = (url) => url.startsWith("https://") ? { protocol: "http2" } : {};
1456
+ var DEFAULT_BASE_URL3 = "https://api.anthropic.com";
1457
+ var API_VERSION = "2023-06-01";
1458
+ var DEFAULT_MAX_TOKENS = 32000;
1459
+ var EVENT_PREFIX_LENGTH2 = 7;
1460
+ var DATA_PREFIX_LENGTH2 = 6;
1461
+ var EMPTY_CHUNKS = [];
1462
+ var isRecord3 = (val) => typeof val === "object" && val !== null;
1463
+ var mapContentBlock = (block) => {
1464
+ if (block.type === "thinking") {
1465
+ return {
1466
+ signature: block.signature,
1467
+ thinking: block.thinking,
1468
+ type: "thinking"
1469
+ };
1470
+ }
1471
+ if (block.type === "image") {
1472
+ return {
1473
+ source: block.source,
1474
+ type: "image"
1475
+ };
1476
+ }
1477
+ if (block.type === "document") {
1478
+ return {
1479
+ source: block.source,
1480
+ type: "document"
1481
+ };
1482
+ }
1483
+ if (block.type === "tool_result") {
1484
+ return {
1485
+ content: block.content,
1486
+ tool_use_id: block.tool_use_id,
1487
+ type: "tool_result"
1488
+ };
1489
+ }
1490
+ if (block.type === "tool_use") {
1491
+ if (block.providerData)
1492
+ return { ...block.providerData };
1493
+ return {
1494
+ id: block.id,
1495
+ input: block.input,
1496
+ name: block.name,
1497
+ type: "tool_use"
1498
+ };
1499
+ }
1500
+ if (block.type === "audio" || block.type === "video") {
1501
+ throw new Error(`Anthropic does not support ${block.type} content blocks`);
1502
+ }
1503
+ if (block.type === "provider_data") {
1504
+ return { ...block.data };
1505
+ }
1506
+ return { text: block.content, type: "text" };
1507
+ };
1508
+ var mapMessage = (msg) => ({
1509
+ content: typeof msg.content === "string" ? msg.content : msg.content.map(mapContentBlock),
1510
+ role: msg.role === "system" ? "user" : msg.role
1511
+ });
1512
+ var mapToolDefinition2 = (tool) => ({
1513
+ description: tool.description,
1514
+ input_schema: tool.input_schema,
1515
+ name: tool.name
1516
+ });
1517
+ var cacheLastContentBlock = (msg) => {
1518
+ const cacheControl = { type: "ephemeral" };
1519
+ if (typeof msg.content === "string") {
1520
+ return {
1521
+ content: [
1522
+ { cache_control: cacheControl, text: msg.content, type: "text" }
1523
+ ],
1524
+ role: msg.role
1525
+ };
1526
+ }
1527
+ if (msg.content.length === 0)
1528
+ return msg;
1529
+ const blocks = [...msg.content];
1530
+ blocks[blocks.length - 1] = {
1531
+ ...blocks[blocks.length - 1],
1532
+ cache_control: cacheControl
1533
+ };
1534
+ return { content: blocks, role: msg.role };
1535
+ };
1536
+ var buildRequestBody3 = (params, configuredMax, configCaching) => {
1537
+ const caching = params.promptCaching ?? configCaching;
1538
+ const cacheSystem = params.cacheSystemPrompt ?? caching;
1539
+ const messages = params.messages.filter((msg) => msg.role !== "system").map(mapMessage);
1540
+ if (caching && messages.length > 1) {
1541
+ const last = messages[messages.length - 1];
1542
+ if (last) {
1543
+ messages[messages.length - 1] = cacheLastContentBlock(last);
1544
+ }
1545
+ }
1546
+ const max = typeof params.maxTokens === "number" ? params.maxTokens : configuredMax;
1547
+ const body = {
1548
+ max_tokens: max,
1549
+ messages,
1550
+ model: params.model,
1551
+ stream: true
1552
+ };
1553
+ if (params.systemPrompt) {
1554
+ body.system = cacheSystem ? [
1555
+ {
1556
+ cache_control: { type: "ephemeral" },
1557
+ text: params.systemPrompt,
1558
+ type: "text"
1559
+ }
1560
+ ] : params.systemPrompt;
1561
+ }
1562
+ if (params.tools && params.tools.length > 0) {
1563
+ const tools = params.tools.map(mapToolDefinition2);
1564
+ if (caching) {
1565
+ tools[tools.length - 1] = {
1566
+ ...tools[tools.length - 1],
1567
+ cache_control: { type: "ephemeral" }
1568
+ };
1569
+ }
1570
+ body.tools = tools;
1571
+ if (params.toolChoice === "auto" || params.toolChoice === "none") {
1572
+ body.tool_choice = { type: params.toolChoice };
1573
+ } else if (params.toolChoice === "required") {
1574
+ body.tool_choice = { type: "any" };
1575
+ } else if (params.toolChoice && typeof params.toolChoice === "object") {
1576
+ body.tool_choice = { name: params.toolChoice.name, type: "tool" };
1577
+ }
1578
+ }
1579
+ if (params.stopSequences && params.stopSequences.length > 0) {
1580
+ body.stop_sequences = params.stopSequences;
1581
+ }
1582
+ const mode = params.reasoning ? anthropicReasoningMode(params.model) : "none";
1583
+ const thinkingActive = mode !== "none";
1584
+ if (!thinkingActive && anthropicSupportsSampling(params.model)) {
1585
+ if (typeof params.temperature === "number") {
1586
+ body.temperature = params.temperature;
1587
+ }
1588
+ if (typeof params.topP === "number")
1589
+ body.top_p = params.topP;
1590
+ }
1591
+ if (mode === "effort" || mode === "adaptive") {
1592
+ body.thinking = { type: "adaptive" };
1593
+ if (mode === "effort" && params.reasoning) {
1594
+ const effort = anthropicEffortValue(params.model, params.reasoning);
1595
+ if (effort)
1596
+ body.output_config = { effort };
1597
+ }
1598
+ } else if (mode === "legacy" && params.reasoning) {
1599
+ const budget = resolveBudgetTokens(params.reasoning);
1600
+ if (budget) {
1601
+ body.thinking = { budget_tokens: budget, type: "enabled" };
1602
+ body.max_tokens = Math.max(max, budget + max);
1603
+ }
1604
+ }
1605
+ return body;
1606
+ };
1607
+ var classifyLine = (line) => {
1608
+ if (line.startsWith("event: ")) {
1609
+ return {
1610
+ field: "event",
1611
+ value: line.slice(EVENT_PREFIX_LENGTH2)
1612
+ };
1613
+ }
1614
+ if (line.startsWith("data: ")) {
1615
+ return {
1616
+ field: "data",
1617
+ value: line.slice(DATA_PREFIX_LENGTH2)
1618
+ };
1619
+ }
1620
+ return;
1621
+ };
1622
+ var applyClassified = (acc, classified) => {
1623
+ if (!classified) {
1624
+ return acc;
1625
+ }
1626
+ if (classified.field === "event") {
1627
+ return { eventData: acc.eventData, eventType: classified.value };
1628
+ }
1629
+ return { eventData: classified.value, eventType: acc.eventType };
1630
+ };
1631
+ var parseEventLines = (event) => event.split(`
1632
+ `).reduce((acc, line) => applyClassified(acc, classifyLine(line)), {
1633
+ eventData: "",
1634
+ eventType: ""
1635
+ });
1636
+ var safeParse = (text) => {
1637
+ try {
1638
+ const result = JSON.parse(text);
1639
+ return result;
1640
+ } catch {
1641
+ return;
1642
+ }
1643
+ };
1644
+ var tryParseJson = (text) => {
1645
+ const result = safeParse(text);
1646
+ if (isRecord3(result)) {
1647
+ return result;
1648
+ }
1649
+ return;
1650
+ };
1651
+ var getRecord = (obj, key) => {
1652
+ const val = obj[key];
1653
+ if (isRecord3(val)) {
1654
+ return val;
1655
+ }
1656
+ return;
1657
+ };
1658
+ var getString = (obj, key) => {
1659
+ const val = obj[key];
1660
+ if (typeof val === "string") {
1661
+ return val;
1662
+ }
1663
+ return "";
1664
+ };
1665
+ var getNumber = (obj, key) => {
1666
+ const val = obj[key];
1667
+ if (typeof val === "number") {
1668
+ return val;
1669
+ }
1670
+ return 0;
1671
+ };
1672
+ var handleContentBlockStart = (parsed, state) => {
1673
+ const block = getRecord(parsed, "content_block");
1674
+ if (block && block.type === "tool_use") {
1675
+ state.currentToolId = getString(block, "id");
1676
+ state.currentToolName = getString(block, "name");
1677
+ state.toolInputJson = "";
1678
+ state.isThinkingBlock = false;
1679
+ state.currentProviderBlock = undefined;
1680
+ } else if (block && block.type === "thinking") {
1681
+ state.isThinkingBlock = true;
1682
+ state.thinkingSignature = "";
1683
+ state.currentProviderBlock = undefined;
1684
+ } else {
1685
+ state.isThinkingBlock = false;
1686
+ state.currentProviderBlock = block && block.type !== "text" ? { ...block } : undefined;
1687
+ state.providerBlockInputJson = "";
1688
+ }
1689
+ };
1690
+ var handleContentBlockDelta = (parsed, state) => {
1691
+ const delta = getRecord(parsed, "delta");
1692
+ if (!delta) {
1693
+ return;
1694
+ }
1695
+ if (delta.type === "thinking_delta") {
1696
+ return {
1697
+ content: getString(delta, "thinking"),
1698
+ type: "thinking"
1699
+ };
1700
+ }
1701
+ if (delta.type === "text_delta") {
1702
+ return {
1703
+ content: getString(delta, "text"),
1704
+ type: "text"
1705
+ };
1706
+ }
1707
+ if (delta.type === "input_json_delta") {
1708
+ if (state.currentProviderBlock) {
1709
+ state.providerBlockInputJson += getString(delta, "partial_json");
1710
+ } else {
1711
+ state.toolInputJson += getString(delta, "partial_json");
1712
+ }
1713
+ }
1714
+ if (delta.type === "signature_delta") {
1715
+ state.thinkingSignature += getString(delta, "signature");
1716
+ }
1717
+ return;
1718
+ };
1719
+ var handleContentBlockStop = (state) => {
1720
+ if (state.isThinkingBlock && state.thinkingSignature) {
1721
+ state.isThinkingBlock = false;
1722
+ const signature = state.thinkingSignature;
1723
+ state.thinkingSignature = "";
1724
+ return {
1725
+ content: "",
1726
+ signature,
1727
+ type: "thinking"
1728
+ };
1729
+ }
1730
+ if (state.currentProviderBlock) {
1731
+ const data = { ...state.currentProviderBlock };
1732
+ if (state.providerBlockInputJson) {
1733
+ data.input = tryParseJson(state.providerBlockInputJson) ?? state.providerBlockInputJson;
1734
+ }
1735
+ state.currentProviderBlock = undefined;
1736
+ state.providerBlockInputJson = "";
1737
+ return {
1738
+ data,
1739
+ provider: state.providerName,
1740
+ type: "provider_event"
1741
+ };
1742
+ }
1743
+ if (!state.currentToolId) {
1744
+ return;
1745
+ }
1746
+ const input = tryParseJson(state.toolInputJson) ?? state.toolInputJson;
1747
+ const chunk = {
1748
+ id: state.currentToolId,
1749
+ input,
1750
+ name: state.currentToolName,
1751
+ type: "tool_use"
1752
+ };
1753
+ state.currentToolId = "";
1754
+ state.currentToolName = "";
1755
+ state.toolInputJson = "";
1756
+ return chunk;
1757
+ };
1758
+ var extractUsage3 = (usageRecord, existingUsage) => {
1759
+ if (!usageRecord) {
1760
+ return existingUsage;
1761
+ }
1762
+ const normalized = {
1763
+ cacheReadInputTokens: getNumber(usageRecord, "cache_read_input_tokens") || existingUsage?.cacheReadInputTokens || 0,
1764
+ cacheWriteInputTokens: getNumber(usageRecord, "cache_creation_input_tokens") || existingUsage?.cacheWriteInputTokens || 0,
1765
+ inputTokens: getNumber(usageRecord, "input_tokens") || existingUsage?.inputTokens || 0,
1766
+ outputTokens: getNumber(usageRecord, "output_tokens") || existingUsage?.outputTokens || 0,
1767
+ costCredits: getNumber(usageRecord, "cost") || existingUsage?.costCredits,
1768
+ reasoningTokens: getNumber(usageRecord, "reasoning_tokens") || existingUsage?.reasoningTokens,
1769
+ upstreamInferenceCostCredits: getNumber(getRecord(usageRecord, "cost_details") ?? {}, "upstream_inference_cost") || existingUsage?.upstreamInferenceCostCredits
1770
+ };
1771
+ const serverToolUse = getRecord(usageRecord, "server_tool_use");
1772
+ if (serverToolUse) {
1773
+ normalized.serverToolUse = Object.fromEntries(Object.entries(serverToolUse).filter((entry) => typeof entry[1] === "number"));
1774
+ }
1775
+ return normalized;
1776
+ };
1777
+ var mergeMetadata = (source, state) => {
1778
+ const providerMetadata = getRecord(source, "openrouter_metadata");
1779
+ const generationId = getString(source, "id") || undefined;
1780
+ const model = getString(source, "model") || undefined;
1781
+ const provider = getString(source, "provider") || undefined;
1782
+ const serviceTier = getString(source, "service_tier") || undefined;
1783
+ if (!providerMetadata && !generationId && !model && !provider && !serviceTier)
1784
+ return;
1785
+ state.metadata = {
1786
+ ...state.metadata,
1787
+ generationId: generationId ?? state.metadata?.generationId,
1788
+ model: model ?? state.metadata?.model,
1789
+ provider: provider ?? state.metadata?.provider,
1790
+ providerMetadata: {
1791
+ ...state.metadata?.providerMetadata,
1792
+ ...providerMetadata
1793
+ },
1794
+ serviceTier: serviceTier ?? state.metadata?.serviceTier
1795
+ };
1796
+ };
1797
+ var handleMessageDelta = (parsed, state) => {
1798
+ const deltaUsage = getRecord(parsed, "usage");
1799
+ state.usage = extractUsage3(deltaUsage, state.usage);
1800
+ const delta = getRecord(parsed, "delta");
1801
+ const stopReason = delta ? getString(delta, "stop_reason") : "";
1802
+ if (stopReason)
1803
+ state.stopReason = stopReason;
1804
+ };
1805
+ var handleMessageStart = (parsed, state) => {
1806
+ const message = getRecord(parsed, "message");
1807
+ if (!message) {
1808
+ return;
1809
+ }
1810
+ const startUsage = getRecord(message, "usage");
1811
+ state.usage = extractUsage3(startUsage, state.usage);
1812
+ mergeMetadata(message, state);
1813
+ };
1814
+ var handleError = (parsed, state) => {
1815
+ const error = getRecord(parsed, "error");
1816
+ const errorMessage = error ? getString(error, "message") : "";
1817
+ const nativeErrorType = error ? getString(error, "type") : "";
1818
+ const errorType = error ? getString(error, "error_type") || nativeErrorType : "";
1819
+ const retryable = errorType === "provider_overloaded" || errorType === "rate_limit_exceeded" || errorType === "provider_unavailable" || errorType === "server" || nativeErrorType === "overloaded_error" || nativeErrorType === "rate_limit_error" || nativeErrorType === "api_error";
1820
+ throw new ProviderError({
1821
+ message: errorMessage || "Anthropic API error",
1822
+ metadata: error,
1823
+ provider: state.providerName,
1824
+ retryable,
1825
+ type: errorType || null
1826
+ });
1827
+ };
1828
+ var processEvent = (eventType, parsed, state) => {
1829
+ switch (eventType) {
1830
+ case "content_block_start": {
1831
+ handleContentBlockStart(parsed, state);
1832
+ return;
1833
+ }
1834
+ case "content_block_delta": {
1835
+ return handleContentBlockDelta(parsed, state);
1836
+ }
1837
+ case "content_block_stop": {
1838
+ return handleContentBlockStop(state);
1839
+ }
1840
+ case "message_delta": {
1841
+ handleMessageDelta(parsed, state);
1842
+ mergeMetadata(parsed, state);
1843
+ return;
1844
+ }
1845
+ case "message_start": {
1846
+ handleMessageStart(parsed, state);
1847
+ return;
1848
+ }
1849
+ case "message_stop": {
1850
+ mergeMetadata(parsed, state);
1851
+ return {
1852
+ stopReason: state.stopReason,
1853
+ metadata: state.metadata,
1854
+ type: "done",
1855
+ usage: state.usage
1856
+ };
1857
+ }
1858
+ case "error": {
1859
+ handleError(parsed, state);
1860
+ return;
1861
+ }
1862
+ default: {
1863
+ return;
1864
+ }
1865
+ }
1866
+ };
1867
+ var processSingleEvent = (event, state) => {
1868
+ if (!event.trim()) {
1869
+ return;
1870
+ }
1871
+ const { eventData, eventType } = parseEventLines(event);
1872
+ if (!eventData) {
1873
+ return;
1874
+ }
1875
+ const parsed = tryParseJson(eventData);
1876
+ if (!parsed) {
1877
+ return;
1878
+ }
1879
+ return processEvent(eventType, parsed, state);
1880
+ };
1881
+ var collectChunk = (event, state) => {
1882
+ const chunk = processSingleEvent(event, state);
1883
+ return chunk ? [chunk] : [];
1884
+ };
1885
+ var processBufferedEvents = (eventsText, state) => {
1886
+ const events = eventsText.split(`
1887
+
1888
+ `);
1889
+ state.buffer = events.pop() ?? "";
1890
+ return events.flatMap((event) => collectChunk(event, state));
1891
+ };
1892
+ var readNextChunks = async (reader, decoder, state, signal) => {
1893
+ if (signal?.aborted) {
1894
+ return { chunks: EMPTY_CHUNKS, done: true };
1895
+ }
1896
+ const { done, value } = await reader.read();
1897
+ if (done) {
1898
+ return { chunks: EMPTY_CHUNKS, done: true };
1899
+ }
1900
+ const rawText = state.buffer + decoder.decode(value, { stream: true });
1901
+ const chunks = processBufferedEvents(rawText, state);
1902
+ return { chunks, done: false };
1903
+ };
1904
+ var findDoneChunk = (chunks) => chunks.findIndex((c) => c.type === "done");
1905
+ var sseStreamLoop = async (reader, decoder, state, signal) => {
1906
+ const result = await readNextChunks(reader, decoder, state, signal);
1907
+ if (result.done) {
1908
+ return { chunks: result.chunks, finished: true };
1909
+ }
1910
+ const doneIdx = findDoneChunk(result.chunks);
1911
+ if (doneIdx >= 0) {
1912
+ return { chunks: result.chunks.slice(0, doneIdx + 1), finished: true };
1913
+ }
1914
+ return { chunks: result.chunks, finished: false };
1915
+ };
1916
+ async function* streamChunks(reader, decoder, state, signal) {
1917
+ let finished = false;
1918
+ while (!finished) {
1919
+ const result = await sseStreamLoop(reader, decoder, state, signal);
1920
+ ({ finished } = result);
1921
+ yield* result.chunks;
1922
+ }
1923
+ }
1924
+ async function* parseSSEStream3(body, providerName, signal) {
1925
+ const reader = body.getReader();
1926
+ const decoder = new TextDecoder;
1927
+ const state = {
1928
+ buffer: "",
1929
+ currentToolId: "",
1930
+ currentToolName: "",
1931
+ isThinkingBlock: false,
1932
+ stopReason: "",
1933
+ thinkingSignature: "",
1934
+ toolInputJson: "",
1935
+ usage: undefined,
1936
+ providerName,
1937
+ providerBlockInputJson: ""
1938
+ };
1939
+ try {
1940
+ yield* streamChunks(reader, decoder, state, signal);
1941
+ } finally {
1942
+ reader.releaseLock();
1943
+ }
1944
+ }
1945
+ var fetchAndStream = async function* (baseUrl, config2, params, configuredMax, promptCaching, providerName) {
1946
+ const builtBody = buildRequestBody3(params, configuredMax, promptCaching);
1947
+ const body = config2.transformRequestBody ? config2.transformRequestBody(builtBody, params) : builtBody;
1948
+ const target = `${baseUrl}/v1/messages`;
1949
+ const fetchImpl = config2.fetch ?? fetch;
1950
+ const token = config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
1951
+ const suppliedHeaders = typeof config2.headers === "function" ? await config2.headers(params) : config2.headers ?? {};
1952
+ const requestHeaders = new Headers(suppliedHeaders);
1953
+ requestHeaders.set("Content-Type", "application/json");
1954
+ if (config2.authStyle === "bearer") {
1955
+ requestHeaders.set("Authorization", `Bearer ${token}`);
1956
+ } else {
1957
+ requestHeaders.set("anthropic-version", API_VERSION);
1958
+ requestHeaders.set("x-api-key", token);
1959
+ }
1960
+ const response = await fetchImpl(target, {
1961
+ ...h2IfHttps3(target),
1962
+ body: JSON.stringify(body),
1963
+ headers: requestHeaders,
1964
+ method: "POST",
1965
+ signal: params.signal
1966
+ });
1967
+ if (!response.ok) {
1968
+ const errorText = await response.text();
1969
+ throw ProviderError.fromResponse(providerName, response.status, errorText);
1970
+ }
1971
+ if (!response.body) {
1972
+ throw new ProviderError({
1973
+ message: `${providerName} Messages API returned no response body`,
1974
+ provider: providerName,
1975
+ retryable: true
1976
+ });
1977
+ }
1978
+ yield* parseSSEStream3(response.body, providerName, params.signal);
1979
+ };
1980
+ var anthropic = (config2) => {
1981
+ if (!config2.apiKey && !config2.tokenSource)
1982
+ throw new Error("anthropic() requires either apiKey or tokenSource");
1983
+ const baseUrl = config2.baseUrl ?? DEFAULT_BASE_URL3;
1984
+ const configuredMax = config2.maxTokens ?? DEFAULT_MAX_TOKENS;
1985
+ const promptCaching = config2.promptCaching ?? true;
1986
+ const providerName = config2.providerName ?? "anthropic";
1987
+ return instrumentAIProvider({
1988
+ stream: (params) => fetchAndStream(baseUrl, config2, params, configuredMax, promptCaching, providerName)
1989
+ }, providerName);
1990
+ };
1991
+
1327
1992
  // src/ai/providers/openrouterClient.ts
1328
- var DEFAULT_BASE_URL3 = "https://openrouter.ai/api/v1";
1993
+ var OPENROUTER_PRICING_KEYS = [
1994
+ "prompt",
1995
+ "completion",
1996
+ "request",
1997
+ "image",
1998
+ "web_search",
1999
+ "internal_reasoning",
2000
+ "input_cache_read",
2001
+ "input_cache_write"
2002
+ ];
2003
+ var estimateOpenRouterCost = (pricing, units) => {
2004
+ const components = {};
2005
+ let total = 0;
2006
+ for (const key of OPENROUTER_PRICING_KEYS) {
2007
+ const quantity = units[key];
2008
+ if (quantity === undefined)
2009
+ continue;
2010
+ if (!Number.isFinite(quantity) || quantity < 0)
2011
+ throw new Error(`OpenRouter ${key} units must be non-negative`);
2012
+ const rawPrice = pricing[key];
2013
+ if (rawPrice === undefined)
2014
+ continue;
2015
+ const price = Number(rawPrice);
2016
+ if (!Number.isFinite(price) || price < 0)
2017
+ throw new Error(`OpenRouter ${key} price must be non-negative`);
2018
+ components[key] = price * quantity;
2019
+ total += components[key];
2020
+ }
2021
+ return { components, total };
2022
+ };
2023
+ var estimateOpenRouterModelCost = (model, units) => estimateOpenRouterCost(model.pricing ?? {}, units);
2024
+ var DEFAULT_BASE_URL4 = "https://openrouter.ai/api/v1";
2025
+ var DEFAULT_BATCH_BASE_URL = "https://openrouter.ai/api/beta";
2026
+ var DEFAULT_SITE_URL = "https://openrouter.ai";
2027
+ var TERMINAL_BATCH_STATUSES = new Set([
2028
+ "completed",
2029
+ "failed",
2030
+ "expired",
2031
+ "cancelled"
2032
+ ]);
1329
2033
  var withoutLatestPrefix = (model) => model.startsWith("~") ? model.slice(1) : model;
1330
2034
  var openRouterModelMatchesRule = (model, rule) => {
1331
2035
  const normalizedModel = withoutLatestPrefix(model);
@@ -1339,6 +2043,22 @@ var assertAllowedModel = (model, allowedModels) => {
1339
2043
  return;
1340
2044
  throw new Error(`OpenRouter model "${model}" is not allowed`);
1341
2045
  };
2046
+ var assertAllowedModelsInValue = (value, allowedModels, key = "") => {
2047
+ if (key === "model" && typeof value === "string")
2048
+ assertAllowedModel(value, allowedModels);
2049
+ if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
2050
+ for (const model of value)
2051
+ if (typeof model === "string")
2052
+ assertAllowedModel(model, allowedModels);
2053
+ }
2054
+ if (Array.isArray(value)) {
2055
+ for (const item of value)
2056
+ assertAllowedModelsInValue(item, allowedModels);
2057
+ } else if (value && typeof value === "object") {
2058
+ for (const [childKey, child] of Object.entries(value))
2059
+ assertAllowedModelsInValue(child, allowedModels, childKey);
2060
+ }
2061
+ };
1342
2062
  var normalizePath = (path) => path.startsWith("/") ? path : `/${path}`;
1343
2063
  var encodeModelPath = (model) => model.split("/").map(encodeURIComponent).join("/");
1344
2064
  var withQuery = (url, query) => {
@@ -1351,13 +2071,142 @@ var withQuery = (url, query) => {
1351
2071
  }
1352
2072
  return result.toString();
1353
2073
  };
2074
+ var parseImageSSE = async function* (response) {
2075
+ if (!response.body)
2076
+ throw new Error("OpenRouter image stream has no body");
2077
+ const reader = response.body.getReader();
2078
+ const decoder = new TextDecoder;
2079
+ let buffer = "";
2080
+ try {
2081
+ for (;; ) {
2082
+ const result = await reader.read();
2083
+ buffer += decoder.decode(result.value, { stream: !result.done });
2084
+ const lines = buffer.split(`
2085
+ `);
2086
+ buffer = lines.pop() ?? "";
2087
+ for (const line of lines) {
2088
+ if (!line.startsWith("data: "))
2089
+ continue;
2090
+ const data = line.slice(6);
2091
+ if (data === "[DONE]")
2092
+ return;
2093
+ try {
2094
+ const parsed = JSON.parse(data);
2095
+ if (parsed && typeof parsed === "object" && "type" in parsed)
2096
+ yield parsed;
2097
+ } catch {}
2098
+ }
2099
+ if (result.done)
2100
+ break;
2101
+ }
2102
+ if (buffer.startsWith("data: ")) {
2103
+ const parsed = JSON.parse(buffer.slice(6));
2104
+ if (parsed && typeof parsed === "object" && "type" in parsed)
2105
+ yield parsed;
2106
+ }
2107
+ } finally {
2108
+ reader.releaseLock();
2109
+ }
2110
+ };
2111
+ var toBytes = (value) => typeof value === "string" ? new TextEncoder().encode(value) : value;
2112
+ var toBase64Url = (bytes) => {
2113
+ let binary = "";
2114
+ for (const byte of bytes)
2115
+ binary += String.fromCharCode(byte);
2116
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
2117
+ };
2118
+ var generateOpenRouterPKCE = async () => {
2119
+ const random = crypto.getRandomValues(new Uint8Array(32));
2120
+ const codeVerifier = toBase64Url(random);
2121
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
2122
+ return {
2123
+ codeChallenge: toBase64Url(new Uint8Array(digest)),
2124
+ codeChallengeMethod: "S256",
2125
+ codeVerifier
2126
+ };
2127
+ };
2128
+ var createOpenRouterAuthorizationUrl = (options = {}) => {
2129
+ const url = new URL("/auth", options.baseUrl ?? DEFAULT_SITE_URL);
2130
+ if (options.callbackUrl)
2131
+ url.searchParams.set("callback_url", options.callbackUrl);
2132
+ if (options.codeChallenge)
2133
+ url.searchParams.set("code_challenge", options.codeChallenge);
2134
+ if (options.codeChallengeMethod)
2135
+ url.searchParams.set("code_challenge_method", options.codeChallengeMethod);
2136
+ if (options.keyLabel)
2137
+ url.searchParams.set("key_label", options.keyLabel);
2138
+ return url.toString();
2139
+ };
2140
+ var exchangeOpenRouterAuthCode = async (body, options = {}) => {
2141
+ const response = await (options.fetch ?? globalThis.fetch)(`${(options.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/$/, "")}/auth/keys`, {
2142
+ body: JSON.stringify(body),
2143
+ headers: { "Content-Type": "application/json" },
2144
+ method: "POST"
2145
+ });
2146
+ if (!response.ok)
2147
+ throw ProviderError.fromResponse("openrouter", response.status, await response.text());
2148
+ return response.json();
2149
+ };
2150
+ var createOpenRouterKeyLinks = async (key, siteUrl = DEFAULT_SITE_URL) => {
2151
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(key)));
2152
+ const hash = Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
2153
+ const root = siteUrl.replace(/\/$/, "");
2154
+ return {
2155
+ hash,
2156
+ logsUrl: `${root}/logs?api_key_hash=${hash}`,
2157
+ settingsUrl: `${root}/keys/${hash}`
2158
+ };
2159
+ };
2160
+ var hexToBytes = (hex) => {
2161
+ if (!/^[0-9a-f]+$/iu.test(hex) || hex.length % 2 !== 0)
2162
+ return;
2163
+ const bytes = new Uint8Array(hex.length / 2);
2164
+ for (let index = 0;index < bytes.length; index += 1) {
2165
+ bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
2166
+ }
2167
+ return bytes;
2168
+ };
2169
+ var constantTimeEqual = (left, right) => {
2170
+ if (left.length !== right.length)
2171
+ return false;
2172
+ let mismatch = 0;
2173
+ for (let index = 0;index < left.length; index += 1)
2174
+ mismatch |= (left[index] ?? 0) ^ (right[index] ?? 0);
2175
+ return mismatch === 0;
2176
+ };
2177
+ var verifyOpenRouterWebhookSignature = async (options) => {
2178
+ const fields = new Map(options.header.split(",").map((part) => {
2179
+ const [key2, ...rest] = part.trim().split("=");
2180
+ return [key2, rest.join("=")];
2181
+ }));
2182
+ const timestamp = fields.get("t");
2183
+ const supplied = fields.get("v1");
2184
+ if (!timestamp || !supplied)
2185
+ return false;
2186
+ const timestampNumber = Number(timestamp);
2187
+ const now = options.nowSeconds ?? Math.floor(Date.now() / 1000);
2188
+ const tolerance = options.toleranceSeconds ?? 300;
2189
+ if (!Number.isFinite(timestampNumber) || Math.abs(now - timestampNumber) > tolerance)
2190
+ return false;
2191
+ const key = await crypto.subtle.importKey("raw", Uint8Array.from(toBytes(options.secret)).buffer, { hash: "SHA-256", name: "HMAC" }, false, ["sign"]);
2192
+ const prefix = new TextEncoder().encode(`${timestamp},`);
2193
+ const body = toBytes(options.body);
2194
+ const payload = new Uint8Array(prefix.length + body.length);
2195
+ payload.set(prefix);
2196
+ payload.set(body, prefix.length);
2197
+ const expected = new Uint8Array(await crypto.subtle.sign("HMAC", key, payload.buffer));
2198
+ const suppliedBytes = hexToBytes(supplied);
2199
+ return suppliedBytes ? constantTimeEqual(expected, suppliedBytes) : false;
2200
+ };
1354
2201
  var createOpenRouterClient = (config2) => {
1355
2202
  if (!config2.apiKey && !config2.tokenSource)
1356
2203
  throw new Error("createOpenRouterClient() requires either apiKey or tokenSource");
1357
- const baseUrl = (config2.baseUrl ?? DEFAULT_BASE_URL3).replace(/\/$/, "");
2204
+ const baseUrl = (config2.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/$/, "");
2205
+ const batchBaseUrl = (config2.batchBaseUrl ?? (config2.baseUrl ? new URL("../beta", `${baseUrl}/`).toString() : DEFAULT_BATCH_BASE_URL)).replace(/\/$/, "");
1358
2206
  const fetchImpl = config2.fetch ?? globalThis.fetch;
1359
2207
  const allowedModels = config2.allowedModels ? [...config2.allowedModels] : undefined;
1360
- const requestRaw = async (path, options = {}) => {
2208
+ const defaultWorkspaceId = config2.workspaceId;
2209
+ const requestRawAt = async (rootUrl, path, options = {}) => {
1361
2210
  const token = config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
1362
2211
  const suppliedHeaders = typeof config2.headers === "function" ? await config2.headers() : config2.headers ?? {};
1363
2212
  const headers = new Headers(suppliedHeaders);
@@ -1371,13 +2220,16 @@ var createOpenRouterClient = (config2) => {
1371
2220
  body = JSON.stringify(options.body);
1372
2221
  }
1373
2222
  const { query, ...requestInit } = options;
1374
- const response = await fetchImpl(withQuery(`${baseUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
2223
+ const response = await fetchImpl(withQuery(`${rootUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
1375
2224
  if (!response.ok) {
1376
2225
  throw ProviderError.fromResponse("openrouter", response.status, await response.text());
1377
2226
  }
1378
2227
  return response;
1379
2228
  };
2229
+ const requestRaw = (path, options = {}) => requestRawAt(baseUrl, path, options);
1380
2230
  const request = async (path, options = {}) => (await requestRaw(path, options)).json();
2231
+ const requestBatch = async (path, options = {}) => (await requestRawAt(batchBaseUrl, path, options)).json();
2232
+ const getBatch = (id) => requestBatch(`/batches/${encodeURIComponent(id)}`);
1381
2233
  const listModels = async (query) => {
1382
2234
  const result = await request("/models", { query });
1383
2235
  if (!allowedModels)
@@ -1396,10 +2248,45 @@ var createOpenRouterClient = (config2) => {
1396
2248
  };
1397
2249
  };
1398
2250
  return {
1399
- cancelBatch: (id) => request(`/batches/${encodeURIComponent(id)}/cancel`, {
2251
+ addWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/add`, { body: { user_ids: [...userIds] }, method: "POST" }),
2252
+ createAuthCode: (body) => request("/auth/keys/code", {
2253
+ body: {
2254
+ ...body,
2255
+ workspace_id: body.workspace_id ?? defaultWorkspaceId
2256
+ },
1400
2257
  method: "POST"
1401
2258
  }),
1402
- createBatch: (body) => request("/batches", { body, method: "POST" }),
2259
+ createPresetFromChatCompletions: (slug, body) => {
2260
+ assertAllowedModelsInValue(body, allowedModels);
2261
+ return request(`/presets/${encodeURIComponent(slug)}/chat/completions`, { body, method: "POST" });
2262
+ },
2263
+ createPresetFromMessages: (slug, body) => {
2264
+ assertAllowedModelsInValue(body, allowedModels);
2265
+ return request(`/presets/${encodeURIComponent(slug)}/messages`, { body, method: "POST" });
2266
+ },
2267
+ createPresetFromResponses: (slug, body) => {
2268
+ assertAllowedModelsInValue(body, allowedModels);
2269
+ return request(`/presets/${encodeURIComponent(slug)}/responses`, { body, method: "POST" });
2270
+ },
2271
+ createWorkspace: (body) => {
2272
+ assertAllowedModelsInValue(body, allowedModels);
2273
+ return request("/workspaces", {
2274
+ body,
2275
+ method: "POST"
2276
+ });
2277
+ },
2278
+ createBatch: (body) => {
2279
+ assertAllowedModel(body.model, allowedModels);
2280
+ return requestBatch("/batches", {
2281
+ body: {
2282
+ endpoint: body.endpoint,
2283
+ model: body.model,
2284
+ requests: body.requests,
2285
+ ...body.completion_window ? { completion_window: body.completion_window } : {}
2286
+ },
2287
+ method: "POST"
2288
+ });
2289
+ },
1403
2290
  createEmbedding: (body) => {
1404
2291
  assertAllowedModel(body.model, allowedModels);
1405
2292
  return request("/embeddings", {
@@ -1414,6 +2301,17 @@ var createOpenRouterClient = (config2) => {
1414
2301
  method: "POST"
1415
2302
  });
1416
2303
  },
2304
+ deleteFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
2305
+ deleteWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`, {
2306
+ method: "DELETE"
2307
+ }),
2308
+ deleteWorkspaceBudget: (id, interval) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { method: "DELETE" }),
2309
+ downloadFile: (id, workspaceId = defaultWorkspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
2310
+ query: { workspace_id: workspaceId }
2311
+ }),
2312
+ downloadVideo: (id, index = 0) => requestRaw(`/videos/${encodeURIComponent(id)}/content`, {
2313
+ query: { index }
2314
+ }),
1417
2315
  generateVideo: (body) => {
1418
2316
  assertAllowedModel(body.model, allowedModels);
1419
2317
  return request("/videos", {
@@ -1421,25 +2319,90 @@ var createOpenRouterClient = (config2) => {
1421
2319
  method: "POST"
1422
2320
  });
1423
2321
  },
1424
- getBatch: (id) => request(`/batches/${encodeURIComponent(id)}`),
2322
+ getBatch,
2323
+ getActivity: (query) => request("/activity", {
2324
+ query: {
2325
+ ...query,
2326
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2327
+ }
2328
+ }),
2329
+ getAnalyticsMeta: () => request("/analytics/meta"),
1425
2330
  getCredits: () => request("/credits"),
1426
2331
  getCurrentKey: () => request("/key"),
2332
+ getFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, {
2333
+ query: { workspace_id: workspaceId }
2334
+ }),
1427
2335
  getGeneration: (id) => request("/generation", {
1428
2336
  query: { id }
1429
2337
  }),
2338
+ getGenerationContent: (id) => request("/generation/content", {
2339
+ query: { id }
2340
+ }),
1430
2341
  getModelEndpoints: (model) => {
1431
2342
  assertAllowedModel(model, allowedModels);
1432
2343
  return request(`/models/${encodeModelPath(model)}/endpoints`);
1433
2344
  },
2345
+ getModel: (model) => {
2346
+ assertAllowedModel(model, allowedModels);
2347
+ return request(`/model/${encodeModelPath(model)}`);
2348
+ },
2349
+ getImageModelEndpoints: (model) => {
2350
+ assertAllowedModel(model, allowedModels);
2351
+ return request(`/images/models/${encodeModelPath(model)}/endpoints`);
2352
+ },
2353
+ getPreset: (slug) => request(`/presets/${encodeURIComponent(slug)}`),
2354
+ getPresetVersion: (slug, version) => request(`/presets/${encodeURIComponent(slug)}/versions/${encodeURIComponent(String(version))}`),
2355
+ getTaskClassifications: (window = "7d") => request("/classifications/task", {
2356
+ query: { window }
2357
+ }),
1434
2358
  getVideo: (id) => request(`/videos/${encodeURIComponent(id)}`),
2359
+ getWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`),
1435
2360
  listImageModels: async () => filterModelList(await request("/images/models")),
2361
+ listFiles: (query) => request("/files", {
2362
+ query: {
2363
+ ...query,
2364
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2365
+ }
2366
+ }),
1436
2367
  listModels,
1437
- listPresets: (offset = 0, limit = 100) => request("/presets", { query: { limit, offset } }),
2368
+ listUserModels: async () => filterModelList(await request("/models/user")),
2369
+ listZdrEndpoints: async () => {
2370
+ const result = await request("/endpoints/zdr");
2371
+ if (!allowedModels)
2372
+ return result;
2373
+ return {
2374
+ ...result,
2375
+ data: result.data.filter((endpoint) => allowedModels.some((rule) => openRouterModelMatchesRule(endpoint.model_id, rule)))
2376
+ };
2377
+ },
2378
+ countModels: (outputModalities) => request("/models/count", {
2379
+ query: { output_modalities: outputModalities }
2380
+ }),
2381
+ listPresets: (offset = 0, limit = 100) => request("/presets", {
2382
+ query: { limit, offset }
2383
+ }),
2384
+ listPresetVersions: (slug, offset = 0, limit = 100) => request(`/presets/${encodeURIComponent(slug)}/versions`, { query: { limit, offset } }),
1438
2385
  listProviders: () => request("/providers"),
1439
2386
  listRerankModels: async () => filterModelList(await request("/rerank/models")),
1440
2387
  listVideoModels: async () => filterModelList(await request("/videos/models")),
2388
+ listWorkspaceBudgets: (id) => request(`/workspaces/${encodeURIComponent(id)}/budgets`),
2389
+ listWorkspaces: (offset = 0, limit = 100) => request("/workspaces", { query: { limit, offset } }),
2390
+ queryAnalytics: (body) => request("/analytics/query", {
2391
+ body,
2392
+ method: "POST"
2393
+ }),
2394
+ removeWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/remove`, { body: { user_ids: [...userIds] }, method: "POST" }),
1441
2395
  request,
1442
2396
  requestRaw,
2397
+ streamImage: async function* (body, options = {}) {
2398
+ assertAllowedModel(body.model, allowedModels);
2399
+ const response = await requestRaw("/images", {
2400
+ ...options,
2401
+ body: { ...body, stream: true },
2402
+ method: "POST"
2403
+ });
2404
+ yield* parseImageSSE(response);
2405
+ },
1443
2406
  respond: (body) => {
1444
2407
  assertAllowedModel(body.model, allowedModels);
1445
2408
  return body.stream ? requestRaw("/responses", { body, method: "POST" }) : request("/responses", {
@@ -1471,12 +2434,57 @@ var createOpenRouterClient = (config2) => {
1471
2434
  body,
1472
2435
  method: "POST"
1473
2436
  });
2437
+ },
2438
+ uploadFile: (file, options = {}) => {
2439
+ const body = new FormData;
2440
+ if (options.filename)
2441
+ body.append("file", file, options.filename);
2442
+ else
2443
+ body.append("file", file);
2444
+ return request("/files", {
2445
+ body,
2446
+ method: "POST",
2447
+ query: { workspace_id: options.workspaceId ?? defaultWorkspaceId }
2448
+ });
2449
+ },
2450
+ updateWorkspace: (id, body) => {
2451
+ assertAllowedModelsInValue(body, allowedModels);
2452
+ return request(`/workspaces/${encodeURIComponent(id)}`, { body, method: "PATCH" });
2453
+ },
2454
+ upsertWorkspaceBudget: (id, interval, limitUsd) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { body: { limit_usd: limitUsd }, method: "PUT" }),
2455
+ waitForBatch: async (id, options = {}) => {
2456
+ const intervalMs = options.intervalMs ?? 1000;
2457
+ const timeoutMs = options.timeoutMs;
2458
+ if (!Number.isFinite(intervalMs) || intervalMs < 0)
2459
+ throw new Error("OpenRouter batch intervalMs must be non-negative");
2460
+ if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0))
2461
+ throw new Error("OpenRouter batch timeoutMs must be non-negative");
2462
+ const startedAt = Date.now();
2463
+ for (;; ) {
2464
+ options.signal?.throwIfAborted();
2465
+ const batch = await getBatch(id);
2466
+ if (TERMINAL_BATCH_STATUSES.has(batch.status))
2467
+ return batch;
2468
+ if (timeoutMs !== undefined && Date.now() - startedAt + intervalMs > timeoutMs)
2469
+ throw new Error(`Timed out waiting for OpenRouter batch "${id}"`);
2470
+ await new Promise((resolve, reject) => {
2471
+ const onAbort = () => {
2472
+ clearTimeout(timeout);
2473
+ reject(options.signal?.reason);
2474
+ };
2475
+ const timeout = setTimeout(() => {
2476
+ options.signal?.removeEventListener("abort", onAbort);
2477
+ resolve();
2478
+ }, intervalMs);
2479
+ options.signal?.addEventListener("abort", onAbort, { once: true });
2480
+ });
2481
+ }
1474
2482
  }
1475
2483
  };
1476
2484
  };
1477
2485
 
1478
2486
  // src/ai/providers/openrouter.ts
1479
- var DEFAULT_BASE_URL4 = "https://openrouter.ai/api";
2487
+ var DEFAULT_BASE_URL5 = "https://openrouter.ai/api";
1480
2488
  var MAX_APP_CATEGORIES = 2;
1481
2489
  var withoutLatestPrefix2 = (model) => model.startsWith("~") ? model.slice(1) : model;
1482
2490
  var modelForOpenAICapabilities = (model) => {
@@ -1607,7 +2615,7 @@ var assertAllowedPreset = (preset, allowedPresets) => {
1607
2615
  var assertIndirectModels = (value, allowedModels, key = "") => {
1608
2616
  if (key === "model" && typeof value === "string")
1609
2617
  assertAllowedModel2(value, allowedModels);
1610
- if (key === "models" && Array.isArray(value)) {
2618
+ if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
1611
2619
  for (const model of value) {
1612
2620
  if (typeof model === "string")
1613
2621
  assertAllowedModel2(model, allowedModels);
@@ -1638,6 +2646,7 @@ var assertRequestOptions = (options, allowedModels, allowedPresets, allowedProvi
1638
2646
  assertAllowedModel2(model, allowedModels);
1639
2647
  }
1640
2648
  assertIndirectModels(options.serverTools, allowedModels);
2649
+ assertIndirectModels(options.messagesTools, allowedModels);
1641
2650
  assertIndirectModels(options.plugins, allowedModels);
1642
2651
  if (options.extraBody) {
1643
2652
  const unsafe = Object.keys(options.extraBody).find((key) => SECURITY_SENSITIVE_EXTRA_BODY_FIELDS.has(key));
@@ -1656,17 +2665,41 @@ var snapshotPolicy = (config2) => ({
1656
2665
  allowedModels: config2.allowedModels ? [...config2.allowedModels] : undefined,
1657
2666
  allowedPresets: config2.allowedPresets ? [...config2.allowedPresets] : undefined
1658
2667
  });
1659
- var transformOpenRouterRequest = (config2, allowedModels, allowedPresets, body, params) => {
2668
+ var transformOpenRouterRequest = (config2, allowedModels, allowedPresets, body, params, skin = "openai") => {
1660
2669
  const options = requestOptionsFor(params, config2.requestOptions);
1661
2670
  assertRequestOptions(options, allowedModels, allowedPresets, config2.allowedProviders);
1662
2671
  const transformed = { ...body, ...options.extraBody };
1663
- if (params.reasoning?.budgetTokens !== undefined) {
1664
- transformed.reasoning = { max_tokens: params.reasoning.budgetTokens };
1665
- delete transformed.reasoning_effort;
1666
- } else if (params.reasoning?.effort) {
1667
- transformed.reasoning = { effort: params.reasoning.effort };
1668
- delete transformed.reasoning_effort;
1669
- }
2672
+ if (options.audioOutput) {
2673
+ transformed.audio = options.audioOutput;
2674
+ transformed.modalities = ["text", "audio"];
2675
+ }
2676
+ if (skin === "openai") {
2677
+ const requestedReasoning = {};
2678
+ if (params.reasoning?.budgetTokens !== undefined) {
2679
+ requestedReasoning.max_tokens = params.reasoning.budgetTokens;
2680
+ delete transformed.reasoning_effort;
2681
+ } else if (params.reasoning?.effort) {
2682
+ requestedReasoning.effort = params.reasoning.effort;
2683
+ delete transformed.reasoning_effort;
2684
+ }
2685
+ if (options.reasoning) {
2686
+ Object.assign(requestedReasoning, options.reasoning);
2687
+ if (options.reasoning.maxTokens !== undefined) {
2688
+ requestedReasoning.max_tokens = options.reasoning.maxTokens;
2689
+ delete requestedReasoning.maxTokens;
2690
+ }
2691
+ }
2692
+ if (Object.keys(requestedReasoning).length > 0)
2693
+ transformed.reasoning = requestedReasoning;
2694
+ }
2695
+ const automaticCacheControl = params.promptCaching === true || params.cacheSystemPrompt === true ? { type: "ephemeral" } : undefined;
2696
+ const cacheControl = options.cacheControl ?? automaticCacheControl;
2697
+ if (cacheControl)
2698
+ transformed.cache_control = cacheControl;
2699
+ if (options.promptCacheKey)
2700
+ transformed.prompt_cache_key = options.promptCacheKey;
2701
+ if (options.promptCacheOptions)
2702
+ transformed.prompt_cache_options = options.promptCacheOptions;
1670
2703
  const routing = mapRouting({ ...config2.routing, ...options.routing }, config2.allowedProviders);
1671
2704
  if (Object.keys(routing).length > 0)
1672
2705
  transformed.provider = routing;
@@ -1686,12 +2719,22 @@ var transformOpenRouterRequest = (config2, allowedModels, allowedPresets, body,
1686
2719
  ...options.serverTools
1687
2720
  ];
1688
2721
  }
2722
+ if (options.messagesTools) {
2723
+ if (skin !== "messages")
2724
+ throw new Error("OpenRouter messagesTools requires openrouterMessages()");
2725
+ transformed.tools = [
2726
+ ...Array.isArray(transformed.tools) ? transformed.tools : [],
2727
+ ...options.messagesTools
2728
+ ];
2729
+ }
1689
2730
  if (options.serviceTier)
1690
2731
  transformed.service_tier = options.serviceTier;
1691
2732
  if (options.sessionId)
1692
2733
  transformed.session_id = options.sessionId;
1693
2734
  if (options.stopServerToolsWhen)
1694
2735
  transformed.stop_server_tools_when = options.stopServerToolsWhen;
2736
+ if (options.trace)
2737
+ transformed.trace = options.trace;
1695
2738
  if (options.transforms)
1696
2739
  transformed.transforms = [...options.transforms];
1697
2740
  if (options.user)
@@ -1721,7 +2764,7 @@ var openrouter = (config2) => {
1721
2764
  const { allowedModels, allowedPresets } = snapshotPolicy(config2);
1722
2765
  const provider = openai({
1723
2766
  apiKey: config2.apiKey,
1724
- baseUrl: config2.baseUrl ?? DEFAULT_BASE_URL4,
2767
+ baseUrl: config2.baseUrl ?? DEFAULT_BASE_URL5,
1725
2768
  fetch: config2.fetch,
1726
2769
  headers: (params) => resolveAttributionHeaders(config2, params),
1727
2770
  modelForCapabilities: modelForOpenAICapabilities,
@@ -1736,7 +2779,7 @@ var openrouterResponses = (config2) => {
1736
2779
  const { allowedModels, allowedPresets } = snapshotPolicy(config2);
1737
2780
  const provider = openaiResponses({
1738
2781
  apiKey: config2.apiKey,
1739
- baseUrl: config2.baseUrl ?? DEFAULT_BASE_URL4,
2782
+ baseUrl: config2.baseUrl ?? DEFAULT_BASE_URL5,
1740
2783
  fetch: config2.fetch,
1741
2784
  headers: (params) => resolveAttributionHeaders(config2, params),
1742
2785
  modelForCapabilities: modelForOpenAICapabilities,
@@ -1746,12 +2789,35 @@ var openrouterResponses = (config2) => {
1746
2789
  });
1747
2790
  return withOpenRouterPolicy(provider, allowedModels, allowedPresets);
1748
2791
  };
2792
+ var openrouterMessages = (config2) => {
2793
+ assertRoutingPolicy(config2);
2794
+ const { allowedModels, allowedPresets } = snapshotPolicy(config2);
2795
+ const provider = anthropic({
2796
+ apiKey: config2.apiKey,
2797
+ authStyle: "bearer",
2798
+ baseUrl: config2.baseUrl ?? DEFAULT_BASE_URL5,
2799
+ fetch: config2.fetch,
2800
+ headers: (params) => resolveAttributionHeaders(config2, params),
2801
+ providerName: "openrouter",
2802
+ tokenSource: config2.tokenSource,
2803
+ transformRequestBody: (body, params) => transformOpenRouterRequest(config2, allowedModels, allowedPresets, body, params, "messages")
2804
+ });
2805
+ return withOpenRouterPolicy(provider, allowedModels, allowedPresets);
2806
+ };
1749
2807
  export {
2808
+ verifyOpenRouterWebhookSignature,
1750
2809
  openrouterResponses,
2810
+ openrouterMessages,
1751
2811
  openrouter,
1752
2812
  openRouterModelMatchesRule,
1753
- createOpenRouterClient
2813
+ generateOpenRouterPKCE,
2814
+ exchangeOpenRouterAuthCode,
2815
+ estimateOpenRouterModelCost,
2816
+ estimateOpenRouterCost,
2817
+ createOpenRouterKeyLinks,
2818
+ createOpenRouterClient,
2819
+ createOpenRouterAuthorizationUrl
1754
2820
  };
1755
2821
 
1756
- //# debugId=BFDE217D89D0CFF064756E2164756E21
2822
+ //# debugId=FABF06EDFC815F9A64756E2164756E21
1757
2823
  //# sourceMappingURL=openrouter.js.map