Skip to content

Tools

Plain Python functions become schema-validated tools with @tool.

A tool is any Python function wrapped with @tool. The function name becomes the tool name, the docstring summary becomes the description, and the type hints plus a Google-style Args: section become the JSON Schema the model sees.

from agentling import tool
 
 
@tool
async def search(query: str, limit: int = 5) -> str:
    """Search the docs and return the top matches.
 
    Args:
        query: What to search for.
        limit: How many results to return.
    """
    ...

Both synchronous and asynchronous functions are supported. A synchronous tool runs in a worker thread so it cannot block the event loop.

Schemas and validation#

Supported parameter types map directly to JSON Schema: str, int, float, bool, list[...], dict[...], Optional[...] or X | None (treated as "may be omitted"), and Literal[...] (becomes an enum). Parameters without a default are marked required.

*args, **kwargs, and positional-only parameters are rejected at registration time, because a tool is always called with a JSON object of named arguments.

If the model sends arguments that do not match the schema, a missing required field, a wrong type, or an unknown key, the tool raises a ToolCallError which the loop feeds back to the model as an error observation. The model gets a chance to fix its call rather than the run blowing up. See Error handling for the full recovery story.

The built-in final_answer tool#

Every agent has a built-in final_answer tool. The model can call it to end the run explicitly, or it can just reply with plain text; both terminate the run. See The Agent Loop for how termination works.

Per-tool metadata#

Tools carry their own execution metadata: a per-call timeout, a parallel_safe flag, and max_output_chars to bound how much of the result reaches the model.

Warning

A timeout stops the agent from waiting on a tool and turns it into an observation, but a synchronous tool already running in a thread cannot be forcibly cancelled and will finish in the background. Prefer async tools, or make blocking tools cooperative, when timeouts matter.

Stateful tools#

For stateful tools, subclass Tool directly instead of using the decorator. This is useful when a tool needs a client, a connection pool, or configuration that outlives a single call.

Concurrent execution#

When a single model turn requests several tool calls, they run concurrently with asyncio.gather by default. Set parallel_tools=False on the Agent to run them in order instead, which is useful when tools share state or must not interleave.

Edit this page on GitHub
Share