@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.
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as _ai_sdk_provider from '@ai-sdk/provider';
2
2
  import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3Content, LanguageModelV3FinishReason, LanguageModelV3Usage, SharedV3Warning, LanguageModelV3ResponseMetadata, SharedV3Headers, LanguageModelV3StreamPart, EmbeddingModelV3, SharedV3ProviderMetadata, ImageModelV3, ImageModelV3CallOptions, ImageModelV3ProviderMetadata, ImageModelV3Usage, ProviderV3 } from '@ai-sdk/provider';
3
3
  export { LanguageModelV3, LanguageModelV3Prompt } from '@ai-sdk/provider';
4
+ import { ProviderToolFactory } from '@ai-sdk/provider-utils';
4
5
  import { z } from 'zod/v4';
5
6
 
6
7
  /**
@@ -613,6 +614,19 @@ declare class OpenRouterImageModel implements ImageModelV3 {
613
614
  }>;
614
615
  }
615
616
 
617
+ /**
618
+ * Configuration args for the web search provider tool.
619
+ * These are mapped to snake_case in the API request.
620
+ */
621
+ type WebSearchToolArgs = {
622
+ /** Maximum number of search results to include */
623
+ maxResults?: number;
624
+ /** Custom search prompt to guide the search query */
625
+ searchPrompt?: string;
626
+ /** Search engine to use: 'auto', 'native', or 'exa' */
627
+ engine?: 'auto' | Engine;
628
+ };
629
+
616
630
  interface OpenRouterProvider extends ProviderV3 {
617
631
  (modelId: OpenRouterChatModelId, settings?: OpenRouterCompletionSettings): OpenRouterCompletionLanguageModel;
618
632
  (modelId: OpenRouterChatModelId, settings?: OpenRouterChatSettings): OpenRouterChatLanguageModel;
@@ -639,6 +653,17 @@ interface OpenRouterProvider extends ProviderV3 {
639
653
  Creates an OpenRouter image model for image generation.
640
654
  */
641
655
  imageModel(modelId: OpenRouterImageModelId, settings?: OpenRouterImageSettings): OpenRouterImageModel;
656
+ /**
657
+ * Provider-defined tools for OpenRouter server tools.
658
+ */
659
+ readonly tools: {
660
+ /**
661
+ * Creates an OpenRouter web search server tool.
662
+ *
663
+ * @see https://openrouter.ai/docs/guides/features/server-tools/web-search
664
+ */
665
+ webSearch: ProviderToolFactory<unknown, WebSearchToolArgs>;
666
+ };
642
667
  }
643
668
  interface OpenRouterProviderSettings {
644
669
  /**
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as _ai_sdk_provider from '@ai-sdk/provider';
2
2
  import { LanguageModelV3, LanguageModelV3CallOptions, LanguageModelV3Content, LanguageModelV3FinishReason, LanguageModelV3Usage, SharedV3Warning, LanguageModelV3ResponseMetadata, SharedV3Headers, LanguageModelV3StreamPart, EmbeddingModelV3, SharedV3ProviderMetadata, ImageModelV3, ImageModelV3CallOptions, ImageModelV3ProviderMetadata, ImageModelV3Usage, ProviderV3 } from '@ai-sdk/provider';
3
3
  export { LanguageModelV3, LanguageModelV3Prompt } from '@ai-sdk/provider';
4
+ import { ProviderToolFactory } from '@ai-sdk/provider-utils';
4
5
  import { z } from 'zod/v4';
5
6
 
6
7
  /**
@@ -613,6 +614,19 @@ declare class OpenRouterImageModel implements ImageModelV3 {
613
614
  }>;
614
615
  }
615
616
 
617
+ /**
618
+ * Configuration args for the web search provider tool.
619
+ * These are mapped to snake_case in the API request.
620
+ */
621
+ type WebSearchToolArgs = {
622
+ /** Maximum number of search results to include */
623
+ maxResults?: number;
624
+ /** Custom search prompt to guide the search query */
625
+ searchPrompt?: string;
626
+ /** Search engine to use: 'auto', 'native', or 'exa' */
627
+ engine?: 'auto' | Engine;
628
+ };
629
+
616
630
  interface OpenRouterProvider extends ProviderV3 {
617
631
  (modelId: OpenRouterChatModelId, settings?: OpenRouterCompletionSettings): OpenRouterCompletionLanguageModel;
618
632
  (modelId: OpenRouterChatModelId, settings?: OpenRouterChatSettings): OpenRouterChatLanguageModel;
@@ -639,6 +653,17 @@ interface OpenRouterProvider extends ProviderV3 {
639
653
  Creates an OpenRouter image model for image generation.
640
654
  */
641
655
  imageModel(modelId: OpenRouterImageModelId, settings?: OpenRouterImageSettings): OpenRouterImageModel;
656
+ /**
657
+ * Provider-defined tools for OpenRouter server tools.
658
+ */
659
+ readonly tools: {
660
+ /**
661
+ * Creates an OpenRouter web search server tool.
662
+ *
663
+ * @see https://openrouter.ai/docs/guides/features/server-tools/web-search
664
+ */
665
+ webSearch: ProviderToolFactory<unknown, WebSearchToolArgs>;
666
+ };
642
667
  }
643
668
  interface OpenRouterProviderSettings {
644
669
  /**
package/dist/index.js CHANGED
@@ -2109,6 +2109,46 @@ var postToApi = async ({
2109
2109
  throw handleFetchError({ error, url, requestBodyValues: body.values });
2110
2110
  }
2111
2111
  };
2112
+ function tool(tool2) {
2113
+ return tool2;
2114
+ }
2115
+ function createProviderToolFactory({
2116
+ id,
2117
+ inputSchema
2118
+ }) {
2119
+ return (_a16) => {
2120
+ var _b16 = _a16, {
2121
+ execute,
2122
+ outputSchema,
2123
+ needsApproval,
2124
+ toModelOutput,
2125
+ onInputStart,
2126
+ onInputDelta,
2127
+ onInputAvailable
2128
+ } = _b16, args = __objRest(_b16, [
2129
+ "execute",
2130
+ "outputSchema",
2131
+ "needsApproval",
2132
+ "toModelOutput",
2133
+ "onInputStart",
2134
+ "onInputDelta",
2135
+ "onInputAvailable"
2136
+ ]);
2137
+ return tool({
2138
+ type: "provider",
2139
+ id,
2140
+ args,
2141
+ inputSchema,
2142
+ outputSchema,
2143
+ execute,
2144
+ needsApproval,
2145
+ toModelOutput,
2146
+ onInputStart,
2147
+ onInputDelta,
2148
+ onInputAvailable
2149
+ });
2150
+ };
2151
+ }
2112
2152
  var createJsonErrorResponseHandler = ({
2113
2153
  errorSchema,
2114
2154
  errorToMessage,
@@ -2475,6 +2515,29 @@ function withStreamErrorHandling(source, onError) {
2475
2515
  });
2476
2516
  }
2477
2517
 
2518
+ // src/utils/deterministic-stringify.ts
2519
+ function deterministicStringify(value) {
2520
+ return JSON.stringify(sortKeys(value));
2521
+ }
2522
+ function sortKeys(value) {
2523
+ if (value === null || value === void 0) {
2524
+ return value;
2525
+ }
2526
+ if (Array.isArray(value)) {
2527
+ return value.map(sortKeys);
2528
+ }
2529
+ if (typeof value === "object") {
2530
+ const sorted = {};
2531
+ const entries = Object.entries(value);
2532
+ entries.sort(([a], [b]) => a.localeCompare(b));
2533
+ for (const [key, val] of entries) {
2534
+ sorted[key] = sortKeys(val);
2535
+ }
2536
+ return sorted;
2537
+ }
2538
+ return value;
2539
+ }
2540
+
2478
2541
  // src/utils/reasoning-details-duplicate-tracker.ts
2479
2542
  var _seenKeys;
2480
2543
  var ReasoningDetailsDuplicateTracker = class {
@@ -2806,7 +2869,7 @@ function convertToOpenRouterChatMessages(prompt) {
2806
2869
  type: "function",
2807
2870
  function: {
2808
2871
  name: part.toolName,
2809
- arguments: JSON.stringify(part.input)
2872
+ arguments: deterministicStringify(part.input)
2810
2873
  }
2811
2874
  });
2812
2875
  break;
@@ -2834,7 +2897,7 @@ function convertToOpenRouterChatMessages(prompt) {
2834
2897
  return true;
2835
2898
  }
2836
2899
  const format = (_a17 = detail.format) != null ? _a17 : DEFAULT_REASONING_FORMAT;
2837
- if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */) {
2900
+ if (format !== "anthropic-claude-v1" /* AnthropicClaudeV1 */ && format !== "google-gemini-v1" /* GoogleGeminiV1 */) {
2838
2901
  return true;
2839
2902
  }
2840
2903
  return !!detail.signature;
@@ -2843,7 +2906,7 @@ function convertToOpenRouterChatMessages(prompt) {
2843
2906
  const logger = globalThis.AI_SDK_LOG_WARNINGS;
2844
2907
  if (logger !== false && typeof logger !== "function") {
2845
2908
  console.warn(
2846
- "[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."
2909
+ "[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."
2847
2910
  );
2848
2911
  }
2849
2912
  }
@@ -3369,16 +3432,21 @@ var OpenRouterChatLanguageModel = class {
3369
3432
  cache_control: this.settings.cache_control
3370
3433
  }, this.config.extraBody), this.settings.extraBody);
3371
3434
  if (tools && tools.length > 0) {
3372
- const mappedTools = tools.filter(
3373
- (tool) => tool.type === "function"
3374
- ).map((tool) => ({
3375
- type: "function",
3376
- function: {
3377
- name: tool.name,
3378
- description: tool.description,
3379
- parameters: tool.inputSchema
3435
+ const mappedTools = [];
3436
+ for (const tool2 of tools) {
3437
+ if (tool2.type === "function") {
3438
+ mappedTools.push({
3439
+ type: "function",
3440
+ function: {
3441
+ name: tool2.name,
3442
+ description: tool2.description,
3443
+ parameters: tool2.inputSchema
3444
+ }
3445
+ });
3446
+ } else if (tool2.type === "provider") {
3447
+ mappedTools.push(mapProviderTool(tool2));
3380
3448
  }
3381
- }));
3449
+ }
3382
3450
  return __spreadProps(__spreadValues({}, baseArgs), {
3383
3451
  tools: mappedTools,
3384
3452
  tool_choice: toolChoice ? getChatCompletionToolChoice(toolChoice) : void 0
@@ -3387,7 +3455,7 @@ var OpenRouterChatLanguageModel = class {
3387
3455
  return baseArgs;
3388
3456
  }
3389
3457
  async doGenerate(options) {
3390
- var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
3458
+ var _b16, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v;
3391
3459
  const providerOptions = options.providerOptions || {};
3392
3460
  const openrouterOptions = providerOptions.openrouter || {};
3393
3461
  const _a16 = openrouterOptions, { cacheControl } = _a16, restOpenrouterOptions = __objRest(_a16, ["cacheControl"]);
@@ -3483,12 +3551,18 @@ var OpenRouterChatLanguageModel = class {
3483
3551
  }
3484
3552
  if (choice.message.tool_calls) {
3485
3553
  let reasoningDetailsAttachedToToolCall = false;
3554
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3486
3555
  for (const toolCall of choice.message.tool_calls) {
3556
+ let toolCallId = toolCall.id;
3557
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3558
+ toolCallId = generateId();
3559
+ }
3560
+ seenToolCallIds.add(toolCallId);
3487
3561
  content.push({
3488
3562
  type: "tool-call",
3489
- toolCallId: (_c = toolCall.id) != null ? _c : generateId(),
3563
+ toolCallId,
3490
3564
  toolName: toolCall.function.name,
3491
- input: (_d = toolCall.function.arguments) != null ? _d : "{}",
3565
+ input: (_c = toolCall.function.arguments) != null ? _c : "{}",
3492
3566
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
3493
3567
  openrouter: {
3494
3568
  reasoning_details: reasoningDetails
@@ -3515,19 +3589,19 @@ var OpenRouterChatLanguageModel = class {
3515
3589
  sourceType: "url",
3516
3590
  id: annotation.url_citation.url,
3517
3591
  url: annotation.url_citation.url,
3518
- title: (_e = annotation.url_citation.title) != null ? _e : "",
3592
+ title: (_d = annotation.url_citation.title) != null ? _d : "",
3519
3593
  providerMetadata: {
3520
3594
  openrouter: {
3521
- content: (_f = annotation.url_citation.content) != null ? _f : "",
3522
- startIndex: (_g = annotation.url_citation.start_index) != null ? _g : 0,
3523
- endIndex: (_h = annotation.url_citation.end_index) != null ? _h : 0
3595
+ content: (_e = annotation.url_citation.content) != null ? _e : "",
3596
+ startIndex: (_f = annotation.url_citation.start_index) != null ? _f : 0,
3597
+ endIndex: (_g = annotation.url_citation.end_index) != null ? _g : 0
3524
3598
  }
3525
3599
  }
3526
3600
  });
3527
3601
  }
3528
3602
  }
3529
3603
  }
3530
- const fileAnnotations = (_i = choice.message.annotations) == null ? void 0 : _i.filter(
3604
+ const fileAnnotations = (_h = choice.message.annotations) == null ? void 0 : _h.filter(
3531
3605
  (a) => a.type === "file"
3532
3606
  );
3533
3607
  const hasToolCalls = choice.message.tool_calls && choice.message.tool_calls.length > 0;
@@ -3535,7 +3609,7 @@ var OpenRouterChatLanguageModel = class {
3535
3609
  (d) => d.type === "reasoning.encrypted" /* Encrypted */ && d.data
3536
3610
  );
3537
3611
  const shouldOverrideFinishReason = hasToolCalls && hasEncryptedReasoning && choice.finish_reason === "stop";
3538
- const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_j = choice.finish_reason) != null ? _j : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3612
+ const mappedFinishReason = shouldOverrideFinishReason ? createFinishReason("tool-calls", (_i = choice.finish_reason) != null ? _i : void 0) : mapOpenRouterFinishReason(choice.finish_reason);
3539
3613
  const effectiveFinishReason = hasToolCalls && mappedFinishReason.unified === "other" ? createFinishReason("tool-calls", mappedFinishReason.raw) : mappedFinishReason;
3540
3614
  return {
3541
3615
  content,
@@ -3544,22 +3618,22 @@ var OpenRouterChatLanguageModel = class {
3544
3618
  warnings: [],
3545
3619
  providerMetadata: {
3546
3620
  openrouter: OpenRouterProviderMetadataSchema.parse({
3547
- provider: (_k = response.provider) != null ? _k : "",
3548
- reasoning_details: (_l = choice.message.reasoning_details) != null ? _l : [],
3621
+ provider: (_j = response.provider) != null ? _j : "",
3622
+ reasoning_details: (_k = choice.message.reasoning_details) != null ? _k : [],
3549
3623
  annotations: fileAnnotations && fileAnnotations.length > 0 ? fileAnnotations : void 0,
3550
3624
  usage: __spreadValues(__spreadValues(__spreadValues(__spreadValues({
3551
- promptTokens: (_m = usageInfo.inputTokens.total) != null ? _m : 0,
3552
- completionTokens: (_n = usageInfo.outputTokens.total) != null ? _n : 0,
3553
- totalTokens: ((_o = usageInfo.inputTokens.total) != null ? _o : 0) + ((_p = usageInfo.outputTokens.total) != null ? _p : 0)
3554
- }, ((_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 ? {
3625
+ promptTokens: (_l = usageInfo.inputTokens.total) != null ? _l : 0,
3626
+ completionTokens: (_m = usageInfo.outputTokens.total) != null ? _m : 0,
3627
+ totalTokens: ((_n = usageInfo.inputTokens.total) != null ? _n : 0) + ((_o = usageInfo.outputTokens.total) != null ? _o : 0)
3628
+ }, ((_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 ? {
3555
3629
  promptTokensDetails: {
3556
3630
  cachedTokens: response.usage.prompt_tokens_details.cached_tokens
3557
3631
  }
3558
- } : {}), ((_u = (_t = response.usage) == null ? void 0 : _t.completion_tokens_details) == null ? void 0 : _u.reasoning_tokens) != null ? {
3632
+ } : {}), ((_t = (_s = response.usage) == null ? void 0 : _s.completion_tokens_details) == null ? void 0 : _t.reasoning_tokens) != null ? {
3559
3633
  completionTokensDetails: {
3560
3634
  reasoningTokens: response.usage.completion_tokens_details.reasoning_tokens
3561
3635
  }
3562
- } : {}), ((_w = (_v = response.usage) == null ? void 0 : _v.cost_details) == null ? void 0 : _w.upstream_inference_cost) != null ? {
3636
+ } : {}), ((_v = (_u = response.usage) == null ? void 0 : _u.cost_details) == null ? void 0 : _v.upstream_inference_cost) != null ? {
3563
3637
  costDetails: {
3564
3638
  upstreamInferenceCost: response.usage.cost_details.upstream_inference_cost
3565
3639
  }
@@ -3606,6 +3680,7 @@ var OpenRouterChatLanguageModel = class {
3606
3680
  streamError = err;
3607
3681
  });
3608
3682
  const toolCalls = [];
3683
+ const seenToolCallIds = /* @__PURE__ */ new Set();
3609
3684
  let finishReason = createFinishReason("other");
3610
3685
  const usage = {
3611
3686
  inputTokens: {
@@ -3836,24 +3911,23 @@ var OpenRouterChatLanguageModel = class {
3836
3911
  message: `Expected 'function' type.`
3837
3912
  });
3838
3913
  }
3839
- if (toolCallDelta.id == null) {
3840
- throw new InvalidResponseDataError({
3841
- data: toolCallDelta,
3842
- message: `Expected 'id' to be a string.`
3843
- });
3844
- }
3845
3914
  if (((_k = toolCallDelta.function) == null ? void 0 : _k.name) == null) {
3846
3915
  throw new InvalidResponseDataError({
3847
3916
  data: toolCallDelta,
3848
3917
  message: `Expected 'function.name' to be a string.`
3849
3918
  });
3850
3919
  }
3920
+ let toolCallId = (_l = toolCallDelta.id) != null ? _l : "";
3921
+ if (!toolCallId || seenToolCallIds.has(toolCallId)) {
3922
+ toolCallId = generateId();
3923
+ }
3924
+ seenToolCallIds.add(toolCallId);
3851
3925
  toolCalls[index] = {
3852
- id: toolCallDelta.id,
3926
+ id: toolCallId,
3853
3927
  type: "function",
3854
3928
  function: {
3855
3929
  name: toolCallDelta.function.name,
3856
- arguments: (_l = toolCallDelta.function.arguments) != null ? _l : ""
3930
+ arguments: (_m = toolCallDelta.function.arguments) != null ? _m : ""
3857
3931
  },
3858
3932
  inputStarted: false,
3859
3933
  sent: false
@@ -3865,7 +3939,7 @@ var OpenRouterChatLanguageModel = class {
3865
3939
  message: `Tool call at index ${index} is missing after creation.`
3866
3940
  });
3867
3941
  }
3868
- if (((_m = toolCall2.function) == null ? void 0 : _m.name) != null && ((_n = toolCall2.function) == null ? void 0 : _n.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3942
+ if (((_n = toolCall2.function) == null ? void 0 : _n.name) != null && ((_o = toolCall2.function) == null ? void 0 : _o.arguments) != null && isParsableJson(toolCall2.function.arguments)) {
3869
3943
  toolCall2.inputStarted = true;
3870
3944
  controller.enqueue({
3871
3945
  type: "tool-input-start",
@@ -3923,22 +3997,22 @@ var OpenRouterChatLanguageModel = class {
3923
3997
  });
3924
3998
  }
3925
3999
  }
3926
- if (((_o = toolCallDelta.function) == null ? void 0 : _o.arguments) != null) {
3927
- toolCall.function.arguments += (_q = (_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null ? _q : "";
4000
+ if (((_p = toolCallDelta.function) == null ? void 0 : _p.arguments) != null) {
4001
+ toolCall.function.arguments += (_r = (_q = toolCallDelta.function) == null ? void 0 : _q.arguments) != null ? _r : "";
3928
4002
  }
3929
4003
  controller.enqueue({
3930
4004
  type: "tool-input-delta",
3931
4005
  id: toolCall.id,
3932
- delta: (_r = toolCallDelta.function.arguments) != null ? _r : ""
4006
+ delta: (_s = toolCallDelta.function.arguments) != null ? _s : ""
3933
4007
  });
3934
- if (((_s = toolCall.function) == null ? void 0 : _s.name) != null && ((_t = toolCall.function) == null ? void 0 : _t.arguments) != null && isParsableJson(toolCall.function.arguments)) {
4008
+ if (((_t = toolCall.function) == null ? void 0 : _t.name) != null && ((_u = toolCall.function) == null ? void 0 : _u.arguments) != null && isParsableJson(toolCall.function.arguments)) {
3935
4009
  controller.enqueue({
3936
4010
  type: "tool-input-end",
3937
4011
  id: toolCall.id
3938
4012
  });
3939
4013
  controller.enqueue({
3940
4014
  type: "tool-call",
3941
- toolCallId: (_u = toolCall.id) != null ? _u : generateId(),
4015
+ toolCallId: toolCall.id,
3942
4016
  toolName: toolCall.function.name,
3943
4017
  input: toolCall.function.arguments,
3944
4018
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -3963,7 +4037,6 @@ var OpenRouterChatLanguageModel = class {
3963
4037
  }
3964
4038
  },
3965
4039
  flush(controller) {
3966
- var _a17;
3967
4040
  const hasToolCalls = toolCalls.length > 0;
3968
4041
  if (streamError != null) {
3969
4042
  finishReason = createFinishReason("error");
@@ -4000,7 +4073,7 @@ var OpenRouterChatLanguageModel = class {
4000
4073
  });
4001
4074
  controller.enqueue({
4002
4075
  type: "tool-call",
4003
- toolCallId: (_a17 = toolCall.id) != null ? _a17 : generateId(),
4076
+ toolCallId: toolCall.id,
4004
4077
  toolName: toolCall.function.name,
4005
4078
  input,
4006
4079
  providerMetadata: !reasoningDetailsAttachedToToolCall ? {
@@ -4063,6 +4136,22 @@ var OpenRouterChatLanguageModel = class {
4063
4136
  };
4064
4137
  }
4065
4138
  };
4139
+ function mapProviderTool(tool2) {
4140
+ const [provider, toolName] = tool2.id.split(".");
4141
+ const apiToolType = `${provider}:${toolName}`;
4142
+ const mappedArgs = {};
4143
+ for (const [key, value] of Object.entries(tool2.args)) {
4144
+ if (value !== void 0) {
4145
+ mappedArgs[camelToSnake(key)] = value;
4146
+ }
4147
+ }
4148
+ return __spreadValues({
4149
+ type: apiToolType
4150
+ }, mappedArgs);
4151
+ }
4152
+ function camelToSnake(str) {
4153
+ return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
4154
+ }
4066
4155
 
4067
4156
  // src/completion/convert-to-openrouter-completion-prompt.ts
4068
4157
  function convertToOpenRouterCompletionPrompt({
@@ -4791,6 +4880,17 @@ function convertImageFileToContentPart(file) {
4791
4880
  };
4792
4881
  }
4793
4882
 
4883
+ // src/tool/web-search.ts
4884
+ var import_v410 = require("zod/v4");
4885
+ var webSearchInputSchema = import_v410.z.object({
4886
+ /** Search results returned by the server tool */
4887
+ results: import_v410.z.array(import_v410.z.unknown()).optional()
4888
+ });
4889
+ var webSearch = createProviderToolFactory({
4890
+ id: "openrouter.web_search",
4891
+ inputSchema: webSearchInputSchema
4892
+ });
4893
+
4794
4894
  // src/utils/remove-undefined.ts
4795
4895
  function removeUndefinedEntries(record) {
4796
4896
  return Object.fromEntries(
@@ -4832,7 +4932,7 @@ function withUserAgentSuffix2(headers, ...userAgentSuffixParts) {
4832
4932
  }
4833
4933
 
4834
4934
  // src/version.ts
4835
- var VERSION2 = false ? "0.0.0-test" : "2.5.0";
4935
+ var VERSION2 = false ? "0.0.0-test" : "2.6.0";
4836
4936
 
4837
4937
  // src/provider.ts
4838
4938
  function createOpenRouter(options = {}) {
@@ -4902,6 +5002,9 @@ function createOpenRouter(options = {}) {
4902
5002
  provider.textEmbeddingModel = createEmbeddingModel;
4903
5003
  provider.embedding = createEmbeddingModel;
4904
5004
  provider.imageModel = createImageModel;
5005
+ provider.tools = {
5006
+ webSearch
5007
+ };
4905
5008
  return provider;
4906
5009
  }
4907
5010
  var openrouter = createOpenRouter({