Skip to main content

codetether_agent/a2a/
client.rs

1//! A2A Client - for connecting to other A2A agents
2
3use super::types::*;
4use anyhow::Result;
5use reqwest::Client;
6
7/// A2A Client for interacting with A2A agents
8pub struct A2AClient {
9    client: Client,
10    base_url: String,
11    auth: Option<AuthenticationInfo>,
12}
13
14#[allow(dead_code)]
15impl A2AClient {
16    /// Create a new A2A client
17    pub fn new(base_url: impl Into<String>) -> Self {
18        Self {
19            client: Client::new(),
20            base_url: base_url.into().trim_end_matches('/').to_string(),
21            auth: None,
22        }
23    }
24
25    /// Set authentication token
26    pub fn with_token(mut self, token: impl Into<String>) -> Self {
27        self.auth = Some(AuthenticationInfo {
28            schemes: vec!["bearer".to_string()],
29            credentials: Some(token.into()),
30        });
31        self
32    }
33
34    /// Get the agent card
35    pub async fn get_agent_card(&self) -> Result<AgentCard> {
36        let url = format!("{}/.well-known/agent.json", self.base_url);
37        let res = self.client.get(&url).send().await?;
38        let card: AgentCard = res.json().await?;
39        Ok(card)
40    }
41
42    /// Send a message to the agent
43    pub async fn send_message(&self, params: MessageSendParams) -> Result<SendMessageResponse> {
44        let request = JsonRpcRequest {
45            jsonrpc: "2.0".to_string(),
46            id: serde_json::json!(1),
47            method: "message/send".to_string(),
48            params: serde_json::to_value(&params)?,
49        };
50
51        let response = self.call_rpc(request).await?;
52
53        if let Some(error) = response.error {
54            anyhow::bail!("RPC error {}: {}", error.code, error.message);
55        }
56
57        let result: SendMessageResponse = serde_json::from_value(
58            response
59                .result
60                .ok_or_else(|| anyhow::anyhow!("No result"))?,
61        )?;
62        Ok(result)
63    }
64
65    /// Get task status
66    #[allow(dead_code)]
67    pub async fn get_task(&self, id: &str, history_length: Option<usize>) -> Result<Task> {
68        let request = JsonRpcRequest {
69            jsonrpc: "2.0".to_string(),
70            id: serde_json::json!(1),
71            method: "tasks/get".to_string(),
72            params: serde_json::to_value(TaskQueryParams {
73                id: id.to_string(),
74                history_length,
75            })?,
76        };
77
78        let response = self.call_rpc(request).await?;
79
80        if let Some(error) = response.error {
81            anyhow::bail!("RPC error {}: {}", error.code, error.message);
82        }
83
84        let task: Task = serde_json::from_value(
85            response
86                .result
87                .ok_or_else(|| anyhow::anyhow!("No result"))?,
88        )?;
89        Ok(task)
90    }
91
92    /// Cancel a task
93    #[allow(dead_code)]
94    pub async fn cancel_task(&self, id: &str) -> Result<Task> {
95        let request = JsonRpcRequest {
96            jsonrpc: "2.0".to_string(),
97            id: serde_json::json!(1),
98            method: "tasks/cancel".to_string(),
99            params: serde_json::json!({ "id": id }),
100        };
101
102        let response = self.call_rpc(request).await?;
103
104        if let Some(error) = response.error {
105            anyhow::bail!("RPC error {}: {}", error.code, error.message);
106        }
107
108        let task: Task = serde_json::from_value(
109            response
110                .result
111                .ok_or_else(|| anyhow::anyhow!("No result"))?,
112        )?;
113        Ok(task)
114    }
115
116    /// Make a JSON-RPC call
117    pub async fn call_rpc(&self, request: JsonRpcRequest) -> Result<JsonRpcResponse> {
118        let mut req = self.client.post(&self.base_url);
119
120        if let Some(ref auth) = self.auth {
121            if let Some(ref creds) = auth.credentials {
122                req = req.bearer_auth(creds);
123            }
124        }
125
126        let res = req
127            .header("Content-Type", "application/json")
128            .json(&request)
129            .send()
130            .await?;
131
132        let response: JsonRpcResponse = res.json().await?;
133        Ok(response)
134    }
135}