Skip to main content

adk_tool/builtin/
gemini_extra.rs

1use adk_core::{Result, Tool, ToolContext};
2use async_trait::async_trait;
3use serde_json::{Value, json};
4use std::sync::Arc;
5
6/// Contextual Google Maps location used by Gemini retrieval config.
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub struct GoogleMapsContext {
9    latitude: f64,
10    longitude: f64,
11}
12
13impl GoogleMapsContext {
14    /// Create a new contextual location.
15    pub fn new(latitude: f64, longitude: f64) -> Self {
16        Self { latitude, longitude }
17    }
18
19    fn to_json(self) -> Value {
20        json!({
21            "retrievalConfig": {
22                "latLng": {
23                    "latitude": self.latitude,
24                    "longitude": self.longitude,
25                }
26            }
27        })
28    }
29}
30
31/// Gemini built-in Google Maps grounding tool.
32#[derive(Debug, Clone, Default)]
33pub struct GoogleMapsTool {
34    enable_widget: bool,
35    context: Option<GoogleMapsContext>,
36}
37
38impl GoogleMapsTool {
39    /// Create a new `GoogleMapsTool` with default settings.
40    pub fn new() -> Self {
41        Self::default()
42    }
43
44    /// Enable or disable the interactive widget in the response.
45    pub fn with_widget(mut self, enable_widget: bool) -> Self {
46        self.enable_widget = enable_widget;
47        self
48    }
49
50    /// Set the contextual location for map queries.
51    pub fn with_context(mut self, context: GoogleMapsContext) -> Self {
52        self.context = Some(context);
53        self
54    }
55}
56
57#[async_trait]
58impl Tool for GoogleMapsTool {
59    fn name(&self) -> &str {
60        "google_maps"
61    }
62
63    fn description(&self) -> &str {
64        "Grounds responses with Google Maps data for places, routes, and local context."
65    }
66
67    fn is_builtin(&self) -> bool {
68        true
69    }
70
71    fn declaration(&self) -> Value {
72        json!({
73            "name": self.name(),
74            "description": self.description(),
75            "x-adk-gemini-tool": {
76                "google_maps": {
77                    "enable_widget": self.enable_widget.then_some(true),
78                }
79            },
80            "x-adk-gemini-tool-config": self.context.map(GoogleMapsContext::to_json),
81        })
82    }
83
84    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
85        Err(adk_core::AdkError::tool("GoogleMaps is handled internally by Gemini"))
86    }
87}
88
89/// Gemini built-in code execution tool.
90#[derive(Debug, Clone, Default)]
91pub struct GeminiCodeExecutionTool;
92
93impl GeminiCodeExecutionTool {
94    /// Create a new `GeminiCodeExecutionTool`.
95    pub fn new() -> Self {
96        Self
97    }
98}
99
100#[async_trait]
101impl Tool for GeminiCodeExecutionTool {
102    fn name(&self) -> &str {
103        "gemini_code_execution"
104    }
105
106    fn description(&self) -> &str {
107        "Allows Gemini to write and execute Python code server-side."
108    }
109
110    fn is_builtin(&self) -> bool {
111        true
112    }
113
114    fn declaration(&self) -> Value {
115        json!({
116            "name": self.name(),
117            "description": self.description(),
118            "x-adk-gemini-tool": {
119                "code_execution": {}
120            }
121        })
122    }
123
124    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
125        Err(adk_core::AdkError::tool("Gemini code execution is handled internally by Gemini"))
126    }
127}
128
129/// Gemini built-in file search tool.
130#[derive(Debug, Clone)]
131pub struct GeminiFileSearchTool {
132    file_search_store_names: Vec<String>,
133}
134
135impl GeminiFileSearchTool {
136    /// Create a new `GeminiFileSearchTool` with the given store names.
137    pub fn new(file_search_store_names: impl IntoIterator<Item = impl Into<String>>) -> Self {
138        Self {
139            file_search_store_names: file_search_store_names.into_iter().map(Into::into).collect(),
140        }
141    }
142}
143
144#[async_trait]
145impl Tool for GeminiFileSearchTool {
146    fn name(&self) -> &str {
147        "gemini_file_search"
148    }
149
150    fn description(&self) -> &str {
151        "Searches Gemini File Search stores for relevant documents."
152    }
153
154    fn is_builtin(&self) -> bool {
155        true
156    }
157
158    fn declaration(&self) -> Value {
159        json!({
160            "name": self.name(),
161            "description": self.description(),
162            "x-adk-gemini-tool": {
163                "file_search": {
164                    "file_search_store_names": self.file_search_store_names
165                }
166            }
167        })
168    }
169
170    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
171        Err(adk_core::AdkError::tool("Gemini file search is handled internally by Gemini"))
172    }
173}
174
175/// Target environment for Gemini computer use.
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177pub enum GeminiComputerEnvironment {
178    /// Browser-based environment.
179    Browser,
180}
181
182impl GeminiComputerEnvironment {
183    fn as_wire(self) -> &'static str {
184        match self {
185            Self::Browser => "ENVIRONMENT_BROWSER",
186        }
187    }
188}
189
190/// Gemini built-in computer use tool declaration.
191#[derive(Debug, Clone)]
192pub struct GeminiComputerUseTool {
193    environment: GeminiComputerEnvironment,
194    excluded_predefined_functions: Vec<String>,
195}
196
197impl Default for GeminiComputerUseTool {
198    fn default() -> Self {
199        Self {
200            environment: GeminiComputerEnvironment::Browser,
201            excluded_predefined_functions: Vec::new(),
202        }
203    }
204}
205
206impl GeminiComputerUseTool {
207    /// Create a new `GeminiComputerUseTool` for the given environment.
208    pub fn new(environment: GeminiComputerEnvironment) -> Self {
209        Self { environment, ..Default::default() }
210    }
211
212    /// Exclude specific predefined functions from computer use.
213    pub fn with_excluded_functions(
214        mut self,
215        excluded_predefined_functions: impl IntoIterator<Item = impl Into<String>>,
216    ) -> Self {
217        self.excluded_predefined_functions =
218            excluded_predefined_functions.into_iter().map(Into::into).collect();
219        self
220    }
221}
222
223#[async_trait]
224impl Tool for GeminiComputerUseTool {
225    fn name(&self) -> &str {
226        "gemini_computer_use"
227    }
228
229    fn description(&self) -> &str {
230        "Enables Gemini computer use, which emits predefined UI action function calls."
231    }
232
233    fn is_builtin(&self) -> bool {
234        true
235    }
236
237    fn declaration(&self) -> Value {
238        json!({
239            "name": self.name(),
240            "description": self.description(),
241            "x-adk-gemini-tool": {
242                "computer_use": {
243                    "environment": self.environment.as_wire(),
244                    "excluded_predefined_functions": (!self.excluded_predefined_functions.is_empty())
245                        .then_some(self.excluded_predefined_functions.clone()),
246                }
247            }
248        })
249    }
250
251    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
252        Err(adk_core::AdkError::tool("Gemini computer use actions must be executed client-side"))
253    }
254}