use crate::error::{BrowserError, Result};
use crate::tools::{Tool, ToolContext, ToolResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ReadLinksParams {}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Link {
pub text: String,
pub href: String,
}
#[derive(Default)]
pub struct ReadLinksTool;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ReadLinksOutput {
pub links: Vec<Link>,
pub count: usize,
}
impl Tool for ReadLinksTool {
type Params = ReadLinksParams;
type Output = ReadLinksOutput;
fn name(&self) -> &str {
"read_links"
}
fn execute_typed(
&self,
_params: ReadLinksParams,
context: &mut ToolContext,
) -> Result<ToolResult> {
let js_code = r#"
JSON.stringify(
Array.from(document.querySelectorAll('a[href]'))
.map(el => ({
text: el.innerText || '',
href: el.getAttribute('href') || ''
}))
.filter(link => link.href !== '')
)
"#;
let result = context
.session
.tab()?
.evaluate(js_code, false)
.map_err(|e| BrowserError::EvaluationFailed(e.to_string()))?;
let links: Vec<Link> = result
.value
.and_then(|v| v.as_str().map(String::from))
.and_then(|s| serde_json::from_str(&s).ok())
.unwrap_or_default();
Ok(ToolResult::success_with(ReadLinksOutput {
count: links.len(),
links,
}))
}
}