showcase/shell-docs/src/content/ag-ui/sdk/rust/client/subscriber.mdx
The AgentSubscriber trait provides an event-driven system for handling agent lifecycle events, message updates, and state mutations during agent execution.
use ag_ui_client::subscriber::AgentSubscriber;
Implement any subset of the callback methods to react to events. Handlers can optionally return an AgentStateMutation to update the in-flight messages and/or state and to stop propagation to later subscribers.
Subscriber callbacks are async-friendly via async_trait.
Pass subscribers to Agent::run_agent using any of these forms via IntoSubscribers:
T where T: AgentSubscriber(T,) single-element tupleVec<T>&[T]() or Option<()> when no subscribers are neededuse ag_ui_client::{Agent, HttpAgent};
use ag_ui_client::agent::RunAgentParams;
use ag_ui_client::subscriber::AgentSubscriber;
use async_trait::async_trait;
struct Logger;
#[async_trait]
impl AgentSubscriber for Logger {
async fn on_text_message_content_event(
&self,
event: &ag_ui_client::core::event::TextMessageContentEvent,
_buffer: &str,
_params: ag_ui_client::subscriber::AgentSubscriberParams<'async_trait, serde_json::Value, serde_json::Value>,
) -> Result<ag_ui_client::agent::AgentStateMutation, ag_ui_client::agent::AgentError> {
println!("chunk: {}", event.content);
Ok(Default::default())
}
}
let params = RunAgentParams::new().user("Hello!");
let result = agent.run_agent(¶ms, [Logger]).await?;
Handlers may return a mutation to modify state/messages or stop propagation:
use ag_ui_client::agent::AgentStateMutation;
AgentStateMutation {
messages: None,
state: None,
stop_propagation: false,
}
Common parameters passed to most subscriber methods:
use ag_ui_client::subscriber::AgentSubscriberParams;
use ag_ui_client::core::types::{Message, RunAgentInput};
pub struct AgentSubscriberParams<'a, StateT, FwdPropsT> {
pub messages: &'a [Message],
pub state: &'a StateT,
pub input: &'a RunAgentInput<StateT, FwdPropsT>,
}
You can implement specific typed callbacks or the catch‑all on_event. Key callbacks include:
All callbacks have sensible defaults that return Ok(Default::default()). Only implement what you need.
use ag_ui_client::subscriber::{AgentSubscriber, AgentSubscriberParams};
use ag_ui_client::agent::{AgentStateMutation, AgentError};
use ag_ui_client::core::event::{StateSnapshotEvent, StateDeltaEvent};
use async_trait::async_trait;
#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, Default)]
struct Plan { steps: Vec<String> }
struct Logger;
#[async_trait]
impl AgentSubscriber<Plan, ()> for Logger {
async fn on_state_snapshot_event(
&self,
event: &StateSnapshotEvent<Plan>,
_params: AgentSubscriberParams<'async_trait, Plan, ()>,
) -> Result<AgentStateMutation<Plan>, AgentError> {
println!("snapshot: {} steps", event.snapshot.steps.len());
Ok(Default::default())
}
async fn on_state_delta_event(
&self,
event: &StateDeltaEvent,
_params: AgentSubscriberParams<'async_trait, Plan, ()>,
) -> Result<AgentStateMutation<Plan>, AgentError> {
println!("delta patches: {}", event.delta.len());
Ok(Default::default())
}
}