Introduction
For responsive chat interfaces, it is usually not enough to wait forexecute() to finish and then render the final answer. The Agents package exposes the execution lifecycle through events, and the AgentEventBroadcaster converts selected events into UI-friendly envelopes that can be forwarded to SSE, WebSocket, or any custom transport.
This gives your application a simple observation layer:
- live text chunks while the LLM is producing output
- step and tool status updates while the agent is working
- execution status transitions such as
processing,completed, andfailed
When to Use It
UseAgentEventBroadcaster when your app needs to reflect agent progress while execution is still in flight:
- chat UIs that should show text as it arrives
- TUIs that need progress indicators and tool activity
- web apps that stream agent status over SSE or WebSockets
- observability dashboards that track step, tool, and continuation events
execute() is enough. If you need step-by-step inspection, use iterate(). If you need UI updates during execution, attach a broadcaster.
How It Works
AgentLoop, the active driver, and the underlying inference runtime share the same event dispatcher. AgentEventBroadcaster listens to that dispatcher and translates selected events into envelopes such as:
agent.statusagent.step.startedagent.step.completedagent.tool.startedagent.tool.completedagent.stream.chunk
CanBroadcastAgentEvents.
Required Steps
To make agent events available to your application, set up four pieces:- Create the agent with a shared event bus. The default builder and
AgentLoop::default()already do this. - Implement
CanBroadcastAgentEventsto forward envelopes to your transport. - Add
UseAgentBroadcastingto the builder so the relevant listeners are registered for you. - If you want streamed text chunks, make sure the LLM request is created with
stream: true.
Enabling Live Text Chunks
agent.stream.chunk is emitted only when the underlying inference request is streamed. Attaching a broadcaster alone is not enough: the LLM request must be created with streaming enabled.
In practice, that means configuring the driver so its inference request includes stream: true in the request options.
Minimal example with an explicit driver:
Transport Integration
AgentEventBroadcaster emits envelopes through a simple contract:
- SSE endpoint writes each envelope as a server-sent event
- WebSocket handler publishes envelopes to a client-specific channel
- queue worker forwards envelopes to Redis or another pub/sub layer
- CLI/TUI adapter renders envelopes directly to the terminal
Advanced Option
If you need lower-level control, you can createAgentEventBroadcaster yourself and attach it via $agent->wiretap($broadcaster->wiretap()). UseAgentBroadcasting is just the prewired integration path for the event set that is usually useful in interactive applications.
Choosing a Broadcast Configuration
BroadcastConfig provides three presets:
minimal()for status-only trackingstandard()for status plus streamed text chunksdebug()for status, stream chunks, continuation trace, and tool arguments
standard() is the right default.
What the UI Can Rely On
The broadcaster emits stable, app-facing event types. A typical UI flow looks like this:agent.statuschanges toprocessingagent.step.startedappears- zero or more
agent.stream.chunkenvelopes arrive - zero or more
agent.tool.started/agent.tool.completedenvelopes arrive agent.step.completedappearsagent.statuschanges tocompleted,failed,cancelled, orstopped
- typing indicators
- streaming assistant text
- tool activity rows
- execution status badges
Notes
AgentEventBroadcasteris transport-agnostic. It formats envelopes but does not send HTTP responses or manage sockets.- The broadcaster does not replace
iterate(). Useiterate()for application-side control flow, and use broadcasting for UI observation. - If you need additional behavior, you can attach your own listeners alongside the broadcaster with
onEvent().