auto_storage_sqlx/
auto_storage_sqlx.rs1use a2a_agents::core::{AgentBuilder, BuildError};
12use a2a_rs::{
13 domain::{A2AError, Message, Part, Role, Task, TaskState},
14 port::AsyncMessageHandler,
15};
16use async_trait::async_trait;
17use uuid::Uuid;
18
19#[derive(Clone)]
21struct PersistentEchoHandler;
22
23#[async_trait]
24impl AsyncMessageHandler for PersistentEchoHandler {
25 async fn process_message(
26 &self,
27 task_id: &str,
28 message: &Message,
29 _session_id: Option<&str>,
30 ) -> Result<Task, A2AError> {
31 let text = message
32 .parts
33 .iter()
34 .find_map(|part| match part {
35 Part::Text { text, .. } => Some(text.clone()),
36 _ => None,
37 })
38 .unwrap_or_else(|| "No text provided".to_string());
39
40 let response = Message::builder()
41 .role(Role::Agent)
42 .parts(vec![Part::text(format!("Echo (from SQLx): {}", text))])
43 .message_id(Uuid::new_v4().to_string())
44 .context_id(message.context_id.clone().unwrap_or_default())
45 .build();
46
47 Ok(Task::builder()
48 .id(task_id.to_string())
49 .context_id(message.context_id.clone().unwrap_or_default())
50 .status(a2a_rs::domain::TaskStatus {
51 state: TaskState::Completed,
52 message: Some(response.clone()),
53 timestamp: Some(chrono::Utc::now()),
54 })
55 .history(vec![message.clone(), response])
56 .build())
57 }
58
59 async fn validate_message(&self, message: &Message) -> Result<(), A2AError> {
60 if message.parts.is_empty() {
61 return Err(A2AError::ValidationError {
62 field: "parts".to_string(),
63 message: "Message must contain at least one part".to_string(),
64 });
65 }
66 Ok(())
67 }
68}
69
70#[tokio::main]
71async fn main() -> Result<(), BuildError> {
72 dotenvy::dotenv().ok();
74
75 tracing_subscriber::fmt()
77 .with_env_filter(
78 tracing_subscriber::EnvFilter::from_default_env()
79 .add_directive(tracing::Level::INFO.into()),
80 )
81 .init();
82
83 println!("🚀 Starting agent with automatic SQLx storage");
84 println!(" Database URL from config: ${{DATABASE_URL}}");
85 println!(" Migrations will be run automatically");
86 println!();
87
88 let migrations = &[
91 r#"
93 CREATE TABLE IF NOT EXISTS echo_stats (
94 id INTEGER PRIMARY KEY AUTOINCREMENT,
95 message_count INTEGER NOT NULL DEFAULT 0,
96 last_echo TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
97 )
98 "#,
99 ];
100
101 AgentBuilder::from_file("examples/auto_storage_sqlx.toml")?
110 .with_handler(PersistentEchoHandler)
111 .build_with_auto_storage_and_migrations(migrations)
112 .await?
113 .run()
114 .await
115 .map_err(|e| BuildError::RuntimeError(e.to_string()))?;
116
117 Ok(())
118}