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
56 .result
57 .ok_or_else(|| anyhow::anyhow!("No result"))?,
58 )?;
59 Ok(task)
60 }
61
62 #[allow(dead_code)]
64 pub async fn get_task(&self, id: &str, history_length: Option<usize>) -> Result<Task> {
65 let request = JsonRpcRequest {
66 jsonrpc: "2.0".to_string(),
67 id: serde_json::json!(1),
68 method: "tasks/get".to_string(),
69 params: serde_json::to_value(TaskQueryParams {
70 id: id.to_string(),
71 history_length,
72 })?,
73 };
74
75 let response = self.call_rpc(request).await?;
76
77 if let Some(error) = response.error {
78 anyhow::bail!("RPC error {}: {}", error.code, error.message);
79 }
80
81 let task: Task = serde_json::from_value(
82 response
83 .result
84 .ok_or_else(|| anyhow::anyhow!("No result"))?,
85 )?;
86 Ok(task)
87 }
88
89 #[allow(dead_code)]
91 pub async fn cancel_task(&self, id: &str) -> Result<Task> {
92 let request = JsonRpcRequest {
93 jsonrpc: "2.0".to_string(),
94 id: serde_json::json!(1),
95 method: "tasks/cancel".to_string(),
96 params: serde_json::json!({ "id": id }),
97 };
98
99 let response = self.call_rpc(request).await?;
100
101 if let Some(error) = response.error {
102 anyhow::bail!("RPC error {}: {}", error.code, error.message);
103 }
104
105 let task: Task = serde_json::from_value(
106 response
107 .result
108 .ok_or_else(|| anyhow::anyhow!("No result"))?,
109 )?;
110 Ok(task)
111 }
112
113 pub async fn call_rpc(&self, request: JsonRpcRequest) -> Result<JsonRpcResponse> {
115 let mut req = self.client.post(&self.base_url);
116
117 if let Some(ref token) = self.token {
118 req = req.bearer_auth(token);
119 }
120
121 let res = req
122 .header("Content-Type", "application/json")
123 .json(&request)
124 .send()
125 .await?;
126
127 let response: JsonRpcResponse = res.json().await?;
128 Ok(response)
129 }
130}