use async_trait::async_trait;
use serde_json::{Value, json};
use crate::tools::Tool;
pub struct BrowserOpenTool;
#[async_trait]
impl Tool for BrowserOpenTool {
fn definition(&self) -> crate::tools::ToolDefinition {
crate::tools::ToolDefinition {
name: "browser_open".to_string(),
description: "使用系统默认浏览器打开指定的 URL。适用于预览网页、文档或在线资源。"
.to_string(),
parameters: json!({
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "要打开的 URL"
}
},
"required": ["url"]
}),
..Default::default()
}
}
async fn execute(&self, params: Value) -> anyhow::Result<String> {
let url = params["url"]
.as_str()
.ok_or_else(|| anyhow::anyhow!("missing 'url' parameter"))?;
let url = url.trim();
if url.is_empty() {
return Err(anyhow::anyhow!("URL 不能为空"));
}
let url = if url.starts_with("http://") || url.starts_with("https://") {
url.to_string()
} else {
format!("https://{}", url)
};
#[cfg(target_os = "windows")]
let result = {
std::process::Command::new("cmd")
.args(["/C", "start", &url])
.spawn()
.map(|_| ())
.map_err(|e| anyhow::anyhow!("无法打开浏览器: {}", e))
};
#[cfg(target_os = "macos")]
let result = {
std::process::Command::new("open")
.arg(&url)
.spawn()
.map(|_| ())
.map_err(|e| anyhow::anyhow!("无法打开浏览器: {}", e))
};
#[cfg(target_os = "linux")]
let result = {
std::process::Command::new("xdg-open")
.arg(&url)
.spawn()
.map(|_| ())
.map_err(|e| anyhow::anyhow!("无法打开浏览器: {}", e))
};
result.map(|_| format!("已打开浏览器: {}", url))
}
}