OpenMAIC Agent Execution Events: Complete Guide to Director Graph Event Emission
OpenMAIC emits seven distinct StatelessEvent types during agent execution in its director graph, streamed from two core nodes to enable real‑time multi‑agent orchestration.
The OpenMAIC director graph is a LangGraph‑based state machine that coordinates agent conversations. During each request, it streams granular progress updates via StatelessEvent objects, allowing clients to render typing indicators, partial responses, and tool invocations as they occur. This guide breaks down every event emitted during the execution lifecycle, with source‑level precision from the THU‑MAIC/OpenMAIC repository.
Events Emitted by the Director Node
Located in lib/orchestration/director-graph.ts, the director node manages conversation flow and routing decisions. It emits two event families:
thinking Events
The director signals its internal reasoning through thinking events with distinct stage values:
agent_loading— Emitted when the director selects a single agent (fast‑path) or trigger agent. Payload includesagentId. Sourced at lines 20‑33.director— Emitted immediately before the LLM call that determines the next speaker in multi‑agent mode. Sourced at lines 59‑71.
cue_user Event
When the director determines the user should speak—either after the sole agent responds or as a deliberate handoff—it emits cue_user with an optional fromAgentId field indicating which agent yielded control. Sourced at lines 59‑71.
Events Emitted by the Agent Generate Node
The agent generate node handles actual LLM streaming and tool execution. It emits five event types, all defined in lib/orchestration/director-graph.ts between lines 60‑197:
| Event | Purpose | Key Payload Fields | Source Lines |
|---|---|---|---|
agent_start |
Signals generation beginning | messageId, agentId, agentName, agentAvatar, agentColor |
60‑70 |
text_delta |
Streams incremental text output | content, messageId |
78‑87 |
action |
Delivers structured tool commands | actionId, actionName, params, agentId, messageId |
123‑130 |
error |
Captures generation failures | message |
165‑176 |
agent_end |
Marks generation completion | messageId, agentId |
190‑197 |
The text_delta and action events are produced by parsing LLM chunks in lib/orchestration/stateless-generate.ts, which structures streamed responses into ordered sequences that the graph then emits as discrete events.
Complete Event Handling Example
Client applications consume these events through a LangGraph writer stream. Here is a type‑safe handler implementation:
import type { StatelessEvent } from '@/lib/types/chat';
function handleEvent(event: StatelessEvent) {
switch (event.type) {
case 'thinking':
console.log(`Director stage: ${event.data.stage}`, event.data);
// Render loading indicator or "AI is thinking" UI
break;
case 'cue_user':
console.log('User input requested', event.data.fromAgentId);
// Activate chat input field
break;
case 'agent_start':
console.log('Agent initialized', event.data.agentName);
// Display agent avatar and color
break;
case 'text_delta':
process.stdout.write(event.data.content);
// Append to streaming message buffer
break;
case 'action':
console.log('Executing action', event.data.actionName, event.data.params);
// Route to whiteboard or tool handler
break;
case 'error':
console.error('Stream failed:', event.data.message);
// Surface error to user with retry option
break;
case 'agent_end':
console.log('Generation complete', event.data.messageId);
// Finalize message rendering
break;
}
}
Event Payload Type Definitions
The StatelessEvent union type in lib/types/chat.d.ts enforces the following discriminated structure:
- Base fields:
type,data thinking.data:{ stage: 'agent_loading' | 'director', agentId?: string }cue_user.data:{ fromAgentId?: string }agent_start.data:{ messageId: string, agentId: string, agentName: string, agentAvatar: string, agentColor: string }text_delta.data:{ content: string, messageId: string }action.data:{ actionId: string, actionName: string, params: Record<string, unknown>, agentId: string, messageId: string }error.data:{ message: string }agent_end.data:{ messageId: string, agentId: string }
Key Source Files for OpenMAIC Agent Events
| File | Role in Event Lifecycle |
|---|---|
lib/orchestration/director-graph.ts |
Core LangGraph implementation; all seven event types are written here via writer() calls |
lib/orchestration/director-prompt.ts |
Constructs director LLM prompts that precede the thinking‑director event |
lib/orchestration/stateless-generate.ts |
Parses raw LLM streams into text_delta and action sequences |
lib/types/chat.d.ts |
Source of truth for StatelessEvent type definitions |
Summary
- OpenMAIC agent execution emits seven
StatelessEventtypes across two graph nodes. - Director node handles routing with
thinkingandcue_userevents. - Agent generate node handles streaming with
agent_start,text_delta,action,error, andagent_endevents. - All events are defined and emitted in
lib/orchestration/director-graph.tsvia LangGraph's writer API. - Client handlers should switch on
event.typeand destructureevent.dataaccording to the discriminated union defined inlib/types/chat.d.ts.
Frequently Asked Questions
What triggers the thinking event with stage: 'director'?
This event fires immediately before the director LLM receives its prompt to select the next speaker. According to the source at lib/orchestration/director-graph.ts lines 59‑71, it precedes the generateDirectResponse call in multi‑agent conversations, providing a hook for UI loading states.
How does OpenMAIC distinguish between text and action outputs from the LLM?
The stateless-generate.ts parser inspects each streamed chunk for structural markers. Plain text becomes text_delta events; detected command structures trigger action events with full parameter serialization. Both route through the same agent generate node in director-graph.ts.
Can custom events be added to the OpenMAIC director graph?
The current StatelessEvent union in lib/types/chat.d.ts is fixed. To extend event types, you must modify the type definition and add corresponding writer() calls in director-graph.ts. The LangGraph architecture supports arbitrary event shapes through its streaming interface.
What happens to agent_end if an error event was previously emitted?
agent_end fires unconditionally after generation terminates, regardless of success or failure. Per lines 190‑197, it executes in a finally block, ensuring clients can clean up rendering state even when errors interrupt the stream.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →