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