# How to Use the agent_tool Decorator to Define Agent Functions in aisuite

> Learn how to use the agent_tool decorator in aisuite to turn any Agent into a callable tool. Effortlessly handle execution and context for parent agents.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: how-to-guide
- Published: 2026-07-28

---

**The `agent_tool` decorator in `aisuite` converts any Agent into a callable tool that parent agents can invoke, automatically handling execution and context propagation.**

The `aisuite` library by Andrew Ng enables hierarchical agent compositions by allowing one Agent to call another as a tool. The `agent_tool` helper function, located in [`aisuite/agents/tools.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/tools.py), wraps sub-agents into standard Python callables that can be registered in a parent agent's `tools` list. This pattern preserves trace IDs, metadata, and execution context across agent boundaries while letting large language models treat specialized agents as modular capabilities.

## What is agent_tool?

`agent_tool` is a factory function that generates a Python callable from an existing Agent instance. When invoked, this callable executes the sub-agent synchronously and returns its `final_output` as a string. The wrapper automatically captures the active run context— including trace IDs, tags, and client configuration—via `get_active_run_context` from [`aisuite/agents/context.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/context.py), ensuring observability flows through the entire call chain.

The generated function inherits a `__name__` and docstring based on the parameters you provide, making it self-documenting for LLM tool selection. Parent agents can then request the sub-agent through standard tool-calling syntax without manual context management.

## How agent_tool Works Internally

When you invoke `agent_tool(agent, ...)`, the implementation in [`aisuite/agents/tools.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/tools.py) performs four key operations:

1. **Normalizes the tool identifier** (`_tool_name`) based on the provided name or the agent's default name.
2. **Captures the active run context** using `get_active_run_context()` to preserve the caller's trace state.
3. **Invokes the Runner** by calling `Runner.run_sync` (defined in [`aisuite/agents/runner.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/runner.py)) with the sub-agent and propagated context values.
4. **Returns the final output** as a string, or an empty string if the sub-agent produces no output.

Because the helper returns a ready-to-use function object, you can use it either as a standard function assignment or as a Python decorator—though note that when used as a decorator, the decorator replaces the entire function body with the generated wrapper.

## Defining Sub-Agent Functions with agent_tool

You can expose a sub-agent to a parent agent in two ways: by assigning the tool to a variable or by using the decorator syntax.

### Basic Usage

First, import the required classes and define your sub-agent using the `Agent` dataclass from [`aisuite/agents/types.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/types.py):

```python
from aisuite.agents.types import Agent
from aisuite.agents.tools import agent_tool

# Define a specialized sub-agent

echo_agent = Agent(
    name="EchoAgent",
    model="gpt-4o-mini",
    system_prompt="You are a helpful echo bot that repeats the user's input exactly.",
)

# Create a tool wrapper

echo_tool = agent_tool(
    echo_agent,
    name="echo",
    description="Runs EchoAgent and returns its reply verbatim."
)

```

The `echo_tool` variable is now a callable that accepts string input and returns the sub-agent's output, ready to be added to any parent agent's tool list.

### Using agent_tool as a Decorator

You can also apply `agent_tool` as a decorator. When used this way, the decorator completely replaces the decorated function with the generated wrapper, meaning the original function body is never executed:

```python
@agent_tool(echo_agent, name="shout", description="Runs EchoAgent and converts output to uppercase.")
def shout(input: str) -> str:
    pass  # This body is ignored; the decorator replaces it with the agent wrapper

# shout is now a callable tool that runs echo_agent

```

The function signature you define serves only as documentation for the LLM. The actual implementation comes entirely from the `agent_tool` wrapper.

### Registering Tools with Parent Agents

Once you have created tool wrappers, register them in a parent agent's `tools` parameter. The parent agent can then invoke these tools during execution:

```python

# Create parent agent with access to sub-agent tools

parent = Agent(
    name="ParentAgent",
    model="gpt-4o",
    system_prompt="You can call tools to delegate specialized tasks.",
    tools=[echo_tool, shout]  # Register both tools

)

# Execute the parent agent

result = parent.run_sync("Please echo the phrase: 'Hello world!'")
print(result.final_output)  # Output: Hello world!

```

When the parent agent decides to invoke `echo` or `shout`, `aisuite` handles the synchronous execution via `Runner.run_sync`, automatically passing the current trace context, client configuration, and tags to the sub-agent.

## Key Implementation Details

**Context Propagation**: The wrapper automatically extracts the active run context using `get_active_run_context()` before calling `Runner.run_sync`. This ensures that child agents inherit trace IDs, group tags, and metadata from their parents without manual intervention.

**Return Values**: The tool always returns the sub-agent's `final_output` attribute as a string. If the sub-agent completes without generating output, the tool returns an empty string.

**Synchronous Execution**: Despite the async-capable nature of modern LLM clients, `agent_tool` specifically uses `run_sync` to execute sub-agents, making it suitable for use in synchronous tool chains.

## Summary

- **`agent_tool`** (in [`aisuite/agents/tools.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/tools.py)) wraps Agent instances as callable tools that parent agents can invoke.
- The wrapper preserves execution context automatically via `get_active_run_context` and `Runner.run_sync`.
- You can assign the tool to a variable or use it as a decorator; when used as a decorator, the original function body is replaced entirely.
- Register wrapped tools in a parent Agent's `tools` list to enable hierarchical agent delegation.

## Frequently Asked Questions

### Can I use agent_tool with async agents?

No. The `agent_tool` helper specifically uses `Runner.run_sync` from [`aisuite/agents/runner.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/runner.py) to execute sub-agents synchronously. If you need asynchronous execution, you would need to implement a custom wrapper that calls `Runner.run` instead.

### What happens if the sub-agent returns no output?

If the wrapped agent completes its run but produces no `final_output`, `agent_tool` returns an empty string. This prevents `None` values from propagating into the parent agent's context while still indicating that the tool executed successfully.

### Does the decorated function's signature matter?

Yes, but only for documentation purposes. When using `@agent_tool` as a decorator, the LLM sees the decorated function's signature and docstring to understand what parameters to pass. However, the actual function body is never executed because the decorator replaces the entire function with the agent wrapper.

### How does context tracing work across agent boundaries?

`agent_tool` automatically calls `get_active_run_context()` from [`aisuite/agents/context.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/agents/context.py) at invocation time, capturing the current trace ID, tags, and metadata. It then passes these values to `Runner.run_sync`, ensuring the sub-agent's execution is properly correlated with the parent run in observability dashboards.