Skip to main content

mofa_plugins/tools/
http.rs

1use super::*;
2use reqwest::Client;
3use serde_json::json;
4
5/// HTTP 请求工具 - 发送网络请求
6pub struct HttpRequestTool {
7    definition: ToolDefinition,
8    client: Client,
9}
10
11impl Default for HttpRequestTool {
12    fn default() -> Self {
13        Self::new()
14    }
15}
16
17impl HttpRequestTool {
18    pub fn new() -> Self {
19        Self {
20            definition: ToolDefinition {
21                name: "http_request".to_string(),
22                description: "Send HTTP requests (GET, POST, PUT, DELETE) to URLs. Useful for fetching web content or calling APIs.".to_string(),
23                parameters: json!({
24                    "type": "object",
25                    "properties": {
26                        "method": {
27                            "type": "string",
28                            "enum": ["GET", "POST", "PUT", "DELETE"],
29                            "description": "HTTP method"
30                        },
31                        "url": {
32                            "type": "string",
33                            "description": "The URL to send the request to"
34                        },
35                        "headers": {
36                            "type": "object",
37                            "description": "Optional HTTP headers as key-value pairs",
38                            "additionalProperties": { "type": "string" }
39                        },
40                        "body": {
41                            "type": "string",
42                            "description": "Optional request body for POST/PUT requests"
43                        }
44                    },
45                    "required": ["method", "url"]
46                }),
47                requires_confirmation: false,
48            },
49            client: Client::builder()
50                .timeout(std::time::Duration::from_secs(30))
51                .build()
52                .unwrap(),
53        }
54    }
55}
56
57#[async_trait::async_trait]
58impl ToolExecutor for HttpRequestTool {
59    fn definition(&self) -> &ToolDefinition {
60        &self.definition
61    }
62
63    async fn execute(&self, arguments: serde_json::Value) -> PluginResult<serde_json::Value> {
64        let method = arguments["method"].as_str().unwrap_or("GET");
65        let url = arguments["url"]
66            .as_str()
67            .ok_or_else(|| anyhow::anyhow!("URL is required"))?;
68
69        let mut request = match method {
70            "GET" => self.client.get(url),
71            "POST" => self.client.post(url),
72            "PUT" => self.client.put(url),
73            "DELETE" => self.client.delete(url),
74            _ => return Err(anyhow::anyhow!("Unsupported HTTP method: {}", method)),
75        };
76
77        // Add headers if provided
78        if let Some(headers) = arguments.get("headers").and_then(|h| h.as_object()) {
79            for (key, value) in headers {
80                if let Some(v) = value.as_str() {
81                    request = request.header(key.as_str(), v);
82                }
83            }
84        }
85
86        // Add body if provided
87        if let Some(body) = arguments.get("body").and_then(|b| b.as_str()) {
88            request = request.body(body.to_string());
89        }
90
91        let response = request.send().await?;
92        let status = response.status().as_u16();
93        let headers: std::collections::HashMap<String, String> = response
94            .headers()
95            .iter()
96            .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
97            .collect();
98
99        let body = response.text().await?;
100
101        // Truncate body if too long
102        let truncated_body = if body.len() > 5000 {
103            format!(
104                "{}... [truncated, total {} bytes]",
105                &body[..5000],
106                body.len()
107            )
108        } else {
109            body
110        };
111
112        Ok(json!({
113            "status": status,
114            "headers": headers,
115            "body": truncated_body
116        }))
117    }
118}