browser_use/tools/
extract.rs

1use 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    /// CSS selector (optional, defaults to body)
9    #[serde(skip_serializing_if = "Option::is_none")]
10    pub selector: Option<String>,
11
12    /// Format: "text" or "html"
13    #[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) = &params.selector {
37            let element = context.session.find_element(selector)?;
38
39            if params.format == "html" {
40                element
41                    .get_content()
42                    .map_err(|e| BrowserError::ToolExecutionFailed {
43                        tool: "extract".to_string(),
44                        reason: e.to_string(),
45                    })?
46            } else {
47                element
48                    .get_inner_text()
49                    .map_err(|e| BrowserError::ToolExecutionFailed {
50                        tool: "extract".to_string(),
51                        reason: e.to_string(),
52                    })?
53            }
54        } else {
55            // Extract from body
56            let js_code = if params.format == "html" {
57                "document.body.innerHTML"
58            } else {
59                "document.body.innerText"
60            };
61
62            let result = context
63                .session
64                .tab()
65                .evaluate(js_code, false)
66                .map_err(|e| BrowserError::EvaluationFailed(e.to_string()))?;
67
68            result
69                .value
70                .and_then(|v| v.as_str().map(String::from))
71                .unwrap_or_default()
72        };
73
74        Ok(ToolResult::success_with(serde_json::json!({
75            "content": content,
76            "format": params.format,
77            "length": content.len()
78        })))
79    }
80}