Skip to main content

deepseek_rust_cli/tools/
web_tools.rs

1use std::{collections::HashMap, path::Path};
2
3use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::Value;
6
7use crate::{agent::types::UndoAction, tools, tools::base::Tool};
8
9pub struct RunPythonTool;
10#[async_trait]
11impl Tool for RunPythonTool {
12    fn name(&self) -> &str {
13        "run_python_code"
14    }
15    async fn execute(
16        &self,
17        args: &HashMap<String, Value>,
18        _undo: &mut Vec<UndoAction>,
19        _cwd: Option<&Path>,
20    ) -> Result<String> {
21        let code = args
22            .get("code")
23            .and_then(|v| v.as_str())
24            .ok_or_else(|| anyhow::anyhow!("Missing 'code'"))?;
25        tools::code_ops::run_python_code(code).await
26    }
27}
28
29pub struct FetchUrlTool;
30#[async_trait]
31impl Tool for FetchUrlTool {
32    fn name(&self) -> &str {
33        "fetch_url"
34    }
35    async fn execute(
36        &self,
37        args: &HashMap<String, Value>,
38        _undo: &mut Vec<UndoAction>,
39        _cwd: Option<&Path>,
40    ) -> Result<String> {
41        let url = args
42            .get("url")
43            .and_then(|v| v.as_str())
44            .ok_or_else(|| anyhow::anyhow!("Missing 'url'"))?;
45        tools::web_ops::fetch_url(url).await
46    }
47}
48
49pub struct GetEnvVarTool;
50#[async_trait]
51impl Tool for GetEnvVarTool {
52    fn name(&self) -> &str {
53        "get_env_var"
54    }
55    async fn execute(
56        &self,
57        args: &HashMap<String, Value>,
58        _undo: &mut Vec<UndoAction>,
59        _cwd: Option<&Path>,
60    ) -> Result<String> {
61        let name = args
62            .get("name")
63            .and_then(|v| v.as_str())
64            .ok_or_else(|| anyhow::anyhow!("Missing 'name'"))?;
65        Ok(tools::web_ops::get_env_var(name))
66    }
67}
68
69pub struct ScreenshotWebappTool;
70#[async_trait]
71impl Tool for ScreenshotWebappTool {
72    fn name(&self) -> &str {
73        "screenshot_webapp"
74    }
75    async fn execute(
76        &self,
77        args: &HashMap<String, Value>,
78        _undo: &mut Vec<UndoAction>,
79        _cwd: Option<&Path>,
80    ) -> Result<String> {
81        let url = args
82            .get("url")
83            .and_then(|v| v.as_str())
84            .ok_or_else(|| anyhow::anyhow!("Missing 'url'"))?;
85        let output_path = args
86            .get("output_path")
87            .and_then(|v| v.as_str())
88            .ok_or_else(|| anyhow::anyhow!("Missing 'output_path'"))?;
89
90        let p = crate::tools::base::validate_path(output_path)?;
91        if let Some(parent) = p.parent() {
92            tokio::fs::create_dir_all(parent).await?;
93        }
94        let p_str = p.to_string_lossy().to_string();
95
96        let mut cmd = tokio::process::Command::new("msedge");
97        cmd.arg("--headless")
98            .arg("--disable-gpu")
99            .arg(format!("--screenshot={}", p_str))
100            .arg(url);
101
102        let res = cmd.output().await;
103        match res {
104            Ok(output) if output.status.success() => Ok(format!("Screenshot saved to {}", p_str)),
105            _ => {
106                let mut cmd2 = tokio::process::Command::new("chrome");
107                cmd2.arg("--headless")
108                    .arg("--disable-gpu")
109                    .arg(format!("--screenshot={}", p_str))
110                    .arg(url);
111                match cmd2.output().await {
112                    Ok(output) if output.status.success() => {
113                        Ok(format!("Screenshot saved to {}", p_str))
114                    }
115                    Ok(output) => Err(anyhow::anyhow!(
116                        "Browser exited with error: {}",
117                        String::from_utf8_lossy(&output.stderr)
118                    )),
119                    Err(e) => Err(anyhow::anyhow!(
120                        "Failed to start msedge or chrome. Make sure at least one is installed \
121                         and in your PATH. Error: {}",
122                        e
123                    )),
124                }
125            }
126        }
127    }
128}
129
130pub struct WebSearchDuckDuckGoTool;
131#[async_trait]
132impl Tool for WebSearchDuckDuckGoTool {
133    fn name(&self) -> &str {
134        "web_search_duckduckgo"
135    }
136    async fn execute(
137        &self,
138        args: &HashMap<String, Value>,
139        _undo: &mut Vec<UndoAction>,
140        _cwd: Option<&Path>,
141    ) -> Result<String> {
142        let query = args
143            .get("query")
144            .and_then(|v| v.as_str())
145            .ok_or_else(|| anyhow::anyhow!("Missing 'query'"))?;
146        tools::web_ops::web_search_duckduckgo(query).await
147    }
148}