# Multi-Agent Example

This example demonstrates a router-based multi-agent system with specialized agents for different tasks.

## Structure

```
multi_agent/
├── agents/           # Specialist agents
│   ├── router.py     # Routes to specialists
│   ├── research.py   # Information gathering
│   ├── analyst.py    # Data analysis
│   ├── code.py       # Programming help
│   ├── writer.py     # Content creation
│   └── support.py    # Customer support
├── models/           # Output models
│   └── outputs.py    # ResearchResult, AnalysisResult, etc.
├── toolsets/         # Tool compositions
│   └── compositions.py
└── __init__.py       # Package exports
```

## Usage

```python
import asyncio
from examples.multi_agent import router_agent
from pydanticai_multiagent import create_mock_search_deps

async def main():
    deps = create_mock_search_deps()
    result = await router_agent.run("What is Python?", deps=deps)
    print(result.output)

asyncio.run(main())
```

## How It Works

1. **Router Agent** (gpt-4o-mini) analyzes the request
2. Delegates to the appropriate **Specialist Agent** (gpt-4o)
3. Specialist uses its **Toolset** to gather information
4. Returns structured output via **Pydantic Model**

## Agents

| Agent | Deps | Output | Purpose |
|-------|------|--------|---------|
| `router_agent` | `SearchDeps` | `str` | Routes to specialists |
| `research_agent` | `SearchDeps` | `ResearchResult` | Information gathering |
| `analyst_agent` | `BaseDeps` | `AnalysisResult` | Data analysis |
| `code_agent` | `BaseDeps` | `CodeResponse` | Programming help |
| `writer_agent` | `BaseDeps` | `str` | Content creation |
| `support_agent` | `AuthDeps` | `SupportResponse` | Customer support |

## Adding a New Specialist

1. Create the agent in `agents/my_specialist.py`:

```python
from pydantic_ai import Agent
from pydanticai_multiagent import BaseDeps
from ..models import MyOutput
from ..toolsets import my_toolset

my_agent: Agent[BaseDeps, MyOutput] = Agent(
    "openai:gpt-4o",
    deps_type=BaseDeps,
    output_type=MyOutput,
    toolsets=[my_toolset],
    instructions="...",
)
```

2. Define output model in `models/outputs.py`

3. Create toolset in `toolsets/compositions.py`

4. Add delegation tool to `agents/router.py`:

```python
@router_agent.tool
async def delegate_to_my_specialist(ctx: RunContext[SearchDeps], query: str) -> str:
    """Delegate to my specialist agent."""
    result = await my_agent.run(query, deps=ctx.deps.to_base_deps(), usage=ctx.usage)
    return result.output.model_dump_json()
```

## Extending with Domain Tools

The router supports dynamic toolset injection:

```python
from pydantic_ai.toolsets import FunctionToolset

my_tools: FunctionToolset[SearchDeps] = FunctionToolset()

@my_tools.tool
async def my_domain_tool(ctx, query: str) -> str:
    return "domain-specific result"

deps = create_mock_search_deps()
deps.domain_toolset = my_tools  # Router now has access to my_domain_tool

result = await router_agent.run("Use my domain tool", deps=deps)
```
