Skip to main content

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.

@register_tool turns a Python function into a tool the agent can invoke. The SDK extracts type hints and the docstring to build a schema and description automatically: there’s no manual schema writing.
from xpander_sdk import register_tool

@register_tool
def calculate_sum(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b
After this runs (typically at module import), calculate_sum is available to every Agents().aget(...) call as a local tool with id "calculate_sum".

Decorator forms

@register_tool                                    # plain
def fn(...): ...

@register_tool(add_to_graph=True)                 # with options
def fn(...): ...
ParameterTypeDefaultDescription
add_to_graphboolFalseWhen True, the tool is pushed into the agent’s execution graph (so the platform routes calls through it). When False, the tool is only available in-process.

What it does

  1. Inspects the function’s parameters and type hints.
  2. Builds a Pydantic model (<FunctionName>Args) from the parameters: required if no default, optional otherwise.
  3. Constructs a Tool with:
    • id = function name
    • name = function name
    • description = function docstring
    • parameters = generated JSON schema
    • fn = the function
    • is_local = True
    • should_add_to_graph = add_to_graph
  4. Registers the tool in ToolsRepository’s class-level _local_tools list (process-wide singleton).
  5. Returns the original function unchanged: calculate_sum(2, 3) still works as plain Python.

Examples

Async functions are supported

@register_tool
async def fetch_url(url: str) -> str:
    """Fetch the body of a URL."""
    async with httpx.AsyncClient() as client:
        response = await client.get(url)
    return response.text
When the agent calls this tool, the SDK awaits the coroutine.

Optional parameters

@register_tool
def search(query: str, limit: int = 10, region: str = "US") -> list[str]:
    """Search the catalog. Returns matching SKUs."""
    ...
Defaults become optional fields in the JSON schema.

Push to the agent graph

@register_tool(add_to_graph=True)
async def analyze_data(data: list, analysis_type: str) -> dict:
    """Analyze incoming data; returns aggregated metrics."""
    ...
add_to_graph=True makes the tool visible in the platform’s graph view for the next agents.aget(...): the SDK sync runs in the background after aget returns.

Use the function directly

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

# Still callable as a regular function
add(2, 3)   # 5

Visibility rules

The decorator registers tools at module-import time on a process-wide registry. That means:
  • Every agent loaded by Agents().aget(...) in this process inherits the local tools.
  • Tools defined inside a function body register the first time the function runs, but stay registered for the rest of the process’s lifetime.
  • If you del or rename a function after decoration, the registered Tool keeps its captured reference (the fn attribute): it doesn’t unregister itself.
For per-invocation tools, use Backend.aget_args(tools=[fn]) instead: that adds callables to one specific aget_args call without polluting the global registry.

Schema details

The generated schema uses Pydantic’s model_json_schema(mode="serialization"). Parameter names, types, and defaults map directly:
@register_tool
def book_flight(origin: str, destination: str, date: str = "tomorrow") -> dict:
    """Book a flight."""
    ...
generates roughly:
{
  "properties": {
    "origin": {"type": "string", "title": "Origin"},
    "destination": {"type": "string", "title": "Destination"},
    "date": {"type": "string", "title": "Date", "default": "tomorrow"}
  },
  "required": ["origin", "destination"],
  "title": "BookFlightArgs",
  "type": "object"
}
The agent’s LLM sees this schema; the docstring becomes the tool’s description. Write docstrings the way you’d write a tool description: that’s exactly what the LLM reads.