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 auth: Option<AuthenticationInfo>,
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 auth: None,
22 }
23 }
24
25 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 pub async fn get_agent_card(&self) -> Result<AgentCard> {
36 let url = format!("{}/.well-known/agent.json", self.base_url);
37 let mut req = self.client.get(&url);
38
39 if let Some(ref auth) = self.auth
40 && let Some(ref creds) = auth.credentials
41 {
42 req = req.bearer_auth(creds);
43 }
44
45 let res = req.send().await?.error_for_status()?;
46 let card: AgentCard = res.json().await?;
47 Ok(card)
48 }
49
50 pub async fn send_message(&self, params: MessageSendParams) -> Result<SendMessageResponse> {
52 let request = JsonRpcRequest {
53 jsonrpc: "2.0".to_string(),
54 id: serde_json::json!(1),
55 method: "message/send".to_string(),
56 params: serde_json::to_value(¶ms)?,
57 };
58
59 let response = self.call_rpc(request).await?;
60
61 if let Some(error) = response.error {
62 anyhow::bail!("RPC error {}: {}", error.code, error.message);
63 }
64
65 let result: SendMessageResponse = serde_json::from_value(
66 response
67 .result
68 .ok_or_else(|| anyhow::anyhow!("No result"))?,
69 )?;
70 Ok(result)
71 }
72
73 #[allow(dead_code)]
75 pub async fn get_task(&self, id: &str, history_length: Option<usize>) -> Result<Task> {
76 let request = JsonRpcRequest {
77 jsonrpc: "2.0".to_string(),
78 id: serde_json::json!(1),
79 method: "tasks/get".to_string(),
80 params: serde_json::to_value(TaskQueryParams {
81 id: id.to_string(),
82 history_length,
83 })?,
84 };
85
86 let response = self.call_rpc(request).await?;
87
88 if let Some(error) = response.error {
89 anyhow::bail!("RPC error {}: {}", error.code, error.message);
90 }
91
92 let task: Task = serde_json::from_value(
93 response
94 .result
95 .ok_or_else(|| anyhow::anyhow!("No result"))?,
96 )?;
97 Ok(task)
98 }
99
100 #[allow(dead_code)]
102 pub async fn cancel_task(&self, id: &str) -> Result<Task> {
103 let request = JsonRpcRequest {
104 jsonrpc: "2.0".to_string(),
105 id: serde_json::json!(1),
106 method: "tasks/cancel".to_string(),
107 params: serde_json::json!({ "id": id }),
108 };
109
110 let response = self.call_rpc(request).await?;
111
112 if let Some(error) = response.error {
113 anyhow::bail!("RPC error {}: {}", error.code, error.message);
114 }
115
116 let task: Task = serde_json::from_value(
117 response
118 .result
119 .ok_or_else(|| anyhow::anyhow!("No result"))?,
120 )?;
121 Ok(task)
122 }
123
124 pub async fn call_rpc(&self, request: JsonRpcRequest) -> Result<JsonRpcResponse> {
126 let mut req = self.client.post(&self.base_url);
127
128 if let Some(ref auth) = self.auth
129 && let Some(ref creds) = auth.credentials
130 {
131 req = req.bearer_auth(creds);
132 }
133
134 let res = req
135 .header("Content-Type", "application/json")
136 .json(&request)
137 .send()
138 .await?;
139
140 let response: JsonRpcResponse = res.json().await?;
141 Ok(response)
142 }
143}