codetether_agent/a2a/
client.rs1use super::types::*;
4use anyhow::Result;
5use reqwest::Client;
6
7pub struct A2AClient {
9 client: Client,
10 base_url: String,
11 token: Option<String>,
12}
13
14#[allow(dead_code)]
15impl A2AClient {
16 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 token: None,
22 }
23 }
24
25 pub fn with_token(mut self, token: impl Into<String>) -> Self {
27 self.token = Some(token.into());
28 self
29 }
30
31 pub async fn get_agent_card(&self) -> Result<AgentCard> {
33 let url = format!("{}/.well-known/agent.json", self.base_url);
34 let res = self.client.get(&url).send().await?;
35 let card: AgentCard = res.json().await?;
36 Ok(card)
37 }
38
39 pub async fn send_message(&self, params: MessageSendParams) -> Result<Task> {
41 let request = JsonRpcRequest {
42 jsonrpc: "2.0".to_string(),
43 id: serde_json::json!(1),
44 method: "message/send".to_string(),
45 params: serde_json::to_value(¶ms)?,
46 };
47
48 let response = self.call_rpc(request).await?;
49
50 if let Some(error) = response.error {
51 anyhow::bail!("RPC error {}: {}", error.code, error.message);
52 }
53
54 let task: Task = serde_json::from_value(
55 response.result.ok_or_else(|| anyhow::anyhow!("No result"))?,
56 )?;
57 Ok(task)
58 }
59
60 #[allow(dead_code)]
62 pub async fn get_task(&self, id: &str, history_length: Option<usize>) -> Result<Task> {
63 let request = JsonRpcRequest {
64 jsonrpc: "2.0".to_string(),
65 id: serde_json::json!(1),
66 method: "tasks/get".to_string(),
67 params: serde_json::to_value(TaskQueryParams {
68 id: id.to_string(),
69 history_length,
70 })?,
71 };
72
73 let response = self.call_rpc(request).await?;
74
75 if let Some(error) = response.error {
76 anyhow::bail!("RPC error {}: {}", error.code, error.message);
77 }
78
79 let task: Task = serde_json::from_value(
80 response.result.ok_or_else(|| anyhow::anyhow!("No result"))?,
81 )?;
82 Ok(task)
83 }
84
85 #[allow(dead_code)]
87 pub async fn cancel_task(&self, id: &str) -> Result<Task> {
88 let request = JsonRpcRequest {
89 jsonrpc: "2.0".to_string(),
90 id: serde_json::json!(1),
91 method: "tasks/cancel".to_string(),
92 params: serde_json::json!({ "id": id }),
93 };
94
95 let response = self.call_rpc(request).await?;
96
97 if let Some(error) = response.error {
98 anyhow::bail!("RPC error {}: {}", error.code, error.message);
99 }
100
101 let task: Task = serde_json::from_value(
102 response.result.ok_or_else(|| anyhow::anyhow!("No result"))?,
103 )?;
104 Ok(task)
105 }
106
107 pub async fn call_rpc(&self, request: JsonRpcRequest) -> Result<JsonRpcResponse> {
109 let mut req = self.client.post(&self.base_url);
110
111 if let Some(ref token) = self.token {
112 req = req.bearer_auth(token);
113 }
114
115 let res = req
116 .header("Content-Type", "application/json")
117 .json(&request)
118 .send()
119 .await?;
120
121 let response: JsonRpcResponse = res.json().await?;
122 Ok(response)
123 }
124}