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):

  1. Fast-path triggering: Optionally trigger a specific agent on the first turn
  2. LLM deliberation: Call the model through AISdkLangGraphAdapter with a system prompt built via buildDirectorPrompt
  3. Decision parsing: Extract routing decisions using parseDirectorDecision to determine nextAgentId or shouldEnd

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:

  1. Parses structured JSON chunks for actions
  2. Emits text_delta events for incremental text display
  3. Triggers action events for whiteboard or slide modifications
  4. 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.Root defined in lib/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 buildDirectorPrompt and parseDirectorDecision
  • Event-driven architecture streams StatelessEvent objects via config.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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →