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}