How to Execute a Complete Agent Loop with Tool Execution Using `agent.run()`

The Needle.run method in needle/__init__.py orchestrates an autonomous feedback loop where the LLM decides which tools to call, the SDK executes the corresponding Python functions, and the results are fed back to the model until a final answer is reached or the step limit is hit.

The cactus-compute/needle SDK provides a lightweight framework for building autonomous agents that can execute Python tools dynamically. When you need to execute a complete agent loop with tool execution using agent.run(), the library handles the entire lifecycle—from initial LLM completion through iterative tool calling and result accumulation—without requiring manual state management.

The Agent Loop Architecture in needle/__init__.py

The core autonomous behavior is implemented in the Needle.run method (lines 83‑115 of needle/__init__.py). When invoked, agent.run(query) enters a closed feedback loop that continues until the model stops requesting tool calls or reaches the configured maximum steps.

Step 1: Initial Completion

The loop begins by calling the internal _complete routine to obtain the LLM's first response. If the model determines it needs external data, it returns a function_calls list containing the names and arguments of requested tools.

Step 2: Tool Execution and Validation

For each iteration (up to max_steps, default 8), the SDK performs the following actions:

  • Extracts pending function calls from the LLM response
  • Validates arguments against the _ungrounded_paths check (lines 94‑101 of needle/__init__.py) to detect hallucinated parameters
  • When strict=True, aborts execution if ungrounded arguments are detected
  • Looks up the Python implementation in the _functions registry (populated at agent initialization)
  • Executes the tool, capturing return values or exceptions

Step 3: Result Feedback and Iteration

After execution, the SDK appends outcomes to an executed list and serializes them via json.dumps(results) to create a new prompt. This feedback is sent back to the LLM, allowing the model to reason over the concrete tool outputs before deciding on the next action or providing a final answer.

Defining Tools with needle/agent/tools.py

Tool definitions rely on utilities in needle/agent/tools.py. The @tool decorator inspects Python callables, extracts type hints and docstrings, and generates JSON-Schema definitions that the LLM can understand.

The build_schema(fn) function handles the conversion, while the decorator attaches this schema via a hidden _needle_tool attribute, automatically registering the function in the agent's _functions registry.

Complete Implementation Example

Here is how to execute a complete agent loop with tool execution using agent.run():

from needle import Needle, tool

@tool
def get_weather(city: str) -> str:
    """Return a simple weather description for *city*."""
    return f"Sunny in {city} with a temperature of 23°C."

# Initialize agent with tools

agent = Needle(tools=[get_weather], system="You are a helpful assistant.")

# Execute the full loop

response = agent.run(
    query="What should I wear today in Paris?",
    max_steps=5,
    strict=True
)

print(response["type"])     # → "final"

print(response["results"])  # → [{'city': 'Paris', 'output': 'Sunny...'}]

print(response["content"])  # → Model's final natural-language answer

Multi-Tool Workflows

The loop handles complex multi-step reasoning automatically when multiple tools are registered:

@tool
def add(a: int, b: int) -> int:
    """Return the sum of *a* and *b*."""
    return a + b

@tool
def multiply(x: int, y: int) -> int:
    """Return the product of *x* and *y*."""
    return x * y

agent = Needle(tools=[add, multiply])
resp = agent.run(
    query="What is (2 + 3) times (4 + 5)?",
    max_steps=4
)

# Results show intermediate calculations and final output

print(resp["results"])  # → [{'result': 5}, {'result': 9}, {'result': 45}]

Configuration Parameters

  • max_steps: Integer limiting loop iterations (default 8). Prevents infinite loops during tool execution.
  • strict: Boolean flag enabling validation of grounded arguments. When True, the loop aborts if the LLM provides arguments not present in the schema.

Summary

  • The Needle.run method in needle/__init__.py implements the complete agent loop, handling LLM completions, tool execution, and result feedback automatically.
  • Tools are defined using the @tool decorator from needle/agent/tools.py, which generates JSON-Schema definitions via build_schema().
  • The loop extracts function calls, validates arguments against _ungrounded_paths (lines 94‑101), executes registered Python functions from the _functions registry, and feeds results back to the model.
  • Configuration options max_steps and strict control execution depth and argument validation behavior.
  • The final response includes type, content, and a results array containing ordered tool execution outcomes.

Frequently Asked Questions

How does agent.run() handle tool execution errors?

The SDK captures any exceptions raised during tool execution and includes them in the feedback payload sent back to the LLM. This allows the model to react to failures and potentially request corrective actions or alternative tool calls within the same loop.

What is the maximum number of tool calls in a single agent.run() session?

By default, the loop terminates after 8 iterations (max_steps=8), but you can configure this parameter when calling the method. Each iteration may execute multiple tools if the LLM requests parallel function calls, with all results accumulated in the executed list before the next completion request.

How does the strict parameter prevent hallucinated arguments?

When strict=True, the SDK checks tool arguments against _ungrounded_paths (implemented in needle/__init__.py lines 94‑101) to ensure they exist in the original schema defined by build_schema(). If the LLM provides parameters not defined in the function signature, the loop aborts immediately rather than executing with invalid inputs.

Where are tool schemas generated in the Needle SDK?

Schema generation occurs in needle/agent/tools.py via the build_schema() function, which introspects Python callables to extract type hints and docstrings. The @tool decorator attaches this schema to functions via the _needle_tool attribute, making them available to the agent's internal _functions registry.

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 →