Skip to main content

adk_tool/builtin/
google_search.rs

1use crate::builtin::bypass::BypassMultiToolsLimit;
2use adk_core::{Result, Tool, ToolContext};
3use async_trait::async_trait;
4use serde_json::{Value, json};
5use std::sync::Arc;
6
7/// GoogleSearch is a built-in tool that is automatically invoked by Gemini
8/// models to retrieve search results from Google Search.
9/// The tool operates internally within the model and does not require or
10/// perform local code execution.
11#[derive(Default)]
12pub struct GoogleSearchTool;
13
14impl GoogleSearchTool {
15    /// Create a new `GoogleSearchTool`.
16    pub fn new() -> Self {
17        Self
18    }
19}
20
21/// Bypass support: convert the built-in Google Search tool into a
22/// function-calling tool so it can be used alongside custom function tools.
23///
24/// The Gemini Interactions API forbids mixing built-in (server-side) tools with
25/// custom function tools in one request. Implementing [`BypassMultiToolsLimit`]
26/// mirrors ADK-Python's `bypass_multi_tools_limit=True`: the converted tool
27/// reports `is_builtin() == false`, declares a normal `query: string` function
28/// schema, and performs grounded search by delegating to an internal
29/// single-turn agent.
30///
31/// Because `adk-tool` cannot depend on `adk-agent`, the internal
32/// grounded-search agent is supplied by the caller. It is expected to be an
33/// `LlmAgent` configured with [`GoogleSearchTool`] and a Gemini model so that
34/// the grounding happens server-side.
35///
36/// # Example
37///
38/// ```rust,ignore
39/// use adk_tool::{BypassMultiToolsLimit, GoogleSearchTool};
40/// use std::sync::Arc;
41///
42/// // `search_agent` is an LlmAgent with GoogleSearchTool + a Gemini model.
43/// let tool = GoogleSearchTool::new().with_bypass_multi_tools_limit(Arc::new(search_agent));
44/// assert!(!tool.is_builtin());
45/// ```
46impl BypassMultiToolsLimit for GoogleSearchTool {
47    fn bypass_name(&self) -> String {
48        self.name().to_string()
49    }
50
51    fn bypass_description(&self) -> String {
52        "Performs a Google search to retrieve information from the web.".to_string()
53    }
54
55    fn bypass_parameters_schema(&self) -> Value {
56        json!({
57            "type": "object",
58            "properties": {
59                "query": {
60                    "type": "string",
61                    "description": "The search query to look up on Google."
62                }
63            },
64            "required": ["query"]
65        })
66    }
67
68    fn bypass_query_field(&self) -> String {
69        "query".to_string()
70    }
71}
72
73#[async_trait]
74impl Tool for GoogleSearchTool {
75    fn name(&self) -> &str {
76        "google_search"
77    }
78
79    fn description(&self) -> &str {
80        "Performs a Google search to retrieve information from the web."
81    }
82
83    fn is_builtin(&self) -> bool {
84        true
85    }
86
87    fn declaration(&self) -> Value {
88        json!({
89            "name": self.name(),
90            "description": self.description(),
91            "x-adk-gemini-tool": {
92                "google_search": {}
93            }
94        })
95    }
96
97    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
98        // Google Search is handled internally by Gemini models
99        // This should not be called directly
100        Err(adk_core::AdkError::tool("GoogleSearch is handled internally by Gemini"))
101    }
102}