> ## Documentation Index
> Fetch the complete documentation index at: https://praison.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent as Tool

> Use agents as callable tools for hierarchical agent composition

Agent as Tool turns any agent into a callable tool so a parent agent can invoke specialists and keep control of the result.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

researcher = Agent(name="Researcher", instructions="Research topics thoroughly")
writer = Agent(
    name="Writer",
    instructions="Write polished copy using specialist tools",
    tools=[researcher.as_tool()],
)
writer.start("Write a short post about quantum computing with cited facts")
```

> [!NOTE]
>
> `as_tool()` returns a `Handoff` object; passing it into `tools=[...]` (as the examples on this page do) works reliably as of PraisonAI PR [#4146](https://github.com/MervinPraison/PraisonAI/pull/4146). The parent agent's constructor converts every `Handoff` in `tools=` into a callable tool the LLM can see and `execute_tool` can dispatch. Before that fix the pattern silently produced an agent the model saw as having **no tools at all** — no error, only a subtly worse answer.

The user asks for a polished article; the writer agent invokes the researcher as a tool and composes the answer.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Agent as Tool"
        Req[📋 User Request] --> Parent[🤖 Parent Agent]
        Parent --> Tool[🔧 Specialist as Tool]
        Tool --> Result[✅ Composed Answer]
    end

    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef tool fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff

    class Req input
    class Parent agent
    class Tool tool
    class Result output
```

## Quick Start

**1. Simple Usage**

```python Basic Usage theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

# Create specialist agents
researcher = Agent(
    name="Researcher",
    instructions="Research topics thoroughly and return findings"
)

coder = Agent(
    name="Coder", 
    instructions="Write clean Python code"
)

# Parent agent uses specialists as tools
writer = Agent(
    name="Writer",
    instructions="Write technical articles using your tools",
    tools=[
        researcher.as_tool("Research a topic and return findings"),
        coder.as_tool("Write Python code for a given task"),
    ]
)

# Writer invokes researcher and coder as needed
result = writer.start("Write an article about async Python patterns")
```

```python Custom Tool Names theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

analyst = Agent(name="DataAnalyst", instructions="Analyze data")

# Custom tool name and description
tool = analyst.as_tool(
    description="Analyze dataset and return insights",
    tool_name="analyze_data"
)

coordinator = Agent(
    name="Coordinator",
    tools=[tool]
)
```

**2. With Configuration**

Pass custom tool\_name and description to as\_tool() when the default labels are not clear enough for the parent LLM.

**3. Direct Invocation**

Call the generated tool yourself with `execute_tool` — the tool exposes an explicit `task` parameter:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

coder = Agent(name="Coder", instructions="Write clean Python code")
writer = Agent(
    name="Writer",
    instructions="Delegate coding to Coder",
    tools=[coder.as_tool(tool_name="invoke_coder")],
)

# New in PR #4232: the tool exposes an explicit `task` parameter
writer.execute_tool("invoke_coder", {"task": "write a haiku about async I/O"})
```

The generated tool now has `(task: str)` in its signature — the LLM sees it in the schema and fills it, and direct callers must pass it.

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Writer
    participant Researcher

    User->>Writer: "Write a post about quantum computing"
    Writer->>Researcher: invoke_researcher("quantum computing")
    Researcher-->>Writer: Research findings
    Writer-->>User: Polished article with cited facts
```

| Step | What happens |
| - | - |
| 1. Request | User asks the parent agent for a result |
| 2. Invoke | Parent LLM decides to call the specialist as a tool |
| 3. Execute | Specialist agent runs with a clean context |
| 4. Return | Result is returned to the parent agent |
| 5. Respond | Parent composes the final response |

## as\_tool() vs Handoffs

> [!TIP]
>
> **Key Difference**: With `as_tool()`, the parent agent **retains control** and receives results. With handoffs, control **transfers entirely** to the target agent.

| Feature | `as_tool()` | Handoffs |
| - | - | - |
| **Control** | Parent retains control | Control transfers to target |
| **Context** | No history passed (clean slate) | Context passed based on policy |
| **Tool naming** | `invoke_{name}` | `transfer_to_{name}` |
| **Context policy** | `ContextPolicy.NONE` (clean slate) | Default `ContextPolicy.SUMMARY` |
| **Use Case** | Hierarchical composition | Task delegation |
| **Return** | Result returned to parent | Target continues conversation |

If you previously "worked around" the broken `as_tool()` by switching to `handoffs=`, note the workaround wasn't equivalent — `invoke_{name}` runs with `ContextPolicy.NONE` (a genuine clean slate, now that context policies take effect) while `transfer_to_{name}` shares context per its policy (`SUMMARY` by default). Now that `as_tool()` works in `tools=[...]`, switch back if you want the clean-slate behaviour.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    subgraph AsTool["as_tool() Pattern"]
        direction LR
        P1[Parent] -->|"invoke"| C1[Child Tool]
        C1 -->|"result"| P1
    end

    subgraph Handoff["Handoff Pattern"]
        direction LR
        P2[Source] -->|"transfer"| C2[Target]
        C2 -->|"continues"| U[User]
    end

    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef tool fill:#189AB4,stroke:#7C90A0,color:#fff

    class P1,P2,U agent
    class C1,C2 tool
```

## API Reference

### `Agent.as_tool()`

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
def as_tool(
    self,
    description: Optional[str] = None,
    tool_name: Optional[str] = None,
) -> Handoff
```

**description** `str`

Tool description for the LLM. Describes what this agent does.
Default: `"Invoke {agent_name} to complete a subtask and return the result"`

**tool\_name** `str`

Custom tool name. Default: `invoke_{agent_name}` (snake\_case)

**return** `Handoff`

A Handoff configured with `ContextPolicy.NONE` (no history passed to child).

The return type is `Handoff` (not a callable) because `to_tool_function()` needs the *parent* agent that will own this tool — and at `as_tool()` call time, that parent doesn't exist yet. Conversion happens automatically the moment you place the result inside a parent's `tools=[...]`.

### Generated tool signature

Because `as_tool()` always pins `ContextPolicy.NONE`, the generated callable exposes a `task: str` keyword-only parameter. This is what the LLM tool schema advertises and what direct `execute_tool` calls must supply.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
def invoke_<agent_name>(*, task: str) -> str
```

**task** `str` *required*

The prompt passed verbatim to the sub-agent. If `task` is not provided, `prompt` is accepted as an alias.

## Examples

> [accordion] Research + Writing Pipeline
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent
>
> # Specialist agents
> researcher = Agent(
>     name="Researcher",
>     instructions="Search the web and compile research findings"
> )
>
> fact_checker = Agent(
>     name="FactChecker", 
>     instructions="Verify facts and cite sources"
> )
>
> # Writer uses both as tools
> writer = Agent(
>     name="Writer",
>     instructions="""Write articles using your tools:
>     - Use invoke_researcher for initial research
>     - Use invoke_factchecker to verify claims""",
>     tools=[
>         researcher.as_tool("Research a topic"),
>         fact_checker.as_tool("Verify facts and claims"),
>     ]
> )
>
> result = writer.start("Write about quantum computing breakthroughs in 2024")
> ```

> [accordion] Code Review Pipeline
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent
>
> # Specialist agents
> linter = Agent(
>     name="Linter",
>     instructions="Check code for style issues and bugs"
> )
>
> security_scanner = Agent(
>     name="SecurityScanner",
>     instructions="Scan code for security vulnerabilities"
> )
>
> # Reviewer orchestrates both
> reviewer = Agent(
>     name="CodeReviewer",
>     instructions="Review code using your analysis tools",
>     tools=[
>         linter.as_tool("Lint code for issues"),
>         security_scanner.as_tool("Scan for security vulnerabilities"),
>     ]
> )
>
> code = """
> def login(username, password):
>     query = f"SELECT * FROM users WHERE name='{username}'"
>     return db.execute(query)
> """
>
> result = reviewer.start(f"Review this code:\n{code}")
> ```

> [accordion] Multi-Step Analysis
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents import Agent
>
> # Create a chain of specialists
> data_fetcher = Agent(name="DataFetcher", instructions="Fetch data from APIs")
> analyzer = Agent(name="Analyzer", instructions="Analyze data patterns")
> visualizer = Agent(name="Visualizer", instructions="Create visualizations")
>
> # Orchestrator uses all three
> orchestrator = Agent(
>     name="Orchestrator",
>     instructions="Coordinate data analysis workflow",
>     tools=[
>         data_fetcher.as_tool("Fetch data from a source"),
>         analyzer.as_tool("Analyze data and find patterns"),
>         visualizer.as_tool("Create charts and visualizations"),
>     ]
> )
>
> result = orchestrator.start("Analyze sales trends for Q4 2024")
> ```

## Best Practices

> [accordion] Clear Descriptions
>
> Provide clear tool descriptions so the LLM knows when to invoke each specialist.

> [accordion] Single Responsibility
>
> Each specialist agent should have one clear purpose.

> [accordion] Avoid Deep Nesting
>
> Keep hierarchies shallow (2-3 levels max) for clarity.

> [accordion] Test Individually
>
> Test each specialist agent independently before composing.

> [accordion] Cloning for channels rebinds handoffs
>
> Each channel's clone rebinds the `as_tool()` handoff to itself, not the source agent. This means Discord and Telegram clones each get their own `invoke_researcher` bound to their own `chat_history` / `tools` / `memory` — no cross-channel leakage. You do not need to rebuild `tools=[...]` per channel; `clone_for_channel()` handles it.

## Troubleshooting

> [!WARNING]
>
> **Seeing `Tool  not recognized` in the logs and an empty tool schema?** You're on a PraisonAI version prior to PR [#4146](https://github.com/MervinPraison/PraisonAI/pull/4146). Upgrade to the fixed version, or as a temporary workaround move the entries from `tools=` to `handoffs=` (note the different naming and context policy — see the comparison table above).

> [!WARNING]
>
> **Seeing `"…completed, but no specific task was provided."` returned from the tool, and `Agent.chat` on the sub-agent was never called?** You are on a PraisonAI version prior to PR [#4232](https://github.com/MervinPraison/PraisonAI/pull/4232). Upgrade — the generated tool now takes a `task` string parameter and passes it verbatim as the sub-agent's prompt.

## Related

> [card] [Handoffs](https://praison.ai/docs/features/handoffs.md)
>
> Transfer control between agents

> [card] [Multi-Agent Workflows](https://praison.ai/docs/features/workflows.md)
>
> Coordinate multiple agents

> [card] [Toolsets](https://praison.ai/docs/features/toolsets.md)
>
> Create custom tools


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.