Skip to main content

Overview

Plan Mode adds a TodoList middleware to the agent, providing task tracking capabilities for complex multi-step workflows. When enabled, the agent can break down tasks, track progress, and provide visibility into what’s being done.
Plan Mode uses LangChain’s built-in TodoListMiddleware with custom DeerFlow-style prompts.

Benefits

Task Breakdown

Break complex tasks into manageable steps

Progress Tracking

Track task status in real-time

User Visibility

Users see what the agent is working on

Parallel Execution

Multiple tasks can be in progress simultaneously

Enabling Plan Mode

Plan Mode is controlled via runtime configuration through the is_plan_mode parameter in RunnableConfig.
Plan Mode is disabled by default. You must explicitly enable it per request.

Basic Configuration

from langchain_core.runnables import RunnableConfig
from src.agents.lead_agent.agent import make_lead_agent

# Enable plan mode
config = RunnableConfig(
    configurable={
        "thread_id": "example-thread",
        "thinking_enabled": True,
        "is_plan_mode": True,  # Enable plan mode
    }
)

# Create agent with plan mode enabled
agent = make_lead_agent(config)

Dynamic Plan Mode

You can enable/disable plan mode dynamically based on task complexity:
def create_agent_for_task(task_complexity: str):
    """Create agent with plan mode based on task complexity."""
    is_complex = task_complexity in ["high", "very_high"]
    
    config = RunnableConfig(
        configurable={
            "thread_id": f"task-{task_complexity}",
            "thinking_enabled": True,
            "is_plan_mode": is_complex,  # Enable only for complex tasks
        }
    )
    
    return make_lead_agent(config)

# Simple task - no TodoList needed
simple_agent = create_agent_for_task("low")

# Complex task - TodoList enabled
complex_agent = create_agent_for_task("high")

How It Works

1

Agent Creation

When make_lead_agent(config) is called, it extracts is_plan_mode from config.configurable.
2

Middleware Chain

Config is passed to _build_middlewares(config) which reads is_plan_mode and calls _create_todo_list_middleware(is_plan_mode).
3

TodoList Middleware

If is_plan_mode=True, a TodoListMiddleware instance is created and added to the middleware chain.
4

Tool Registration

The middleware automatically adds a write_todos tool to the agent’s toolset.
5

State Management

The middleware handles the todo list state and provides it to the agent on each turn.

Middleware Architecture

make_lead_agent(config)

  ├─> Extracts: is_plan_mode = config.configurable.get("is_plan_mode", False)

  └─> _build_middlewares(config)

        ├─> ThreadDataMiddleware
        ├─> SandboxMiddleware
        ├─> UploadsMiddleware
        ├─> SummarizationMiddleware (if enabled)
        ├─> TodoListMiddleware (if is_plan_mode=True) ← NEW
        ├─> TitleMiddleware
        └─> ClarificationMiddleware

The write_todos Tool

When Plan Mode is enabled, the agent has access to a write_todos tool:

Tool Description

Manage a todo list to track multi-step tasks and complex workflows.
Use this tool to break down complex requests into manageable steps.

When to Use:
- Complex multi-step tasks (3+ distinct steps)
- Non-trivial tasks requiring careful planning
- When user explicitly requests a todo list
- When user provides multiple tasks

When NOT to Use:
- Single, straightforward tasks
- Trivial tasks (< 3 steps)
- Purely conversational requests

Task States

Task not yet started.
{
  "task": "Research competitor pricing",
  "status": "pending"
}

Using write_todos

The agent uses the tool to manage its task list:
{
  "todos": [
    {"task": "Research competitor pricing", "status": "pending"},
    {"task": "Analyze market trends", "status": "pending"},
    {"task": "Create comparison report", "status": "pending"}
  ]
}

When to Use Plan Mode

Ideal Use Cases

When tasks require:
  • Multiple searches from different angles
  • Data collection from various sources
  • Synthesis of information
Example: “Research AI trends in healthcare and create a report”
When creating:
  • Presentations (research → outline → slides)
  • Reports (gather data → analyze → write)
  • Web pages (research design → implement)
Example: “Create a slide deck about climate change solutions”
When building:
  • Applications with multiple components
  • Features requiring setup, implementation, testing
  • Refactoring projects
Example: “Build a todo app with authentication”
When performing:
  • Data analysis with multiple stages
  • Comparative analysis
  • Complex calculations
Example: “Analyze this dataset and create visualizations”

When NOT to Use

  • ❌ Single, straightforward questions
  • ❌ Quick conversational queries
  • ❌ Simple file operations
  • ❌ Trivial calculations

Custom Prompts

DeerFlow uses custom prompts that match the overall prompt style:

System Prompt Features

  • Uses XML tags (<todo_list_system>) for consistency
  • Emphasizes CRITICAL rules and best practices
  • Clear “When to Use” vs “When NOT to Use” guidelines
  • Focuses on real-time updates and immediate completion

Tool Description Features

  • Detailed usage scenarios with examples
  • Strong emphasis on NOT using for simple tasks
  • Clear task state definitions
  • Comprehensive best practices
  • Task completion requirements
Custom prompts are defined in _create_todo_list_middleware() in backend/src/agents/lead_agent/agent.py:57.

Example Workflow

Here’s how Plan Mode works in practice:
1

User Request

User asks: “Research AI coding assistants and create a comparison report”
2

Initial Planning

Agent recognizes this is complex and uses write_todos:
{
  "todos": [
    {"task": "Research popular AI coding assistants", "status": "pending"},
    {"task": "Gather feature comparisons", "status": "pending"},
    {"task": "Analyze pricing models", "status": "pending"},
    {"task": "Create comparison report", "status": "pending"}
  ]
}
3

Task Execution

Agent works through tasks, updating status:
{
  "todos": [
    {"task": "Research popular AI coding assistants", "status": "completed"},
    {"task": "Gather feature comparisons", "status": "in_progress"},
    {"task": "Analyze pricing models", "status": "pending"},
    {"task": "Create comparison report", "status": "pending"}
  ]
}
4

Completion

All tasks marked completed:
{
  "todos": [
    {"task": "Research popular AI coding assistants", "status": "completed"},
    {"task": "Gather feature comparisons", "status": "completed"},
    {"task": "Analyze pricing models", "status": "completed"},
    {"task": "Create comparison report", "status": "completed"}
  ]
}

Accessing Todo State

The todo list is stored in the thread state:
from src.agents.lead_agent.state import ThreadState

# Access current todos
def get_todos(state: ThreadState) -> list[dict]:
    return state.get("todos", [])

# Example todos structure
todos = [
    {
        "task": "Research competitors",
        "status": "completed"
    },
    {
        "task": "Create report",
        "status": "in_progress"
    }
]

Best Practices

Enable Plan Mode for tasks that genuinely benefit from tracking:
  • 3+ distinct steps
  • Multiple stages
  • Long-running operations
Don’t use for simple queries.
Tasks should be:
  • Specific and actionable
  • Independent when possible
  • Properly sequenced when dependent
✅ Good: “Research competitor pricing models” ❌ Bad: “Do research”
Mark tasks as completed immediately after finishing:
  • Don’t batch multiple completions
  • Update status before moving to next task
  • Ensure “completed” reflects actual completion
Multiple tasks can be in_progress simultaneously for:
  • Independent tasks
  • Waiting on external operations
  • Parallel research

Troubleshooting

Verify plan mode is enabled:
config = RunnableConfig(
    configurable={
        "is_plan_mode": True  # Must be True
    }
)
Task might be too simple. Try:
  • More complex, multi-step requests
  • Explicit instruction: “Create a plan first”
  • Check if task has 3+ distinct steps
Agent might not be updating status. This is usually:
  • Expected behavior (task not started yet)
  • Processing issue (check logs)
  • Task might be blocked waiting for clarification
Agent might be over-planning. Consider:
  • Using a less complex prompt
  • Disabling plan mode for this task
  • Providing more specific instructions

Configuration Reference

Runtime Configuration

RunnableConfig(
    configurable={
        "thread_id": str,          # Required: Thread identifier
        "thinking_enabled": bool,   # Optional: Enable thinking mode
        "is_plan_mode": bool,      # Optional: Enable plan mode (default: False)
    }
)

Middleware Position

TodoListMiddleware is positioned before ClarificationMiddleware:
1. ThreadDataMiddleware
2. SandboxMiddleware
3. UploadsMiddleware
4. SummarizationMiddleware (if enabled)
5. TodoListMiddleware (if plan_mode) ← HERE
6. TitleMiddleware
7. ClarificationMiddleware
This allows todo management during clarification flows.

Next Steps

Creating Skills

Build skills that leverage Plan Mode

Custom Tools

Create tools for task execution

Configuration

Learn about agent configuration

Architecture

Understand agent and middleware architecture

Build docs developers (and LLMs) love