gemini_adk_rs/tools/
google_search.rs

1//! Built-in server-side Google Search tool.
2//!
3//! Does not execute locally -- modifies the [`LlmRequest`] to include the
4//! appropriate search configuration depending on the model version:
5//!
6//! * **Gemini 2.x+**: adds [`Tool::google_search()`]
7//! * **Gemini 1.x**: adds a `Tool` with `google_search_retrieval`
8//! * **Non-Gemini models**: no-op (the request is left unchanged)
9
10use crate::llm::LlmRequest;
11use crate::utils::model_name::{is_gemini1_model, is_gemini2_or_above};
12use gemini_genai_rs::prelude::{GoogleSearchRetrieval, Tool};
13
14/// Built-in server-side Google Search tool.
15///
16/// This tool does not perform any local execution. Instead, it modifies
17/// the outgoing [`LlmRequest`] to include the Google Search tool
18/// configuration appropriate for the target model.
19#[derive(Debug, Clone, Copy, Default)]
20pub struct GoogleSearchTool;
21
22impl GoogleSearchTool {
23    /// Create a new `GoogleSearchTool`.
24    pub fn new() -> Self {
25        Self
26    }
27
28    /// Add Google Search configuration to the given request.
29    ///
30    /// Inspects the `model` string to determine which variant to use:
31    ///
32    /// * Gemini 2.x or above: adds `Tool::google_search()` (the `googleSearch`
33    ///   field).
34    /// * Gemini 1.x: adds a `Tool` with `google_search_retrieval`.
35    /// * Non-Gemini models: the request is left unchanged (no-op).
36    pub fn process_llm_request(&self, request: &mut LlmRequest, model: &str) {
37        if is_gemini2_or_above(model) {
38            request.tools.push(Tool::google_search());
39        } else if is_gemini1_model(model) {
40            request.tools.push(Tool {
41                function_declarations: None,
42                url_context: None,
43                google_search: None,
44                code_execution: None,
45                google_search_retrieval: Some(GoogleSearchRetrieval {}),
46            });
47        }
48        // Non-Gemini models: no-op
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn gemini2_adds_google_search() {
58        let tool = GoogleSearchTool::new();
59        let mut request = LlmRequest::default();
60        tool.process_llm_request(&mut request, "gemini-2.5-flash");
61
62        assert_eq!(request.tools.len(), 1);
63        assert!(request.tools[0].google_search.is_some());
64        assert!(request.tools[0].google_search_retrieval.is_none());
65    }
66
67    #[test]
68    fn gemini2_0_adds_google_search() {
69        let tool = GoogleSearchTool::new();
70        let mut request = LlmRequest::default();
71        tool.process_llm_request(&mut request, "gemini-2.0-flash");
72
73        assert_eq!(request.tools.len(), 1);
74        assert!(request.tools[0].google_search.is_some());
75    }
76
77    #[test]
78    fn gemini1_adds_google_search_retrieval() {
79        let tool = GoogleSearchTool::new();
80        let mut request = LlmRequest::default();
81        tool.process_llm_request(&mut request, "gemini-1.5-pro");
82
83        assert_eq!(request.tools.len(), 1);
84        assert!(request.tools[0].google_search_retrieval.is_some());
85        assert!(request.tools[0].google_search.is_none());
86    }
87
88    #[test]
89    fn gemini1_0_adds_google_search_retrieval() {
90        let tool = GoogleSearchTool::new();
91        let mut request = LlmRequest::default();
92        tool.process_llm_request(&mut request, "gemini-1.0-pro");
93
94        assert_eq!(request.tools.len(), 1);
95        assert!(request.tools[0].google_search_retrieval.is_some());
96    }
97
98    #[test]
99    fn non_gemini_model_is_noop() {
100        let tool = GoogleSearchTool::new();
101        let mut request = LlmRequest::default();
102        tool.process_llm_request(&mut request, "claude-3-opus");
103
104        assert!(request.tools.is_empty());
105    }
106
107    #[test]
108    fn unknown_model_is_noop() {
109        let tool = GoogleSearchTool::new();
110        let mut request = LlmRequest::default();
111        tool.process_llm_request(&mut request, "gpt-4");
112
113        assert!(request.tools.is_empty());
114    }
115
116    #[test]
117    fn empty_model_string_is_noop() {
118        let tool = GoogleSearchTool::new();
119        let mut request = LlmRequest::default();
120        tool.process_llm_request(&mut request, "");
121
122        assert!(request.tools.is_empty());
123    }
124
125    #[test]
126    fn full_resource_path_gemini2() {
127        let tool = GoogleSearchTool::new();
128        let mut request = LlmRequest::default();
129        tool.process_llm_request(
130            &mut request,
131            "projects/my-proj/locations/us-central1/publishers/google/models/gemini-2.5-flash",
132        );
133
134        assert_eq!(request.tools.len(), 1);
135        assert!(request.tools[0].google_search.is_some());
136    }
137
138    #[test]
139    fn full_resource_path_gemini1() {
140        let tool = GoogleSearchTool::new();
141        let mut request = LlmRequest::default();
142        tool.process_llm_request(
143            &mut request,
144            "projects/my-proj/locations/us-central1/publishers/google/models/gemini-1.5-pro-002",
145        );
146
147        assert_eq!(request.tools.len(), 1);
148        assert!(request.tools[0].google_search_retrieval.is_some());
149    }
150
151    #[test]
152    fn preserves_existing_tools() {
153        let tool = GoogleSearchTool::new();
154        let mut request = LlmRequest::default();
155        // Add a pre-existing tool
156        request.tools.push(Tool::code_execution());
157
158        tool.process_llm_request(&mut request, "gemini-2.5-flash");
159
160        assert_eq!(request.tools.len(), 2);
161        assert!(request.tools[0].code_execution.is_some());
162        assert!(request.tools[1].google_search.is_some());
163    }
164
165    #[test]
166    fn gemini3_future_version() {
167        let tool = GoogleSearchTool::new();
168        let mut request = LlmRequest::default();
169        tool.process_llm_request(&mut request, "gemini-3.0-ultra");
170
171        assert_eq!(request.tools.len(), 1);
172        assert!(request.tools[0].google_search.is_some());
173    }
174}