browser_use/tools/
get_clickable_elements.rs1use crate::error::Result;
2use crate::tools::{Tool, ToolContext, ToolResult};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
8pub struct GetClickableElementsParams {}
9
10#[derive(Default)]
12pub struct GetClickableElementsTool;
13
14impl Tool for GetClickableElementsTool {
15 type Params = GetClickableElementsParams;
16
17 fn name(&self) -> &str {
18 "get_clickable_elements"
19 }
20
21 fn execute_typed(
22 &self,
23 _params: GetClickableElementsParams,
24 context: &mut ToolContext,
25 ) -> Result<ToolResult> {
26 let dom = context.get_dom()?;
28
29 let indices = dom.interactive_indices();
31
32 if indices.is_empty() {
33 return Ok(ToolResult::success_with(serde_json::json!({
34 "elements": "",
35 "count": 0
36 })));
37 }
38
39 let mut formatted_elements = Vec::new();
44
45 for &index in &indices {
46 if let Some(node) = dom.find_node_by_index(index) {
47 let tag_name = &node.tag_name;
48
49 let text_content = if let Some(text) = &node.text_content {
51 let trimmed = text.trim();
52 if trimmed.len() > 100 {
53 format!("{}...", &trimmed[..97])
54 } else {
55 trimmed.to_string()
56 }
57 } else {
58 String::new()
59 };
60
61 let formatted = if text_content.is_empty() {
63 format!("[{}]<{}>", index, tag_name)
64 } else {
65 format!("[{}]<{}>{}</{}>", index, tag_name, text_content, tag_name)
66 };
67
68 formatted_elements.push(formatted);
69 }
70 }
71
72 let elements_string = formatted_elements.join("\n");
73 let count = indices.len();
74
75 Ok(ToolResult::success_with(serde_json::json!({
76 "elements": elements_string,
77 "count": count
78 })))
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use crate::dom::DomTree;
86 use crate::dom::ElementNode;
87
88 #[test]
89 fn test_get_clickable_elements_params() {
90 let params = GetClickableElementsParams {};
91 let json = serde_json::to_value(params).unwrap();
92 assert!(json.is_object());
93 }
94
95 #[test]
96 fn test_tool_name() {
97 let tool = GetClickableElementsTool;
98 assert_eq!(tool.name(), "get_clickable_elements");
99 }
100
101 #[test]
104 fn test_empty_dom_tree() {
105 let root = ElementNode::new("body");
107 let dom_tree = DomTree::new(root);
108
109 assert_eq!(dom_tree.count_interactive(), 0);
112 }
113}