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

# invoke_tool

> Invoke a single tool bound to an agent.

`Agent.ainvoke_tool` runs a single tool from the agent's `ToolsRepository` and returns a `ToolInvocationResult`. Use it when you want to test a tool, or when you're building an agent loop yourself and the framework's tool dispatcher isn't a good fit.

```python theme={"dark"}
from xpander_sdk import Agents

agent = await Agents().aget("agent-123")
weather_tool = agent.tools.get_tool_by_id("get_weather")

result = await agent.ainvoke_tool(
    tool=weather_tool,
    payload={"city": "New York"},
)
print(result.is_success, result.result)
```

### Parameters

| Parameter           | Type   | Required | Default | Description                                                                                |
| ------------------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------ |
| `tool`              | `Tool` | Yes      | –       | A `Tool` instance, typically from `agent.tools.get_tool_by_id(...)` or `agent.tools.list`. |
| `payload`           | `Any`  | Yes      | –       | Tool input. Validated against `tool.schema` before execution.                              |
| `payload_extension` | `dict` | No       | `{}`    | Extra fields deep-merged into the payload (e.g. headers, auth params).                     |
| `task_id`           | `str`  | No       | `None`  | Associate the invocation with a specific task (for activity logging).                      |
| `tool_call_id`      | `str`  | No       | `None`  | Correlation ID for this call (matches LLM tool-call IDs).                                  |

### Returns `ToolInvocationResult`

| Field          | Type          | Description                                                        |
| -------------- | ------------- | ------------------------------------------------------------------ |
| `tool_id`      | `str`         | The tool's id.                                                     |
| `tool_call_id` | `str \| None` | The correlation ID, if passed.                                     |
| `task_id`      | `str \| None` | The task ID, if passed.                                            |
| `payload`      | `Any`         | The payload that was sent.                                         |
| `result`       | `Any`         | The tool's response. Shape depends on the tool.                    |
| `is_success`   | `bool`        | `True` when the call returned 2xx.                                 |
| `is_error`     | `bool`        | `True` when the call raised or returned an error status.           |
| `status_code`  | `int`         | HTTP status from the remote tool, or `500` for client-side errors. |
| `is_local`     | `bool`        | `True` for tools registered via `@register_tool`.                  |

`is_success` and `is_error` are mutually exclusive in normal operation; check `is_error` first.

## Examples

### With `payload_extension`

```python theme={"dark"}
result = await agent.ainvoke_tool(
    tool=weather_tool,
    payload={"city": "Tokyo"},
    payload_extension={"headers": {"X-Trace-ID": "abc-123"}},
)
```

`payload_extension` is deep-merged with `payload`, so nested objects compose naturally.

### Local Python tools

Tools registered with `@register_tool` are invoked locally (the `fn` runs in-process) and pass through the same `ToolInvocationResult` interface:

```python theme={"dark"}
from xpander_sdk import register_tool

@register_tool
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

# 'add' is now in the global tool registry
agent = await Agents().aget("agent-123")
add_tool = agent.tools.get_tool_by_id("add")

result = await agent.ainvoke_tool(tool=add_tool, payload={"a": 2, "b": 3})
result.result  # 5
result.is_local  # True
```

See [`@register_tool`](/developers/sdk-reference/tools/register-tool) for details.

### Inside an `@on_task` handler

```python theme={"dark"}
from xpander_sdk import on_task
from xpander_sdk.modules.tasks.sub_modules.task import Task

@on_task
async def handler(task: Task) -> Task:
    agent = await Agents().aget(task.agent_id)
    tool = agent.tools.get_tool_by_id("my_tool")

    result = await agent.ainvoke_tool(
        tool=tool,
        payload={"x": 1},
        task_id=task.id,        # links the invocation to this task in the dashboard
    )
    task.result = str(result.result)
    return task
```

Passing `task_id` ensures the invocation appears in `task.aget_activity_log()`.

### Sync version

```python theme={"dark"}
result = agent.invoke_tool(tool=weather_tool, payload={"city": "Berlin"})
```

## Notes

* Payload validation: if `payload` doesn't match `tool.schema`, the SDK raises `ValueError` (not `ModuleException`). Catch it separately if you're invoking with untrusted input.
* Lifecycle hooks ([`@on_tool_before` / `@on_tool_after` / `@on_tool_error`](/developers/sdk-reference/decorators/on-tool)) fire around the invocation.
* For invocations outside an agent context, use `tool.get_invocation_function()` instead: it requires a `connector_id` and `operation_id` resolved via `tools.aload_tool_by_id(...)`.
