LangGraph Multi-Agent Orchestration in OpenMAIC: How the Director Graph Coordinates AI Agents
OpenMAIC leverages LangGraph's StateGraph to create a deterministic state machine that separates orchestration logic from agent generation, enabling real-time multi-agent coordination through a Director node that decides who speaks next and streams events via Server-Sent Events.
The OpenMAIC repository implements sophisticated multi-agent conversations using the @langchain/langgraph package. At the heart of this system lies a carefully architected graph structure defined in lib/orchestration/director-graph.ts that treats agent coordination as a typed state machine, making complex interactions predictable and debuggable.
StateGraph Architecture and State Management
The foundation of OpenMAIC's orchestration is a StateGraph built using LangGraph's Annotation.Root system. This architecture enforces clear boundaries between immutable inputs and mutable state fields that evolve as the conversation progresses.
Defining the Orchestrator State
In lib/orchestration/director-graph.ts (lines 48-78), the OrchestratorState is defined as a LangGraph Annotation.Root containing:
- Immutable inputs: Messages, model configuration, agent list, and user profile
- Mutable fields: Current agent selection, turn count, accumulated responses, and whiteboard ledger
This strict typing ensures that each node in the graph receives a well-defined state shape while allowing specific fields to update as the workflow executes.
Graph Topology and Linear Execution Flow
The createOrchestrationGraph function (lines 84-95) constructs a deliberately linear flow:
START → director → agent_generate → END
│
└─(end)→ END
Unlike typical LangGraph implementations that might loop indefinitely, OpenMAIC executes at most one director → agent cycle per request. The client serializes multiple requests to continue dialogue, meaning the graph itself never loops. This design eliminates the need for a maxTurns counter—the graph's topology itself bounds execution, preventing runaway agent conversations.
The Director Node: Orchestration Decision Logic
The directorNode function serves as the brain of the operation, determining which agent should speak next or whether to cue the user for input.
Single-Agent Fast Path
When a conversation involves only one agent, the director uses pure code logic without LLM calls (lines 91-128). It dispatches the agent on turn 0 and automatically cues the user afterwards, avoiding unnecessary model latency for trivial routing decisions.
Multi-Agent LLM-Driven Planning
For multi-agent scenarios, the director can employ sophisticated LLM-based reasoning (lines 149-190):
- Fast-path triggering: Optionally trigger a specific agent on the first turn
- LLM deliberation: Call the model through
AISdkLangGraphAdapterwith a system prompt built viabuildDirectorPrompt - Decision parsing: Extract routing decisions using
parseDirectorDecisionto determinenextAgentIdorshouldEnd
The prompt includes the conversation summary, available agent personas, whiteboard state, and user profile, allowing the LLM to make context-aware routing decisions.
Real-Time Event Streaming
Throughout execution, the node streams StatelessEvent objects via config.writer, enabling real-time Server-Sent Events (SSE) to the front-end. Event types include thinking, cue_user, agent_start, and agent_end, providing granular visibility into the orchestration process.
Agent Generation and Structured Output Parsing
Once the Director selects an agent, the runAgentGeneration function (lines 235-277) handles the actual response generation and action execution.
System Prompt Construction
The node builds a comprehensive system prompt combining:
- The selected agent's persona and allowed actions
- Current store state and conversation history
- Whiteboard context from previous turns
Streaming and Parsing
While streaming the model output, the system:
- Parses structured JSON chunks for actions
- Emits
text_deltaevents for incremental text display - Triggers
actionevents for whiteboard or slide modifications - Records whiteboard actions for persistence via the ledger
Stateless Runtime Execution
The entry point lib/orchestration/stateless-generate.ts contains the statelessGenerate function (lines 5-13) that bridges the graph with the API layer.
import { createOrchestrationGraph, buildInitialState } from '@/lib/orchestration/director-graph';
import { statelessGenerate } from '@/lib/orchestration/stateless-generate';
import { OpenAI } from '@langchain/openai';
// Build the graph state from the incoming request
const llm = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const initialState = buildInitialState(chatRequest, llm);
// Stream events from the graph execution
for await (const ev of statelessGenerate(chatRequest, abortSignal, llm)) {
switch (ev.type) {
case 'thinking':
// Display loading indicator
break;
case 'agent_start':
// Initialize new message bubble
break;
case 'text_delta':
// Append streamed text
break;
case 'action':
// Execute whiteboard updates
break;
case 'cue_user':
// Enable user input
break;
}
}
This implementation creates the graph, initializes state from the StatelessChatRequest, and yields events that the front-end consumes for UI updates, action execution, and turn bookkeeping.
Summary
- LangGraph StateGraph provides the backbone for OpenMAIC's multi-agent coordination, offering type-safe state management through
Annotation.Rootdefined inlib/orchestration/director-graph.ts - Deterministic execution is enforced through a linear graph topology that executes at most one cycle per request, eliminating infinite loops without requiring turn counters
- Dual-mode Director blends fast code paths for single-agent scenarios with LLM-driven deliberation for complex multi-agent routing using
buildDirectorPromptandparseDirectorDecision - Event-driven architecture streams
StatelessEventobjects viaconfig.writer, enabling real-time UI updates through Server-Sent Events - Clean separation of concerns isolates orchestration logic (Director node) from generation logic (Agent-generate node), making the system extensible and maintainable
Frequently Asked Questions
What is LangGraph and why did OpenMAIC choose it for multi-agent orchestration?
LangGraph is a framework for building stateful, multi-actor applications with LLMs. OpenMAIC selected it because it provides a deterministic, typed state machine that cleanly separates decision-making from generation. Unlike ad-hoc orchestration scripts, LangGraph's StateGraph enforces explicit state definitions and transition logic, making complex multi-agent systems predictable and debuggable.
How does the Director node decide which agent speaks next?
The Director node employs a two-tier decision strategy. For single-agent conversations, it uses pure code logic to dispatch the agent and cue the user without LLM latency. For multi-agent scenarios, it constructs a system prompt via buildDirectorPrompt containing conversation summaries and agent personas, then calls an LLM through AISdkLangGraphAdapter to analyze context and return the nextAgentId via parseDirectorDecision.
What are StatelessEvents and how does the front-end consume them?
StatelessEvent objects are typed events streamed from the graph execution via config.writer. They include variants like thinking, agent_start, text_delta, action, and cue_user. The front-end receives these via Server-Sent Events and maps them to UI behaviors—showing loading indicators, appending text to message bubbles, executing whiteboard actions, or enabling user input fields.
Why doesn't the OpenMAIC graph use loops for continuing conversations?
OpenMAIC uses a linear graph topology (START → director → agent_generate → END) intentionally to prevent runaway agent loops. The architecture treats each turn as a discrete request; the client serializes multiple requests to continue dialogue. This eliminates the need for maxTurns counters and makes the system more predictable, as the graph's shape itself bounds execution rather than runtime logic.
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 →