@openrouter/ai-sdk-provider 2.5.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2441,6 +2441,29 @@ function withStreamErrorHandling(source, onError) {
2441
2441
  });
2442
2442
  }
2443
2443
 
2444
+ // src/utils/deterministic-stringify.ts
2445
+ function deterministicStringify(value) {
2446
+ return JSON.stringify(sortKeys(value));
2447
+ }
2448
+ function sortKeys(value) {
2449
+ if (value === null || value === void 0) {
2450
+ return value;
2451
+ }
2452
+ if (Array.isArray(value)) {
2453
+ return value.map(sortKeys);
2454
+ }
2455
+ if (typeof value === "object") {
2456
+ const sorted = {};
2457
+ const entries = Object.entries(value);
2458
+ entries.sort(([a], [b]) => a.localeCompare(b));
2459
+ for (const [key, val] of entries) {
2460
+ sorted[key] = sortKeys(val);
2461
+ }
2462
+ return sorted;
2463
+ }
2464
+ return value;
2465
+ }
2466
+
2444
2467
  // src/utils/reasoning-details-duplicate-tracker.ts
2445
2468
  var _seenKeys;
2446
2469
  var ReasoningDetailsDuplicateTracker = class {
@@ -2772,7 +2795,7 @@ function convertToOpenRouterChatMessages(prompt) {
2772
2795
  type: "function",
2773
2796
  function: {
2774
2797
  name: part.toolName,
2775
- arguments: JSON.stringify(part.input)
2798
+ arguments: deterministicStringify(part.input)
2776
2799
  }
2777
2800
  });
2778
2801
  break;
@@ -2800,7 +2823,7 @@ function convertToOpenRouterChatMessages(prompt) {
2800
2823
  return true;
2801
2824
  }
2802
2825
  const format = (_a17 = detail.format) != null ? _a17 : DEFAULT_REASONING_FORMAT;
2803
- if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */) {
2826
+ if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */ && format !== "google-gemini-v1" /* GoogleGeminiV1 */) {
2804
2827
  return true;
2805
2828
  }
2806
2829
  return !!detail.signature;
@@ -2809,7 +2832,7 @@ function convertToOpenRouterChatMessages(prompt) {
2809
2832
  const logger = globalThis.AI_SDK_LOG_WARNINGS;
2810
2833
  if (logger !== false && typeof logger !== "function") {
2811
2834
  console.warn(
2812
- "[openrouter] Some reasoning_details entries were removed because they were missing signatures. See https://github.com/OpenRouterTeam/ai-sdk-provider/issues/423 for more details."
2835
+ "[openrouter] Some reasoning_details entries were removed because they were missing signatures. See https://github.com/OpenRouterTeam/ai-sdk-provider/issues/423 and https://github.com/OpenRouterTeam/ai-sdk-provider/issues/418 for more details."
2813
2836
  );
2814
2837
  }
2815
2838
  }
@@ -3335,16 +3358,21 @@ var OpenRouterChatLanguageModel = class {
3335
3358
  cache_control: this.settings.cache_control
3336
3359
  }, this.config.extraBody), this.settings.extraBody);
3337
3360
  if (tools && tools.length > 0) {
3338
- const mappedTools = tools.filter(
3339
- (tool) => tool.type === "function"
3340
- ).map((tool) => ({
3341
- type: "function",
3342
- function: {
3343
- name: tool.name,
3344
- description: tool.description,
3345
- parameters: tool.inputSchema
3361
+ const mappedTools = [];
3362
+ for (const tool of tools) {
3363
+ if (tool.type === "function") {
3364
+ mappedTools.push({
3365
+ type: "function",
3366
+ function: {
3367
+ name: tool.name,
3368
+ description: tool.description,
3369
+ parameters: tool.inputSchema
3370
+ }
3371
+ });
3372
+ } else if (tool.type === "provider") {
3373
+ mappedTools.push(mapProviderTool(tool));
3346
3374
  }
3347
- }));
3375
+ }
3348
3376
  return __spreadProps(__spreadValues({}, baseArgs), {
3349
3377
  tools: mappedTools,
3350
3378
  tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
@@ -3353,7 +3381,7 @@ var OpenRouterChatLanguageModel = class {
3353
3381
  return baseArgs;
3354
3382
  }
3355
3383
  async doGenerate(options) {
3356
- var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
3384
+ var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
3357
3385
  const providerOptions = options.providerOptions || {};
3358
3386
  const openrouterOptions = providerOptions.openrouter || {};
3359
3387
  const _a16 = openrouterOptions, { cacheControl } = _a16, restOpenrouterOptions = __objRest(_a16, ["cacheControl"]);
@@ -3449,12 +3477,18 @@ var OpenRouterChatLanguageModel = class {
3449
3477
  }
3450
3478
  if (choice.message.tool_calls) {
3451
3479
  let reasoningDetailsAttachedToToolCall = false;
3480
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3452
3481
  for (const toolCall of choice.message.tool_calls) {
3482
+ let toolCallId = toolCall.id;
3483
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3484
+ toolCallId = generateId();
3485
+ }
3486
+ seenToolCallIds.add(toolCallId);
3453
3487
  content.push({
3454
3488
  type: "tool-call",
3455
- toolCallId: (_c = toolCall.id) != null ? _c : generateId(),
3489
+ toolCallId,
3456
3490
  toolName: toolCall.function.name,
3457
- input: (_d = toolCall.function.arguments) != null ? _d : "{}",
3491
+ input: (_c = toolCall.function.arguments) != null ? _c : "{}",
3458
3492
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
3459
3493
  openrouter: {
3460
3494
  reasoning_details: reasoningDetails
@@ -3481,19 +3515,19 @@ var OpenRouterChatLanguageModel = class {
3481
3515
  sourceType: "url",
3482
3516
  id: annotation.url_citation.url,
3483
3517
  url: annotation.url_citation.url,
3484
- title: (_e = annotation.url_citation.title) != null ? _e : "",
3518
+ title: (_d = annotation.url_citation.title) != null ? _d : "",
3485
3519
  providerMetadata: {
3486
3520
  openrouter: {
3487
- content: (_f = annotation.url_citation.content) != null ? _f : "",
3488
- startIndex: (_g = annotation.url_citation.start_index) != null ? _g : 0,
3489
- endIndex: (_h = annotation.url_citation.end_index) != null ? _h : 0
3521
+ content: (_e = annotation.url_citation.content) != null ? _e : "",
3522
+ startIndex: (_f = annotation.url_citation.start_index) != null ? _f : 0,
3523
+ endIndex: (_g = annotation.url_citation.end_index) != null ? _g : 0
3490
3524
  }
3491
3525
  }
3492
3526
  });
3493
3527
  }
3494
3528
  }
3495
3529
  }
3496
- const fileAnnotations = (_i = choice.message.annotations) == null ? void 0 : _i.filter(
3530
+ const fileAnnotations = (_h = choice.message.annotations) == null ? void 0 : _h.filter(
3497
3531
  (a) => a.type === "file"
3498
3532
  );
3499
3533
  const hasToolCalls = choice.message.tool_calls && choice.message.tool_calls.length > 0;
@@ -3501,7 +3535,7 @@ var OpenRouterChatLanguageModel = class {
3501
3535
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3502
3536
  );
3503
3537
  const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
3504
- const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3538
+ const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_i = choice.finish_reason) != null ? _i : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3505
3539
  const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
3506
3540
  return {
3507
3541
  content,
@@ -3510,22 +3544,22 @@ var OpenRouterChatLanguageModel = class {
3510
3544
  warnings: [],
3511
3545
  providerMetadata: {
3512
3546
  openrouter: OpenRouterProviderMetadataSchema.parse({
3513
- provider: (_k = response.provider) != null ? _k : "",
3514
- reasoning_details: (_l = choice.message.reasoning_details) != null ? _l : [],
3547
+ provider: (_j = response.provider) != null ? _j : "",
3548
+ reasoning_details: (_k = choice.message.reasoning_details) != null ? _k : [],
3515
3549
  annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
3516
3550
  usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
3517
- promptTokens: (_m = usageInfo.inputTokens.total) != null ? _m : 0,
3518
- completionTokens: (_n = usageInfo.outputTokens.total) != null ? _n : 0,
3519
- totalTokens: ((_o = usageInfo.inputTokens.total) != null ? _o : 0) + ((_p = usageInfo.outputTokens.total) != null ? _p : 0)
3520
- }, ((_q = response.usage) == null ? void 0 : _q.cost) != null ? { cost: response.usage.cost } : {}), ((_s = (_r = response.usage) == null ? void 0 : _r.prompt_tokens_details) == null ? void 0 : _s.cached_tokens) != null ? {
3551
+ promptTokens: (_l = usageInfo.inputTokens.total) != null ? _l : 0,
3552
+ completionTokens: (_m = usageInfo.outputTokens.total) != null ? _m : 0,
3553
+ totalTokens: ((_n = usageInfo.inputTokens.total) != null ? _n : 0) + ((_o = usageInfo.outputTokens.total) != null ? _o : 0)
3554
+ }, ((_p = response.usage) == null ? void 0 : _p.cost) != null ? { cost: response.usage.cost } : {}), ((_r = (_q = response.usage) == null ? void 0 : _q.prompt_tokens_details) == null ? void 0 : _r.cached_tokens) != null ? {
3521
3555
  promptTokensDetails: {
3522
3556
  cachedTokens: response.usage.prompt_tokens_details.cached_tokens
3523
3557
  }
3524
- } : {}), ((_u = (_t = response.usage) == null ? void 0 : _t.completion_tokens_details) == null ? void 0 : _u.reasoning_tokens) != null ? {
3558
+ } : {}), ((_t = (_s = response.usage) == null ? void 0 : _s.completion_tokens_details) == null ? void 0 : _t.reasoning_tokens) != null ? {
3525
3559
  completionTokensDetails: {
3526
3560
  reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
3527
3561
  }
3528
- } : {}), ((_w = (_v = response.usage) == null ? void 0 : _v.cost_details) == null ? void 0 : _w.upstream_inference_cost) != null ? {
3562
+ } : {}), ((_v = (_u = response.usage) == null ? void 0 : _u.cost_details) == null ? void 0 : _v.upstream_inference_cost) != null ? {
3529
3563
  costDetails: {
3530
3564
  upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
3531
3565
  }
@@ -3572,6 +3606,7 @@ var OpenRouterChatLanguageModel = class {
3572
3606
  streamError = err;
3573
3607
  });
3574
3608
  const toolCalls = [];
3609
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3575
3610
  let finishReason = createFinishReason("other");
3576
3611
  const usage = {
3577
3612
  inputTokens: {
@@ -3802,24 +3837,23 @@ var OpenRouterChatLanguageModel = class {
3802
3837
  message: `Expected 'function' type.`
3803
3838
  });
3804
3839
  }
3805
- if (toolCallDelta.id == null) {
3806
- throw new InvalidResponseDataError({
3807
- data: toolCallDelta,
3808
- message: `Expected 'id' to be a string.`
3809
- });
3810
- }
3811
3840
  if (((_k = toolCallDelta.function) == null ? void 0 : _k.name) == null) {
3812
3841
  throw new InvalidResponseDataError({
3813
3842
  data: toolCallDelta,
3814
3843
  message: `Expected 'function.name' to be a string.`
3815
3844
  });
3816
3845
  }
3846
+ let toolCallId = (_l = toolCallDelta.id) != null ? _l : "";
3847
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3848
+ toolCallId = generateId();
3849
+ }
3850
+ seenToolCallIds.add(toolCallId);
3817
3851
  toolCalls[index] = {
3818
- id: toolCallDelta.id,
3852
+ id: toolCallId,
3819
3853
  type: "function",
3820
3854
  function: {
3821
3855
  name: toolCallDelta.function.name,
3822
- arguments: (_l = toolCallDelta.function.arguments) != null ? _l : ""
3856
+ arguments: (_m = toolCallDelta.function.arguments) != null ? _m : ""
3823
3857
  },
3824
3858
  inputStarted: false,
3825
3859
  sent: false
@@ -3831,7 +3865,7 @@ var OpenRouterChatLanguageModel = class {
3831
3865
  message: `Tool call at index ${index} is missing after creation.`
3832
3866
  });
3833
3867
  }
3834
- if (((_m = toolCall2.function) == null ? void 0 : _m.name) != null && ((_n = toolCall2.function) == null ? void 0 : _n.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3868
+ if (((_n = toolCall2.function) == null ? void 0 : _n.name) != null && ((_o = toolCall2.function) == null ? void 0 : _o.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3835
3869
  toolCall2.inputStarted = true;
3836
3870
  controller.enqueue({
3837
3871
  type: "tool-input-start",
@@ -3889,22 +3923,22 @@ var OpenRouterChatLanguageModel = class {
3889
3923
  });
3890
3924
  }
3891
3925
  }
3892
- if (((_o = toolCallDelta.function) == null ? void 0 : _o.arguments) != null) {
3893
- toolCall.function.arguments += (_q = (_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null ? _q : "";
3926
+ if (((_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null) {
3927
+ toolCall.function.arguments += (_r = (_q = toolCallDelta.function) == null ? void 0 : _q.arguments) != null ? _r : "";
3894
3928
  }
3895
3929
  controller.enqueue({
3896
3930
  type: "tool-input-delta",
3897
3931
  id: toolCall.id,
3898
- delta: (_r = toolCallDelta.function.arguments) != null ? _r : ""
3932
+ delta: (_s = toolCallDelta.function.arguments) != null ? _s : ""
3899
3933
  });
3900
- if (((_s = toolCall.function) == null ? void 0 : _s.name) != null && ((_t = toolCall.function) == null ? void 0 : _t.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3934
+ if (((_t = toolCall.function) == null ? void 0 : _t.name) != null && ((_u = toolCall.function) == null ? void 0 : _u.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3901
3935
  controller.enqueue({
3902
3936
  type: "tool-input-end",
3903
3937
  id: toolCall.id
3904
3938
  });
3905
3939
  controller.enqueue({
3906
3940
  type: "tool-call",
3907
- toolCallId: (_u = toolCall.id) != null ? _u : generateId(),
3941
+ toolCallId: toolCall.id,
3908
3942
  toolName: toolCall.function.name,
3909
3943
  input: toolCall.function.arguments,
3910
3944
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -3929,7 +3963,6 @@ var OpenRouterChatLanguageModel = class {
3929
3963
  }
3930
3964
  },
3931
3965
  flush(controller) {
3932
- var _a17;
3933
3966
  const hasToolCalls = toolCalls.length > 0;
3934
3967
  if (streamError != null) {
3935
3968
  finishReason = createFinishReason("error");
@@ -3966,7 +3999,7 @@ var OpenRouterChatLanguageModel = class {
3966
3999
  });
3967
4000
  controller.enqueue({
3968
4001
  type: "tool-call",
3969
- toolCallId: (_a17 = toolCall.id) != null ? _a17 : generateId(),
4002
+ toolCallId: toolCall.id,
3970
4003
  toolName: toolCall.function.name,
3971
4004
  input,
3972
4005
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -4029,6 +4062,22 @@ var OpenRouterChatLanguageModel = class {
4029
4062
  };
4030
4063
  }
4031
4064
  };
4065
+ function mapProviderTool(tool) {
4066
+ const [provider, toolName] = tool.id.split(".");
4067
+ const apiToolType = `${provider}:${toolName}`;
4068
+ const mappedArgs = {};
4069
+ for (const [key, value] of Object.entries(tool.args)) {
4070
+ if (value !== void 0) {
4071
+ mappedArgs[camelToSnake(key)] = value;
4072
+ }
4073
+ }
4074
+ return __spreadValues({
4075
+ type: apiToolType
4076
+ }, mappedArgs);
4077
+ }
4078
+ function camelToSnake(str) {
4079
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
4080
+ }
4032
4081
 
4033
4082
  // src/completion/convert-to-openrouter-completion-prompt.ts
4034
4083
  function convertToOpenRouterCompletionPrompt({