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_pathscheck (lines 94‑101 ofneedle/__init__.py) to detect hallucinated parameters - When
strict=True, aborts execution if ungrounded arguments are detected - Looks up the Python implementation in the
_functionsregistry (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.runmethod inneedle/__init__.pyimplements the complete agent loop, handling LLM completions, tool execution, and result feedback automatically. - Tools are defined using the
@tooldecorator fromneedle/agent/tools.py, which generates JSON-Schema definitions viabuild_schema(). - The loop extracts function calls, validates arguments against
_ungrounded_paths(lines 94‑101), executes registered Python functions from the_functionsregistry, and feeds results back to the model. - Configuration options
max_stepsandstrictcontrol execution depth and argument validation behavior. - The final response includes
type,content, and aresultsarray 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →