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    pub fn new() -> Self {
40        Self::default()
41    }
42
43    pub fn with_widget(mut self, enable_widget: bool) -> Self {
44        self.enable_widget = enable_widget;
45        self
46    }
47
48    pub fn with_context(mut self, context: GoogleMapsContext) -> Self {
49        self.context = Some(context);
50        self
51    }
52}
53
54#[async_trait]
55impl Tool for GoogleMapsTool {
56    fn name(&self) -> &str {
57        "google_maps"
58    }
59
60    fn description(&self) -> &str {
61        "Grounds responses with Google Maps data for places, routes, and local context."
62    }
63
64    fn is_builtin(&self) -> bool {
65        true
66    }
67
68    fn declaration(&self) -> Value {
69        json!({
70            "name": self.name(),
71            "description": self.description(),
72            "x-adk-gemini-tool": {
73                "google_maps": {
74                    "enable_widget": self.enable_widget.then_some(true),
75                }
76            },
77            "x-adk-gemini-tool-config": self.context.map(GoogleMapsContext::to_json),
78        })
79    }
80
81    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
82        Err(adk_core::AdkError::tool("GoogleMaps is handled internally by Gemini"))
83    }
84}
85
86/// Gemini built-in code execution tool.
87#[derive(Debug, Clone, Default)]
88pub struct GeminiCodeExecutionTool;
89
90impl GeminiCodeExecutionTool {
91    pub fn new() -> Self {
92        Self
93    }
94}
95
96#[async_trait]
97impl Tool for GeminiCodeExecutionTool {
98    fn name(&self) -> &str {
99        "gemini_code_execution"
100    }
101
102    fn description(&self) -> &str {
103        "Allows Gemini to write and execute Python code 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-gemini-tool": {
115                "code_execution": {}
116            }
117        })
118    }
119
120    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
121        Err(adk_core::AdkError::tool("Gemini code execution is handled internally by Gemini"))
122    }
123}
124
125/// Gemini built-in file search tool.
126#[derive(Debug, Clone)]
127pub struct GeminiFileSearchTool {
128    file_search_store_names: Vec<String>,
129}
130
131impl GeminiFileSearchTool {
132    pub fn new(file_search_store_names: impl IntoIterator<Item = impl Into<String>>) -> Self {
133        Self {
134            file_search_store_names: file_search_store_names.into_iter().map(Into::into).collect(),
135        }
136    }
137}
138
139#[async_trait]
140impl Tool for GeminiFileSearchTool {
141    fn name(&self) -> &str {
142        "gemini_file_search"
143    }
144
145    fn description(&self) -> &str {
146        "Searches Gemini File Search stores for relevant documents."
147    }
148
149    fn is_builtin(&self) -> bool {
150        true
151    }
152
153    fn declaration(&self) -> Value {
154        json!({
155            "name": self.name(),
156            "description": self.description(),
157            "x-adk-gemini-tool": {
158                "file_search": {
159                    "file_search_store_names": self.file_search_store_names
160                }
161            }
162        })
163    }
164
165    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
166        Err(adk_core::AdkError::tool("Gemini file search is handled internally by Gemini"))
167    }
168}
169
170/// Target environment for Gemini computer use.
171#[derive(Debug, Clone, Copy, PartialEq, Eq)]
172pub enum GeminiComputerEnvironment {
173    Browser,
174}
175
176impl GeminiComputerEnvironment {
177    fn as_wire(self) -> &'static str {
178        match self {
179            Self::Browser => "ENVIRONMENT_BROWSER",
180        }
181    }
182}
183
184/// Gemini built-in computer use tool declaration.
185#[derive(Debug, Clone)]
186pub struct GeminiComputerUseTool {
187    environment: GeminiComputerEnvironment,
188    excluded_predefined_functions: Vec<String>,
189}
190
191impl Default for GeminiComputerUseTool {
192    fn default() -> Self {
193        Self {
194            environment: GeminiComputerEnvironment::Browser,
195            excluded_predefined_functions: Vec::new(),
196        }
197    }
198}
199
200impl GeminiComputerUseTool {
201    pub fn new(environment: GeminiComputerEnvironment) -> Self {
202        Self { environment, ..Default::default() }
203    }
204
205    pub fn with_excluded_functions(
206        mut self,
207        excluded_predefined_functions: impl IntoIterator<Item = impl Into<String>>,
208    ) -> Self {
209        self.excluded_predefined_functions =
210            excluded_predefined_functions.into_iter().map(Into::into).collect();
211        self
212    }
213}
214
215#[async_trait]
216impl Tool for GeminiComputerUseTool {
217    fn name(&self) -> &str {
218        "gemini_computer_use"
219    }
220
221    fn description(&self) -> &str {
222        "Enables Gemini computer use, which emits predefined UI action function calls."
223    }
224
225    fn is_builtin(&self) -> bool {
226        true
227    }
228
229    fn declaration(&self) -> Value {
230        json!({
231            "name": self.name(),
232            "description": self.description(),
233            "x-adk-gemini-tool": {
234                "computer_use": {
235                    "environment": self.environment.as_wire(),
236                    "excluded_predefined_functions": (!self.excluded_predefined_functions.is_empty())
237                        .then_some(self.excluded_predefined_functions.clone()),
238                }
239            }
240        })
241    }
242
243    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
244        Err(adk_core::AdkError::tool("Gemini computer use actions must be executed client-side"))
245    }
246}