tool & Tool
Reference for the tool decorator and the Tool dataclass — how AgentRoute turns a Python function into a model-callable tool.
A tool is a Python function the agent can call mid-run. The tool decorator wraps a function into a Tool, auto-extracting the model-visible parameter schema from the function's type hints and docstring. You register tools by passing them to Agent(tools=[...]) or with the @agent.tool decorator.
For the conceptual overview — when to reach for a tool, approval gates, and the agentic loop — see Tools.
tool
tool — wraps a plain function into a Tool.
from agentroute import tooldef tool(
fn: Callable[..., Any] | None = None,
/,
*,
name: str | None = None,
description: str | None = None,
needs_approval: bool | Callable[[Context, dict[str, Any]], bool] = False,
timeout: float | None = None,
) -> Tool | Callable[[Callable[..., Any]], Tool]:
...It is a dual-call decorator: bare @tool and parameterized @tool(name="...") both work. Bare usage returns a Tool directly; parameterized usage returns a decorator that returns a Tool.
| Parameter | Type | Default | Description |
|---|---|---|---|
fn | Callable[..., Any] | None | None | The function to wrap. Passed positionally by the bare @tool form; leave it unset when calling @tool(...) with keyword options. |
name | str | None | None | Override the tool name the model sees. Defaults to the function's name. |
description | str | None | None | Override the tool description. Defaults to the function's docstring. |
needs_approval | bool | Callable[[Context, dict], bool] | False | Gate execution behind human approval. Pass True to always require approval, or a callable (ctx, args) -> bool to decide per call. |
timeout | float | None | None | Maximum seconds the tool may run before it is cancelled. None means no timeout. |
Tool (bare form) or a decorator returning a Tool (parameterized form).Dual-call forms
Both forms produce an equivalent Tool.
from agentroute import tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
@tool(name="lookup_weather", timeout=5.0)
def get_weather_2(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."Schema extraction
The parameter schema is built from the function's type hints and docstring — you do not write JSON Schema by hand. A parameter annotated Context is auto-injected at call time and is omitted from the model-visible schema.
from agentroute import Context, tool
@tool
def add_note(ctx: Context, text: str) -> str:
"""Save a note to memory.
Args:
text: The note body to store.
"""
# `ctx` is injected by the runtime, not chosen by the model.
# The model only sees the `text` parameter.
return "saved"The docstring becomes the tool description the model reads, and per-argument descriptions (when present) flow into the parameter schema. Write it for the model.
Registering tools on an agent
Pass Tool objects or plain callables to the agent, or decorate with @agent.tool to register in place.
from agentroute import Agent, tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
agent = Agent(
name="assistant",
model="claude-sonnet-4",
tools=[get_weather],
)
@agent.tool(needs_approval=True)
def delete_file(path: str) -> str:
"""Delete a file from disk."""
return f"deleted {path}"
result = agent.run("What's the weather in Berlin?")
print(result) # It's sunny in Berlin.Tool
Tool — a callable tool the agent can invoke.
from agentroute import Tool@dataclass
class Tool:
name: str
description: str
params_schema: dict[str, Any]
fn: Callable[..., Any]
takes_context: bool = False
needs_approval: bool | Callable[[Context, dict[str, Any]], bool] = False
timeout: float | None = NoneYou rarely construct a Tool by hand — the tool decorator builds one for you. The fields are useful for inspection (for example via agent.tools_map).
| Parameter | Type | Default | Description |
|---|---|---|---|
namerequired | str | — | The tool name exposed to the model. |
descriptionrequired | str | — | Human- and model-readable description, sourced from the docstring. |
params_schemarequired | dict[str, Any] | — | The JSON-Schema parameters object the model sees, auto-extracted from the function signature. |
fnrequired | Callable[..., Any] | — | The underlying function executed when the tool is called. |
takes_context | bool | False | Whether the first positional parameter is annotated Context and should receive the active Context at call time. Set automatically during extraction. |
needs_approval | bool | Callable[[Context, dict], bool] | False | Approval gate — True to always require approval, or a predicate (ctx, args) -> bool. |
timeout | float | None | None | Maximum seconds the tool may run, or None for no limit. |
invoke
Run the tool with model-supplied arguments and the active context.
async def invoke(self, args: dict[str, Any], *, ctx: Context) -> Any:
...| Parameter | Type | Default | Description |
|---|---|---|---|
argsrequired | dict[str, Any] | — | The arguments parsed from the model's tool call, keyed by parameter name. |
ctxrequired | Context | — | The active run context, injected as the first positional argument when takes_context is True. |
Execution behavior:
- Async functions are awaited directly.
- Sync functions are offloaded with
asyncio.to_thread, so a blocking call does not stall the event loop. - When
takes_contextisTrue,ctxis passed as the first positional argument; the rest ofargsis splatted as keyword arguments.
During a run the agent matches the model's tool call to a registered Tool and awaits invoke internally. You only call it directly when testing a tool in isolation.
Calling a tool directly
Useful in tests. Build a Context and await invoke.
import asyncio
from agentroute import Context, tool
@tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"It's sunny in {city}."
async def main() -> None:
ctx = Context()
out = await get_weather.invoke({"city": "Berlin"}, ctx=ctx)
print(out) # It's sunny in Berlin.
asyncio.run(main())A context-aware tool reads from ctx — note the model still only supplies text:
import asyncio
from agentroute import Context, Memory, tool
@tool
async def remember_fact(ctx: Context, key: str, value: str) -> str:
"""Store a fact for later recall."""
await ctx.memory.remember(key, value)
return "ok"
async def main() -> None:
ctx = Context(memory=Memory())
out = await remember_fact.invoke({"key": "city", "value": "Berlin"}, ctx=ctx)
print(out) # ok
asyncio.run(main())Next steps
When to use tools, approval gates, and the agentic loop.
The Context object injected into context-aware tools.
Register tools with tools=[...] or @agent.tool.
Read and write durable state from inside a tool via ctx.memory.