How to Access Tool Results from the Needle.run() Method Response

Access tool execution results via the "results" key in the dictionary returned by Needle.run(), which contains a list of all return values from tools invoked during the agent's execution loop.

The run() method in the cactus-compute/needle repository provides a high-level interface for autonomous agent execution, handling the complete "think-tool-think" loop internally. When you need to programmatically access the outputs of executed tools from the run() method's response, the implementation automatically aggregates these values into a dedicated field within the final response envelope.

Understanding the Needle.run() Execution Loop

The run() method drives the interaction cycle between the language model and registered tools. According to the source code in needle/__init__.py (lines 125-146), the method executes the following sequence:

  1. Initial Completion: Calls complete() to obtain the LLM's first response, which may contain a "function_calls" array specifying which tools to invoke.
  2. Tool Invocation: Iterates up to max_steps, invoking each tool listed in "function_calls" via the internal _functions registry.
  3. Result Collection: Accumulates the return values (or error dictionaries) of each invoked tool in an internal list named executed.
  4. Contextual Feedback: Feeds the list of results back to the model with subsequent complete() calls, allowing the LLM to reason on the tool outputs.
  5. Response Assembly: Attaches the accumulated list of tool results to the final envelope under the key "results" before returning the complete response dictionary.

This architecture ensures that every tool output generated during the autonomous loop is preserved and accessible after execution completes.

Accessing the Results Dictionary

After calling run(), the response dictionary contains a "results" key that holds the aggregated outputs. The rest of the response keys—including "type", "content", and "function_calls"—remain available for inspecting the raw LLM response.

agent = Needle(tools=[my_tool], system="You are a helpful assistant.")
response = agent.run("Summarize the data from my_tool", max_steps=4)

# Access the list of tool outputs

tool_outputs = response["results"]

The "results" value is a list containing each tool's returned value in the order they were executed. If a tool raises an exception, the list contains an error dictionary for that invocation rather than the return value.

Practical Implementation Examples

Retrieving Results from a Single Tool Call

When executing a simple tool that returns a dictionary, you can extract the specific fields directly from the first element of the results list.

from needle import Needle, tool
import json

@tool
def echo(message: str) -> dict:
    """Return the provided message unchanged."""
    return {"message": message}

agent = Needle(tools=[echo])

# Execute the tool through the agent

resp = agent.run("Please echo the phrase 'Hello world!'", max_steps=2)

# Extract the tool results

print(resp["results"])

# → [{'message': 'Hello world!'}]

# Inspect the full response envelope

print(json.dumps(resp, indent=2))

# {

#   "type": "call",

#   "function_calls": [...],

#   "results": [{"message": "Hello world!"}],

#   "confidence": null,

#   ...

# }

Handling Multiple Tool Executions

For workflows requiring sequential tool calls, iterate over the results list to process each output individually.

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

agent = Needle(tools=[add])

# Request multiple calculations in one session

response = agent.run(
    "Add 3 and 4, then add the result to 10.", max_steps=3
)

# Process each intermediate result

for i, result in enumerate(response["results"], start=1):
    print(f"Result {i}: {result}")

# Possible output:

# Result 1: 7

# Result 2: 17

Summary

  • The Needle.run() method implements an autonomous execution loop in needle/__init__.py that handles tool invocation and result aggregation automatically.
  • Tool outputs are collected in an internal executed list during the iteration process and attached to the final response under the "results" key.
  • The "results" field contains a list of return values (or error dictionaries) from every tool invoked during the session, preserving execution order.
  • Additional response metadata—including "function_calls", "type", and "content"—remains accessible alongside the tool results.

Frequently Asked Questions

What data structure contains the tool results?

The tool results are stored in a Python list accessed via response["results"]. Each element corresponds to the return value of a single tool invocation in the order executed during the run() loop.

How does Needle handle errors during tool execution?

If a tool raises an exception during invocation, the run() method captures the error as a dictionary and includes it in the "results" list at the corresponding position. This allows the agent to continue execution while preserving error context for downstream processing or logging.

Can I limit the number of tool execution steps?

Yes. The run() method accepts a max_steps parameter (e.g., agent.run(query, max_steps=4)) that constrains the number of "think-tool-think" iterations. The loop terminates when either the LLM stops requesting tool calls or the step limit is reached, whichever occurs first.

Where is the run() method implementation located?

The core implementation resides in needle/__init__.py between lines 125-146. This section contains the logic for calling complete(), managing the _functions registry, collecting results into the executed list, and assembling the final response envelope with the "results" key.

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 →