@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.
@@ -2407,6 +2407,29 @@ function withStreamErrorHandling(source, onError) {
2407
2407
  });
2408
2408
  }
2409
2409
 
2410
+ // src/utils/deterministic-stringify.ts
2411
+ function deterministicStringify(value) {
2412
+ return JSON.stringify(sortKeys(value));
2413
+ }
2414
+ function sortKeys(value) {
2415
+ if (value === null || value === void 0) {
2416
+ return value;
2417
+ }
2418
+ if (Array.isArray(value)) {
2419
+ return value.map(sortKeys);
2420
+ }
2421
+ if (typeof value === "object") {
2422
+ const sorted = {};
2423
+ const entries = Object.entries(value);
2424
+ entries.sort(([a], [b]) => a.localeCompare(b));
2425
+ for (const [key, val] of entries) {
2426
+ sorted[key] = sortKeys(val);
2427
+ }
2428
+ return sorted;
2429
+ }
2430
+ return value;
2431
+ }
2432
+
2410
2433
  // src/utils/reasoning-details-duplicate-tracker.ts
2411
2434
  var _seenKeys;
2412
2435
  var ReasoningDetailsDuplicateTracker = class {
@@ -2738,7 +2761,7 @@ function convertToOpenRouterChatMessages(prompt) {
2738
2761
  type: "function",
2739
2762
  function: {
2740
2763
  name: part.toolName,
2741
- arguments: JSON.stringify(part.input)
2764
+ arguments: deterministicStringify(part.input)
2742
2765
  }
2743
2766
  });
2744
2767
  break;
@@ -2766,7 +2789,7 @@ function convertToOpenRouterChatMessages(prompt) {
2766
2789
  return true;
2767
2790
  }
2768
2791
  const format = (_a17 = detail.format) != null ? _a17 : DEFAULT_REASONING_FORMAT;
2769
- if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */) {
2792
+ if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */ && format !== "google-gemini-v1" /* GoogleGeminiV1 */) {
2770
2793
  return true;
2771
2794
  }
2772
2795
  return !!detail.signature;
@@ -2775,7 +2798,7 @@ function convertToOpenRouterChatMessages(prompt) {
2775
2798
  const logger = globalThis.AI_SDK_LOG_WARNINGS;
2776
2799
  if (logger !== false && typeof logger !== "function") {
2777
2800
  console.warn(
2778
- "[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."
2801
+ "[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."
2779
2802
  );
2780
2803
  }
2781
2804
  }
@@ -3301,16 +3324,21 @@ var OpenRouterChatLanguageModel = class {
3301
3324
  cache_control: this.settings.cache_control
3302
3325
  }, this.config.extraBody), this.settings.extraBody);
3303
3326
  if (tools && tools.length > 0) {
3304
- const mappedTools = tools.filter(
3305
- (tool) => tool.type === "function"
3306
- ).map((tool) => ({
3307
- type: "function",
3308
- function: {
3309
- name: tool.name,
3310
- description: tool.description,
3311
- parameters: tool.inputSchema
3327
+ const mappedTools = [];
3328
+ for (const tool of tools) {
3329
+ if (tool.type === "function") {
3330
+ mappedTools.push({
3331
+ type: "function",
3332
+ function: {
3333
+ name: tool.name,
3334
+ description: tool.description,
3335
+ parameters: tool.inputSchema
3336
+ }
3337
+ });
3338
+ } else if (tool.type === "provider") {
3339
+ mappedTools.push(mapProviderTool(tool));
3312
3340
  }
3313
- }));
3341
+ }
3314
3342
  return __spreadProps(__spreadValues({}, baseArgs), {
3315
3343
  tools: mappedTools,
3316
3344
  tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
@@ -3319,7 +3347,7 @@ var OpenRouterChatLanguageModel = class {
3319
3347
  return baseArgs;
3320
3348
  }
3321
3349
  async doGenerate(options) {
3322
- var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
3350
+ var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
3323
3351
  const providerOptions = options.providerOptions || {};
3324
3352
  const openrouterOptions = providerOptions.openrouter || {};
3325
3353
  const _a16 = openrouterOptions, { cacheControl } = _a16, restOpenrouterOptions = __objRest(_a16, ["cacheControl"]);
@@ -3415,12 +3443,18 @@ var OpenRouterChatLanguageModel = class {
3415
3443
  }
3416
3444
  if (choice.message.tool_calls) {
3417
3445
  let reasoningDetailsAttachedToToolCall = false;
3446
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3418
3447
  for (const toolCall of choice.message.tool_calls) {
3448
+ let toolCallId = toolCall.id;
3449
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3450
+ toolCallId = generateId();
3451
+ }
3452
+ seenToolCallIds.add(toolCallId);
3419
3453
  content.push({
3420
3454
  type: "tool-call",
3421
- toolCallId: (_c = toolCall.id) != null ? _c : generateId(),
3455
+ toolCallId,
3422
3456
  toolName: toolCall.function.name,
3423
- input: (_d = toolCall.function.arguments) != null ? _d : "{}",
3457
+ input: (_c = toolCall.function.arguments) != null ? _c : "{}",
3424
3458
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
3425
3459
  openrouter: {
3426
3460
  reasoning_details: reasoningDetails
@@ -3447,19 +3481,19 @@ var OpenRouterChatLanguageModel = class {
3447
3481
  sourceType: "url",
3448
3482
  id: annotation.url_citation.url,
3449
3483
  url: annotation.url_citation.url,
3450
- title: (_e = annotation.url_citation.title) != null ? _e : "",
3484
+ title: (_d = annotation.url_citation.title) != null ? _d : "",
3451
3485
  providerMetadata: {
3452
3486
  openrouter: {
3453
- content: (_f = annotation.url_citation.content) != null ? _f : "",
3454
- startIndex: (_g = annotation.url_citation.start_index) != null ? _g : 0,
3455
- endIndex: (_h = annotation.url_citation.end_index) != null ? _h : 0
3487
+ content: (_e = annotation.url_citation.content) != null ? _e : "",
3488
+ startIndex: (_f = annotation.url_citation.start_index) != null ? _f : 0,
3489
+ endIndex: (_g = annotation.url_citation.end_index) != null ? _g : 0
3456
3490
  }
3457
3491
  }
3458
3492
  });
3459
3493
  }
3460
3494
  }
3461
3495
  }
3462
- const fileAnnotations = (_i = choice.message.annotations) == null ? void 0 : _i.filter(
3496
+ const fileAnnotations = (_h = choice.message.annotations) == null ? void 0 : _h.filter(
3463
3497
  (a) => a.type === "file"
3464
3498
  );
3465
3499
  const hasToolCalls = choice.message.tool_calls && choice.message.tool_calls.length > 0;
@@ -3467,7 +3501,7 @@ var OpenRouterChatLanguageModel = class {
3467
3501
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3468
3502
  );
3469
3503
  const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
3470
- const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3504
+ const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_i = choice.finish_reason) != null ? _i : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3471
3505
  const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
3472
3506
  return {
3473
3507
  content,
@@ -3476,22 +3510,22 @@ var OpenRouterChatLanguageModel = class {
3476
3510
  warnings: [],
3477
3511
  providerMetadata: {
3478
3512
  openrouter: OpenRouterProviderMetadataSchema.parse({
3479
- provider: (_k = response.provider) != null ? _k : "",
3480
- reasoning_details: (_l = choice.message.reasoning_details) != null ? _l : [],
3513
+ provider: (_j = response.provider) != null ? _j : "",
3514
+ reasoning_details: (_k = choice.message.reasoning_details) != null ? _k : [],
3481
3515
  annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
3482
3516
  usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
3483
- promptTokens: (_m = usageInfo.inputTokens.total) != null ? _m : 0,
3484
- completionTokens: (_n = usageInfo.outputTokens.total) != null ? _n : 0,
3485
- totalTokens: ((_o = usageInfo.inputTokens.total) != null ? _o : 0) + ((_p = usageInfo.outputTokens.total) != null ? _p : 0)
3486
- }, ((_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 ? {
3517
+ promptTokens: (_l = usageInfo.inputTokens.total) != null ? _l : 0,
3518
+ completionTokens: (_m = usageInfo.outputTokens.total) != null ? _m : 0,
3519
+ totalTokens: ((_n = usageInfo.inputTokens.total) != null ? _n : 0) + ((_o = usageInfo.outputTokens.total) != null ? _o : 0)
3520
+ }, ((_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 ? {
3487
3521
  promptTokensDetails: {
3488
3522
  cachedTokens: response.usage.prompt_tokens_details.cached_tokens
3489
3523
  }
3490
- } : {}), ((_u = (_t = response.usage) == null ? void 0 : _t.completion_tokens_details) == null ? void 0 : _u.reasoning_tokens) != null ? {
3524
+ } : {}), ((_t = (_s = response.usage) == null ? void 0 : _s.completion_tokens_details) == null ? void 0 : _t.reasoning_tokens) != null ? {
3491
3525
  completionTokensDetails: {
3492
3526
  reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
3493
3527
  }
3494
- } : {}), ((_w = (_v = response.usage) == null ? void 0 : _v.cost_details) == null ? void 0 : _w.upstream_inference_cost) != null ? {
3528
+ } : {}), ((_v = (_u = response.usage) == null ? void 0 : _u.cost_details) == null ? void 0 : _v.upstream_inference_cost) != null ? {
3495
3529
  costDetails: {
3496
3530
  upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
3497
3531
  }
@@ -3538,6 +3572,7 @@ var OpenRouterChatLanguageModel = class {
3538
3572
  streamError = err;
3539
3573
  });
3540
3574
  const toolCalls = [];
3575
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3541
3576
  let finishReason = createFinishReason("other");
3542
3577
  const usage = {
3543
3578
  inputTokens: {
@@ -3768,24 +3803,23 @@ var OpenRouterChatLanguageModel = class {
3768
3803
  message: `Expected 'function' type.`
3769
3804
  });
3770
3805
  }
3771
- if (toolCallDelta.id == null) {
3772
- throw new InvalidResponseDataError({
3773
- data: toolCallDelta,
3774
- message: `Expected 'id' to be a string.`
3775
- });
3776
- }
3777
3806
  if (((_k = toolCallDelta.function) == null ? void 0 : _k.name) == null) {
3778
3807
  throw new InvalidResponseDataError({
3779
3808
  data: toolCallDelta,
3780
3809
  message: `Expected 'function.name' to be a string.`
3781
3810
  });
3782
3811
  }
3812
+ let toolCallId = (_l = toolCallDelta.id) != null ? _l : "";
3813
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3814
+ toolCallId = generateId();
3815
+ }
3816
+ seenToolCallIds.add(toolCallId);
3783
3817
  toolCalls[index] = {
3784
- id: toolCallDelta.id,
3818
+ id: toolCallId,
3785
3819
  type: "function",
3786
3820
  function: {
3787
3821
  name: toolCallDelta.function.name,
3788
- arguments: (_l = toolCallDelta.function.arguments) != null ? _l : ""
3822
+ arguments: (_m = toolCallDelta.function.arguments) != null ? _m : ""
3789
3823
  },
3790
3824
  inputStarted: false,
3791
3825
  sent: false
@@ -3797,7 +3831,7 @@ var OpenRouterChatLanguageModel = class {
3797
3831
  message: `Tool call at index ${index} is missing after creation.`
3798
3832
  });
3799
3833
  }
3800
- if (((_m = toolCall2.function) == null ? void 0 : _m.name) != null && ((_n = toolCall2.function) == null ? void 0 : _n.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3834
+ if (((_n = toolCall2.function) == null ? void 0 : _n.name) != null && ((_o = toolCall2.function) == null ? void 0 : _o.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3801
3835
  toolCall2.inputStarted = true;
3802
3836
  controller.enqueue({
3803
3837
  type: "tool-input-start",
@@ -3855,22 +3889,22 @@ var OpenRouterChatLanguageModel = class {
3855
3889
  });
3856
3890
  }
3857
3891
  }
3858
- if (((_o = toolCallDelta.function) == null ? void 0 : _o.arguments) != null) {
3859
- toolCall.function.arguments += (_q = (_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null ? _q : "";
3892
+ if (((_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null) {
3893
+ toolCall.function.arguments += (_r = (_q = toolCallDelta.function) == null ? void 0 : _q.arguments) != null ? _r : "";
3860
3894
  }
3861
3895
  controller.enqueue({
3862
3896
  type: "tool-input-delta",
3863
3897
  id: toolCall.id,
3864
- delta: (_r = toolCallDelta.function.arguments) != null ? _r : ""
3898
+ delta: (_s = toolCallDelta.function.arguments) != null ? _s : ""
3865
3899
  });
3866
- if (((_s = toolCall.function) == null ? void 0 : _s.name) != null && ((_t = toolCall.function) == null ? void 0 : _t.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3900
+ if (((_t = toolCall.function) == null ? void 0 : _t.name) != null && ((_u = toolCall.function) == null ? void 0 : _u.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3867
3901
  controller.enqueue({
3868
3902
  type: "tool-input-end",
3869
3903
  id: toolCall.id
3870
3904
  });
3871
3905
  controller.enqueue({
3872
3906
  type: "tool-call",
3873
- toolCallId: (_u = toolCall.id) != null ? _u : generateId(),
3907
+ toolCallId: toolCall.id,
3874
3908
  toolName: toolCall.function.name,
3875
3909
  input: toolCall.function.arguments,
3876
3910
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -3895,7 +3929,6 @@ var OpenRouterChatLanguageModel = class {
3895
3929
  }
3896
3930
  },
3897
3931
  flush(controller) {
3898
- var _a17;
3899
3932
  const hasToolCalls = toolCalls.length > 0;
3900
3933
  if (streamError != null) {
3901
3934
  finishReason = createFinishReason("error");
@@ -3932,7 +3965,7 @@ var OpenRouterChatLanguageModel = class {
3932
3965
  });
3933
3966
  controller.enqueue({
3934
3967
  type: "tool-call",
3935
- toolCallId: (_a17 = toolCall.id) != null ? _a17 : generateId(),
3968
+ toolCallId: toolCall.id,
3936
3969
  toolName: toolCall.function.name,
3937
3970
  input,
3938
3971
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -3995,6 +4028,22 @@ var OpenRouterChatLanguageModel = class {
3995
4028
  };
3996
4029
  }
3997
4030
  };
4031
+ function mapProviderTool(tool) {
4032
+ const [provider, toolName] = tool.id.split(".");
4033
+ const apiToolType = `${provider}:${toolName}`;
4034
+ const mappedArgs = {};
4035
+ for (const [key, value] of Object.entries(tool.args)) {
4036
+ if (value !== void 0) {
4037
+ mappedArgs[camelToSnake(key)] = value;
4038
+ }
4039
+ }
4040
+ return __spreadValues({
4041
+ type: apiToolType
4042
+ }, mappedArgs);
4043
+ }
4044
+ function camelToSnake(str) {
4045
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
4046
+ }
3998
4047
 
3999
4048
  // src/completion/convert-to-openrouter-completion-prompt.ts
4000
4049
  function convertToOpenRouterCompletionPrompt({