Skip to content

Nested Subagents

This example shows how subagents can have their own subagents.

Overview

Subagents can delegate to other subagents, creating hierarchical workflows:

Text Only
Parent Agent
    └── Manager Subagent
            ├── Researcher Subagent
            └── Writer Subagent

Basic Nesting

Python
import asyncio
from dataclasses import dataclass, field
from typing import Any

from pydantic_ai import Agent
from subagents_pydantic_ai import create_subagent_toolset, SubAgentConfig


@dataclass
class Deps:
    subagents: dict[str, Any] = field(default_factory=dict)

    def clone_for_subagent(self, max_depth: int = 0) -> "Deps":
        # Important: Reduce depth for nested subagents
        return Deps(
            subagents={} if max_depth <= 0 else self.subagents.copy(),
        )


# Level 2: Leaf subagents (no further delegation)
leaf_subagents = [
    SubAgentConfig(
        name="researcher",
        description="Researches specific topics",
        instructions="You research topics and provide facts.",
    ),
    SubAgentConfig(
        name="writer",
        description="Writes content",
        instructions="You write clear, engaging content.",
    ),
]

# Level 1: Manager that delegates to leaf subagents
manager_subagents = [
    SubAgentConfig(
        name="content-manager",
        description="Manages content creation by delegating to specialists",
        instructions="""You manage content creation.

You have access to these specialists:
- researcher: Researches topics
- writer: Writes content

Workflow:
1. Delegate research to researcher
2. Delegate writing to writer
3. Review and compile results
""",
    ),
]


def create_manager_toolsets(deps: Deps) -> list:
    """Create toolsets for the manager, including nested delegation."""
    return [
        create_subagent_toolset(
            subagents=leaf_subagents,
            max_nesting_depth=0,  # Leaf subagents can't delegate further
        ),
    ]


# Top-level toolset
toolset = create_subagent_toolset(
    subagents=manager_subagents,
    toolsets_factory=create_manager_toolsets,
    max_nesting_depth=1,  # Allow one level of nesting
)

agent = Agent(
    "openai:gpt-4o",
    deps_type=Deps,
    toolsets=[toolset],
    system_prompt="You can delegate complex content tasks to the content-manager.",
)


async def main():
    result = await agent.run(
        "Create a blog post about machine learning",
        deps=Deps(),
    )

    print(result.output)
    # The content-manager delegated to researcher, then to writer


asyncio.run(main())

Controlling Nesting Depth

Use max_nesting_depth to limit how deep delegation can go:

Python
# No nesting (depth=0)
toolset = create_subagent_toolset(
    subagents=subagents,
    max_nesting_depth=0,  # Subagents cannot delegate
)

# One level (depth=1)
toolset = create_subagent_toolset(
    subagents=subagents,
    max_nesting_depth=1,  # Subagents can delegate to leaf agents
)

# Two levels (depth=2)
toolset = create_subagent_toolset(
    subagents=subagents,
    max_nesting_depth=2,  # Subagents can delegate to agents that can delegate
)

Hierarchical Team Structure

Python
# Executive level
executive = SubAgentConfig(
    name="product-lead",
    description="Leads product development",
    instructions="""You lead product development.

Delegate to:
- engineering-manager: For technical work
- design-manager: For design work
""",
)

# Manager level
managers = [
    SubAgentConfig(
        name="engineering-manager",
        description="Manages engineering tasks",
        instructions="""You manage engineering.

Delegate to:
- backend-dev: Backend development
- frontend-dev: Frontend development
""",
    ),
    SubAgentConfig(
        name="design-manager",
        description="Manages design tasks",
        instructions="You manage design work.",
    ),
]

# Individual contributor level
ics = [
    SubAgentConfig(
        name="backend-dev",
        description="Backend developer",
        instructions="You write backend code.",
    ),
    SubAgentConfig(
        name="frontend-dev",
        description="Frontend developer",
        instructions="You write frontend code.",
    ),
]


def create_manager_toolsets(deps):
    return [create_subagent_toolset(subagents=ics, max_nesting_depth=0)]


def create_executive_toolsets(deps):
    return [
        create_subagent_toolset(
            subagents=managers,
            toolsets_factory=create_manager_toolsets,
            max_nesting_depth=1,
        )
    ]


toolset = create_subagent_toolset(
    subagents=[executive],
    toolsets_factory=create_executive_toolsets,
    max_nesting_depth=2,
)

Clone for Subagent

The clone_for_subagent method is crucial for nesting:

Python
@dataclass
class Deps:
    subagents: dict[str, Any] = field(default_factory=dict)
    shared_state: dict = field(default_factory=dict)

    def clone_for_subagent(self, max_depth: int = 0) -> "Deps":
        """Create isolated deps for subagent.

        Args:
            max_depth: How many more levels of nesting to allow.
                       0 = this subagent cannot delegate further.
        """
        return Deps(
            # Clear subagents if no more nesting allowed
            subagents={} if max_depth <= 0 else self.subagents.copy(),
            # Share read-only state
            shared_state=self.shared_state,
        )

Best Practices

1. Limit Depth

Don't nest too deeply. 2-3 levels is usually enough:

Python
# Good: Clear hierarchy
Parent  Manager  Worker

# Avoid: Too deep
Parent  Director  Manager  Lead  Worker  Helper

2. Clear Responsibilities

Each level should have distinct responsibilities:

Python
# Good: Clear separation
"project-manager": Coordinates overall project
"tech-lead": Makes technical decisions
"developer": Writes code

# Avoid: Overlapping roles
"helper1": Does stuff
"helper2": Also does stuff

3. Avoid Circular Delegation

Ensure subagents don't create delegation loops:

Python
# Bad: A delegates to B, B delegates to A
SubAgentConfig(name="A", instructions="Delegate to B")
SubAgentConfig(name="B", instructions="Delegate to A")

# Good: Clear hierarchy with termination
SubAgentConfig(name="manager", instructions="Delegate to workers")
SubAgentConfig(name="worker", instructions="Complete the task directly")

Next Steps