codetether_agent/tool/browserctl/
mod.rs1mod 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
19pub struct BrowserCtlTool;
21
22impl BrowserCtlTool {
23 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}