Implementation:Microsoft Autogen MagenticOne Orchestrator
| Knowledge Sources | |
|---|---|
| Domains | Multi_Agent, Orchestration, LLM, Task_Planning |
| Last Updated | 2026-02-11 17:00 GMT |
Overview
A sophisticated ledger-based orchestrator that manages multi-agent group chats by maintaining task ledgers (facts and plans) and progress tracking to coordinate agent selection and task completion.
Description
The `MagenticOneOrchestrator` is an advanced group chat manager that implements a two-loop orchestration strategy:
Outer Loop (Task Ledger):
- Maintains long-term task context including facts and plans
- Triggered when the inner loop stalls (exceeds max_stalls)
- Updates facts based on new discoveries
- Revises the plan based on current progress
- Resets agents and broadcasts updated ledger
Inner Loop (Progress Ledger):
- Evaluates current progress using structured LLM reasoning
- Determines if the request is satisfied
- Checks if progress is being made or if the team is stuck in a loop
- Selects the next speaker based on task needs
- Generates instructions for the selected agent
- Tracks stall count for outer loop intervention
The orchestrator uses structured JSON output from the LLM to make decisions about:
- Whether the task is complete (is_request_satisfied)
- Whether progress is being made (is_progress_being_made)
- Whether the team is stuck in a loop (is_in_loop)
- What instruction to give next (instruction_or_question)
- Which agent should act next (next_speaker)
Usage
Use MagenticOneOrchestrator when coordinating multiple specialized agents on complex tasks that require planning, fact gathering, and iterative problem-solving with automatic recovery from stalls.
Code Reference
Source Location
- Repository: Microsoft_Autogen
- File: python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_magentic_one/_magentic_one_orchestrator.py
- Lines: 1-536
Signature
class MagenticOneOrchestrator(BaseGroupChatManager):
def __init__(
self,
name: str,
group_topic_type: str,
output_topic_type: str,
participant_topic_types: List[str],
participant_names: List[str],
participant_descriptions: List[str],
max_turns: int | None,
message_factory: MessageFactory,
model_client: ChatCompletionClient,
max_stalls: int,
final_answer_prompt: str,
output_message_queue: asyncio.Queue[BaseAgentEvent | BaseChatMessage | GroupChatTermination],
termination_condition: TerminationCondition | None,
emit_team_events: bool,
)
@rpc
async def handle_start(
self,
message: GroupChatStart,
ctx: MessageContext
) -> None
@event
async def handle_agent_response(
self,
message: GroupChatAgentResponse | GroupChatTeamResponse,
ctx: MessageContext
) -> None
async def save_state(self) -> Mapping[str, Any]
async def load_state(self, state: Mapping[str, Any]) -> None
Import
# MagenticOneOrchestrator is typically used through team configuration
from autogen_agentchat.teams import MagenticOneGroupChat
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| name | str | Yes | Orchestrator's unique identifier |
| group_topic_type | str | Yes | Topic type for group chat messages |
| output_topic_type | str | Yes | Topic type for output messages |
| participant_topic_types | List[str] | Yes | Topic types for each participant agent |
| participant_names | List[str] | Yes | Names of participant agents |
| participant_descriptions | List[str] | Yes | Descriptions of each agent's capabilities |
| max_turns | int | No | Maximum number of orchestration rounds (None for unlimited) |
| message_factory | MessageFactory | Yes | Factory for creating message objects |
| model_client | ChatCompletionClient | Yes | LLM client for orchestration decisions |
| max_stalls | int | Yes | Maximum stalls before triggering outer loop |
| final_answer_prompt | str | Yes | Prompt for generating final answer |
| output_message_queue | asyncio.Queue | Yes | Queue for output events |
| termination_condition | TerminationCondition | No | Custom termination logic |
| emit_team_events | bool | Yes | Whether to emit team coordination events |
Outputs
| Name | Type | Description |
|---|---|---|
| GroupChatMessage | Event | Messages broadcast to participants and output queue |
| GroupChatAgentResponse | Event | Responses from orchestrator including ledgers and instructions |
| SelectSpeakerEvent | Event | Events indicating next speaker selection (if emit_team_events=True) |
| GroupChatTermination | Event | Final termination signal with reason |
| State | Mapping[str, Any] | Serializable state including task, facts, plan, rounds, stalls |
Core Mechanisms
Task Ledger (Outer Loop)
The task ledger is initialized at the start and updated when stalling occurs:
Initial Creation:
- Gather Facts: Ask model to identify known facts about the task (closed-book)
- Create Plan: Ask model to create a plan using the team descriptions and gathered facts
- Broadcast Ledger: Send the complete ledger (task + team + facts + plan) to all agents
Update Process:
- Update Facts: Ask model to revise facts based on conversation history
- Update Plan: Ask model to revise plan based on new facts and progress
Progress Ledger (Inner Loop)
At each orchestration step, the orchestrator:
- Constructs context from message thread (filtering tool calls)
- Prompts model with progress ledger template
- Requests structured JSON with retry (up to max_json_retries=10)
- Validates JSON structure with required keys:
- is_request_satisfied: {reason, answer}
- is_progress_being_made: {reason, answer}
- is_in_loop: {reason, answer}
- instruction_or_question: {reason, answer}
- next_speaker: {reason, answer}
Decision Flow:
- If task satisfied → Prepare final answer and terminate
- If not making progress → Increment stall counter
- If in a loop → Increment stall counter
- If making progress → Decrement stall counter (min 0)
- If stalls >= max_stalls → Update task ledger and restart outer loop
- Otherwise → Broadcast instruction and request next speaker to respond
Stall Detection
The orchestrator tracks two types of stalls:
- Progress Stall: `is_progress_being_made.answer == false`
- Loop Stall: `is_in_loop.answer == true`
When stalls reach the threshold:
- Call `_update_task_ledger()` to revise facts and plan
- Call `_reenter_outer_loop()` to reset agents and restart
- Reset stall counter to 0
Message Context Conversion
The `_thread_to_context()` method converts the message thread to LLM context:
- Tool messages (ToolCallRequestEvent, ToolCallExecutionEvent): Ignored
- Stop/Handoff messages: Converted to UserMessage
- Orchestrator messages: Converted to AssistantMessage
- Agent messages: Converted to UserMessage with agent source
- Vision handling: Images removed if model doesn't support vision
State Management
Serialization
The orchestrator maintains serializable state via `MagenticOneOrchestratorState`:
class MagenticOneOrchestratorState(BaseModel):
message_thread: List[dict] # Serialized messages
current_turn: int
task: str
facts: str
plan: str
n_rounds: int
n_stalls: int
Methods:
- save_state(): Returns dict with current state
- load_state(): Restores state from dict
Reset
The `reset()` method clears:
- Message thread
- Termination condition state
- Round and stall counters
- Task, facts, and plan strings
Usage Examples
Basic Setup
from autogen_agentchat.teams import MagenticOneGroupChat
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.agents import AssistantAgent, CodeExecutorAgent
from autogen_ext.code_executors.docker import DockerCommandLineCodeExecutor
async def main():
model_client = OpenAIChatCompletionClient(model="gpt-4o")
# Create specialized agents
coder = AssistantAgent("coder", model_client=model_client,
description="Writes Python code")
executor = CodeExecutorAgent("executor",
code_executor=DockerCommandLineCodeExecutor(),
description="Executes code")
# MagenticOne team uses the orchestrator internally
team = MagenticOneGroupChat(
participants=[coder, executor],
model_client=model_client,
max_turns=20,
max_stalls=3
)
result = await team.run(task="Calculate the 20th Fibonacci number")
print(result)
State Persistence
# Save state during execution
team = MagenticOneGroupChat(participants=[...])
result = await team.run(task="Long running task")
# Access orchestrator state
state = await team._group_chat_manager.save_state()
# Save to file
import json
with open("orchestrator_state.json", "w") as f:
json.dump(state, f)
# Later, restore state
with open("orchestrator_state.json", "r") as f:
saved_state = json.load(f)
await team._group_chat_manager.load_state(saved_state)
Custom Final Answer Prompt
custom_prompt = """
Based on the conversation history, provide a comprehensive final answer that:
1. Summarizes key findings
2. Lists any assumptions made
3. Provides actionable recommendations
Task: {task}
"""
team = MagenticOneGroupChat(
participants=[...],
model_client=model_client,
final_answer_prompt=custom_prompt
)
Prompts
The orchestrator uses several prompt templates from `_prompts.py`:
- ORCHESTRATOR_TASK_LEDGER_FACTS_PROMPT: Initial fact gathering
- ORCHESTRATOR_TASK_LEDGER_PLAN_PROMPT: Initial plan creation
- ORCHESTRATOR_TASK_LEDGER_FULL_PROMPT: Complete ledger format
- ORCHESTRATOR_PROGRESS_LEDGER_PROMPT: Progress evaluation with JSON schema
- ORCHESTRATOR_TASK_LEDGER_FACTS_UPDATE_PROMPT: Fact revision
- ORCHESTRATOR_TASK_LEDGER_PLAN_UPDATE_PROMPT: Plan revision
- ORCHESTRATOR_FINAL_ANSWER_PROMPT: Final answer generation
Configuration
Key Parameters
- max_stalls: Typically 2-5. Lower values cause more frequent replanning
- max_turns: Overall limit on orchestration rounds (default: None)
- max_json_retries: Retries for malformed JSON (default: 10)
Model Requirements
- Preferably supports structured_output for reliable JSON parsing
- Alternatively, json_output mode with extraction fallback
- Vision capability optional (images removed if unsupported)