use std::error::Error;
use protocol_droid::adapters::secondary::a2a::A2aClient;
use protocol_droid::domain::a2a::list_tasks::ListTasksRequest;
use protocol_droid::domain::a2a::message::{Message, MessageRole, Part, TextPart};
use protocol_droid::domain::a2a::push_notification::TaskPushNotificationConfig;
use protocol_droid::domain::a2a::push_notification_methods::{
CreateTaskPushNotificationConfigRequest, DeleteTaskPushNotificationConfigRequest,
GetTaskPushNotificationConfigRequest, ListTaskPushNotificationConfigsRequest,
};
use protocol_droid::domain::a2a::send_message::{SendMessageRequest, SendMessageResponse};
use protocol_droid::domain::a2a::streaming_events::StreamingEvent;
use protocol_droid::domain::a2a::task_lifecycle::{CancelTaskRequest, GetTaskRequest};
const PEER: &str = "http://127.0.0.1:8080";
#[tokio::main(flavor = "current_thread")]
#[expect(
clippy::too_many_lines,
reason = "the example walks the consumer through every typed A2A method on a single connection; splitting it into per-method helper functions would obscure the one-line shape the example is meant to teach. The function is an example, not production code."
)]
async fn main() -> Result<(), Box<dyn Error>> {
let client = match std::env::var("A2A_BEARER_TOKEN")
.ok()
.filter(|value| !value.is_empty())
{
Some(token) => A2aClient::new(PEER)?.with_bearer_token(token),
None => A2aClient::new(PEER)?,
};
let card = client.card().await?;
eprintln!("discovered {} v{}", card.name, card.version);
let message = Message::new(MessageRole::User).with_part(Part::Text(TextPart {
text: "hello from a2a_typed_client".to_owned(),
metadata: std::collections::BTreeMap::new(),
}));
let request = SendMessageRequest::new(message);
let response = client.send_message(request).await?;
let task_id = match &response {
SendMessageResponse::Task(task) => task.id.to_string(),
SendMessageResponse::Message(_) => {
return Err("peer returned a Message, expected a Task".into());
}
};
eprintln!("SendMessage -> task {task_id}");
let get = client
.get_task(GetTaskRequest::new(task_id.clone()))
.await?;
eprintln!("GetTask({task_id}) -> state {:?}", get.0.status.state);
let listed = client.list_tasks(ListTasksRequest::default()).await?;
eprintln!("ListTasks -> {} tasks", listed.tasks.len());
let cancelled = client
.cancel_task(CancelTaskRequest::new(task_id.clone()))
.await?;
eprintln!(
"CancelTask({task_id}) -> state {:?}",
cancelled.0.status.state
);
let message = Message::new(MessageRole::User).with_part(Part::Text(TextPart {
text: "hello via streaming".to_owned(),
metadata: std::collections::BTreeMap::new(),
}));
let request = SendMessageRequest::new(message);
let events = client.send_streaming_message(request).await?;
eprintln!("SendStreamingMessage -> {} events", events.len());
for (i, event) in events.iter().enumerate() {
let StreamingEvent::Status(status) = event else {
eprintln!(" [{i}] artifact event");
continue;
};
eprintln!(
" [{i}] status {:?} (final = {})",
status.status.state, status.is_final
);
}
let config = TaskPushNotificationConfig {
id: "placeholder".to_owned(),
task_id: "t-1".to_owned(),
url: "http://1.2.3.4:9999/wh".to_owned(),
token: Some("token".to_owned()),
authentication: None,
metadata: std::collections::BTreeMap::new(),
};
let created = client
.create_push_notification_config(CreateTaskPushNotificationConfigRequest::from(config))
.await?;
eprintln!("CreateTaskPushNotificationConfig -> {}", created.0.id);
let got = client
.get_push_notification_config(GetTaskPushNotificationConfigRequest::new(
created.0.id.clone(),
"t-1".to_owned(),
))
.await?;
eprintln!("GetTaskPushNotificationConfig -> ok");
let listed = client
.list_push_notification_configs(ListTaskPushNotificationConfigsRequest {
task_id: "t-1".to_owned(),
page_size: None,
page_token: None,
})
.await?;
eprintln!(
"ListTaskPushNotificationConfigs -> {} configs",
listed.configs.len()
);
client
.delete_push_notification_config(DeleteTaskPushNotificationConfigRequest::new(
got.0.id,
"t-1".to_owned(),
))
.await?;
eprintln!("DeleteTaskPushNotificationConfig -> ok");
if std::env::var("A2A_BEARER_TOKEN").is_ok() {
let extended = client
.get_extended_agent_card(
protocol_droid::domain::a2a::extended_agent_card::GetExtendedAgentCardRequest::new(
),
)
.await?;
eprintln!(
"GetExtendedAgentCard -> {} v{}",
extended.name, extended.version
);
} else {
eprintln!(
"GetExtendedAgentCard -> skipped (set A2A_BEARER_TOKEN on both sides to exercise)"
);
}
Ok(())
}