tool
Python · package toolnexus · SPEC §6 · python/src/toolnexus/native.py
def tool( fn: Callable[..., Any] | None = None, *, name: str | None = None, description: str | None = None, input_schema: JSONSchema | None = None,) -> Tool | Callable[[Callable[..., Any]], Tool]The decorator form of define_tool — same inference, same
ToolResult wrapping, same everything, just spelled @tool above a def you are writing right
now. define_tool(fn, ..., source="native") is the implementation of tool; @tool calls it
with source fixed to "native". The decorated function name is rebound to the resulting Tool,
not the original callable.
When to use it
Section titled “When to use it”You are authoring the function specifically to be a tool — a new capability for an agent, not a
library function you happen to be wrapping. @tool reads top-to-bottom as “this is a tool”, right
where the function is defined.
Why this and not the alternative
Section titled “Why this and not the alternative”Examples
Section titled “Examples”1. Bare @tool — name and description inferred
Section titled “1. Bare @tool — name and description inferred”import asynciofrom toolnexus import tool
@tooldef convert_celsius(value: float) -> str: """Convert Celsius to Fahrenheit.""" return str(value * 9 / 5 + 32)
# `convert_celsius` IS the Tool now — the decorator rebinds the name.assert convert_celsius.name == "convert_celsius"assert convert_celsius.description == "Convert Celsius to Fahrenheit."assert convert_celsius.source == "native"assert convert_celsius.input_schema["required"] == ["value"]
async def main(): res = await convert_celsius.execute({"value": 100}) assert res.output == "212.0" print("ok:", convert_celsius.name, "->", res.output)
asyncio.run(main())2. @tool(...) with overrides, and calling the original function directly
Section titled “2. @tool(...) with overrides, and calling the original function directly”The decorator’s parenthesized form takes the same overrides as define_tool — useful when the
Python name is not the name you want the model to see, but you still want to call the plain
function yourself elsewhere.
import asynciofrom toolnexus import tool
@tool(name="lookup_status", description="Look up an order's shipping status.")def _status(order_id: str) -> str: return f"{order_id}: in transit"
assert _status.name == "lookup_status"assert _status.description == "Look up an order's shipping status."# `_status` is the Tool object, not the function — call it through .execute.
async def main(): res = await _status.execute({"order_id": "A-42"}) assert res.output == "A-42: in transit" print("ok:", _status.name, "->", res.output)
asyncio.run(main())3. An explicit input_schema, and feeding decorated tools to an adapter
Section titled “3. An explicit input_schema, and feeding decorated tools to an adapter”An explicit schema overrides inference — useful for an enum, a format, or per-property
descriptions the type hints cannot express. Decorated tools are ordinary Tools, so they flow
into to_openai (or any adapter) exactly like define_tool output.
import asynciofrom toolnexus import tool, to_openai
@tool( input_schema={ "type": "object", "properties": {"priority": {"type": "string", "enum": ["low", "high"]}}, "required": ["priority"], "additionalProperties": False, })def set_priority(priority: str) -> str: """Set the priority of the current ticket.""" return f"priority set to {priority}"
assert set_priority.input_schema["properties"]["priority"]["enum"] == ["low", "high"]
schema = to_openai([set_priority])assert schema[0]["function"]["name"] == "set_priority"assert schema[0]["function"]["parameters"]["properties"]["priority"]["enum"] == ["low", "high"]
async def main(): res = await set_priority.execute({"priority": "high"}) assert res.output == "priority set to high" print("ok:", res.output)
asyncio.run(main())Options
Section titled “Options”Identical to define_tool minus fn positioned as a decorator
target rather than a first argument, and no source override — @tool always produces
source="native".
| Option | Type | What it does |
|---|---|---|
name |
str | None |
Overrides fn.__name__. |
description |
str | None |
Overrides the first docstring line. |
input_schema |
JSONSchema | None |
Overrides inference entirely. |
Inference rules (type hints → JSON-Schema, ctx/context exclusion, async vs. thread dispatch,
return handling, error handling) are exactly define_tool’s —
see that page for the full table.
See also
Section titled “See also”define_tool— The direct-call form of exactly this, for functions you did not write for this purpose.Tool— What you get back.ToolResult·ToolContextcreate_toolkit— Pass decorated tools in viaextra_tools.