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 res = self.client.get(&url).send().await?;
38 let card: AgentCard = res.json().await?;
39 Ok(card)
40 }
41
42 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(¶ms)?,
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 #[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 #[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 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}