> ## 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.

# Using Tools in YAML

> Reference built-in tools by name in your YAML configuration files

<Info>
  Tools can now be referenced by name directly in YAML files without creating a local `tools.py` file.
</Info>

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant Feature as Using Tools in YAML

    User->>Agent: Request
    Agent->>Feature: Process request
    Feature-->>Agent: Result
    Agent-->>User: Response
```

When you specify tools in your YAML configuration, PraisonAI automatically resolves them from multiple sources. Only tools you list under `tools:` in your YAML (under each role and each task) are loaded. Misspelled or unknown tool names now produce a `warning` log line, not a silent skip.

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

agent = Agent(name="Researcher", tools=["tavily_search"])
agent.start("Summarise today's AI headlines")
```

The user lists tools in agents.yaml; PraisonAI resolves built-ins and runs the configured agent.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart LR
    subgraph YAML["agents.yaml"]
        T["tools: [tavily_search]"]
    end
    
    subgraph Resolution["Tool Resolution"]
        direction TB
        L["1. Local tools.py"]
        B["2. Built-in Tools"]
        E["3. External Tools"]
    end
    
    subgraph Agent["Agent"]
        A["🤖 Agent with Tools"]
    end
    
    T --> Resolution
    Resolution --> Agent
    
    classDef agent fill:#8B0000,color:#fff
    classDef tool fill:#189AB4,color:#fff

    class A agent
    class T,L,B,E tool
```

## Quick Start

<Steps>
  <Step title="Create YAML File">
    Reference tools by name in your `agents.yaml`:

    ```yaml agents.yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    framework: praisonai
    topic: "AI News"

    roles:
      researcher:
        role: AI Researcher
        goal: Search for the latest AI news
        backstory: Expert researcher
        tools:
          - tavily_search
          - internet_search
        tasks:
          search_task:
            description: Search for {topic}
            expected_output: Summary of findings
    ```
  </Step>

  <Step title="Run Your Agents">
    No `tools.py` needed - tools are auto-resolved:

    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    praisonai run agents.yaml
    ```
  </Step>
</Steps>

## Tool Sources

<CardGroup cols={2}>
  <Card title="Built-in Tools" icon="cube">
    70+ tools from `praisonaiagents.tools`

    * `tavily_search`
    * `internet_search`
    * `execute_command`
    * `read_file`
    * And more...
  </Card>

  <Card title="Local tools.py" icon="file-code">
    Custom tools you create

    * Takes precedence
    * Full control
    * Custom variables
  </Card>

  <Card title="External Tools" icon="puzzle-piece">
    120+ tools from `praisonai-tools`

    * `EmailTool`
    * `SlackTool`
    * `GitHubTool`
    * And more...
  </Card>
</CardGroup>

## Resolution Order

Tools are resolved in this order (first match wins):

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
flowchart TB
    subgraph Input["Tool Name: tavily_search"]
        N["'tavily_search'"]
    end
    
    subgraph Check1["1️⃣ Local tools.py"]
        L["Check local file"]
    end
    
    subgraph Check2["2️⃣ Built-in Tools"]
        B["Check praisonaiagents.tools"]
    end
    
    subgraph Check3["3️⃣ External Tools"]
        E["Check praisonai-tools"]
    end
    
    subgraph Result["Result"]
        R["✅ Callable Function"]
    end
    
    N --> L
    L -->|Not Found| B
    L -->|Found| R
    B -->|Not Found| E
    B -->|Found| R
    E -->|Found| R
    
    style Input fill:#8B0000,color:#fff
    style Result fill:#8B0000,color:#fff
    style Check1 fill:#189AB4,color:#fff
    style Check2 fill:#189AB4,color:#fff
    style Check3 fill:#189AB4,color:#fff
```

<Tip>
  Local `tools.py` always takes precedence. This lets you override built-in tools with custom implementations.
</Tip>

## Available Built-in Tools

<AccordionGroup>
  <Accordion title="Search Tools">
    | Tool              | Description                    |
    | ----------------- | ------------------------------ |
    | `tavily_search`   | AI-powered web search          |
    | `tavily_extract`  | Extract content from URLs      |
    | `internet_search` | DuckDuckGo search              |
    | `exa_search`      | Exa semantic search            |
    | `search_web`      | Unified search (auto-fallback) |
  </Accordion>

  <Accordion title="File Tools">
    | Tool          | Description             |
    | ------------- | ----------------------- |
    | `read_file`   | Read file contents      |
    | `write_file`  | Write to files          |
    | `list_files`  | List directory contents |
    | `copy_file`   | Copy files              |
    | `delete_file` | Delete files            |
  </Accordion>

  <Accordion title="Shell Tools">
    | Tool              | Description            |
    | ----------------- | ---------------------- |
    | `execute_command` | Run shell commands     |
    | `list_processes`  | List running processes |
    | `kill_process`    | Terminate processes    |
    | `get_system_info` | System information     |
  </Accordion>

  <Accordion title="Web Crawling">
    | Tool               | Description                |
    | ------------------ | -------------------------- |
    | `crawl4ai`         | Async web crawling         |
    | `crawl4ai_extract` | Extract with CSS selectors |
    | `scrape_page`      | Spider page scraping       |
    | `extract_links`    | Extract page links         |
  </Accordion>
</AccordionGroup>

## CLI Commands

### List Available Tools

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai tools list
```

<Frame>
  ```
  ┌─────────────────────────────────────────────────┐
  │               Available Tools                    │
  ├──────────────────┬──────────┬───────────────────┤
  │ Tool Name        │ Source   │ Description       │
  ├──────────────────┼──────────┼───────────────────┤
  │ crawl4ai         │ builtin  │ Built-in tool...  │
  │ execute_command  │ builtin  │ Built-in tool...  │
  │ internet_search  │ builtin  │ Built-in tool...  │
  │ tavily_search    │ builtin  │ Built-in tool...  │
  │ my_custom_tool   │ local    │ My custom tool... │
  └──────────────────┴──────────┴───────────────────┘
  ```
</Frame>

### Validate YAML Tools

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai tools validate agents.yaml
```

<Tabs>
  <Tab title="Valid">
    ```
    ✓ All tools in agents.yaml are valid!
    Tools found: internet_search, tavily_search
    ```
  </Tab>

  <Tab title="Invalid">
    ```
    ✗ Missing tools in agents.yaml:
      • nonexistent_tool

    Hint: Run 'praisonai tools list' to see available tools.
    ```
  </Tab>
</Tabs>

### Get Tool Info

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai tools info tavily_search
```

## Custom Tools (tools.py)

For custom logic or variables, create a `tools.py` file:

```python tools.py theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Custom tool with your own logic
def my_custom_tool(query: str) -> str:
    """Search using my custom API."""
    # Your implementation
    return f"Results for: {query}"

# Custom variables
API_KEY = "your-key"
BASE_URL = "https://api.example.com"

def api_search(query: str) -> dict:
    """Search with custom API."""
    import requests
    response = requests.get(f"{BASE_URL}/search?q={query}&key={API_KEY}")
    return response.json()
```

Then reference in YAML:

```yaml agents.yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
roles:
  researcher:
    tools:
      - my_custom_tool    # From local tools.py
      - api_search        # From local tools.py
      - tavily_search     # Built-in (still works!)
```

<Warning>
  Local tools with the same name as built-in tools will override them.
</Warning>

## Examples

<CodeGroup>
  ```yaml Simple Search Agent theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  framework: praisonai
  topic: "Latest AI developments"

  roles:
    researcher:
      role: AI Researcher
      goal: Find and summarize AI news
      backstory: Expert in AI research
      tools:
        - tavily_search
      tasks:
        research:
          description: Search for {topic}
          expected_output: Detailed summary
  ```

  ```yaml Multi-Tool Agent theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  framework: praisonai
  topic: "Python web scraping"

  roles:
    developer:
      role: Developer
      goal: Research and implement solutions
      backstory: Senior Python developer
      tools:
        - tavily_search
        - internet_search
        - execute_command
        - read_file
        - write_file
      tasks:
        research:
          description: Research {topic}
          expected_output: Implementation guide
  ```

  ```yaml With Custom Tools theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  framework: praisonai
  topic: "Company data"

  roles:
    analyst:
      role: Data Analyst
      goal: Analyze company data
      backstory: Expert analyst
      tools:
        - my_database_query  # From tools.py
        - tavily_search      # Built-in
      tasks:
        analyze:
          description: Analyze {topic}
          expected_output: Analysis report
  ```
</CodeGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Tool not found">
    1. Check the tool name spelling
    2. Run `praisonai tools list` to see available tools
    3. If using external tools, ensure `praisonai-tools` is installed:
       ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
       pip install praisonai-tools
       ```
  </Accordion>

  <Accordion title="Tool not working as expected">
    1. Check if the tool requires an API key (e.g., `TAVILY_API_KEY`)
    2. Run `praisonai tools info <tool_name>` for details
    3. Test the tool: `praisonai tools test <tool_name>`
  </Accordion>

  <Accordion title="Want to override a built-in tool">
    Create a `tools.py` file with a function of the same name:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    def tavily_search(query: str) -> str:
        """My custom tavily_search implementation."""
        # Your code here
        return "custom result"
    ```
  </Accordion>
</AccordionGroup>

## Per-Agent Tool Resolution

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

# Single agent with default resolver
agent = Agent(
    name="ResearchAgent",
    instructions="Research AI topics using tools",
    tools=["tavily_search", "web_scraper"]
)

agent.start("Search for latest AI developments")
```

***

## Multi-agent: one resolver per agent

When agents need different `tools_py_path` values, construct separate resolvers:

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Multi-Agent Tool Isolation"
        A[🤖 Agent A] --> RA[🔧 Resolver A]
        B[🤖 Agent B] --> RB[🔧 Resolver B]
        RA --> TA[📂 tools_a.py]
        RB --> TB[📂 tools_b.py]
    end
    
    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef resolver fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef tools fill:#10B981,stroke:#7C90A0,color:#fff
    
    class A,B agent
    class RA,RB resolver
    class TA,TB tools
```

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.tool_resolver import ToolResolver, resolve_tool

resolver_a = ToolResolver(tools_py_path="agents/a/tools.py")
resolver_b = ToolResolver(tools_py_path="agents/b/tools.py")

tool_a = resolve_tool("my_tool", resolver=resolver_a)
tool_b = resolve_tool("my_tool", resolver=resolver_b)
```

<Note>
  **Thread Safety:** Each `ToolResolver` instance is safe to share across threads — its local-tools cache is loaded once under a lock and exposed as an immutable `MappingProxyType`.

  **Default resolver:** When you call `resolve_tool(name)` without passing `resolver=`, PraisonAI uses a single process-level cached resolver to avoid recreating it on every call. This cached resolver is anchored to the working directory at first call.

  **When to pass an explicit resolver:** For test isolation, multi-project CLIs, or per-agent `tools_py_path` values, construct your own `ToolResolver(...)` and pass it as `resolver=` to the convenience functions.
</Note>

***

## Caching Behaviour

The convenience functions (`resolve_tool`, `resolve_tools`, `list_available_tools`, `has_tool`, `validate_yaml_tools`) share a single cached `ToolResolver` for the whole process. This means:

* **Fast repeated calls** — `tools.py` is only read once, `praisonai-tools` is only probed once.
* **CWD-anchored** — the cached resolver picks up `./tools.py` from whatever directory was active when the **first** call happened.
* **Need isolation?** Pass an explicit `resolver=ToolResolver(...)` instance — the cached default is bypassed.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.tool_resolver import resolve_tool, ToolResolver

# Uses cached default — fast, anchored to current working directory
tool = resolve_tool("tavily_search")

# Explicit resolver — isolated, useful in tests or multi-project CLIs
tool = resolve_tool("tavily_search", resolver=ToolResolver(tools_py_path="agents/a/tools.py"))
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TD
    Q{Need test isolation<br/>or per-agent tools.py?}
    Q -->|No| D[Use convenience functions<br/>e.g. resolve_tool name]
    Q -->|Yes| E[Construct ToolResolver and<br/>pass via resolver= argument]
    D --> R1[⚡ Cached default - fast]
    E --> R2[🔒 Isolated - explicit]

    classDef question fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef option fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class Q question
    class D,E option
    class R1,R2 result
```

***

## Configuration Options

### Convenience Functions (with optional resolver parameter)

| Function               | Signature                                                                                                | Description              |
| ---------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------ |
| `resolve_tool`         | `resolve_tool(name: str, resolver: Optional[ToolResolver] = None) -> Optional[Callable]`                 | Resolve single tool      |
| `resolve_tools`        | `resolve_tools(names: List[str], resolver: Optional[ToolResolver] = None) -> List[Callable]`             | Resolve multiple tools   |
| `list_available_tools` | `list_available_tools(resolver: Optional[ToolResolver] = None) -> Dict[str, str]`                        | List all available tools |
| `has_tool`             | `has_tool(name: str, resolver: Optional[ToolResolver] = None) -> bool`                                   | Check if tool exists     |
| `validate_yaml_tools`  | `validate_yaml_tools(yaml_config: Dict[str, Any], resolver: Optional[ToolResolver] = None) -> List[str]` | Validate YAML tools      |

### ToolResolver Class

| Method                             | Description                                                                                                                          | Thread Safe        |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------ |
| `resolve(name, instantiate=False)` | Resolve single tool name. Pass `instantiate=True` to get an instance of class tools (BaseTool / langchain) instead of the raw class. | ✅                  |
| `resolve_many(names)`              | Resolve multiple tool names                                                                                                          | ✅                  |
| `list_available()`                 | List available tools                                                                                                                 | ✅                  |
| `has_tool(name)`                   | Check if tool exists                                                                                                                 | ✅                  |
| `clear_cache()`                    | Clear local tools cache                                                                                                              | ✅ (lock-protected) |

***

## Python Usage

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai.tool_resolver import ToolResolver, resolve_tool

# Option 1: Use convenience functions with default resolver
tool = resolve_tool("tavily_search")
tools = resolve_tools(["tavily_search", "internet_search"])
available = list_available_tools()

# Option 2: Use convenience functions with custom resolver
resolver = ToolResolver(tools_py_path="custom/tools.py")
tool = resolve_tool("tavily_search", resolver=resolver)
tools = resolve_tools(["tavily_search"], resolver=resolver)

# Option 3: Use resolver instance directly
resolver = ToolResolver()
tool = resolver.resolve("tavily_search")
tools = resolver.resolve_many(["tavily_search", "internet_search"])
```

## Related

<CardGroup cols={2}>
  <Card title="Custom Tools" icon="wrench" href="/docs/tools/custom">
    Build your own agent tools
  </Card>

  <Card title="Tools Overview" icon="toolbox" href="/docs/tools/tools">
    Browse PraisonAI tool documentation
  </Card>
</CardGroup>
