How to Declare Tools in Needle 2: 3 Methods Explained
In Needle 2, you declare tools using the @needle.tool decorator on Python functions, passing Pydantic models, or providing raw JSON schemas, then supply them to the Needle constructor via the tools parameter.
The cactus-compute/needle repository provides a lightweight framework for building conversational AI agents. Declaring tools in Needle 2 follows a two-step pattern where you first define the tool schema and then register it with the agent.
Using the @needle.tool Decorator
The primary method for declaring tools involves applying the @needle.tool decorator to Python functions. According to the source code in needle/agent/tools.py (lines 68-71), this decorator introspects function signatures, type hints, and docstrings to automatically generate JSON Schema definitions.
Converting Functions to Tool Schemas
When you decorate a function with @needle.tool, the framework inspects the callable and stores the generated schema as fn._needle_tool. The decorator extracts parameter types from annotations and descriptions from the docstring's Args section.
@needle.tool
def set_thermostat(temperature: int,
mode: Literal["heat", "cool", "auto"] = "auto"):
"""Set the thermostat.
Args:
temperature: target temperature in Celsius
mode: heating strategy to use
"""
return {"temperature": temperature, "mode": mode}
Registering Tools with the Agent
After decorating your functions, pass them to the Needle constructor using the tools parameter. As documented in doc/apis.md (line 5), the constructor accepts a list of tool definitions.
agent = needle.Needle(tools=[set_thermostat])
agent.run("make it 21 and cool the room")
Alternative Declaration Methods
Needle 2 supports three alternative approaches for declaring tools beyond the standard decorator pattern.
Direct JSON Schema
You can bypass Python function definitions entirely by constructing raw JSON Schema dictionaries. This method is documented in doc/apis.md (lines 51-68) and passed directly to the tools parameter.
tools = [{
"name": "set_lights",
"description": "Turn a room's lights on/off and set brightness",
"parameters": {
"type": "object",
"properties": {
"room": {"type": "string", "description": "room name"},
"on": {"type": "boolean"},
"brightness": {"type": "integer", "minimum": 0, "maximum": 100},
},
"required": ["room", "on"],
},
}]
agent = needle.Needle(tools=tools)
agent.run("Dim the living room lights to 30%")
Pydantic Models
For complex validation scenarios, define tools using Pydantic models. The framework extracts JSON schemas from BaseModel subclasses via the pydantic_schema function in needle/agent/tools.py.
Field Constraints with typing.Annotated
Use typing.Annotated combined with needle.Field to specify per-argument validation rules such as numeric ranges, regex patterns, and string lengths. This approach is detailed in doc/apis.md (lines 34-48).
from typing import Annotated
@needle.tool
def send_money(
amount: Annotated[float, needle.Field(gt=0, le=10000,
description="USD, up to 10,000")],
to: Annotated[str, needle.Field(pattern=r"^@[a-z0-9_]+$",
description="recipient handle")],
memo: Annotated[str, needle.Field(max_length=80)] = "",
):
"""Send money to a handle."""
return {"sent": amount, "to": to}
agent = needle.Needle(tools=[send_money])
agent.run("Send $25 to @bob")
Complete Working Examples
Here are runnable patterns demonstrating each declaration style:
Simple Function Tool:
@needle.tool
def greet(name: str):
"""Say hello to someone."""
return f"Hello, {name}!"
agent = needle.Needle(tools=[greet])
response = agent.run("Hey, can you greet Alice?")
Summary
- The
@needle.tooldecorator (implemented inneedle/agent/tools.py) automatically generates JSON schemas from Python function signatures and docstrings - Tool registration requires passing decorated functions to the
Needleconstructor via thetoolsparameter - Three declaration methods are supported: decorated functions, raw JSON schemas, and Pydantic models
- Validation constraints can be added using
typing.Annotatedwithneedle.Fieldfor granular control over argument validation
Frequently Asked Questions
What file contains the tool decorator implementation?
The @needle.tool decorator is implemented in needle/agent/tools.py (lines 68-71). This module handles function introspection, schema generation, and the Field constraint helper used with typing.Annotated.
Can I use Pydantic models instead of functions to declare tools?
Yes. Needle 2 accepts Pydantic BaseModel classes as tools. The framework uses the pydantic_schema function in needle/agent/tools.py to extract JSON schemas from model definitions, providing an alternative to the decorator-based approach for complex data structures.
How do I add validation constraints to tool arguments?
Use typing.Annotated combined with needle.Field to specify constraints like numeric ranges (gt, le), regex patterns (pattern), or length limits (max_length). As shown in doc/apis.md (lines 34-48), these annotations integrate directly with the @needle.tool decorator to enforce validation at the schema level.
Does Needle 2 support raw JSON schema definitions?
Yes. You can pass raw JSON Schema dictionaries directly to the Needle constructor via the tools parameter. This approach, documented in doc/apis.md (lines 51-68), allows integration with external schema definitions or languages other than Python.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →