pub trait AgentExecutor:
Send
+ Sync
+ 'static {
// Required method
fn execute<'a>(
&'a self,
ctx: &'a RequestContext,
queue: &'a dyn EventQueueWriter,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>;
// Provided methods
fn cancel<'a>(
&'a self,
ctx: &'a RequestContext,
queue: &'a dyn EventQueueWriter,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>> { ... }
fn on_shutdown<'a>(
&'a self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ... }
}Expand description
Trait for implementing A2A agent execution logic.
Implementors process incoming messages by writing events (status updates,
artifacts) to the provided EventQueueWriter. The executor runs in a
spawned task and should signal completion by writing a terminal status
update and returning Ok(()).
§Object safety
This trait is object-safe: methods return Pin<Box<dyn Future>> so that
executors can be used as Arc<dyn AgentExecutor>. This eliminates the
need for generic parameters on RequestHandler,
RestDispatcher, and
JsonRpcDispatcher, simplifying the entire
server API surface.
§Example
use std::pin::Pin;
use std::future::Future;
use a2a_protocol_server::executor::AgentExecutor;
use a2a_protocol_server::request_context::RequestContext;
use a2a_protocol_server::streaming::EventQueueWriter;
use a2a_protocol_types::error::A2aResult;
struct MyAgent;
impl AgentExecutor for MyAgent {
fn execute<'a>(
&'a self,
ctx: &'a RequestContext,
queue: &'a dyn EventQueueWriter,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>> {
Box::pin(async move {
// Write status updates and artifacts to `queue`.
Ok(())
})
}
}§Ergonomic helpers
Use boxed_future to reduce
boilerplate, or the agent_executor! macro
for a fully declarative approach:
use a2a_protocol_server::agent_executor;
struct EchoAgent;
agent_executor!(EchoAgent, |_ctx, _queue| async {
Ok(())
});Required Methods§
Sourcefn execute<'a>(
&'a self,
ctx: &'a RequestContext,
queue: &'a dyn EventQueueWriter,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
fn execute<'a>( &'a self, ctx: &'a RequestContext, queue: &'a dyn EventQueueWriter, ) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
Executes agent logic for the given request.
Write StreamResponse events to
queue as the agent progresses. The method should return Ok(())
after writing the final event, or Err(...) on failure.
§Errors
Returns an A2aError if execution fails.
Provided Methods§
Sourcefn cancel<'a>(
&'a self,
ctx: &'a RequestContext,
queue: &'a dyn EventQueueWriter,
) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
fn cancel<'a>( &'a self, ctx: &'a RequestContext, queue: &'a dyn EventQueueWriter, ) -> Pin<Box<dyn Future<Output = A2aResult<()>> + Send + 'a>>
Cancels an in-progress task.
The default implementation cancels. It emits the terminal
Canceled status so subscribers see it, best-effort: a task with no
live subscribers has no queue receivers, and that must not fail the
cancel, because the handler persists the state either way. Cancellation
in A2A is cooperative — by the time this runs the handler has already
triggered RequestContext::cancellation_token, which a running
execute is expected to observe.
Override this when the task holds something that must be released — a reserved slot, a parked message, an open handle. Overriding is about releasing state, not about opting in to cancellation.
Before 0.7 the default refused with TaskNotCancelable, which left
Working tasks uncancelable out of the box and reported it as the
task’s fault. Every reference SDK requires agents to support cancel.
§Errors
Returns an A2aError if an
override fails to release what the task holds. The default
implementation does not return an error.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".