agent-relay 0.2.0

Agent-to-agent messaging for AI coding tools. Local or networked — run a relay server and let Claude talk to Gemini across the internet.
Documentation
//! HTTP client for connecting to a remote relay server.

use crate::{AgentRegistration, Message};

pub struct RemoteRelay {
    base_url: String,
}

impl RemoteRelay {
    pub fn new(server_url: &str) -> Self {
        let base_url = server_url.trim_end_matches('/').to_string();
        Self { base_url }
    }

    pub fn health(&self) -> Result<String, String> {
        let resp = ureq::get(&format!("{}/health", self.base_url))
            .call()
            .map_err(|e| format!("Connection failed: {}", e))?;
        resp.into_string().map_err(|e| format!("Read error: {}", e))
    }

    pub fn register(
        &self,
        agent_id: &str,
        session_id: &str,
        pid: u32,
    ) -> Result<AgentRegistration, String> {
        let resp = ureq::post(&format!("{}/agents/register", self.base_url))
            .send_json(serde_json::json!({
                "session_id": session_id,
                "agent_id": agent_id,
                "pid": pid,
            }))
            .map_err(|e| format!("Request failed: {}", e))?;

        let body: AgentRegistration = resp
            .into_json()
            .map_err(|e| format!("Parse error: {}", e))?;
        Ok(body)
    }

    pub fn unregister(&self, session_id: &str) -> Result<(), String> {
        ureq::post(&format!("{}/agents/unregister", self.base_url))
            .send_json(serde_json::json!({"session_id": session_id}))
            .map_err(|e| format!("Request failed: {}", e))?;
        Ok(())
    }

    pub fn agents(&self) -> Result<Vec<AgentRegistration>, String> {
        let resp = ureq::get(&format!("{}/agents", self.base_url))
            .call()
            .map_err(|e| format!("Request failed: {}", e))?;

        let body: Vec<AgentRegistration> = resp
            .into_json()
            .map_err(|e| format!("Parse error: {}", e))?;
        Ok(body)
    }

    pub fn send(
        &self,
        from_session: &str,
        from_agent: &str,
        to_session: Option<&str>,
        content: &str,
    ) -> Result<Message, String> {
        let resp = ureq::post(&format!("{}/messages/send", self.base_url))
            .send_json(serde_json::json!({
                "from_session": from_session,
                "from_agent": from_agent,
                "to_session": to_session,
                "content": content,
            }))
            .map_err(|e| format!("Request failed: {}", e))?;

        let body: Message = resp
            .into_json()
            .map_err(|e| format!("Parse error: {}", e))?;
        Ok(body)
    }

    pub fn inbox(&self, session_id: &str, limit: usize) -> Result<Vec<Message>, String> {
        let resp = ureq::get(&format!(
            "{}/messages/inbox?session={}&limit={}",
            self.base_url, session_id, limit
        ))
        .call()
        .map_err(|e| format!("Request failed: {}", e))?;

        let body: Vec<Message> = resp
            .into_json()
            .map_err(|e| format!("Parse error: {}", e))?;
        Ok(body)
    }

    pub fn unread_count(&self, session_id: &str) -> Result<u64, String> {
        let resp = ureq::get(&format!(
            "{}/messages/unread?session={}",
            self.base_url, session_id
        ))
        .call()
        .map_err(|e| format!("Request failed: {}", e))?;

        let body: serde_json::Value = resp
            .into_json()
            .map_err(|e| format!("Parse error: {}", e))?;
        Ok(body["count"].as_u64().unwrap_or(0))
    }
}