mod execute;
mod params;
mod response;
use async_trait::async_trait;
use serde_json::{Value, json};
use super::{Tool, ToolResult};
pub struct HttpTool {
client: reqwest::Client,
}
impl Default for HttpTool {
fn default() -> Self {
Self::new()
}
}
impl HttpTool {
pub fn new() -> Self {
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(60))
.redirect(reqwest::redirect::Policy::limited(5))
.build()
.expect("Failed to build HTTP client");
Self { client }
}
}
#[async_trait]
impl Tool for HttpTool {
fn id(&self) -> &str {
"http"
}
fn name(&self) -> &str {
"HTTP Request"
}
fn description(&self) -> &str {
"Send an arbitrary HTTP request (method, URL, headers, body). \
Use this to replay API calls captured from browserctl network \
inspection, bypassing the UI entirely. Supports GET, POST, PUT, \
PATCH, DELETE, HEAD, OPTIONS. Body can be raw string or JSON."
}
fn parameters(&self) -> Value {
params::schema()
}
async fn execute(&self, value: Value) -> anyhow::Result<ToolResult> {
let params: params::HttpParams = serde_json::from_value(value)
.map_err(|e| anyhow::anyhow!("invalid params: {e}"))?;
crate::tls::ensure_rustls_crypto_provider();
execute::run(&self.client, params).await
}
}
#[cfg(test)]
pub(crate) fn _status_metadata_key() -> &'static str {
"status"
}