@openrouter/ai-sdk-provider 2.0.4 → 2.1.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
@@ -9,6 +9,9 @@ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
9
9
  var __getProtoOf = Object.getPrototypeOf;
10
10
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
11
  var __propIsEnum = Object.prototype.propertyIsEnumerable;
12
+ var __typeError = (msg) => {
13
+ throw TypeError(msg);
14
+ };
12
15
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
13
16
  var __spreadValues = (a, b) => {
14
17
  for (var prop in b || (b = {}))
@@ -55,6 +58,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
55
58
  mod
56
59
  ));
57
60
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
61
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
62
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
63
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
58
64
 
59
65
  // src/index.ts
60
66
  var index_exports = {};
@@ -2349,6 +2355,54 @@ function createFinishReason(unified, raw) {
2349
2355
  return { unified, raw };
2350
2356
  }
2351
2357
 
2358
+ // src/utils/reasoning-details-duplicate-tracker.ts
2359
+ var _seenKeys;
2360
+ var ReasoningDetailsDuplicateTracker = class {
2361
+ constructor() {
2362
+ __privateAdd(this, _seenKeys, /* @__PURE__ */ new Set());
2363
+ }
2364
+ /**
2365
+ * Attempts to track a detail.
2366
+ * Returns true if this is a NEW detail (not seen before and has valid key),
2367
+ * false if it was skipped (no valid key) or already seen (duplicate).
2368
+ */
2369
+ upsert(detail) {
2370
+ const key = this.getCanonicalKey(detail);
2371
+ if (key === null) {
2372
+ return false;
2373
+ }
2374
+ if (__privateGet(this, _seenKeys).has(key)) {
2375
+ return false;
2376
+ }
2377
+ __privateGet(this, _seenKeys).add(key);
2378
+ return true;
2379
+ }
2380
+ getCanonicalKey(detail) {
2381
+ switch (detail.type) {
2382
+ case "reasoning.summary" /* Summary */:
2383
+ return detail.summary;
2384
+ case "reasoning.encrypted" /* Encrypted */:
2385
+ if (detail.id) {
2386
+ return detail.id;
2387
+ }
2388
+ return detail.data;
2389
+ case "reasoning.text" /* Text */: {
2390
+ if (detail.text) {
2391
+ return detail.text;
2392
+ }
2393
+ if (detail.signature) {
2394
+ return detail.signature;
2395
+ }
2396
+ return null;
2397
+ }
2398
+ default: {
2399
+ return null;
2400
+ }
2401
+ }
2402
+ }
2403
+ };
2404
+ _seenKeys = new WeakMap();
2405
+
2352
2406
  // src/types/openrouter-chat-completions-input.ts
2353
2407
  var OPENROUTER_AUDIO_FORMATS = [
2354
2408
  "wav",
@@ -2480,6 +2534,7 @@ function getCacheControl(providerMetadata) {
2480
2534
  function convertToOpenRouterChatMessages(prompt) {
2481
2535
  var _a16, _b16, _c, _d, _e, _f, _g, _h;
2482
2536
  const messages = [];
2537
+ const reasoningDetailsTracker = new ReasoningDetailsDuplicateTracker();
2483
2538
  for (const { role, content, providerOptions } of prompt) {
2484
2539
  switch (role) {
2485
2540
  case "system": {
@@ -2622,7 +2677,17 @@ function convertToOpenRouterChatMessages(prompt) {
2622
2677
  const parsedProviderOptions = OpenRouterProviderOptionsSchema.safeParse(providerOptions);
2623
2678
  const messageReasoningDetails = parsedProviderOptions.success ? (_e = (_d = parsedProviderOptions.data) == null ? void 0 : _d.openrouter) == null ? void 0 : _e.reasoning_details : void 0;
2624
2679
  const messageAnnotations = parsedProviderOptions.success ? (_g = (_f = parsedProviderOptions.data) == null ? void 0 : _f.openrouter) == null ? void 0 : _g.annotations : void 0;
2625
- const finalReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) && messageReasoningDetails.length > 0 ? messageReasoningDetails : findFirstReasoningDetails(content);
2680
+ const candidateReasoningDetails = messageReasoningDetails && Array.isArray(messageReasoningDetails) && messageReasoningDetails.length > 0 ? messageReasoningDetails : findFirstReasoningDetails(content);
2681
+ let finalReasoningDetails;
2682
+ if (candidateReasoningDetails && candidateReasoningDetails.length > 0) {
2683
+ const uniqueDetails = [];
2684
+ for (const detail of candidateReasoningDetails) {
2685
+ if (reasoningDetailsTracker.upsert(detail)) {
2686
+ uniqueDetails.push(detail);
2687
+ }
2688
+ }
2689
+ finalReasoningDetails = uniqueDetails.length > 0 ? uniqueDetails : void 0;
2690
+ }
2626
2691
  messages.push({
2627
2692
  role: "assistant",
2628
2693
  content: text,
@@ -2791,13 +2856,14 @@ var OpenRouterNonStreamChatCompletionResponseSchema = import_v46.z.union([
2791
2856
  annotations: import_v46.z.array(
2792
2857
  import_v46.z.union([
2793
2858
  // URL citation from web search
2859
+ // title, start_index, end_index are optional as some upstream providers may omit them
2794
2860
  import_v46.z.object({
2795
2861
  type: import_v46.z.literal("url_citation"),
2796
2862
  url_citation: import_v46.z.object({
2797
- end_index: import_v46.z.number(),
2798
- start_index: import_v46.z.number(),
2799
- title: import_v46.z.string(),
2800
2863
  url: import_v46.z.string(),
2864
+ title: import_v46.z.string().optional(),
2865
+ start_index: import_v46.z.number().optional(),
2866
+ end_index: import_v46.z.number().optional(),
2801
2867
  content: import_v46.z.string().optional()
2802
2868
  }).passthrough()
2803
2869
  }).passthrough(),
@@ -2874,13 +2940,14 @@ var OpenRouterStreamChatCompletionChunkSchema = import_v46.z.union([
2874
2940
  annotations: import_v46.z.array(
2875
2941
  import_v46.z.union([
2876
2942
  // URL citation from web search
2943
+ // title, start_index, end_index are optional as some upstream providers may omit them
2877
2944
  import_v46.z.object({
2878
2945
  type: import_v46.z.literal("url_citation"),
2879
2946
  url_citation: import_v46.z.object({
2880
- end_index: import_v46.z.number(),
2881
- start_index: import_v46.z.number(),
2882
- title: import_v46.z.string(),
2883
2947
  url: import_v46.z.string(),
2948
+ title: import_v46.z.string().optional(),
2949
+ start_index: import_v46.z.number().optional(),
2950
+ end_index: import_v46.z.number().optional(),
2884
2951
  content: import_v46.z.string().optional()
2885
2952
  }).passthrough()
2886
2953
  }).passthrough(),
@@ -3027,7 +3094,7 @@ var OpenRouterChatLanguageModel = class {
3027
3094
  return baseArgs;
3028
3095
  }
3029
3096
  async doGenerate(options) {
3030
- var _a16, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
3097
+ var _a16, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
3031
3098
  const providerOptions = options.providerOptions || {};
3032
3099
  const openrouterOptions = providerOptions.openrouter || {};
3033
3100
  const args = __spreadValues(__spreadValues({}, this.getArgs(options)), openrouterOptions);
@@ -3077,7 +3144,8 @@ var OpenRouterChatLanguageModel = class {
3077
3144
  total: (_d = response.usage.completion_tokens) != null ? _d : 0,
3078
3145
  text: void 0,
3079
3146
  reasoning: (_f = (_e = response.usage.completion_tokens_details) == null ? void 0 : _e.reasoning_tokens) != null ? _f : void 0
3080
- }
3147
+ },
3148
+ raw: response.usage
3081
3149
  } : {
3082
3150
  inputTokens: {
3083
3151
  total: 0,
@@ -3089,7 +3157,8 @@ var OpenRouterChatLanguageModel = class {
3089
3157
  total: 0,
3090
3158
  text: void 0,
3091
3159
  reasoning: void 0
3092
- }
3160
+ },
3161
+ raw: void 0
3093
3162
  };
3094
3163
  const reasoningDetails = (_g = choice.message.reasoning_details) != null ? _g : [];
3095
3164
  const reasoning = reasoningDetails.length > 0 ? reasoningDetails.map((detail) => {
@@ -3189,17 +3258,19 @@ var OpenRouterChatLanguageModel = class {
3189
3258
  sourceType: "url",
3190
3259
  id: annotation.url_citation.url,
3191
3260
  url: annotation.url_citation.url,
3192
- title: annotation.url_citation.title,
3261
+ title: (_j = annotation.url_citation.title) != null ? _j : "",
3193
3262
  providerMetadata: {
3194
3263
  openrouter: {
3195
- content: annotation.url_citation.content || ""
3264
+ content: (_k = annotation.url_citation.content) != null ? _k : "",
3265
+ startIndex: (_l = annotation.url_citation.start_index) != null ? _l : 0,
3266
+ endIndex: (_m = annotation.url_citation.end_index) != null ? _m : 0
3196
3267
  }
3197
3268
  }
3198
3269
  });
3199
3270
  }
3200
3271
  }
3201
3272
  }
3202
- const fileAnnotations = (_j = choice.message.annotations) == null ? void 0 : _j.filter(
3273
+ const fileAnnotations = (_n = choice.message.annotations) == null ? void 0 : _n.filter(
3203
3274
  (a) => a.type === "file"
3204
3275
  );
3205
3276
  const hasToolCalls = choice.message.tool_calls && choice.message.tool_calls.length > 0;
@@ -3207,7 +3278,7 @@ var OpenRouterChatLanguageModel = class {
3207
3278
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3208
3279
  );
3209
3280
  const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
3210
- const effectiveFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_k = choice.finish_reason) != null ? _k : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3281
+ const effectiveFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_o = choice.finish_reason) != null ? _o : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3211
3282
  return {
3212
3283
  content,
3213
3284
  finishReason: effectiveFinishReason,
@@ -3215,23 +3286,22 @@ var OpenRouterChatLanguageModel = class {
3215
3286
  warnings: [],
3216
3287
  providerMetadata: {
3217
3288
  openrouter: OpenRouterProviderMetadataSchema.parse({
3218
- provider: (_l = response.provider) != null ? _l : "",
3219
- reasoning_details: (_m = choice.message.reasoning_details) != null ? _m : [],
3289
+ provider: (_p = response.provider) != null ? _p : "",
3290
+ reasoning_details: (_q = choice.message.reasoning_details) != null ? _q : [],
3220
3291
  annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
3221
- usage: __spreadValues(__spreadValues(__spreadValues({
3222
- promptTokens: (_n = usageInfo.inputTokens.total) != null ? _n : 0,
3223
- completionTokens: (_o = usageInfo.outputTokens.total) != null ? _o : 0,
3224
- totalTokens: ((_p = usageInfo.inputTokens.total) != null ? _p : 0) + ((_q = usageInfo.outputTokens.total) != null ? _q : 0),
3225
- cost: (_r = response.usage) == null ? void 0 : _r.cost
3226
- }, ((_t = (_s = response.usage) == null ? void 0 : _s.prompt_tokens_details) == null ? void 0 : _t.cached_tokens) != null ? {
3292
+ usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
3293
+ promptTokens: (_r = usageInfo.inputTokens.total) != null ? _r : 0,
3294
+ completionTokens: (_s = usageInfo.outputTokens.total) != null ? _s : 0,
3295
+ totalTokens: ((_t = usageInfo.inputTokens.total) != null ? _t : 0) + ((_u = usageInfo.outputTokens.total) != null ? _u : 0)
3296
+ }, ((_v = response.usage) == null ? void 0 : _v.cost) != null ? { cost: response.usage.cost } : {}), ((_x = (_w = response.usage) == null ? void 0 : _w.prompt_tokens_details) == null ? void 0 : _x.cached_tokens) != null ? {
3227
3297
  promptTokensDetails: {
3228
3298
  cachedTokens: response.usage.prompt_tokens_details.cached_tokens
3229
3299
  }
3230
- } : {}), ((_v = (_u = response.usage) == null ? void 0 : _u.completion_tokens_details) == null ? void 0 : _v.reasoning_tokens) != null ? {
3300
+ } : {}), ((_z = (_y = response.usage) == null ? void 0 : _y.completion_tokens_details) == null ? void 0 : _z.reasoning_tokens) != null ? {
3231
3301
  completionTokensDetails: {
3232
3302
  reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
3233
3303
  }
3234
- } : {}), ((_x = (_w = response.usage) == null ? void 0 : _w.cost_details) == null ? void 0 : _x.upstream_inference_cost) != null ? {
3304
+ } : {}), ((_B = (_A = response.usage) == null ? void 0 : _A.cost_details) == null ? void 0 : _B.upstream_inference_cost) != null ? {
3235
3305
  costDetails: {
3236
3306
  upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
3237
3307
  }
@@ -3284,9 +3354,11 @@ var OpenRouterChatLanguageModel = class {
3284
3354
  total: void 0,
3285
3355
  text: void 0,
3286
3356
  reasoning: void 0
3287
- }
3357
+ },
3358
+ raw: void 0
3288
3359
  };
3289
3360
  const openrouterUsage = {};
3361
+ let rawUsage;
3290
3362
  const accumulatedReasoningDetails = [];
3291
3363
  let reasoningDetailsAttachedToToolCall = false;
3292
3364
  const accumulatedFileAnnotations = [];
@@ -3300,7 +3372,10 @@ var OpenRouterChatLanguageModel = class {
3300
3372
  stream: response.pipeThrough(
3301
3373
  new TransformStream({
3302
3374
  transform(chunk, controller) {
3303
- var _a17, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
3375
+ var _a17, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
3376
+ if (options.includeRawChunks) {
3377
+ controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
3378
+ }
3304
3379
  if (!chunk.success) {
3305
3380
  finishReason = createFinishReason("error");
3306
3381
  controller.enqueue({ type: "error", error: chunk.error });
@@ -3331,6 +3406,7 @@ var OpenRouterChatLanguageModel = class {
3331
3406
  if (value.usage != null) {
3332
3407
  usage.inputTokens.total = value.usage.prompt_tokens;
3333
3408
  usage.outputTokens.total = value.usage.completion_tokens;
3409
+ rawUsage = value.usage;
3334
3410
  openrouterUsage.promptTokens = value.usage.prompt_tokens;
3335
3411
  if (value.usage.prompt_tokens_details) {
3336
3412
  const cachedInputTokens = (_a17 = value.usage.prompt_tokens_details.cached_tokens) != null ? _a17 : 0;
@@ -3347,7 +3423,9 @@ var OpenRouterChatLanguageModel = class {
3347
3423
  reasoningTokens
3348
3424
  };
3349
3425
  }
3350
- openrouterUsage.cost = value.usage.cost;
3426
+ if (value.usage.cost != null) {
3427
+ openrouterUsage.cost = value.usage.cost;
3428
+ }
3351
3429
  openrouterUsage.totalTokens = value.usage.total_tokens;
3352
3430
  const upstreamInferenceCost = (_c = value.usage.cost_details) == null ? void 0 : _c.upstream_inference_cost;
3353
3431
  if (upstreamInferenceCost != null) {
@@ -3460,10 +3538,12 @@ var OpenRouterChatLanguageModel = class {
3460
3538
  sourceType: "url",
3461
3539
  id: annotation.url_citation.url,
3462
3540
  url: annotation.url_citation.url,
3463
- title: annotation.url_citation.title,
3541
+ title: (_d = annotation.url_citation.title) != null ? _d : "",
3464
3542
  providerMetadata: {
3465
3543
  openrouter: {
3466
- content: annotation.url_citation.content || ""
3544
+ content: (_e = annotation.url_citation.content) != null ? _e : "",
3545
+ startIndex: (_f = annotation.url_citation.start_index) != null ? _f : 0,
3546
+ endIndex: (_g = annotation.url_citation.end_index) != null ? _g : 0
3467
3547
  }
3468
3548
  }
3469
3549
  });
@@ -3479,7 +3559,7 @@ var OpenRouterChatLanguageModel = class {
3479
3559
  }
3480
3560
  if (delta.tool_calls != null) {
3481
3561
  for (const toolCallDelta of delta.tool_calls) {
3482
- const index = (_d = toolCallDelta.index) != null ? _d : toolCalls.length - 1;
3562
+ const index = (_h = toolCallDelta.index) != null ? _h : toolCalls.length - 1;
3483
3563
  if (toolCalls[index] == null) {
3484
3564
  if (toolCallDelta.type !== "function") {
3485
3565
  throw new InvalidResponseDataError({
@@ -3493,7 +3573,7 @@ var OpenRouterChatLanguageModel = class {
3493
3573
  message: `Expected 'id' to be a string.`
3494
3574
  });
3495
3575
  }
3496
- if (((_e = toolCallDelta.function) == null ? void 0 : _e.name) == null) {
3576
+ if (((_i = toolCallDelta.function) == null ? void 0 : _i.name) == null) {
3497
3577
  throw new InvalidResponseDataError({
3498
3578
  data: toolCallDelta,
3499
3579
  message: `Expected 'function.name' to be a string.`
@@ -3504,7 +3584,7 @@ var OpenRouterChatLanguageModel = class {
3504
3584
  type: "function",
3505
3585
  function: {
3506
3586
  name: toolCallDelta.function.name,
3507
- arguments: (_f = toolCallDelta.function.arguments) != null ? _f : ""
3587
+ arguments: (_j = toolCallDelta.function.arguments) != null ? _j : ""
3508
3588
  },
3509
3589
  inputStarted: false,
3510
3590
  sent: false
@@ -3516,7 +3596,7 @@ var OpenRouterChatLanguageModel = class {
3516
3596
  message: `Tool call at index ${index} is missing after creation.`
3517
3597
  });
3518
3598
  }
3519
- if (((_g = toolCall2.function) == null ? void 0 : _g.name) != null && ((_h = toolCall2.function) == null ? void 0 : _h.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3599
+ if (((_k = toolCall2.function) == null ? void 0 : _k.name) != null && ((_l = toolCall2.function) == null ? void 0 : _l.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3520
3600
  toolCall2.inputStarted = true;
3521
3601
  controller.enqueue({
3522
3602
  type: "tool-input-start",
@@ -3567,18 +3647,18 @@ var OpenRouterChatLanguageModel = class {
3567
3647
  toolName: toolCall.function.name
3568
3648
  });
3569
3649
  }
3570
- if (((_i = toolCallDelta.function) == null ? void 0 : _i.arguments) != null) {
3571
- toolCall.function.arguments += (_k = (_j = toolCallDelta.function) == null ? void 0 : _j.arguments) != null ? _k : "";
3650
+ if (((_m = toolCallDelta.function) == null ? void 0 : _m.arguments) != null) {
3651
+ toolCall.function.arguments += (_o = (_n = toolCallDelta.function) == null ? void 0 : _n.arguments) != null ? _o : "";
3572
3652
  }
3573
3653
  controller.enqueue({
3574
3654
  type: "tool-input-delta",
3575
3655
  id: toolCall.id,
3576
- delta: (_l = toolCallDelta.function.arguments) != null ? _l : ""
3656
+ delta: (_p = toolCallDelta.function.arguments) != null ? _p : ""
3577
3657
  });
3578
- if (((_m = toolCall.function) == null ? void 0 : _m.name) != null && ((_n = toolCall.function) == null ? void 0 : _n.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3658
+ if (((_q = toolCall.function) == null ? void 0 : _q.name) != null && ((_r = toolCall.function) == null ? void 0 : _r.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3579
3659
  controller.enqueue({
3580
3660
  type: "tool-call",
3581
- toolCallId: (_o = toolCall.id) != null ? _o : generateId(),
3661
+ toolCallId: (_s = toolCall.id) != null ? _s : generateId(),
3582
3662
  toolName: toolCall.function.name,
3583
3663
  input: toolCall.function.arguments,
3584
3664
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -3655,6 +3735,7 @@ var OpenRouterChatLanguageModel = class {
3655
3735
  if (accumulatedFileAnnotations.length > 0) {
3656
3736
  openrouterMetadata.annotations = accumulatedFileAnnotations;
3657
3737
  }
3738
+ usage.raw = rawUsage;
3658
3739
  controller.enqueue({
3659
3740
  type: "finish",
3660
3741
  finishReason,
@@ -3782,6 +3863,7 @@ var OpenRouterCompletionChunkSchema = import_v47.z.union([
3782
3863
  import_v47.z.object({
3783
3864
  id: import_v47.z.string().optional(),
3784
3865
  model: import_v47.z.string().optional(),
3866
+ provider: import_v47.z.string().optional(),
3785
3867
  choices: import_v47.z.array(
3786
3868
  import_v47.z.object({
3787
3869
  text: import_v47.z.string(),
@@ -3889,7 +3971,7 @@ var OpenRouterCompletionLanguageModel = class {
3889
3971
  }, this.config.extraBody), this.settings.extraBody);
3890
3972
  }
3891
3973
  async doGenerate(options) {
3892
- var _a16, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3974
+ var _a16, _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
3893
3975
  const providerOptions = options.providerOptions || {};
3894
3976
  const openrouterOptions = providerOptions.openrouter || {};
3895
3977
  const args = __spreadValues(__spreadValues({}, this.getArgs(options)), openrouterOptions);
@@ -3946,9 +4028,32 @@ var OpenRouterCompletionLanguageModel = class {
3946
4028
  total: (_h = (_g = response.usage) == null ? void 0 : _g.completion_tokens) != null ? _h : 0,
3947
4029
  text: void 0,
3948
4030
  reasoning: (_k = (_j = (_i = response.usage) == null ? void 0 : _i.completion_tokens_details) == null ? void 0 : _j.reasoning_tokens) != null ? _k : void 0
3949
- }
4031
+ },
4032
+ raw: (_l = response.usage) != null ? _l : void 0
3950
4033
  },
3951
4034
  warnings: [],
4035
+ providerMetadata: {
4036
+ openrouter: OpenRouterProviderMetadataSchema.parse({
4037
+ provider: (_m = response.provider) != null ? _m : "",
4038
+ usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
4039
+ promptTokens: (_o = (_n = response.usage) == null ? void 0 : _n.prompt_tokens) != null ? _o : 0,
4040
+ completionTokens: (_q = (_p = response.usage) == null ? void 0 : _p.completion_tokens) != null ? _q : 0,
4041
+ totalTokens: ((_s = (_r = response.usage) == null ? void 0 : _r.prompt_tokens) != null ? _s : 0) + ((_u = (_t = response.usage) == null ? void 0 : _t.completion_tokens) != null ? _u : 0)
4042
+ }, ((_v = response.usage) == null ? void 0 : _v.cost) != null ? { cost: response.usage.cost } : {}), ((_x = (_w = response.usage) == null ? void 0 : _w.prompt_tokens_details) == null ? void 0 : _x.cached_tokens) != null ? {
4043
+ promptTokensDetails: {
4044
+ cachedTokens: response.usage.prompt_tokens_details.cached_tokens
4045
+ }
4046
+ } : {}), ((_z = (_y = response.usage) == null ? void 0 : _y.completion_tokens_details) == null ? void 0 : _z.reasoning_tokens) != null ? {
4047
+ completionTokensDetails: {
4048
+ reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
4049
+ }
4050
+ } : {}), ((_B = (_A = response.usage) == null ? void 0 : _A.cost_details) == null ? void 0 : _B.upstream_inference_cost) != null ? {
4051
+ costDetails: {
4052
+ upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
4053
+ }
4054
+ } : {})
4055
+ })
4056
+ },
3952
4057
  response: {
3953
4058
  headers: responseHeaders
3954
4059
  }
@@ -3988,14 +4093,20 @@ var OpenRouterCompletionLanguageModel = class {
3988
4093
  total: void 0,
3989
4094
  text: void 0,
3990
4095
  reasoning: void 0
3991
- }
4096
+ },
4097
+ raw: void 0
3992
4098
  };
3993
4099
  const openrouterUsage = {};
4100
+ let provider;
4101
+ let rawUsage;
3994
4102
  return {
3995
4103
  stream: response.pipeThrough(
3996
4104
  new TransformStream({
3997
4105
  transform(chunk, controller) {
3998
4106
  var _a16, _b16, _c;
4107
+ if (options.includeRawChunks) {
4108
+ controller.enqueue({ type: "raw", rawValue: chunk.rawValue });
4109
+ }
3999
4110
  if (!chunk.success) {
4000
4111
  finishReason = createFinishReason("error");
4001
4112
  controller.enqueue({ type: "error", error: chunk.error });
@@ -4007,9 +4118,13 @@ var OpenRouterCompletionLanguageModel = class {
4007
4118
  controller.enqueue({ type: "error", error: value.error });
4008
4119
  return;
4009
4120
  }
4121
+ if (value.provider) {
4122
+ provider = value.provider;
4123
+ }
4010
4124
  if (value.usage != null) {
4011
4125
  usage.inputTokens.total = value.usage.prompt_tokens;
4012
4126
  usage.outputTokens.total = value.usage.completion_tokens;
4127
+ rawUsage = value.usage;
4013
4128
  openrouterUsage.promptTokens = value.usage.prompt_tokens;
4014
4129
  if (value.usage.prompt_tokens_details) {
4015
4130
  const cachedInputTokens = (_a16 = value.usage.prompt_tokens_details.cached_tokens) != null ? _a16 : 0;
@@ -4026,7 +4141,9 @@ var OpenRouterCompletionLanguageModel = class {
4026
4141
  reasoningTokens
4027
4142
  };
4028
4143
  }
4029
- openrouterUsage.cost = value.usage.cost;
4144
+ if (value.usage.cost != null) {
4145
+ openrouterUsage.cost = value.usage.cost;
4146
+ }
4030
4147
  openrouterUsage.totalTokens = value.usage.total_tokens;
4031
4148
  const upstreamInferenceCost = (_c = value.usage.cost_details) == null ? void 0 : _c.upstream_inference_cost;
4032
4149
  if (upstreamInferenceCost != null) {
@@ -4048,14 +4165,19 @@ var OpenRouterCompletionLanguageModel = class {
4048
4165
  }
4049
4166
  },
4050
4167
  flush(controller) {
4168
+ usage.raw = rawUsage;
4169
+ const openrouterMetadata = {
4170
+ usage: openrouterUsage
4171
+ };
4172
+ if (provider !== void 0) {
4173
+ openrouterMetadata.provider = provider;
4174
+ }
4051
4175
  controller.enqueue({
4052
4176
  type: "finish",
4053
4177
  finishReason,
4054
4178
  usage,
4055
4179
  providerMetadata: {
4056
- openrouter: {
4057
- usage: openrouterUsage
4058
- }
4180
+ openrouter: openrouterMetadata
4059
4181
  }
4060
4182
  });
4061
4183
  }
@@ -4085,6 +4207,7 @@ var OpenRouterEmbeddingResponseSchema = import_v48.z.object({
4085
4207
  object: import_v48.z.literal("list"),
4086
4208
  data: import_v48.z.array(openrouterEmbeddingDataSchema),
4087
4209
  model: import_v48.z.string(),
4210
+ provider: import_v48.z.string().optional(),
4088
4211
  usage: openrouterEmbeddingUsageSchema.optional()
4089
4212
  });
4090
4213
 
@@ -4100,7 +4223,7 @@ var OpenRouterEmbeddingModel = class {
4100
4223
  this.config = config;
4101
4224
  }
4102
4225
  async doEmbed(options) {
4103
- var _a16;
4226
+ var _a16, _b16, _c, _d, _e, _f;
4104
4227
  const { values, abortSignal, headers } = options;
4105
4228
  const args = __spreadValues(__spreadValues({
4106
4229
  model: this.modelId,
@@ -4125,13 +4248,16 @@ var OpenRouterEmbeddingModel = class {
4125
4248
  return {
4126
4249
  embeddings: responseValue.data.map((item) => item.embedding),
4127
4250
  usage: responseValue.usage ? { tokens: responseValue.usage.prompt_tokens } : void 0,
4128
- providerMetadata: ((_a16 = responseValue.usage) == null ? void 0 : _a16.cost) ? {
4129
- openrouter: {
4130
- usage: {
4131
- cost: responseValue.usage.cost
4132
- }
4133
- }
4134
- } : void 0,
4251
+ providerMetadata: {
4252
+ openrouter: OpenRouterProviderMetadataSchema.parse({
4253
+ provider: (_a16 = responseValue.provider) != null ? _a16 : "",
4254
+ usage: __spreadValues({
4255
+ promptTokens: (_c = (_b16 = responseValue.usage) == null ? void 0 : _b16.prompt_tokens) != null ? _c : 0,
4256
+ completionTokens: 0,
4257
+ totalTokens: (_e = (_d = responseValue.usage) == null ? void 0 : _d.total_tokens) != null ? _e : 0
4258
+ }, ((_f = responseValue.usage) == null ? void 0 : _f.cost) != null ? { cost: responseValue.usage.cost } : {})
4259
+ })
4260
+ },
4135
4261
  response: {
4136
4262
  headers: responseHeaders,
4137
4263
  body: responseValue
@@ -4198,27 +4324,188 @@ var OpenRouter = class {
4198
4324
  }
4199
4325
  };
4200
4326
 
4327
+ // src/image/schemas.ts
4328
+ var import_v49 = require("zod/v4");
4329
+ var OpenRouterImageResponseSchema = import_v49.z.object({
4330
+ id: import_v49.z.string().optional(),
4331
+ object: import_v49.z.string().optional(),
4332
+ created: import_v49.z.number().optional(),
4333
+ model: import_v49.z.string(),
4334
+ choices: import_v49.z.array(
4335
+ import_v49.z.object({
4336
+ index: import_v49.z.number(),
4337
+ message: import_v49.z.object({
4338
+ role: import_v49.z.string(),
4339
+ content: import_v49.z.string().nullable().optional(),
4340
+ images: import_v49.z.array(
4341
+ import_v49.z.object({
4342
+ type: import_v49.z.literal("image_url"),
4343
+ image_url: import_v49.z.object({
4344
+ url: import_v49.z.string()
4345
+ })
4346
+ }).passthrough()
4347
+ ).optional()
4348
+ }).passthrough(),
4349
+ finish_reason: import_v49.z.string().nullable().optional()
4350
+ }).passthrough()
4351
+ ),
4352
+ usage: import_v49.z.object({
4353
+ prompt_tokens: import_v49.z.number(),
4354
+ completion_tokens: import_v49.z.number(),
4355
+ total_tokens: import_v49.z.number()
4356
+ }).passthrough().optional()
4357
+ }).passthrough();
4358
+
4359
+ // src/image/index.ts
4360
+ var OpenRouterImageModel = class {
4361
+ constructor(modelId, settings, config) {
4362
+ this.specificationVersion = "v3";
4363
+ this.provider = "openrouter";
4364
+ this.maxImagesPerCall = 1;
4365
+ this.modelId = modelId;
4366
+ this.settings = settings;
4367
+ this.config = config;
4368
+ }
4369
+ async doGenerate(options) {
4370
+ var _a16;
4371
+ const {
4372
+ prompt,
4373
+ n,
4374
+ size,
4375
+ aspectRatio,
4376
+ seed,
4377
+ files,
4378
+ mask,
4379
+ abortSignal,
4380
+ headers,
4381
+ providerOptions
4382
+ } = options;
4383
+ const openrouterOptions = (providerOptions == null ? void 0 : providerOptions.openrouter) || {};
4384
+ const warnings = [];
4385
+ if (files !== void 0 && files.length > 0) {
4386
+ throw new UnsupportedFunctionalityError({
4387
+ functionality: "image editing (files parameter)"
4388
+ });
4389
+ }
4390
+ if (mask !== void 0) {
4391
+ throw new UnsupportedFunctionalityError({
4392
+ functionality: "image inpainting (mask parameter)"
4393
+ });
4394
+ }
4395
+ if (n > 1) {
4396
+ warnings.push({
4397
+ type: "unsupported",
4398
+ feature: "n > 1",
4399
+ details: `OpenRouter image generation returns 1 image per call. Requested ${n} images.`
4400
+ });
4401
+ }
4402
+ if (size !== void 0) {
4403
+ warnings.push({
4404
+ type: "unsupported",
4405
+ feature: "size",
4406
+ details: "Use aspectRatio instead. Size parameter is not supported by OpenRouter image generation."
4407
+ });
4408
+ }
4409
+ const imageConfig = aspectRatio !== void 0 ? { aspect_ratio: aspectRatio } : void 0;
4410
+ const body = __spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues(__spreadValues({
4411
+ model: this.modelId,
4412
+ messages: [
4413
+ {
4414
+ role: "user",
4415
+ content: prompt != null ? prompt : ""
4416
+ }
4417
+ ],
4418
+ modalities: ["image", "text"]
4419
+ }, imageConfig !== void 0 && { image_config: imageConfig }), seed !== void 0 && { seed }), this.settings.user !== void 0 && { user: this.settings.user }), this.settings.provider !== void 0 && {
4420
+ provider: this.settings.provider
4421
+ }), this.config.extraBody), this.settings.extraBody), openrouterOptions);
4422
+ const { value: responseValue, responseHeaders } = await postJsonToApi({
4423
+ url: this.config.url({
4424
+ path: "/chat/completions",
4425
+ modelId: this.modelId
4426
+ }),
4427
+ headers: combineHeaders(this.config.headers(), headers),
4428
+ body,
4429
+ failedResponseHandler: openrouterFailedResponseHandler,
4430
+ successfulResponseHandler: createJsonResponseHandler(
4431
+ OpenRouterImageResponseSchema
4432
+ ),
4433
+ abortSignal,
4434
+ fetch: this.config.fetch
4435
+ });
4436
+ const choice = responseValue.choices[0];
4437
+ if (!choice) {
4438
+ throw new NoContentGeneratedError({
4439
+ message: "No choice in response"
4440
+ });
4441
+ }
4442
+ const images = [];
4443
+ if ((_a16 = choice.message) == null ? void 0 : _a16.images) {
4444
+ for (const image of choice.message.images) {
4445
+ const dataUrl = image.image_url.url;
4446
+ images.push(getBase64FromDataUrl(dataUrl));
4447
+ }
4448
+ }
4449
+ const usage = responseValue.usage ? {
4450
+ inputTokens: responseValue.usage.prompt_tokens,
4451
+ outputTokens: responseValue.usage.completion_tokens,
4452
+ totalTokens: responseValue.usage.total_tokens
4453
+ } : void 0;
4454
+ return {
4455
+ images,
4456
+ warnings,
4457
+ response: {
4458
+ timestamp: /* @__PURE__ */ new Date(),
4459
+ modelId: responseValue.model,
4460
+ headers: responseHeaders
4461
+ },
4462
+ usage
4463
+ };
4464
+ }
4465
+ };
4466
+
4201
4467
  // src/utils/remove-undefined.ts
4202
4468
  function removeUndefinedEntries(record) {
4203
4469
  return Object.fromEntries(
4204
- Object.entries(record).filter(([, value]) => value !== null)
4470
+ Object.entries(record).filter(([, value]) => value != null)
4205
4471
  );
4206
4472
  }
4207
4473
 
4208
4474
  // src/utils/with-user-agent-suffix.ts
4475
+ function normalizeHeaders2(headers) {
4476
+ if (!headers) {
4477
+ return {};
4478
+ }
4479
+ if (headers instanceof Headers) {
4480
+ return Object.fromEntries(headers.entries());
4481
+ }
4482
+ if (Array.isArray(headers)) {
4483
+ return Object.fromEntries(headers);
4484
+ }
4485
+ return headers;
4486
+ }
4487
+ function findHeaderKey(headers, targetKey) {
4488
+ const lowerTarget = targetKey.toLowerCase();
4489
+ return Object.keys(headers).find((key) => key.toLowerCase() === lowerTarget);
4490
+ }
4209
4491
  function withUserAgentSuffix2(headers, ...userAgentSuffixParts) {
4210
- const cleanedHeaders = removeUndefinedEntries(
4211
- headers != null ? headers : {}
4492
+ const normalizedHeaders = normalizeHeaders2(headers);
4493
+ const cleanedHeaders = removeUndefinedEntries(normalizedHeaders);
4494
+ const existingUserAgentKey = findHeaderKey(cleanedHeaders, "user-agent");
4495
+ const existingUserAgentValue = existingUserAgentKey ? cleanedHeaders[existingUserAgentKey] : void 0;
4496
+ const userAgent = (existingUserAgentValue == null ? void 0 : existingUserAgentValue.trim()) ? existingUserAgentValue : userAgentSuffixParts.filter(Boolean).join(" ");
4497
+ const headersWithoutUserAgent = Object.fromEntries(
4498
+ Object.entries(cleanedHeaders).filter(
4499
+ ([key]) => key.toLowerCase() !== "user-agent"
4500
+ )
4212
4501
  );
4213
- const currentUserAgentHeader = cleanedHeaders["user-agent"] || "";
4214
- const newUserAgent = [currentUserAgentHeader, ...userAgentSuffixParts].filter(Boolean).join(" ");
4215
- return __spreadProps(__spreadValues({}, cleanedHeaders), {
4216
- "user-agent": newUserAgent
4502
+ return __spreadProps(__spreadValues({}, headersWithoutUserAgent), {
4503
+ "user-agent": userAgent
4217
4504
  });
4218
4505
  }
4219
4506
 
4220
4507
  // src/version.ts
4221
- var VERSION2 = false ? "0.0.0-test" : "2.0.4";
4508
+ var VERSION2 = false ? "0.0.0-test" : "2.1.1";
4222
4509
 
4223
4510
  // src/provider.ts
4224
4511
  function createOpenRouter(options = {}) {
@@ -4260,6 +4547,13 @@ function createOpenRouter(options = {}) {
4260
4547
  fetch: options.fetch,
4261
4548
  extraBody: options.extraBody
4262
4549
  });
4550
+ const createImageModel = (modelId, settings = {}) => new OpenRouterImageModel(modelId, settings, {
4551
+ provider: "openrouter.image",
4552
+ url: ({ path }) => `${baseURL}${path}`,
4553
+ headers: getHeaders,
4554
+ fetch: options.fetch,
4555
+ extraBody: options.extraBody
4556
+ });
4263
4557
  const createLanguageModel = (modelId, settings) => {
4264
4558
  if (new.target) {
4265
4559
  throw new Error(
@@ -4280,6 +4574,7 @@ function createOpenRouter(options = {}) {
4280
4574
  provider.completion = createCompletionModel;
4281
4575
  provider.textEmbeddingModel = createEmbeddingModel;
4282
4576
  provider.embedding = createEmbeddingModel;
4577
+ provider.imageModel = createImageModel;
4283
4578
  return provider;
4284
4579
  }
4285
4580
  var openrouter = createOpenRouter({