browser_use/tools/
extract.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)]
7pub struct ExtractParams {
8 #[serde(skip_serializing_if = "Option::is_none")]
10 pub selector: Option<String>,
11
12 #[serde(default = "default_format")]
14 pub format: String,
15}
16
17fn default_format() -> String {
18 "text".to_string()
19}
20
21#[derive(Default)]
22pub struct ExtractContentTool;
23
24impl Tool for ExtractContentTool {
25 type Params = ExtractParams;
26
27 fn name(&self) -> &str {
28 "extract"
29 }
30
31 fn execute_typed(
32 &self,
33 params: ExtractParams,
34 context: &mut ToolContext,
35 ) -> Result<ToolResult> {
36 let content = if let Some(selector) = ¶ms.selector {
37 let tab = context.session.tab()?;
38 let element = context.session.find_element(&tab, selector)?;
39
40 if params.format == "html" {
41 element
42 .get_content()
43 .map_err(|e| BrowserError::ToolExecutionFailed {
44 tool: "extract".to_string(),
45 reason: e.to_string(),
46 })?
47 } else {
48 element
49 .get_inner_text()
50 .map_err(|e| BrowserError::ToolExecutionFailed {
51 tool: "extract".to_string(),
52 reason: e.to_string(),
53 })?
54 }
55 } else {
56 let js_code = if params.format == "html" {
58 "document.body.innerHTML"
59 } else {
60 "document.body.innerText"
61 };
62
63 let result = context
64 .session
65 .tab()?
66 .evaluate(js_code, false)
67 .map_err(|e| BrowserError::EvaluationFailed(e.to_string()))?;
68
69 result
70 .value
71 .and_then(|v| v.as_str().map(String::from))
72 .unwrap_or_default()
73 };
74
75 Ok(ToolResult::success_with(serde_json::json!({
76 "content": content,
77 "format": params.format,
78 "length": content.len()
79 })))
80 }
81}