# OpenMAIC Agent Execution Events: Complete Guide to Director Graph Event Emission

> Explore OpenMAIC agent execution events. Understand the seven StatelessEvent types emitted from core nodes for real-time multi-agent orchestration in the director graph.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: deep-dive
- Published: 2026-09-05

---

**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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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 includes `agentId`. 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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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:

```typescript
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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts) | Core LangGraph implementation; all seven event types are written here via `writer()` calls |
| [`lib/orchestration/director-prompt.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-prompt.ts) | Constructs director LLM prompts that precede the `thinking`‑director event |
| [`lib/orchestration/stateless-generate.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/stateless-generate.ts) | Parses raw LLM streams into `text_delta` and `action` sequences |
| [`lib/types/chat.d.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/types/chat.d.ts) | Source of truth for `StatelessEvent` type definitions |

## Summary

- **OpenMAIC agent execution emits seven `StatelessEvent` types** across two graph nodes.
- **Director node** handles routing with `thinking` and `cue_user` events.
- **Agent generate node** handles streaming with `agent_start`, `text_delta`, `action`, `error`, and `agent_end` events.
- All events are defined and emitted in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts) via LangGraph's writer API.
- Client handlers should switch on `event.type` and destructure `event.data` according to the discriminated union defined in [`lib/types/chat.d.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/director-graph.ts).

### Can custom events be added to the OpenMAIC director graph?

The current `StatelessEvent` union in [`lib/types/chat.d.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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`](https://github.com/THU-MAIC/OpenMAIC/blob/main/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.