Reactive Agent
A reactive agent is an event-driven, collaborative agent that adapts to its environment and to other agents. Learn what a reactive agent is and how to build one with Mozaik.
A reactive agent is an event-driven, collaborative agent that adapts to its environment and to other agents in real time. Instead of following a hard-coded pipeline, a reactive agent declares which events it cares about and reacts to them as they arrive — messages from humans, function calls from its own model, reasoning traces from a peer agent, or tool outputs from somewhere else in the environment.
Mozaik is built around this model: AgenticEnvironment is an event bus, and every Participant exposes a set of typed handlers. Reactive agents are the natural unit of work.
What is a reactive agent?
A reactive agent has three properties:
- Event-driven — It runs in response to events on the bus (
onMessage,onFunctionCall,onReasoning, …), not on a schedule and not behind a central orchestrator. - Collaborative — It shares an
AgenticEnvironmentwith other reactive agents, observers, humans, and tools. It can react to its own outputs (self handlers) and to others' outputs (onExternal*handlers). - Adaptive — Behavior emerges from how it reacts. Add a critic agent and the reactive agent's outputs are reviewed in real time. Add a logger and you get an audit trail. The reactive agent itself does not change.
Under the hood every capability is non-blocking, so a reactive agent never holds up its peers — even on a slow inference call or a long-running tool.
Reactive agents vs. orchestrated pipelines
| Orchestrated pipeline | Reactive agent |
|---|---|
| A central controller decides whose turn it is. | The environment fans events out; participants react on their own. |
| Adding a step means editing the controller. | Adding behavior means join()ing another participant. |
| One slow step blocks the rest. | Non-blocking events let participants act concurrently. |
| Hard to add cross-cutting concerns (audit, critique, telemetry). | Drop in another observer or reactive agent — existing code untouched. |
Build a reactive agent with Mozaik
A reactive agent extends BaseParticipant and overrides only the handlers it actually needs. Every handler defaults to a no-op, so a reactive agent stays small and explicit about what it reacts to. Capabilities are the free functions runInference and executeFunctionCall — the participant passes itself as caller.
import {
BaseParticipant,
UserMessageItem,
FunctionCallItem,
FunctionCallOutputItem,
ReasoningItem,
ModelMessageItem,
AgenticEnvironment,
ModelContext,
Tool,
runInference,
executeFunctionCall,
} from '@mozaik-ai/core';
export class ReactiveAgent extends BaseParticipant {
constructor(
private readonly environment: AgenticEnvironment,
private readonly context: ModelContext,
private readonly tools: Tool[] = [],
) {
super();
}
async onMessage(message: string): Promise<void> {
this.context.addContextItem(UserMessageItem.create(message));
runInference({
model: 'gpt-5.5',
context: this.context,
tools: this.tools,
caller: this,
environment: this.environment,
});
}
async onFunctionCall(item: FunctionCallItem): Promise<void> {
this.context.addContextItem(item);
const tool = this.tools.find((t) => t.name === item.name);
if (tool) executeFunctionCall(this.environment, item, tool, this);
}
async onFunctionCallOutput(item: FunctionCallOutputItem): Promise<void> {
this.context.addContextItem(item);
runInference({
model: 'gpt-5.5',
context: this.context,
tools: this.tools,
caller: this,
environment: this.environment,
});
}
async onReasoning(item: ReasoningItem): Promise<void> {
this.context.addContextItem(item);
}
async onModelMessage(item: ModelMessageItem): Promise<void> {
this.context.addContextItem(item);
}
}What each handler does
onMessage(message)— Someone sent a plain-text message (a human viasendMessage, another agent, etc.). Record it as aUserMessageItemand trigger inference.onFunctionCall(item)— The agent's own inference returned a tool call. Record it, find the matchingTool, and execute it withexecuteFunctionCall.onFunctionCallOutput(item)— The tool produced a result. Record it and run inference again so the model can use it.onReasoning(item)/onModelMessage(item)— Keep the localModelContextin sync with the model's outputs.
Joining the environment
const environment = new AgenticEnvironment();
const context = ModelContext.create('demo');
const agent = new ReactiveAgent(environment, context, tools);
agent.join(environment);From this point on, the agent reacts to anything that flows through the environment — including events produced by other reactive agents. There is no separate bus to start.
Self handlers vs. external handlers
For every typed event there are two handlers:
| Self | External |
|---|---|
onFunctionCall | onExternalFunctionCall |
onFunctionCallOutput | onExternalFunctionCallOutput |
onReasoning | onExternalReasoning |
onModelMessage | onExternalModelMessage |
onInternalEvent (SemanticEvent<T>) | onExternalEvent (SemanticEvent<T>) |
The reactive agent above reacts to its own outputs (loop the model with tool results) and is silent on what other agents emit. To collaborate with peers, override the onExternal* handlers as well — for example, override onExternalModelMessage to critique another agent's reply.
onMessage has no onExternal variant: messages are conversational and reach every participant the same way (except the sender).
Composing reactive agents
Behaviors compose by reaction, not by orchestration:
- Add a second reactive agent that overrides
onExternalModelMessageto critique the first one → you get a critic loop. - Add a
TranscriptLoggerobserver → you get a live UI stream or audit log. - Add a guardrail participant that watches
onExternalFunctionCalland intercepts unsafe calls → you get policy enforcement.
None of these changes touch the reactive agent itself. That is the point.
For multi-agent patterns at scale — planner + executors + reviewer + observers all sharing one environment — see Agent Swarms.
Agentic environment
The event bus reactive agents join and react to.
Participants
Capabilities and the typed handler API.
Capabilities & Tools
runInference, executeFunctionCall, sendMessage, and Tool definitions.
Streaming
Semantic events and live UIs.
Agent Swarms
Compose many reactive agents into a collaborative swarm.