Skip to content

Giving Subagents Tools

This example shows how to provide tools to your subagents.

Using toolsets_factory

The toolsets_factory creates tools for each subagent:

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)
    workspace: str = "/tmp/workspace"

    def clone_for_subagent(self, max_depth: int = 0) -> "Deps":
        return Deps(
            subagents={} if max_depth <= 0 else self.subagents.copy(),
            workspace=self.workspace,
        )


# Custom toolset for file operations
def create_file_tools():
    """Create simple file operation tools."""
    from pydantic_ai.toolsets import FunctionToolset

    toolset = FunctionToolset()

    @toolset.tool
    async def read_file(path: str) -> str:
        """Read a file's contents."""
        with open(path) as f:
            return f.read()

    @toolset.tool
    async def write_file(path: str, content: str) -> str:
        """Write content to a file."""
        with open(path, "w") as f:
            f.write(content)
        return f"Wrote {len(content)} characters to {path}"

    return toolset


def my_toolsets_factory(deps: Deps) -> list:
    """Create toolsets for subagents."""
    return [create_file_tools()]


subagents = [
    SubAgentConfig(
        name="coder",
        description="Writes and manages code files",
        instructions="""You write Python code.

You have access to file operations:
- read_file(path): Read a file
- write_file(path, content): Write to a file

Write clean, well-documented code.
""",
    ),
]

toolset = create_subagent_toolset(
    subagents=subagents,
    toolsets_factory=my_toolsets_factory,
)

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


async def main():
    result = await agent.run(
        "Create a Python script that prints 'Hello World' and save it to /tmp/hello.py",
        deps=Deps(),
    )
    print(result.output)


asyncio.run(main())

Per-Subagent Toolsets

Give different tools to different subagents:

Python
def selective_toolsets_factory(deps: Deps) -> list:
    """Create toolsets based on the subagent context."""
    # You could check deps or other context to customize
    return [create_file_tools()]


# Or specify toolsets directly in the config
subagents = [
    SubAgentConfig(
        name="reader",
        description="Reads and analyzes files",
        instructions="You read files and analyze their contents.",
        toolsets=[create_read_only_tools()],  # Only read access
    ),
    SubAgentConfig(
        name="writer",
        description="Writes files",
        instructions="You write files.",
        toolsets=[create_file_tools()],  # Full access
    ),
]

Using pydantic-ai-backend

For comprehensive file operations, use pydantic-ai-backend:

Python
from pydantic_ai_backends import create_console_toolset, StateBackend


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

    def clone_for_subagent(self, max_depth: int = 0) -> "Deps":
        return Deps(
            subagents={} if max_depth <= 0 else self.subagents.copy(),
            backend=self.backend,  # Share the backend
        )


def backend_toolsets_factory(deps: Deps) -> list:
    """Create console toolset from backend."""
    return [create_console_toolset(deps.backend)]


subagents = [
    SubAgentConfig(
        name="coder",
        description="Writes code with full filesystem access",
        instructions="""You have access to filesystem operations:
- ls(path): List directory contents
- read_file(path): Read a file
- write_file(path, content): Write to a file
- edit_file(path, old, new): Edit a file
- glob(pattern): Find files matching pattern
- grep(pattern, path): Search file contents
""",
    ),
]

toolset = create_subagent_toolset(
    subagents=subagents,
    toolsets_factory=backend_toolsets_factory,
)

Built-in Tools

Use Pydantic AI's built-in tools:

Python
from pydantic_ai.builtin_tools import WebSearchTool

subagents = [
    SubAgentConfig(
        name="web-researcher",
        description="Researches using web search",
        instructions="You research topics using web search.",
        agent_kwargs={
            "builtin_tools": [WebSearchTool()],
        },
    ),
]

Combining Multiple Toolsets

Python
def comprehensive_toolsets_factory(deps: Deps) -> list:
    """Create multiple toolsets for subagents."""
    return [
        create_console_toolset(deps.backend),  # File operations
        create_todo_toolset(),  # Task tracking
        create_search_toolset(),  # Search capabilities
    ]

Best Practices

1. Principle of Least Privilege

Only give subagents the tools they need:

Python
# Good: Specific tools for specific tasks
SubAgentConfig(
    name="reader",
    instructions="You read and analyze files.",
    toolsets=[create_read_only_tools()],  # No write access
)

# Avoid: Giving everything to everyone
SubAgentConfig(
    name="helper",
    toolsets=[all_tools],  # Too permissive
)

2. Document Available Tools

Include tool documentation in instructions:

Python
SubAgentConfig(
    name="coder",
    instructions="""You write Python code.

Available tools:
- read_file(path): Read file contents
- write_file(path, content): Write to file
- execute(command): Run shell command

Always read existing files before modifying them.
""",
)

3. Handle Tool Errors

Guide subagents on error handling:

Python
instructions="""
If a tool call fails:
1. Check if the path/parameters are correct
2. Try an alternative approach
3. Report the error clearly if unresolvable
"""

Next Steps

  • Questions - Parent-child communication
  • Nesting - Subagents with their own subagents