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

> Easily access tool results from Needle.run() response. Learn to retrieve tool return values using the results key for efficient agent execution.

- Repository: [Cactus Compute, Inc./needle](https://github.com/cactus-compute/needle)
- Tags: how-to-guide
- Published: 2026-08-17

---

**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`](https://github.com/cactus-compute/needle/blob/main/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.

```python
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.

```python
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.

```python
@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`](https://github.com/cactus-compute/needle/blob/main/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`](https://github.com/cactus-compute/needle/blob/main/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.