1use axum::{
18 extract::{Path, State},
19 http::StatusCode,
20 Json,
21};
22use std::sync::Arc;
23use uuid::Uuid;
24
25use super::agent_card::AgentCard;
26use super::task::{TaskRequest, TaskResponse};
27
28pub struct A2aState {
30 pub agent_card: AgentCard,
32 }
37
38impl Default for A2aState {
39 fn default() -> Self {
40 Self {
41 agent_card: AgentCard::vex_default(),
42 }
43 }
44}
45
46pub async fn agent_card_handler(State(state): State<Arc<A2aState>>) -> Json<AgentCard> {
51 Json(state.agent_card.clone())
52}
53
54pub async fn create_task_handler(
63 State(_state): State<Arc<A2aState>>,
64 Json(request): Json<TaskRequest>,
65) -> (StatusCode, Json<TaskResponse>) {
66 let response = TaskResponse::pending(request.id);
78 (StatusCode::ACCEPTED, Json(response))
79}
80
81pub async fn get_task_handler(
85 State(_state): State<Arc<A2aState>>,
86 Path(task_id): Path<Uuid>,
87) -> Result<Json<TaskResponse>, StatusCode> {
88 let response = TaskResponse::pending(task_id);
94 Ok(Json(response))
95}
96
97pub fn a2a_routes(state: Arc<A2aState>) -> axum::Router {
106 use axum::routing::{get, post};
107
108 axum::Router::new()
109 .route("/.well-known/agent.json", get(agent_card_handler))
110 .route("/a2a/tasks", post(create_task_handler))
111 .route("/a2a/tasks/{id}", get(get_task_handler))
112 .with_state(state)
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118 use axum::body::Body;
119 use axum::http::Request;
120 use tower::ServiceExt;
121
122 fn create_test_state() -> Arc<A2aState> {
123 Arc::new(A2aState::default())
124 }
125
126 #[tokio::test]
127 async fn test_agent_card_endpoint() {
128 let state = create_test_state();
129 let app = a2a_routes(state);
130
131 let response = app
132 .oneshot(
133 Request::builder()
134 .uri("/.well-known/agent.json")
135 .body(Body::empty())
136 .unwrap(),
137 )
138 .await
139 .unwrap();
140
141 assert_eq!(response.status(), StatusCode::OK);
142 }
143
144 #[tokio::test]
145 async fn test_create_task_endpoint() {
146 let state = create_test_state();
147 let app = a2a_routes(state);
148
149 let task_req = TaskRequest::new("verify", serde_json::json!({"claim": "test"}));
150 let body = serde_json::to_string(&task_req).unwrap();
151
152 let response = app
153 .oneshot(
154 Request::builder()
155 .method("POST")
156 .uri("/a2a/tasks")
157 .header("content-type", "application/json")
158 .body(Body::from(body))
159 .unwrap(),
160 )
161 .await
162 .unwrap();
163
164 assert_eq!(response.status(), StatusCode::ACCEPTED);
165 }
166
167 #[tokio::test]
168 async fn test_get_task_endpoint() {
169 let state = create_test_state();
170 let app = a2a_routes(state);
171 let task_id = Uuid::new_v4();
172
173 let response = app
174 .oneshot(
175 Request::builder()
176 .uri(format!("/a2a/tasks/{}", task_id))
177 .body(Body::empty())
178 .unwrap(),
179 )
180 .await
181 .unwrap();
182
183 assert_eq!(response.status(), StatusCode::OK);
184 }
185}