browser_use/tools/
select.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 SelectParams {
9 #[serde(flatten)]
11 pub selector: ElementSelector,
12
13 pub value: String,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
18#[serde(untagged)]
19pub enum ElementSelector {
20 Css {
22 selector: String,
24 },
25 Index {
27 index: usize,
29 },
30}
31
32#[derive(Default)]
34pub struct SelectTool;
35
36const SELECT_JS: &str = include_str!("select.js");
37
38impl Tool for SelectTool {
39 type Params = SelectParams;
40
41 fn name(&self) -> &str {
42 "select"
43 }
44
45 fn execute_typed(&self, params: SelectParams, context: &mut ToolContext) -> Result<ToolResult> {
46 let css_selector = match params.selector {
47 ElementSelector::Css { selector } => selector,
48 ElementSelector::Index { index } => {
49 let dom = context.get_dom()?;
50 let selector_info = dom.get_selector(index).ok_or_else(|| {
51 BrowserError::ElementNotFound(format!("No element with index {}", index))
52 })?;
53 selector_info.css_selector.clone()
54 }
55 };
56 let value = params.value;
57
58 let select_config = serde_json::json!({
59 "selector": css_selector,
60 "value": value,
61 });
62 let select_js = SELECT_JS.replace("__SELECT_CONFIG__", &select_config.to_string());
63
64 let result = context
65 .session
66 .tab()
67 .evaluate(&select_js, false)
68 .map_err(|e| BrowserError::ToolExecutionFailed {
69 tool: "select".to_string(),
70 reason: e.to_string(),
71 })?;
72
73 let result_json: serde_json::Value = if let Some(serde_json::Value::String(json_str)) =
75 result.value
76 {
77 serde_json::from_str(&json_str)
78 .unwrap_or(serde_json::json!({"success": false, "error": "Failed to parse result"}))
79 } else {
80 result
81 .value
82 .unwrap_or(serde_json::json!({"success": false, "error": "No result returned"}))
83 };
84
85 if result_json["success"].as_bool() == Some(true) {
86 Ok(ToolResult::success_with(serde_json::json!({
87 "selector": css_selector,
88 "value": value,
89 "selectedText": result_json["selectedText"]
90 })))
91 } else {
92 Err(BrowserError::ToolExecutionFailed {
93 tool: "select".to_string(),
94 reason: result_json["error"]
95 .as_str()
96 .unwrap_or("Unknown error")
97 .to_string(),
98 })
99 }
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106
107 #[test]
108 fn test_select_params_css() {
109 let json = serde_json::json!({
110 "selector": "#country-select",
111 "value": "us"
112 });
113
114 let params: SelectParams = serde_json::from_value(json).unwrap();
115 match params.selector {
116 ElementSelector::Css { selector } => assert_eq!(selector, "#country-select"),
117 _ => panic!("Expected CSS selector"),
118 }
119 assert_eq!(params.value, "us");
120 }
121
122 #[test]
123 fn test_select_params_index() {
124 let json = serde_json::json!({
125 "index": 5,
126 "value": "option2"
127 });
128
129 let params: SelectParams = serde_json::from_value(json).unwrap();
130 match params.selector {
131 ElementSelector::Index { index } => assert_eq!(index, 5),
132 _ => panic!("Expected index selector"),
133 }
134 assert_eq!(params.value, "option2");
135 }
136}