Skip to main content

minimal_agent/
minimal_agent.rs

1//! Minimal agent example using the new declarative API
2//!
3//! This example shows how to create a simple agent with just ~30 lines of code.
4//! The agent echoes back any message it receives.
5
6use a2a_agents::core::{AgentBuilder, BuildError};
7use a2a_rs::{
8    InMemoryTaskStorage,
9    domain::{A2AError, Message, Part, Role, Task, TaskState},
10    port::AsyncMessageHandler,
11};
12use async_trait::async_trait;
13use uuid::Uuid;
14
15/// Simple echo handler that echoes back messages
16#[derive(Clone)]
17struct EchoHandler;
18
19#[async_trait]
20impl AsyncMessageHandler for EchoHandler {
21    async fn process_message(
22        &self,
23        task_id: &str,
24        message: &Message,
25        _session_id: Option<&str>,
26    ) -> Result<Task, A2AError> {
27        // Extract text from the message
28        let text = message
29            .parts
30            .iter()
31            .find_map(|part| part.get_text().map(|s| s.to_string()))
32            .unwrap_or_else(|| "No text provided".to_string());
33
34        // Create echo response
35        let response = Message::builder()
36            .role(Role::Agent)
37            .parts(vec![Part::text(format!("Echo: {}", text))])
38            .message_id(Uuid::new_v4().to_string())
39            .context_id(message.context_id.clone())
40            .build();
41
42        // Return completed task with echo response
43        Ok(Task::builder()
44            .id(task_id.to_string())
45            .context_id(message.context_id.clone())
46            .status(a2a_rs::domain::TaskStatus::new(
47                TaskState::Completed,
48                Some(response.clone()),
49            ))
50            .history(vec![message.clone(), response])
51            .build())
52    }
53
54    async fn validate_message(&self, message: &Message) -> Result<(), A2AError> {
55        if message.parts.is_empty() {
56            return Err(A2AError::ValidationError {
57                field: "parts".to_string(),
58                message: "Message must contain at least one part".to_string(),
59            });
60        }
61        Ok(())
62    }
63}
64
65#[tokio::main]
66async fn main() -> Result<(), BuildError> {
67    // Initialize logging
68    tracing_subscriber::fmt()
69        .with_env_filter(
70            tracing_subscriber::EnvFilter::from_default_env()
71                .add_directive(tracing::Level::INFO.into()),
72        )
73        .init();
74
75    println!("🚀 Starting Echo Agent with declarative configuration");
76    println!();
77
78    // Build and run the agent from configuration file
79    // This is all you need - the rest is handled by the framework!
80    AgentBuilder::from_file("examples/minimal_agent.toml")?
81        .with_handler(EchoHandler)
82        .with_storage(InMemoryTaskStorage::new())
83        .build()?
84        .run()
85        .await
86        .map_err(|e| BuildError::RuntimeError(e.to_string()))?;
87
88    Ok(())
89}