Actor Agents
Actor-based agents run inside a runtime and communicate via typed messages and protocol events. Use them when you need:
- Event streaming for UI updates (turn started/completed, tool calls, streaming chunks)
- Pub/Sub between agents or external actors
- Long-running orchestrations rather than a single direct call
Core Building Blocks
RuntimeandEnvironment: Manage event routing and lifecycle of actor systems.Topic<M>: Typed pub/sub channels for messages of typeM.ActorAgentandActorAgentHandle: Wrap your agent with an actor reference so it can receiveTasks via pub/sub/direct messaging.Event: Streamed protocol events (task start/complete, tool calls, streaming chunks) published by agents during execution.
Typical Wiring Pattern
- Create a runtime and register it in an
Environment. - Spawn your agent as
ActorAgentand subscribe it to one or moreTopic<Task>. - Take the environment’s event receiver and forward events to your UI/log sink.
- Publish
Taskmessages to the relevant topic to trigger work.
Minimal Example
#![allow(unused)]
fn main() {
use autoagents::core::{
agent::prebuilt::executor::ReActAgent,
agent::{AgentBuilder, ActorAgent},
agent::task::Task,
environment::Environment,
runtime::{SingleThreadedRuntime, TypedRuntime},
actor::Topic,
};
use std::sync::Arc;
// 1) Create runtime and environment
let runtime = SingleThreadedRuntime::new(None);
let mut env = Environment::new(None);
env.register_runtime(runtime.clone()).await?;
// 2) Build actor agent and subscribe to a topic
let chat_topic = Topic::<Task>::new("chat");
let handle = AgentBuilder::<_, ActorAgent>::new(ReActAgent::new(MyAgent {}))
.llm(my_llm)
.runtime(runtime.clone())
.subscribe(chat_topic.clone())
.build()
.await?;
// 3) Consume events (UI updates, tool calls, streaming)
let receiver = env.take_event_receiver(None).await?;
tokio::spawn(async move { /* forward events to UI */ });
// 4) Publish tasks
runtime.publish(&chat_topic, Task::new("Hello!"))
.await?;
}
Event Handling Patterns
- Pub/Sub: Publish
TasktoTopic<Task>; all subscribed agents receive the message. - Direct send: Use
TypedRuntime::send_messageto deliver a message directly to a specific actor. - Protocol events:
Event::TaskStarted,Event::TurnStarted,Event::ToolCallRequested,Event::StreamChunk, etc. are emitted by agents while running.
Protocol Events Reference
These map to autoagents::core::protocol::Event variants emitted by actor agents and the runtime:
TaskStarted { sub_id, actor_id, actor_name, task_description }- Emitted when an agent begins processing a task.
TaskComplete { sub_id, actor_id, actor_name, result }- Final result for a task.
resultis a pretty JSON string; parse into your agent output type when needed.
- Final result for a task.
TaskError { sub_id, actor_id, error }- Any executor/provider error surfaced during execution.
TurnStarted { turn_number, max_turns }- Multi-turn executors (e.g., ReAct) mark each turn start.
TurnCompleted { turn_number, final_turn }- Marks turn completion;
final_turnis true when the loop ends.
- Marks turn completion;
ToolCallRequested { id, tool_name, arguments }- The LLM requested a tool call with JSON arguments (as string).
ToolCallCompleted { id, tool_name, result }- Tool finished successfully;
resultis JSON.
- Tool finished successfully;
ToolCallFailed { id, tool_name, error }- Tool failed; error string is included.
StreamChunk { sub_id, chunk }- Streaming delta content;
chunkmatches provider’s streaming shape.
- Streaming delta content;
StreamToolCall { sub_id, tool_call }- Streaming tool call delta (when provider emits incremental tool-call info).
StreamComplete { sub_id }- Streaming finished for the current task.
Internally, the runtime also routes PublishMessage for typed pub/sub (Topic<M>), but that variant is skipped in serde and used only inside the runtime.
When To Use Actor Agents vs Direct Agents
- Use Direct agents for one-shot calls (no runtime, minimal wiring).
- Use Actor agents when you need: real-time events, multiple agents, pub/sub routing, or running agents as durable tasks.