Skip to content

Orchestration modes

Supervisor and grounded topologies, mode_config settings, NodeConfig per-node customization, and resource_id for grounded context anchoring.

Intended audience: Stakeholders, Business analysts, Solution architects, Developers, Testers

Learning outcomes by role

Stakeholders

  • Contrast supervisor versus grounded modes for complexity and safety postures.

Business analysts

  • Capture mode_config and node-level customization in acceptance language.

Solution architects

  • Explain resource_id anchoring and topology constraints for integration designs.

Developers

  • Apply mode_config and NodeConfig fields when building orchestrator configs.

Testers

  • Validate mode-specific settings, grounded context injection, and per-node override behavior.

An orchestration mode defines the routing topology inside the agent graph — how intent is classified, how tools are called, how results are validated, and how the final response is assembled. The mode is set at creation alongside framework_type and both are immutable for the life of the orchestrator.

Implemented in OrchestratorFactory (runtime load): supervisor, coordinator, and handoff for both langgraph and openai_agents; grounded is langgraph only (no openai_agents + grounded backend). Additional topologies (pipeline, reflection, ensemble, hierarchical) exist in the factory registry but are not accepted by the public create API schema.

API validation (FRAMEWORK_SUPPORTED_MODES in cadence/core/constants/framework.py) must allow the framework + mode pair at create time — see Orchestration backends.

ModeFrameworkStatusUse case
supervisorlanggraph, openai_agentsActiveOpen-ended assistant with multi-step tool routing, planning, and optional validation
groundedlanggraphActiveAnswers scoped to a specific resource anchor — resource_id required per chat request
coordinatorlanggraph, openai_agentsActiveMulti-agent coordination topology
handofflanggraph, openai_agentsActiveSequential agent handoffs
flowchart TD
IN[Incoming message] --> CL[Router node]
CL -->|direct response| RE[Responder node]
CL -->|clarify| CLA[Clarifier node]
CL -->|plan| PL[Planner node]
PL --> EX[Executor node — tool calls]
EX --> |tool results| PL
PL --> |max_agent_hops reached or done| SY[Synthesizer node]
RE --> OUT[Response]
SY --> VA{enabled_llm_validation?}
VA -->|yes| VN[Validation node]
VA -->|no| OUT
VN --> OUT

The supervisor topology routes incoming intent through a router node, which decides whether to answer directly, ask for clarification, or plan a multi-step tool sequence. The planner calls tools through the executor, iterates up to max_agent_hops times, then passes results to the synthesizer. Each logical node in the graph can be customized individually via NodeConfig.

mode_config is nested inside the orchestrator’s config JSON object. All keys are optional; omitting a key uses the default value.

orchestrator config.mode_config (supervisor example)
{
"default_llm_config_id": "<uuid>",
"mode_config": {
"max_agent_hops": 25,
"max_tool_rounds": 3,
"enabled_parallel_tool_calls": true,
"node_execution_timeout": 60,
"enabled_llm_validation": false,
"enabled_clarification_intent": true
}
}

From BaseOrchestratorSettings — apply to every mode:

FieldDefaultDescription
node_execution_timeout60Per-node execution timeout in seconds
max_context_window16000Maximum token context window
message_context_window10Number of past messages included in context (supervisor overrides this to 5)
enabled_auto_compactfalseAuto-compact context when it exceeds the window
enabled_suggestionfalseEnable follow-up suggestion generation after each response

From BaseSupervisorSettings:

FieldDefaultDescription
max_agent_hops25Maximum recursive tool-call cycles before forced synthesis
max_tool_rounds3Maximum tool call rounds per planner step
enabled_parallel_tool_callstrueAllow concurrent tool calls in a single planner step
enabled_llm_validationfalseRun a validation LLM pass on the draft response before sending
enabled_clarification_intenttrueRoute ambiguous queries through the clarifier before planning
message_context_window5Supervisor overrides the base default of 10

From BaseGroundedSettings:

FieldDefaultDescription
scope_rules""Free-text constraints injected into the agent’s system context at runtime
max_agent_hops25Maximum recursive tool-call cycles before forced synthesis
max_tool_rounds3Maximum tool-call rounds before forced synthesis
enabled_validatortrueRun a validator pass to check answer quality against the resource

Each logical node in the graph can have its own LLM config, model, and prompt override, independent of the orchestrator’s default_llm_config_id. This lets you run a cheap model for routing and a more capable one for synthesis.

cadence/engine/base/node_config.py
class NodeConfig(BaseModel):
llm_config_id: Optional[str] = None # Override org-level default for this node
model_name: Optional[str] = None # Model name override (e.g. "gpt-4o-mini" for fast nodes)
prompt: Optional[str] = None # System prompt override for this node
temperature: Optional[float] = None
max_tokens: Optional[int] = None
timeout: Optional[int] = None # Per-node timeout in seconds

Nodes that accept NodeConfig overrides:

ModeConfigurable nodes
Supervisorrouter_node, planner_node, synthesizer_node, validation_node, clarifier_node, responder_node, autocompact, suggestion_node, error_handler_node
Groundedrouter_node, planner_node (alias: agent_node), synthesizer_node, autocompact, suggestion_node, error_handler_node

Example: cheap model for routing, stronger model for synthesis

Section titled “Example: cheap model for routing, stronger model for synthesis”
orchestrator config
{
"default_llm_config_id": "<gpt4o-config-uuid>",
"mode_config": {
"router_node": {
"model_name": "gpt-4o-mini"
},
"synthesizer_node": {
"model_name": "gpt-4o",
"temperature": 0.3
}
}
}

Grounded mode requires a resource_id on every chat request. This is the anchor object — a document ID, URL, database record ID, or any string — that constrains what the agent is allowed to answer about.

cadence/api/chat/schemas.py
class ChatCompletionRequest(BaseModel):
message: str # Required; 1–1000 characters
conversation_id: Optional[str] # Resumes an existing thread
stream: bool = True
resource_id: Optional[str] # Required for grounded mode

The resource_id value is written into the graph’s initial state as state.resource_id. Plugin tool nodes read it to scope their queries:

plugin tool handler (example)
resource_id = state.get("resource_id")
results = await db.query(doc_id=resource_id, question=query)
POST /api/orgs/{org_id}/orchestrators
{
"name": "General Purpose Assistant",
"framework_type": "langgraph",
"mode": "supervisor",
"active_plugin_ids": ["com.example.web-search"],
"tier": "hot",
"config": {
"default_llm_config_id": "<uuid>",
"mode_config": {
"max_agent_hops": 10,
"max_tool_rounds": 3,
"enabled_parallel_tool_calls": true,
"enabled_clarification_intent": true,
"enabled_llm_validation": false
}
}
}
SymptomCauseFix
Chat returns UnsupportedOperationErrorOrchestrator mode is registered but not yet implemented (coordinator, handoff, etc.)Use supervisor or grounded mode
Agent loops without completingmax_agent_hops too high or tool always returns partial resultsReduce max_agent_hops; fix tool return logic
Grounded mode ignores resource_idPlugin tool doesn’t read state.resource_idUpdate the plugin to scope queries using state["resource_id"]
Chat fails in grounded moderesource_id missing from requestAlways pass resource_id in the chat body for grounded orchestrators
Router sends all queries to the same pathenabled_clarification_intent catching too broadlySet enabled_clarification_intent: false or tune the router via router_node.prompt
Validation node rejects valid responsesenabled_llm_validation prompt too strictSet enabled_llm_validation: false or override validation_node.prompt
Need to change modeMode is immutableCreate a new orchestrator; update central points to reference it