Skip to main content

adk_tool/builtin/
web_search.rs

1use adk_core::{Result, Tool, ToolContext};
2use async_trait::async_trait;
3use serde_json::{Value, json};
4use std::sync::Arc;
5
6/// Approximate user location for Anthropic's web search tool.
7#[derive(Debug, Clone, Default)]
8pub struct WebSearchUserLocation {
9    city: Option<String>,
10    country: Option<String>,
11    region: Option<String>,
12    timezone: Option<String>,
13}
14
15impl WebSearchUserLocation {
16    pub fn new() -> Self {
17        Self::default()
18    }
19
20    pub fn with_city(mut self, city: impl Into<String>) -> Self {
21        self.city = Some(city.into());
22        self
23    }
24
25    pub fn with_country(mut self, country: impl Into<String>) -> Self {
26        self.country = Some(country.into());
27        self
28    }
29
30    pub fn with_region(mut self, region: impl Into<String>) -> Self {
31        self.region = Some(region.into());
32        self
33    }
34
35    pub fn with_timezone(mut self, timezone: impl Into<String>) -> Self {
36        self.timezone = Some(timezone.into());
37        self
38    }
39
40    fn to_json(&self) -> Value {
41        json!({
42            "type": "approximate",
43            "city": self.city,
44            "country": self.country,
45            "region": self.region,
46            "timezone": self.timezone,
47        })
48    }
49}
50
51/// WebSearch is a built-in tool for Anthropic Claude models that enables
52/// server-side web search. The model searches the web internally and returns
53/// results as ServerToolUse / WebSearchToolResult content blocks.
54#[derive(Debug, Clone, Default)]
55pub struct WebSearchTool {
56    allowed_domains: Option<Vec<String>>,
57    blocked_domains: Option<Vec<String>>,
58    max_uses: Option<i32>,
59    user_location: Option<WebSearchUserLocation>,
60}
61
62impl WebSearchTool {
63    pub fn new() -> Self {
64        Self::default()
65    }
66
67    pub fn with_allowed_domains(
68        mut self,
69        domains: impl IntoIterator<Item = impl Into<String>>,
70    ) -> Self {
71        self.allowed_domains = Some(domains.into_iter().map(Into::into).collect());
72        self.blocked_domains = None;
73        self
74    }
75
76    pub fn with_blocked_domains(
77        mut self,
78        domains: impl IntoIterator<Item = impl Into<String>>,
79    ) -> Self {
80        self.blocked_domains = Some(domains.into_iter().map(Into::into).collect());
81        self.allowed_domains = None;
82        self
83    }
84
85    pub fn with_max_uses(mut self, max_uses: i32) -> Self {
86        self.max_uses = Some(max_uses);
87        self
88    }
89
90    pub fn with_user_location(mut self, user_location: WebSearchUserLocation) -> Self {
91        self.user_location = Some(user_location);
92        self
93    }
94}
95
96#[async_trait]
97impl Tool for WebSearchTool {
98    fn name(&self) -> &str {
99        "web_search"
100    }
101
102    fn description(&self) -> &str {
103        "Searches the web for current information (server-side)."
104    }
105
106    fn is_builtin(&self) -> bool {
107        true
108    }
109
110    fn declaration(&self) -> Value {
111        json!({
112            "name": self.name(),
113            "description": self.description(),
114            "x-adk-anthropic-tool": {
115                "type": "web_search_20250305",
116                "name": "web_search",
117                "allowed_domains": self.allowed_domains,
118                "blocked_domains": self.blocked_domains,
119                "max_uses": self.max_uses,
120                "user_location": self.user_location.as_ref().map(WebSearchUserLocation::to_json),
121            }
122        })
123    }
124
125    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
126        Err(adk_core::AdkError::tool("WebSearch is handled internally by Anthropic"))
127    }
128}