Skip to main content

codetether_agent/tool/browserctl/
mod.rs

1//! Browser control tool implementation.
2//!
3//! The tool parses browserctl JSON input, dispatches to the shared browser
4//! session, and formats browser outputs as tool results.
5
6mod actions;
7mod dispatch;
8mod helpers;
9mod input;
10mod response;
11mod schema;
12mod screenshot;
13
14use super::{Tool, ToolResult};
15use anyhow::{Context, Result};
16use async_trait::async_trait;
17use serde_json::Value;
18
19/// Tool entry point for browser automation commands.
20pub struct BrowserCtlTool;
21
22impl BrowserCtlTool {
23    /// Create a browser control tool.
24    pub fn new() -> Self {
25        Self
26    }
27}
28
29impl Default for BrowserCtlTool {
30    fn default() -> Self {
31        Self::new()
32    }
33}
34
35#[async_trait]
36impl Tool for BrowserCtlTool {
37    fn id(&self) -> &str {
38        "browserctl"
39    }
40    fn name(&self) -> &str {
41        "Browser Control"
42    }
43    fn description(&self) -> &str {
44        "Control the browser session for navigation, DOM inspection, evaluation, screenshots, tabs, and robust interaction with modern web apps."
45    }
46    fn parameters(&self) -> Value {
47        schema::parameters_schema()
48    }
49
50    async fn execute(&self, args: Value) -> Result<ToolResult> {
51        let input: input::BrowserCtlInput =
52            serde_json::from_value(args).context("Invalid browserctl args")?;
53        if matches!(&input.action, input::BrowserCtlAction::Detect) {
54            return Ok(detect_result());
55        }
56        let result = match dispatch::dispatch(&input).await {
57            Ok(output) => response::success_result(&input, output).await?,
58            Err(error) => response::error_result(error),
59        };
60        if matches!(&input.action, input::BrowserCtlAction::Stop) && result.success {
61            crate::browser::browser_service().clear();
62        }
63        Ok(result)
64    }
65}
66
67fn detect_result() -> ToolResult {
68    match crate::browser::detect_browser() {
69        Some(path) => {
70            let output = serde_json::json!({
71                "found": true,
72                "executable_path": path.display().to_string(),
73                "platform": std::env::consts::OS,
74            });
75            ToolResult {
76                output: serde_json::to_string_pretty(&output).unwrap_or_default(),
77                success: true,
78                metadata: Default::default(),
79            }
80        }
81        None => {
82            let output = serde_json::json!({
83                "found": false,
84                "platform": std::env::consts::OS,
85                "hint": "No external browser executable is required; browserctl uses the native TetherScript backend.",
86            });
87            ToolResult {
88                output: serde_json::to_string_pretty(&output).unwrap_or_default(),
89                success: true,
90                metadata: Default::default(),
91            }
92        }
93    }
94}