Skip to main content

adk_browser/tools/
navigate.rs

1//! Navigate tool for browser navigation.
2
3use crate::session::BrowserSession;
4use adk_core::{Result, Tool, ToolContext};
5use async_trait::async_trait;
6use serde_json::{Value, json};
7use std::sync::Arc;
8
9/// Tool for navigating to URLs.
10pub struct NavigateTool {
11    browser: Arc<BrowserSession>,
12}
13
14impl NavigateTool {
15    /// Create a new navigate tool with a shared browser session.
16    pub fn new(browser: Arc<BrowserSession>) -> Self {
17        Self { browser }
18    }
19}
20
21#[async_trait]
22impl Tool for NavigateTool {
23    fn name(&self) -> &str {
24        "browser_navigate"
25    }
26
27    fn description(&self) -> &str {
28        "Navigate the browser to a specified URL. Use this to open web pages."
29    }
30
31    fn parameters_schema(&self) -> Option<Value> {
32        Some(json!({
33            "type": "object",
34            "properties": {
35                "url": {
36                    "type": "string",
37                    "description": "The URL to navigate to (e.g., 'https://example.com')"
38                }
39            },
40            "required": ["url"]
41        }))
42    }
43
44    fn response_schema(&self) -> Option<Value> {
45        Some(json!({
46            "type": "object",
47            "properties": {
48                "success": { "type": "boolean" },
49                "url": { "type": "string" },
50                "title": { "type": "string" }
51            }
52        }))
53    }
54
55    async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
56        let url = args
57            .get("url")
58            .and_then(|v| v.as_str())
59            .ok_or_else(|| adk_core::AdkError::Tool("Missing 'url' parameter".to_string()))?;
60
61        // Validate URL
62        url::Url::parse(url)
63            .map_err(|e| adk_core::AdkError::Tool(format!("Invalid URL '{}': {}", url, e)))?;
64
65        // Navigate
66        self.browser.navigate(url).await?;
67
68        // Get result info
69        let current_url = self.browser.current_url().await.unwrap_or_default();
70        let title = self.browser.title().await.unwrap_or_default();
71
72        // Include page context like interaction tools do
73        match self.browser.page_context().await {
74            Ok(page) => Ok(json!({
75                "success": true,
76                "url": current_url,
77                "title": title,
78                "page": page
79            })),
80            Err(e) => Ok(json!({
81                "success": true,
82                "url": current_url,
83                "title": title,
84                "page_context_error": e.to_string()
85            })),
86        }
87    }
88}
89
90/// Tool for going back in browser history.
91pub struct BackTool {
92    browser: Arc<BrowserSession>,
93}
94
95impl BackTool {
96    pub fn new(browser: Arc<BrowserSession>) -> Self {
97        Self { browser }
98    }
99}
100
101#[async_trait]
102impl Tool for BackTool {
103    fn name(&self) -> &str {
104        "browser_back"
105    }
106
107    fn description(&self) -> &str {
108        "Go back to the previous page in browser history."
109    }
110
111    fn parameters_schema(&self) -> Option<Value> {
112        Some(json!({
113            "type": "object",
114            "properties": {}
115        }))
116    }
117
118    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
119        self.browser.back().await?;
120
121        let url = self.browser.current_url().await.unwrap_or_default();
122        let title = self.browser.title().await.unwrap_or_default();
123
124        // Include page context like interaction tools do
125        match self.browser.page_context().await {
126            Ok(page) => Ok(json!({
127                "success": true,
128                "url": url,
129                "title": title,
130                "page": page
131            })),
132            Err(e) => Ok(json!({
133                "success": true,
134                "url": url,
135                "title": title,
136                "page_context_error": e.to_string()
137            })),
138        }
139    }
140}
141
142/// Tool for going forward in browser history.
143pub struct ForwardTool {
144    browser: Arc<BrowserSession>,
145}
146
147impl ForwardTool {
148    pub fn new(browser: Arc<BrowserSession>) -> Self {
149        Self { browser }
150    }
151}
152
153#[async_trait]
154impl Tool for ForwardTool {
155    fn name(&self) -> &str {
156        "browser_forward"
157    }
158
159    fn description(&self) -> &str {
160        "Go forward to the next page in browser history."
161    }
162
163    fn parameters_schema(&self) -> Option<Value> {
164        Some(json!({
165            "type": "object",
166            "properties": {}
167        }))
168    }
169
170    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
171        self.browser.forward().await?;
172
173        let url = self.browser.current_url().await.unwrap_or_default();
174        let title = self.browser.title().await.unwrap_or_default();
175
176        // Include page context like interaction tools do
177        match self.browser.page_context().await {
178            Ok(page) => Ok(json!({
179                "success": true,
180                "url": url,
181                "title": title,
182                "page": page
183            })),
184            Err(e) => Ok(json!({
185                "success": true,
186                "url": url,
187                "title": title,
188                "page_context_error": e.to_string()
189            })),
190        }
191    }
192}
193
194/// Tool for refreshing the current page.
195pub struct RefreshTool {
196    browser: Arc<BrowserSession>,
197}
198
199impl RefreshTool {
200    pub fn new(browser: Arc<BrowserSession>) -> Self {
201        Self { browser }
202    }
203}
204
205#[async_trait]
206impl Tool for RefreshTool {
207    fn name(&self) -> &str {
208        "browser_refresh"
209    }
210
211    fn description(&self) -> &str {
212        "Refresh the current page."
213    }
214
215    fn parameters_schema(&self) -> Option<Value> {
216        Some(json!({
217            "type": "object",
218            "properties": {}
219        }))
220    }
221
222    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
223        self.browser.refresh().await?;
224
225        let url = self.browser.current_url().await.unwrap_or_default();
226        let title = self.browser.title().await.unwrap_or_default();
227
228        // Include page context like interaction tools do
229        match self.browser.page_context().await {
230            Ok(page) => Ok(json!({
231                "success": true,
232                "url": url,
233                "title": title,
234                "page": page
235            })),
236            Err(e) => Ok(json!({
237                "success": true,
238                "url": url,
239                "title": title,
240                "page_context_error": e.to_string()
241            })),
242        }
243    }
244}