browser_use/tools/
click.rs1use crate::error::{BrowserError, Result};
2use crate::tools::{Tool, ToolContext, ToolResult};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
8pub struct ClickParams {
9 #[serde(skip_serializing_if = "Option::is_none")]
11 pub selector: Option<String>,
12
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub index: Option<usize>,
16}
17
18#[derive(Default)]
20pub struct ClickTool;
21
22impl Tool for ClickTool {
23 type Params = ClickParams;
24
25 fn name(&self) -> &str {
26 "click"
27 }
28
29 fn execute_typed(&self, params: ClickParams, context: &mut ToolContext) -> Result<ToolResult> {
30 match (¶ms.selector, ¶ms.index) {
32 (Some(_), Some(_)) => {
33 return Err(BrowserError::ToolExecutionFailed {
34 tool: "click".to_string(),
35 reason: "Cannot specify both 'selector' and 'index'. Use one or the other."
36 .to_string(),
37 });
38 }
39 (None, None) => {
40 return Err(BrowserError::ToolExecutionFailed {
41 tool: "click".to_string(),
42 reason: "Must specify either 'selector' or 'index'.".to_string(),
43 });
44 }
45 _ => {}
46 }
47
48 if let Some(selector) = params.selector {
49 let tab = context.session.tab()?;
51 let element = context.session.find_element(&tab, &selector)?;
52 element
53 .click()
54 .map_err(|e| BrowserError::ToolExecutionFailed {
55 tool: "click".to_string(),
56 reason: e.to_string(),
57 })?;
58
59 Ok(ToolResult::success_with(serde_json::json!({
60 "selector": selector,
61 "method": "css"
62 })))
63 } else if let Some(index) = params.index {
64 let css_selector = {
66 let dom = context.get_dom()?;
67 let selector = dom.get_selector(index).ok_or_else(|| {
68 BrowserError::ElementNotFound(format!("No element with index {}", index))
69 })?;
70 selector.clone()
71 };
72
73 let tab = context.session.tab()?;
74 let element = context.session.find_element(&tab, &css_selector)?;
75 element
76 .click()
77 .map_err(|e| BrowserError::ToolExecutionFailed {
78 tool: "click".to_string(),
79 reason: e.to_string(),
80 })?;
81
82 Ok(ToolResult::success_with(serde_json::json!({
83 "index": index,
84 "selector": css_selector,
85 "method": "index"
86 })))
87 } else {
88 unreachable!("Validation above ensures one field is Some")
89 }
90 }
91}