# How the OpenMAIC Director Graph Decides Which Agent Speaks Next

> Discover how the OpenMAIC Director Graph selects the next speaking agent. Learn about fast-path evaluation and LLM-based decision making for efficient AI conversation flow.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: internals
- Published: 2026-09-11

---

**The OpenMAIC Director Graph decides which agent speaks next by evaluating deterministic fast-paths for single-agent or trigger-agent scenarios first, then falling back to an LLM-based selection process that returns a structured decision containing `nextAgentId` and `shouldEnd` parameters.**

The Director Graph serves as the core orchestration engine in the OpenMAIC multi-agent framework, managing conversation flow through a state-driven graph architecture where the client serializes additional turns across requests. For each user request, the system executes exactly one director-to-agent cycle, with the Director Node determining whether to dispatch an agent, cue the user, or terminate the session. This mechanism relies on a tiered decision hierarchy that prioritizes efficiency through code-level logic before invoking expensive LLM calls.

## Single-Agent Deterministic Mode

When the system operates with only one available agent, the Director Graph bypasses the LLM entirely for maximum efficiency. According to the source code in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts) (lines 15-32), the logic follows a strict turn-based protocol:

- **Turn 0**: The director immediately dispatches the sole available agent.
- **Turn ≥ 1**: The director cues the user for follow-up input and ends the current round.

This pure code-level implementation eliminates latency from model inference in single-agent scenarios, as the orchestration logic requires no semantic reasoning to select participants.

## Multi-Agent Trigger Fast Path

For multi-agent configurations, the Director Graph implements a fast-path optimization for the initial turn. Located at lines 34-44 in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts), this logic checks if a `triggerAgentId` exists in the request state and validates it against `state.availableAgentIds`:

```typescript
// Inside directorNode – fast-path for a trigger agent
if (state.turnCount === 0 && state.triggerAgentId) {
  const triggerId = state.triggerAgentId;
  if (state.availableAgentIds.includes(triggerId)) {
    write({ type: 'thinking', data: { stage: 'agent_loading', agentId: triggerId } });
    return { currentAgentId: triggerId, shouldEnd: false };
  }
}

```

If the trigger agent exists in the registry, the director dispatches it immediately without constructing prompts or calling the language model. This optimization ensures predictable first-turn behavior while conserving computational resources.

## LLM-Based Agent Selection

When neither deterministic path applies, the Director Graph constructs a rich contextual prompt and delegates the decision to a language model. This process involves three distinct phases: prompt construction, generation, and structured output parsing.

### Prompt Construction with buildDirectorPrompt

The director initiates LLM-based decisions by calling `buildDirectorPrompt`, implemented starting at line 64 in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts). This function assembles a comprehensive system prompt containing:

- Available agent descriptions and capabilities
- Conversation summary and history
- Prior agent responses stored in state
- Current whiteboard state (shared memory)
- Discussion context and metadata

The resulting prompt is passed to `AISdkLangGraphAdapter._generate`, which interfaces with the configured language model to produce a structured decision.

### Parsing and Executing the Decision

The raw LLM output undergoes processing by `parseDirectorDecision` (lines 86-88), which extracts a structured object with two critical fields:

- **`nextAgentId`**: The identifier of the selected agent, or the special token **`USER`** to indicate the human participant should speak next.
- **`shouldEnd`**: A boolean flag indicating whether the conversation should terminate.

The execution logic at lines 89-110 implements the following branching behavior:

1. If `shouldEnd` is true or `nextAgentId` is falsy, the graph transitions to the END state.
2. If `nextAgentId === 'USER'`, the system emits a `cue_user` event and ends the round.
3. Otherwise, the system sets `state.currentAgentId` to the chosen agent and proceeds to the `agent_generate` node.

```typescript
// Example LLM decision parsing (simplified)
const decision = parseDirectorDecision(llmOutput);
if (decision.shouldEnd) {
  return { shouldEnd: true };
}
if (decision.nextAgentId === 'USER') {
  write({ type: 'cue_user', data: { fromAgentId: state.currentAgentId } });
  return { shouldEnd: true };
}

```

## Integration with the Orchestration Graph

The Director Graph itself is instantiated via `createOrchestrationGraph` in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts), while the execution loop resides in [`lib/chat/pi/director-loop.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/chat/pi/director-loop.ts). The graph follows this flow:

```text
START → director ──(end)──→ END
              │
              └─(next)→ agent_generate → END

```

Supporting infrastructure includes [`lib/orchestration/director-prompt.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-prompt.ts) for prompt templates, [`lib/orchestration/registry/store.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/registry/store.ts) for agent registry access, and [`lib/prompts/index.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/prompts/index.ts) for base prompt construction utilities.

```typescript
// Example: building the initial state for a request
import { buildInitialState, createOrchestrationGraph } from '@/lib/orchestration/director-graph';
import { someLanguageModel } from '@/lib/ai';

// 1. Create the graph once
const graph = createOrchestrationGraph();

// 2. Build the request‑scoped state
const initState = buildInitialState(request, someLanguageModel);

// 3. Run a single director → agent iteration
const result = await graph.invoke(initState);

```

## Summary

- The Director Graph uses **deterministic logic** for single-agent configurations, bypassing the LLM entirely on lines 15-32 of [`director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/director-graph.ts).
- A **trigger-agent fast path** at lines 34-44 allows immediate first-turn dispatch without model inference.
- **LLM-based decisions** rely on `buildDirectorPrompt` (lines 64-71) and `parseDirectorDecision` (lines 86-88) to select agents based on conversation context.
- The special **`USER`** token signals the director to cue human input rather than dispatching an agent.
- Decision execution (lines 89-110) handles termination, user cues, and transitions to the `agent_generate` node.

## Frequently Asked Questions

### What happens if the Director Graph cannot determine a valid next agent?

If `parseDirectorDecision` returns a falsy `nextAgentId` or sets `shouldEnd` to true, the graph immediately transitions to the END state, terminating the current conversation round. This safety mechanism prevents the orchestration from entering undefined states when the LLM produces malformed output or when no suitable agent exists for the current context.

### How does the trigger agent fast path optimize performance?

The trigger agent fast path checks `state.turnCount === 0` and validates `state.triggerAgentId` against `state.availableAgentIds` before any LLM calls occur. By returning `{ currentAgentId: triggerId, shouldEnd: false }` immediately at lines 34-44, the system avoids prompt construction and model inference latency, reducing first-turn response time significantly in multi-agent workflows.

### What information does the Director Graph send to the LLM for agent selection?

The `buildDirectorPrompt` function constructs a comprehensive context packet including available agent capabilities, conversation summaries stored in state, prior agent responses, whiteboard state, and discussion metadata. This rich prompt enables the language model to make informed routing decisions based on agent specialties and conversation history.

### Where does the Director Graph store its decision state?

The Director Graph maintains ephemeral state through the LangGraph `StateGraph` architecture defined in [`lib/orchestration/director-graph.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/director-graph.ts). Key decision parameters like `currentAgentId`, `turnCount`, and `shouldEnd` persist within the graph's state object during the single director-to-agent cycle, while long-term agent registry data resides in [`lib/orchestration/registry/store.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/orchestration/registry/store.ts).