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

# Async Tool Safety

> Safety mechanisms now apply to async tool execution paths

Async tool calls in `agent.achat()` now route through the same safety mechanisms as sync execution, including approval checks, circuit breakers, and timeouts.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Async Tool Safety Pipeline"
        Call[🔄 Async Tool Call] --> Approval[✋ Approval Check]
        Approval --> Cast[🔧 Type Casting]
        Cast --> Breaker[⚡ Circuit Breaker]
        Breaker --> Timeout[⏱️ Timeout]
        Timeout --> Execute[▶️ Execute]
        Execute --> Events[📊 Trace Events]
        Events --> Result[✅ Result]
    end
    
    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef safety fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef execution fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef output fill:#10B981,stroke:#7C90A0,color:#fff
    
    class Call input
    class Approval,Cast,Breaker,Timeout safety
    class Execute,Events execution
    class Result output
```

## Quick Start

<Steps>
  <Step title="Async Tool with Approval">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent

    def risky_tool():
        """Tool that requires approval"""
        return "Executed risky operation"

    agent = Agent(
        name="Safety Agent",
        instructions="Execute tools safely",
        tools=[risky_tool],
        require_approval=True  # Now works in async mode too
    )

    # Approval prompt will appear during async execution
    response = await agent.achat("Use the risky tool")
    ```
  </Step>

  <Step title="Task-Scoped Tools">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent, Task

    def special_tool():
        return "Special operation completed"

    agent = Agent(name="Tool Agent")

    # Task-specific tools override agent tools in async mode
    task = Task(
        description="Use special tool",
        agent=agent,
        tools=[special_tool]  # Available only for this task
    )

    # special_tool is available during async chat execution
    ```
  </Step>
</Steps>

***

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant User
    participant Agent
    participant ToolSafety
    participant Tool
    
    User->>Agent: achat("Use tool X")
    Agent->>ToolSafety: execute_tool_async()
    ToolSafety->>ToolSafety: Check approval
    alt Approval Required
        ToolSafety-->>User: Approval prompt
        User->>ToolSafety: Approve/Deny
    end
    ToolSafety->>ToolSafety: Type casting
    ToolSafety->>ToolSafety: Circuit breaker check
    ToolSafety->>Tool: Execute with timeout
    Tool-->>ToolSafety: Result
    ToolSafety->>ToolSafety: Emit trace events
    ToolSafety-->>Agent: Wrapped result
    Agent-->>User: Response
```

| Safety Layer              | Sync Mode | Async Mode |
| ------------------------- | --------- | ---------- |
| **Approval checks**       | ✅         | ✅          |
| **Argument type casting** | ✅         | ✅          |
| **Circuit breaker**       | ✅         | ✅          |
| **Tool timeout**          | ✅         | ✅          |
| **Doom-loop tracking**    | ✅         | ✅          |
| **Trace events**          | ✅         | ✅          |
| **Output truncation**     | ✅         | ✅          |
| **Error wrapping**        | ✅         | ✅          |

***

## Safety Mechanisms

### Approval Checks

User approval prompts now appear during async tool execution:

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

agent = Agent(
    name="Approved Agent",
    tools=[dangerous_operation],
    require_approval=True
)

# Approval workflow works in async mode
async def safe_execution():
    response = await agent.achat("Delete all files")
    # User sees: "Agent wants to use dangerous_operation. Approve? (y/n)"
    return response
```

### Circuit Breaker Protection

Tool failure rates are tracked across async calls:

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

agent = Agent(
    name="Circuit Breaker Agent", 
    tools=[unreliable_api],
    # Circuit breaker automatically protects async calls
)

# Failed async calls contribute to circuit breaker state
await agent.achat("Call unreliable API")  # May be blocked if failure rate is high
```

### Timeout Controls

Async tool execution respects timeout settings:

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

def slow_tool():
    import time
    time.sleep(10)  # Long operation
    return "Done"

agent = Agent(
    name="Timeout Agent",
    tools=[slow_tool],
    tool_timeout=5  # 5 second limit applies to async calls
)

# Timeout enforced in async mode
await agent.achat("Use slow tool")  # Will timeout after 5 seconds
```

***

## Task-Scoped Tools

The `tools_override` parameter allows tasks to provide their own tool set for async execution:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.agent.execution_mixin import execute_tool_async

# Internal usage (SDK implementation detail)
result = await execute_tool_async(
    agent=agent,
    tool_call=tool_call,
    tools_override=task.tools  # Task tools take precedence
)
```

For users, this manifests as task-specific tools being available during async chat:

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

def task_specific_tool():
    return "Task-specific result"

agent = Agent(name="Base Agent", tools=[])

task = Task(
    description="Use task tool",
    agent=agent,
    tools=[task_specific_tool]
)

# task_specific_tool is available during task execution
# even though agent has no tools
```

***

## Trace Events

Async tool execution now emits the same trace events as sync execution:

| Event              | When             | Data                     |
| ------------------ | ---------------- | ------------------------ |
| `TOOL_CALL_START`  | Before execution | tool\_name, arguments    |
| `TOOL_CALL_RESULT` | After execution  | result, duration, errors |

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

# Trace events work the same for async calls
agent = Agent(
    name="Traced Agent",
    tools=[my_tool],
    # Observability hooks capture async tool calls
)

# Events emitted during async execution
await agent.achat("Use my tool")
```

***

## Migration Notes

No code changes required - async tool safety is automatically enabled:

**Before:** Async calls bypassed safety mechanisms

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Previously: approval, circuit breaker, etc. were skipped
await agent.achat("Use dangerous tool")  # No approval prompt
```

**After:** Async calls use full safety pipeline

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Now: full safety pipeline including approval
await agent.achat("Use dangerous tool")  # Approval prompt appears
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Handle Approval in Async Context">
    When using approval in async environments, ensure your event loop can handle user input:

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

    agent = Agent(require_approval=True, tools=[my_tool])

    async def safe_async_execution():
        # Approval prompts work in async context
        result = await agent.achat("Use tool")
        return result

    # Run with proper event loop
    asyncio.run(safe_async_execution())
    ```
  </Accordion>

  <Accordion title="Configure Timeouts for Async Tools">
    Set appropriate timeouts for async tool execution:

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

    agent = Agent(
        name="Async Agent",
        tools=[async_api_call],
        tool_timeout=30  # 30 second limit for async tools
    )
    ```
  </Accordion>

  <Accordion title="Monitor Circuit Breaker in Async Workflows">
    Circuit breaker state affects all calls - monitor in async workflows:

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

    async def monitored_workflow():
        for i in range(10):
            try:
                result = await agent.achat(f"Process item {i}")
            except ToolExecutionError as e:
                if "circuit breaker" in str(e).lower():
                    # Circuit breaker is open, wait before retrying
                    await asyncio.sleep(60)
    ```
  </Accordion>

  <Accordion title="Task Tools Override Agent Tools">
    Design task tools to be self-contained since they override agent tools:

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

    # Agent tools
    def general_tool():
        return "General purpose"

    # Task-specific tools (will override agent tools)  
    def specialized_tool():
        return "Task-specific operation"

    agent = Agent(tools=[general_tool])

    task = Task(
        description="Specialized work",
        agent=agent,
        tools=[specialized_tool]  # Only this tool available during task
    )
    ```
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Approval" icon="shield-check" href="/features/approval">
    Tool approval configuration
  </Card>

  <Card title="Tool Circuit Breaker" icon="zap" href="/features/tool-circuit-breaker">
    Tool failure protection
  </Card>
</CardGroup>
