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 ExtractParams {
#[serde(skip_serializing_if = "Option::is_none")]
pub selector: Option<String>,
#[serde(default = "default_format")]
pub format: String,
}
fn default_format() -> String {
"text".to_string()
}
#[derive(Default)]
pub struct ExtractContentTool;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ExtractOutput {
pub content: String,
pub format: String,
pub length: usize,
}
impl Tool for ExtractContentTool {
type Params = ExtractParams;
type Output = ExtractOutput;
fn name(&self) -> &str {
"extract"
}
fn execute_typed(
&self,
params: ExtractParams,
context: &mut ToolContext,
) -> Result<ToolResult> {
let content = if let Some(selector) = ¶ms.selector {
let tab = context.session.tab()?;
let element = context.session.find_element(&tab, selector)?;
if params.format == "html" {
element
.get_content()
.map_err(|e| BrowserError::ToolExecutionFailed {
tool: "extract".to_string(),
reason: e.to_string(),
})?
} else {
element
.get_inner_text()
.map_err(|e| BrowserError::ToolExecutionFailed {
tool: "extract".to_string(),
reason: e.to_string(),
})?
}
} else {
let js_code = if params.format == "html" {
"document.body.innerHTML"
} else {
"document.body.innerText"
};
let result = context
.session
.tab()?
.evaluate(js_code, false)
.map_err(|e| BrowserError::EvaluationFailed(e.to_string()))?;
result
.value
.and_then(|v| v.as_str().map(String::from))
.unwrap_or_default()
};
Ok(ToolResult::success_with(ExtractOutput {
length: content.len(),
format: params.format,
content,
}))
}
}