How to Initialize a Needle Agent with Tools: Complete Setup Guide

You initialize a Needle agent by passing a list of tools—functions decorated with @tool, Pydantic models, or raw JSON schemas—to the tools argument of the Needle constructor, which automatically serializes them to JSON and binds the native engine.

The Needle class in the cactus-compute/needle repository serves as the core entry point for creating LLM agents that execute user-defined operations. When you initialize a Needle agent with tools, the constructor handles schema extraction and native engine registration without requiring manual JSON formatting. This article examines the internal resolution logic defined in needle/__init__.py and provides runnable implementations for each supported tool type.

The Needle Constructor and Tool Binding

The initialization process centers on the Needle class defined in needle/__init__.py. When you instantiate the class, the tools parameter accepts an iterable of callable functions, Pydantic models, or dictionary schemas.

According to the source code at lines 55–67, the constructor immediately processes the tools argument through the _resolve method, stores the serialized JSON in self._tools_json, and binds the engine. The _bind method (lines 70–95) then passes this schema data to needle_init along with an optional system prompt, completing the agent setup.

How Tool Resolution Works

During initialization, Needle._resolve iterates over the tools list and categorizes each entry into one of three formats:

Pydantic Models are converted using pydantic_schema (lines 99–101), which extracts the model's JSON schema definition.

Callable Functions are processed via the @tool decorator or build_schema utility (lines 64–66 in needle/agent/tools.py), automatically generating the schema from type hints and docstrings.

Dictionary Objects are validated as raw JSON schemas and passed through unchanged (lines 107–108), allowing direct specification of complex parameter structures.

The resulting list of schemas is stored in self._tools_json and serialized via json.dumps before transmission to the native engine.

Step-by-Step Initialization Process

Follow these steps to properly configure a Needle agent:

  1. Define your tools using the @tool decorator for functions, Pydantic models for structured data, or raw dictionaries for custom schemas.

  2. Instantiate the agent by passing the tools list to the constructor: Needle(tools=[...]).

  3. Provide optional configuration such as a system prompt (line 63) to set agent behavior context.

  4. Allow automatic binding where _bind loads weights and initializes the engine via needle_init (lines 91–94).

  5. Execute queries using agent.run(prompt) or agent.complete(prompt) (lines 27–48), which triggers tool invocation when the model detects relevant function calls.

Practical Code Examples

Example 1: Function-Based Tool with Decorator

Use the @tool decorator to automatically generate schemas from Python functions:

from needle import Needle, tool, Field

@tool
def set_lights(room: str, state: str, brightness: int = Field(default=100, ge=0, le=100)):
    """Turn lights on/off or dim them."""
    return {"room": room, "state": state, "brightness": brightness}

# Initialize the agent with the function above

agent = Needle(
    tools=[set_lights],
    system="You are a home-automation assistant."
)

# Run a query that triggers the tool

response = agent.run("Dim the bedroom lights to 20 percent")
print(response["results"])          # → [{'room': 'bedroom', 'state': 'on', 'brightness': 20}]

Example 2: Pydantic Model as Tool

Pass Pydantic models directly without additional decorators:

import pydantic
from needle import Needle

class Weather(pydantic.BaseModel):
    """Weather query."""
    city: str
    units: str = "metric"

# Initialize with the model (no extra decorator needed)

agent = Needle(tools=[Weather])

# Ask a question that the model can extract

extracted = agent.extract("What is the weather in Paris?", Weather)
print(extracted)                    # → Weather(city='Paris', units='metric')

Example 3: Raw JSON Schema Definition

Provide manually crafted JSON schemas for maximum control over parameter specifications:

custom_schema = {
    "name": "open_website",
    "description": "Open a website in a new tab.",
    "parameters": {
        "type": "object",
        "properties": {
            "url": {"type": "string", "description": "The site to open."}
        },
        "required": ["url"]
    }
}

agent = Needle(tools=[custom_schema])

Key Source Files

Understanding these files helps debug initialization issues:

  • needle/__init__.py – Contains the Needle class definition, the _resolve method for tool processing, and the _bind method for engine initialization.
  • needle/agent/tools.py – Implements the @tool decorator, the build_schema function for callable introspection, and pydantic_schema for model conversion.
  • tests/test_tools.py – Provides unit tests demonstrating valid tool declarations and schema generation edge cases.

Summary

  • The Needle constructor accepts tools via the tools argument and processes them through the internal _resolve method.
  • Three tool formats are supported: decorated functions, Pydantic models, and raw JSON dictionaries.
  • Tool schemas are serialized to JSON and stored in self._tools_json before being passed to the native engine via needle_init in the _bind method.
  • After initialization, agents immediately support tool invocation through run() and complete() methods.
  • All tool processing logic resides in needle/__init__.py (lines 55–108) with helper utilities in needle/agent/tools.py.

Frequently Asked Questions

What types of tools can I pass when initializing a Needle agent?

You can pass three types: Python functions decorated with @tool, Pydantic BaseModel subclasses, or raw dictionaries containing valid JSON Schema definitions. The Needle class automatically detects the type and applies the appropriate serialization logic in its _resolve method.

Does the Needle agent support async tool functions?

The source code in needle/__init__.py shows standard synchronous initialization via needle_init. While the _resolve method handles schema generation for callables, the actual execution context depends on the engine binding. For async support, verify the specific engine implementation in your environment.

How do I add a system prompt when initializing the agent?

Pass the system argument to the Needle constructor alongside your tools list. According to line 63 in needle/__init__.py, this string is encoded and supplied to the engine during the _bind call, establishing the agent's behavioral context before processing begins.

Where does the tool schema validation happen?

Schema extraction occurs in needle/__init__.py during initialization (lines 99–108), where _resolve delegates to pydantic_schema for models and needle/agent/tools.py for callable introspection. Raw dictionaries bypass conversion and are assumed valid JSON schemas.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →