use crate::session::BrowserSession;
use crate::tools::*;
use adk_core::{ReadonlyContext, Result, Tool, Toolset};
use async_trait::async_trait;
use std::sync::Arc;
pub struct BrowserToolset {
browser: Arc<BrowserSession>,
include_navigation: bool,
include_interaction: bool,
include_extraction: bool,
include_wait: bool,
include_screenshot: bool,
include_js: bool,
include_cookies: bool,
include_windows: bool,
include_frames: bool,
include_actions: bool,
}
impl BrowserToolset {
pub fn new(browser: Arc<BrowserSession>) -> Self {
Self {
browser,
include_navigation: true,
include_interaction: true,
include_extraction: true,
include_wait: true,
include_screenshot: true,
include_js: true,
include_cookies: true,
include_windows: true,
include_frames: true,
include_actions: true,
}
}
pub fn with_navigation(mut self, enabled: bool) -> Self {
self.include_navigation = enabled;
self
}
pub fn with_interaction(mut self, enabled: bool) -> Self {
self.include_interaction = enabled;
self
}
pub fn with_extraction(mut self, enabled: bool) -> Self {
self.include_extraction = enabled;
self
}
pub fn with_wait(mut self, enabled: bool) -> Self {
self.include_wait = enabled;
self
}
pub fn with_screenshot(mut self, enabled: bool) -> Self {
self.include_screenshot = enabled;
self
}
pub fn with_js(mut self, enabled: bool) -> Self {
self.include_js = enabled;
self
}
pub fn with_cookies(mut self, enabled: bool) -> Self {
self.include_cookies = enabled;
self
}
pub fn with_windows(mut self, enabled: bool) -> Self {
self.include_windows = enabled;
self
}
pub fn with_frames(mut self, enabled: bool) -> Self {
self.include_frames = enabled;
self
}
pub fn with_actions(mut self, enabled: bool) -> Self {
self.include_actions = enabled;
self
}
pub fn all_tools(&self) -> Vec<Arc<dyn Tool>> {
let mut tools: Vec<Arc<dyn Tool>> = Vec::new();
if self.include_navigation {
tools.push(Arc::new(NavigateTool::new(self.browser.clone())));
tools.push(Arc::new(BackTool::new(self.browser.clone())));
tools.push(Arc::new(ForwardTool::new(self.browser.clone())));
tools.push(Arc::new(RefreshTool::new(self.browser.clone())));
}
if self.include_interaction {
tools.push(Arc::new(ClickTool::new(self.browser.clone())));
tools.push(Arc::new(DoubleClickTool::new(self.browser.clone())));
tools.push(Arc::new(TypeTool::new(self.browser.clone())));
tools.push(Arc::new(ClearTool::new(self.browser.clone())));
tools.push(Arc::new(SelectTool::new(self.browser.clone())));
}
if self.include_extraction {
tools.push(Arc::new(ExtractTextTool::new(self.browser.clone())));
tools.push(Arc::new(ExtractAttributeTool::new(self.browser.clone())));
tools.push(Arc::new(ExtractLinksTool::new(self.browser.clone())));
tools.push(Arc::new(PageInfoTool::new(self.browser.clone())));
tools.push(Arc::new(PageSourceTool::new(self.browser.clone())));
}
if self.include_wait {
tools.push(Arc::new(WaitForElementTool::new(self.browser.clone())));
tools.push(Arc::new(WaitTool::new()));
tools.push(Arc::new(WaitForPageLoadTool::new(self.browser.clone())));
tools.push(Arc::new(WaitForTextTool::new(self.browser.clone())));
}
if self.include_screenshot {
tools.push(Arc::new(ScreenshotTool::new(self.browser.clone())));
}
if self.include_js {
tools.push(Arc::new(EvaluateJsTool::new(self.browser.clone())));
tools.push(Arc::new(ScrollTool::new(self.browser.clone())));
tools.push(Arc::new(HoverTool::new(self.browser.clone())));
tools.push(Arc::new(AlertTool::new(self.browser.clone())));
}
if self.include_cookies {
tools.push(Arc::new(GetCookiesTool::new(self.browser.clone())));
tools.push(Arc::new(GetCookieTool::new(self.browser.clone())));
tools.push(Arc::new(AddCookieTool::new(self.browser.clone())));
tools.push(Arc::new(DeleteCookieTool::new(self.browser.clone())));
tools.push(Arc::new(DeleteAllCookiesTool::new(self.browser.clone())));
}
if self.include_windows {
tools.push(Arc::new(ListWindowsTool::new(self.browser.clone())));
tools.push(Arc::new(NewTabTool::new(self.browser.clone())));
tools.push(Arc::new(NewWindowTool::new(self.browser.clone())));
tools.push(Arc::new(SwitchWindowTool::new(self.browser.clone())));
tools.push(Arc::new(CloseWindowTool::new(self.browser.clone())));
tools.push(Arc::new(MaximizeWindowTool::new(self.browser.clone())));
tools.push(Arc::new(MinimizeWindowTool::new(self.browser.clone())));
tools.push(Arc::new(SetWindowSizeTool::new(self.browser.clone())));
}
if self.include_frames {
tools.push(Arc::new(SwitchToFrameTool::new(self.browser.clone())));
tools.push(Arc::new(SwitchToParentFrameTool::new(self.browser.clone())));
tools.push(Arc::new(SwitchToDefaultContentTool::new(self.browser.clone())));
}
if self.include_actions {
tools.push(Arc::new(DragAndDropTool::new(self.browser.clone())));
tools.push(Arc::new(RightClickTool::new(self.browser.clone())));
tools.push(Arc::new(FocusTool::new(self.browser.clone())));
tools.push(Arc::new(ElementStateTool::new(self.browser.clone())));
tools.push(Arc::new(PressKeyTool::new(self.browser.clone())));
tools.push(Arc::new(FileUploadTool::new(self.browser.clone())));
tools.push(Arc::new(PrintToPdfTool::new(self.browser.clone())));
}
tools
}
}
#[async_trait]
impl Toolset for BrowserToolset {
fn name(&self) -> &str {
"browser"
}
async fn tools(&self, _ctx: Arc<dyn ReadonlyContext>) -> Result<Vec<Arc<dyn Tool>>> {
Ok(self.all_tools())
}
}
pub fn minimal_browser_tools(browser: Arc<BrowserSession>) -> Vec<Arc<dyn Tool>> {
vec![
Arc::new(NavigateTool::new(browser.clone())),
Arc::new(ClickTool::new(browser.clone())),
Arc::new(TypeTool::new(browser.clone())),
Arc::new(ExtractTextTool::new(browser.clone())),
Arc::new(WaitForElementTool::new(browser.clone())),
Arc::new(ScreenshotTool::new(browser)),
]
}
pub fn readonly_browser_tools(browser: Arc<BrowserSession>) -> Vec<Arc<dyn Tool>> {
vec![
Arc::new(NavigateTool::new(browser.clone())),
Arc::new(ExtractTextTool::new(browser.clone())),
Arc::new(ExtractAttributeTool::new(browser.clone())),
Arc::new(ExtractLinksTool::new(browser.clone())),
Arc::new(PageInfoTool::new(browser.clone())),
Arc::new(ScreenshotTool::new(browser.clone())),
Arc::new(ScrollTool::new(browser)),
]
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::BrowserConfig;
#[test]
fn test_toolset_all_tools() {
let browser = Arc::new(BrowserSession::new(BrowserConfig::default()));
let toolset = BrowserToolset::new(browser);
let tools = toolset.all_tools();
assert!(tools.len() > 40);
let tool_names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
assert!(tool_names.contains(&"browser_navigate"));
assert!(tool_names.contains(&"browser_click"));
assert!(tool_names.contains(&"browser_type"));
assert!(tool_names.contains(&"browser_screenshot"));
assert!(tool_names.contains(&"browser_get_cookies"));
assert!(tool_names.contains(&"browser_new_tab"));
assert!(tool_names.contains(&"browser_switch_to_frame"));
assert!(tool_names.contains(&"browser_drag_and_drop"));
}
#[test]
fn test_toolset_selective() {
let browser = Arc::new(BrowserSession::new(BrowserConfig::default()));
let toolset = BrowserToolset::new(browser)
.with_navigation(true)
.with_interaction(false)
.with_extraction(false)
.with_wait(false)
.with_screenshot(false)
.with_js(false)
.with_cookies(false)
.with_windows(false)
.with_frames(false)
.with_actions(false);
let tools = toolset.all_tools();
assert_eq!(tools.len(), 4);
}
#[test]
fn test_minimal_tools() {
let browser = Arc::new(BrowserSession::new(BrowserConfig::default()));
let tools = minimal_browser_tools(browser);
assert_eq!(tools.len(), 6);
}
}