use async_trait::async_trait;
use super::error::AgentError;
use super::types::{AgentCard, TaskRequest, TaskResponse, TaskState, TaskStatus};
#[async_trait]
pub trait Agent: Send + Sync {
fn card(&self) -> AgentCard;
async fn handle_task(&self, request: TaskRequest) -> Result<TaskResponse, AgentError>;
async fn handle_cancel(&self, _task_id: &str) -> Result<TaskStatus, AgentError> {
Ok(TaskStatus {
state: TaskState::Canceled,
message: None,
timestamp: None,
})
}
}
#[async_trait]
pub trait Middleware: Send + Sync {
async fn process(
&self,
request: TaskRequest,
next: &dyn Agent,
) -> Result<TaskResponse, AgentError>;
}
pub struct MiddlewareStack {
agent: Box<dyn Agent>,
middlewares: Vec<Box<dyn Middleware>>,
}
struct ChainedAgent<'a> {
agent: &'a dyn Agent,
remaining: &'a [Box<dyn Middleware>],
}
#[async_trait]
impl Agent for ChainedAgent<'_> {
fn card(&self) -> AgentCard {
self.agent.card()
}
async fn handle_task(&self, request: TaskRequest) -> Result<TaskResponse, AgentError> {
if let Some((current, rest)) = self.remaining.split_first() {
let next = ChainedAgent {
agent: self.agent,
remaining: rest,
};
current.process(request, &next).await
} else {
self.agent.handle_task(request).await
}
}
async fn handle_cancel(&self, task_id: &str) -> Result<TaskStatus, AgentError> {
self.agent.handle_cancel(task_id).await
}
}
impl MiddlewareStack {
pub fn new(agent: impl Agent + 'static) -> Self {
Self {
agent: Box::new(agent),
middlewares: Vec::new(),
}
}
#[must_use]
pub fn with(mut self, middleware: impl Middleware + 'static) -> Self {
self.middlewares.push(Box::new(middleware));
self
}
}
#[async_trait]
impl Agent for MiddlewareStack {
fn card(&self) -> AgentCard {
self.agent.card()
}
async fn handle_task(&self, request: TaskRequest) -> Result<TaskResponse, AgentError> {
if self.middlewares.is_empty() {
return self.agent.handle_task(request).await;
}
let chain = ChainedAgent {
agent: self.agent.as_ref(),
remaining: &self.middlewares,
};
chain.handle_task(request).await
}
async fn handle_cancel(&self, task_id: &str) -> Result<TaskStatus, AgentError> {
self.agent.handle_cancel(task_id).await
}
}
pub struct LoggingMiddleware;
#[async_trait]
impl Middleware for LoggingMiddleware {
async fn process(
&self,
request: TaskRequest,
next: &dyn Agent,
) -> Result<TaskResponse, AgentError> {
tracing::info!(task_id = %request.id, "handling task request");
let result = next.handle_task(request).await;
match &result {
Ok(resp) => {
tracing::info!(task_id = %resp.id, state = ?resp.status.state, "task completed");
}
Err(e) => {
tracing::error!(error = %e, "task failed");
}
}
result
}
}