use a2a_protocol_types::AgentCard;
use crate::builder::ClientBuilder;
use crate::config::ClientConfig;
use crate::error::ClientResult;
use crate::interceptor::{ClientRequest, InterceptorChain};
use crate::streaming::EventStream;
use crate::transport::Transport;
pub struct A2aClient {
pub(crate) transport: Box<dyn Transport>,
pub(crate) interceptors: InterceptorChain,
pub(crate) config: ClientConfig,
}
impl A2aClient {
pub fn from_card(card: &AgentCard) -> ClientResult<Self> {
ClientBuilder::from_card(card)?.build()
}
#[must_use]
pub const fn config(&self) -> &ClientConfig {
&self.config
}
pub(crate) const fn configure_stream(&self, stream: EventStream) -> EventStream {
stream
.with_first_event_timeout(self.config.stream_first_event_timeout)
.with_idle_timeout(self.config.stream_idle_timeout)
.with_max_event_size(self.config.max_event_size)
}
#[must_use]
pub(crate) fn new(
transport: Box<dyn Transport>,
interceptors: InterceptorChain,
config: ClientConfig,
) -> Self {
Self {
transport,
interceptors,
config,
}
}
pub(crate) async fn send_intercepted(
&self,
method: &str,
req: &mut ClientRequest,
) -> ClientResult<serde_json::Value> {
let params = std::mem::take(&mut req.params);
let result = self
.transport
.send_request(method, params, &req.extra_headers)
.await;
if let Err(ref e) = result {
self.interceptors.run_on_error(req, e).await;
}
result
}
pub(crate) async fn send_streaming_intercepted(
&self,
method: &str,
req: &mut ClientRequest,
) -> ClientResult<EventStream> {
let params = std::mem::take(&mut req.params);
let result = self
.transport
.send_streaming_request(method, params, &req.extra_headers)
.await;
if let Err(ref e) = result {
self.interceptors.run_on_error(req, e).await;
}
result
}
}
impl std::fmt::Debug for A2aClient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("A2aClient")
.field("interceptors", &self.interceptors)
.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::transport::JsonRpcTransport;
#[test]
fn client_new_stores_config() {
let transport = JsonRpcTransport::new("http://localhost:8080").expect("transport");
let client = A2aClient::new(
Box::new(transport),
InterceptorChain::new(),
ClientConfig::default_http(),
);
assert_eq!(
client.config().request_timeout,
std::time::Duration::from_secs(30)
);
}
#[test]
fn client_debug_impl() {
let transport = JsonRpcTransport::new("http://localhost:8080").expect("transport");
let client = A2aClient::new(
Box::new(transport),
InterceptorChain::new(),
ClientConfig::default_http(),
);
let dbg = format!("{client:?}");
assert!(dbg.contains("A2aClient"));
}
}