browser_use/tools/
read_links.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 ReadLinksParams {}
8
9#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
10pub struct Link {
11    /// The visible text content of the link
12    pub text: String,
13    /// The href attribute of the link
14    pub href: String,
15}
16
17#[derive(Default)]
18pub struct ReadLinksTool;
19
20impl Tool for ReadLinksTool {
21    type Params = ReadLinksParams;
22
23    fn name(&self) -> &str {
24        "read_links"
25    }
26
27    fn execute_typed(
28        &self,
29        _params: ReadLinksParams,
30        context: &mut ToolContext,
31    ) -> Result<ToolResult> {
32        // JavaScript code to extract all links on the page
33        // We use JSON.stringify to ensure the result is returned properly
34        let js_code = r#"
35            JSON.stringify(
36                Array.from(document.querySelectorAll('a[href]'))
37                    .map(el => ({
38                        text: el.innerText || '',
39                        href: el.getAttribute('href') || ''
40                    }))
41                    .filter(link => link.href !== '')
42            )
43        "#;
44
45        let result = context
46            .session
47            .tab()
48            .evaluate(js_code, false)
49            .map_err(|e| BrowserError::EvaluationFailed(e.to_string()))?;
50
51        // Parse the JSON string result into Link structs
52        let links: Vec<Link> = result
53            .value
54            .and_then(|v| v.as_str().map(String::from))
55            .and_then(|s| serde_json::from_str(&s).ok())
56            .unwrap_or_default();
57
58        Ok(ToolResult::success_with(serde_json::json!({
59            "links": links,
60            "count": links.len()
61        })))
62    }
63}