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 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            // Extract from body
57            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}