Orchestration & Planning
How Sophon breaks down complex requests into multi-step execution plans with parallel execution, retry logic, and approval gates.
Overview
When you send Sophon a message, it flows through an orchestration pipeline — a series of middleware layers that handle everything from routing to tool execution. For complex, multi-step requests, the Planning middleware automatically decomposes your request into an execution plan and runs each step in the optimal order.
The Orchestration Pipeline
Every message passes through these middleware layers in order:
| Middleware | Purpose |
|---|---|
| Session Event | Logs the message to session history |
| Budget | Checks token/cost budgets before proceeding |
| Capability Routing | Selects the best model provider for the request |
| Context Window | Manages context size, truncates if needed |
| Tool Filter | Determines which tools are available for this request |
| Planning | Decides if a plan is needed and generates/executes it |
| Approval | Gates sensitive actions behind human approval |
| Sub-Agent | Spawns child agents for delegated tasks |
| Agentic Loop | Runs the core agent loop (LLM call + tool execution) |
| Tool Execution | Executes tool calls returned by the LLM |
| Parallel Execution | Runs independent tool calls concurrently |
| LLM Invoker | Makes the actual LLM API call |
When Planning Activates
The Planning middleware supports four modes:
| Mode | Behavior |
|---|---|
| Auto (default) | Uses a heuristic classifier to detect complex requests |
| LlmDecides | Asks a fast-tier model "does this need a plan?" |
| Always | Every request gets a plan |
| Never | Planning is disabled |
Heuristic Complexity Classifier
In Auto mode, Sophon scores your message to decide if it needs a plan:
- +1 if the message is longer than 100 characters
- +2 if it contains conjunction phrases like "and then", "after that", "first...then", "followed by"
- +2 if it contains multi-step language like "steps", "plan", "sequence", "step by step"
- +1 if it contains 2 or more action verbs (search, create, send, compare, analyze, etc.)
If the score reaches 3 or higher, the request is classified as Complex and a plan is generated.
Examples:
"What's the weather?"→ Simple (score 0) → direct execution"Search my emails for the invoice from Acme, then create a Jira ticket with the amount and send a summary to the team Slack channel"→ Complex (score 5+) → plan generated
Plan Generation
When a plan is needed, Sophon sends your request to the LLM with a structured prompt asking it to decompose the task into steps. The LLM returns a JSON plan:
{
"goal": "Find invoice, create ticket, notify team",
"steps": [
{
"id": "step_1",
"description": "Search emails for the Acme invoice",
"dependsOn": [],
"toolHints": ["email.search"],
"estimatedRisk": "None"
},
{
"id": "step_2",
"description": "Create a Jira ticket with the invoice amount",
"dependsOn": ["step_1"],
"toolHints": ["jira.create_issue"],
"estimatedRisk": "Medium"
},
{
"id": "step_3",
"description": "Send a summary to the team Slack channel",
"dependsOn": ["step_1"],
"toolHints": ["slack.send"],
"estimatedRisk": "Medium"
}
]
}Each step has:
- id — unique identifier
- description — what the step does
- dependsOn — which steps must complete before this one can start
- toolHints — suggested tools (optional, helps the LLM choose tools)
- estimatedRisk — None, Low, Medium, High, or Critical
Plan Execution
Topological Ordering
Sophon uses Kahn's algorithm to determine execution order. Steps are organized into batches based on their dependencies:
step_1 (no deps) → Batch 1 (runs first)
step_2 (needs step_1) → Batch 2 (runs after step_1)
step_3 (needs step_1) → Batch 2 (runs in parallel with step_2)Steps within the same batch run in parallel since they have no dependencies on each other.
Approval Gates
Before execution begins, Sophon checks the maximum risk level across all steps. If any step has Medium risk or higher, the entire plan is presented for human approval:
- You see the full plan with step descriptions, dependencies, and risk levels
- You can approve, reject, or edit the plan before execution
- Editing lets you modify step descriptions, remove steps, or reorder them
- If approval times out (default: 10 minutes), the plan is rejected
Smart Retry
When a step fails, Sophon doesn't give up immediately:
- The error is sent to the LLM with a prompt: "Suggest an alternative approach"
- If the LLM provides an alternative, the step is retried once with the modified description
- If the retry also fails, the step is marked as failed
Smart Cascade
When a step fails and other steps depend on it, Sophon applies intelligent cascade logic:
- If a dependent step has other completed dependencies, it can still proceed with partial context
- If all of a step's dependencies have failed, the step is skipped
- This prevents a single failure from cancelling the entire plan unnecessarily
Cancellation
Plans can be cancelled mid-execution. When cancelled:
- Currently running steps finish their current operation
- All pending steps are marked as skipped
- The plan status is set to Cancelled
Real-Time Status
During plan execution, Sophon emits status events via SignalR that the Dashboard and Mobile app display in real time:
| Event | When |
|---|---|
plan_start | Plan begins executing |
plan_step_start | A step begins |
plan_step_complete | A step finishes successfully |
plan_step_failed | A step fails (after retry if attempted) |
plan_step_retry | A step is being retried with an alternative |
plan_step_skipped | A step is skipped (dependency failed or plan cancelled) |
plan_complete | All steps finished |
plan_failed | Plan finished with one or more failed steps |
Each event includes metadata: plan ID, goal, step index, total steps, step status, and (for completed steps) a truncated output preview.
Configuration
Planning behavior can be configured in appsettings.user.json:
{
"AgentExecution": {
"PlanMaxSteps": 20,
"PlanningMode": "Auto"
}
}| Setting | Default | Description |
|---|---|---|
PlanMaxSteps | 20 | Maximum number of steps in a generated plan |
PlanningMode | Auto | One of: Auto, LlmDecides, Always, Never |
Example: Multi-Step Workflow
User request:
"Check my Google Calendar for meetings tomorrow, draft a preparation email for each meeting with relevant context from my Confluence pages, and create a Jira ticket to review the quarterly report"
What happens:
- Classifier scores this as Complex (multiple action verbs, conjunction phrases, length > 100)
- Plan generation produces 4 steps with dependencies
- Approval — step risk includes Medium (email, Jira), so plan is shown for approval
- Execution:
- Step 1:
calendar.list— fetch tomorrow's meetings (no deps, runs first) - Step 2:
confluence.search— find relevant pages (no deps, runs in parallel with step 1) - Step 3:
email.send— draft emails (depends on steps 1 & 2, waits for both) - Step 4:
jira.create_issue— create ticket (depends on step 1 only, runs after step 1)
- Step 1:
- Result — combined output from all steps returned to the user