adk_browser/tools/
frames.rs

1//! Frame/iframe management tools.
2
3use crate::session::BrowserSession;
4use adk_core::{AdkError, Result, Tool, ToolContext};
5use async_trait::async_trait;
6use serde_json::{json, Value};
7use std::sync::Arc;
8
9/// Tool for switching to a frame by index.
10pub struct SwitchToFrameTool {
11    browser: Arc<BrowserSession>,
12}
13
14impl SwitchToFrameTool {
15    pub fn new(browser: Arc<BrowserSession>) -> Self {
16        Self { browser }
17    }
18}
19
20#[async_trait]
21impl Tool for SwitchToFrameTool {
22    fn name(&self) -> &str {
23        "browser_switch_to_frame"
24    }
25
26    fn description(&self) -> &str {
27        "Switch to an iframe by index number or CSS selector."
28    }
29
30    fn parameters_schema(&self) -> Option<Value> {
31        Some(json!({
32            "type": "object",
33            "properties": {
34                "index": {
35                    "type": "integer",
36                    "description": "Frame index (0-based)"
37                },
38                "selector": {
39                    "type": "string",
40                    "description": "CSS selector for the iframe element"
41                }
42            }
43        }))
44    }
45
46    async fn execute(&self, _ctx: Arc<dyn ToolContext>, args: Value) -> Result<Value> {
47        let index = args.get("index").and_then(|v| v.as_u64());
48        let selector = args.get("selector").and_then(|v| v.as_str());
49
50        if let Some(idx) = index {
51            self.browser.switch_to_frame_by_index(idx as u16).await?;
52            Ok(json!({
53                "success": true,
54                "switched_to_frame": idx
55            }))
56        } else if let Some(sel) = selector {
57            self.browser.switch_to_frame_by_selector(sel).await?;
58            Ok(json!({
59                "success": true,
60                "switched_to_frame": sel
61            }))
62        } else {
63            Err(AdkError::Tool("Must provide either 'index' or 'selector'".to_string()))
64        }
65    }
66}
67
68/// Tool for switching to the parent frame.
69pub struct SwitchToParentFrameTool {
70    browser: Arc<BrowserSession>,
71}
72
73impl SwitchToParentFrameTool {
74    pub fn new(browser: Arc<BrowserSession>) -> Self {
75        Self { browser }
76    }
77}
78
79#[async_trait]
80impl Tool for SwitchToParentFrameTool {
81    fn name(&self) -> &str {
82        "browser_switch_to_parent_frame"
83    }
84
85    fn description(&self) -> &str {
86        "Switch to the parent frame (exit current iframe)."
87    }
88
89    fn parameters_schema(&self) -> Option<Value> {
90        Some(json!({
91            "type": "object",
92            "properties": {}
93        }))
94    }
95
96    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
97        self.browser.switch_to_parent_frame().await?;
98
99        Ok(json!({
100            "success": true,
101            "message": "Switched to parent frame"
102        }))
103    }
104}
105
106/// Tool for switching to the default/main content.
107pub struct SwitchToDefaultContentTool {
108    browser: Arc<BrowserSession>,
109}
110
111impl SwitchToDefaultContentTool {
112    pub fn new(browser: Arc<BrowserSession>) -> Self {
113        Self { browser }
114    }
115}
116
117#[async_trait]
118impl Tool for SwitchToDefaultContentTool {
119    fn name(&self) -> &str {
120        "browser_switch_to_default_content"
121    }
122
123    fn description(&self) -> &str {
124        "Switch back to the main page content (exit all iframes)."
125    }
126
127    fn parameters_schema(&self) -> Option<Value> {
128        Some(json!({
129            "type": "object",
130            "properties": {}
131        }))
132    }
133
134    async fn execute(&self, _ctx: Arc<dyn ToolContext>, _args: Value) -> Result<Value> {
135        self.browser.switch_to_default_content().await?;
136
137        Ok(json!({
138            "success": true,
139            "message": "Switched to default content"
140        }))
141    }
142}