What Does the `type` Field in Needle 2’s Response Signify?
The type field indicates whether the model produced a tool invocation ("call"), plain text ("text"), or a refusal ("refuse"), allowing your application to branch its handling logic accordingly.
The type field is a critical component of the JSON response object returned by every interaction with Needle 2, an open-source agent framework from cactus-compute/needle. This discriminator tells your application exactly how to interpret the remaining payload—whether to execute a function, display text to the user, or handle a safety refusal. Understanding the semantics of the type field is essential for correctly implementing the response contract defined in the project's API documentation.
The Three Possible Values of the type Field
"call" – Tool Invocation
When the type field equals "call", the model has decided to invoke a tool (function) that you registered. The response includes a name field specifying which tool to execute and an arguments field containing the filled-in parameters. According to the test suite in tests/test_inference.py (lines 16-17), this is asserted as response["type"] == "call" when the model determines a tool is required to satisfy the request.
"text" – Natural Language Reply
A type value of "text" signifies that the model is responding with plain natural-language content and does not require any tool execution. This typically represents the final answer to the user's query after any necessary tool calls have been completed and their results fed back into the conversation.
"refuse" – Content Refusal
The "refuse" value indicates that the model has declined to comply with the request, typically due to safety constraints or disallowed content policies. In this case, the response may include a reason field explaining why the request was denied.
Handling Response Types in Your Application
The response contract documented in doc/apis.md defines how your application should process each type:
- If
type == "call"→ Locate the matching function in yourtoolslist, execute it with the providedarguments, and feed the result back to Needle viarun()orcomplete(). The final response will then carrytype: "text"and aresultsfield containing the accumulated tool outputs. - If
type == "text"→ Render the content directly to the user. - If
type == "refuse"→ Present the refusal message or trigger an alternative workflow.
The core implementation in needle/__init__.py manages the run() and complete() loop that returns these dictionaries, while needle/agent/tools.py handles the JSON schema generation for tool parameters that feed into the "call" type responses.
Practical Code Examples
The following examples demonstrate how to interpret the type field in real-world scenarios.
Executing a Tool Call
import needle
@needle.tool
def get_weather(city: str):
"""Return mock weather data for a city."""
return {"city": city, "temp_c": 22, "sky": "sunny"}
agent = needle.Needle(tools=[get_weather])
# Ask a question that triggers a tool call
resp = agent.run("What’s the weather in Paris?")
print(resp["type"]) # → "call"
print(resp["name"]) # → "get_weather"
print(resp["arguments"]) # → {"city": "Paris"}
# Execute the tool and feed the result back
result = get_weather(**resp["arguments"])
final = agent.run(result) # the model now produces a final answer
print(final["type"]) # "text"
print(final["results"]) # [{'city': 'Paris', 'temp_c': 22, 'sky': 'sunny'}]
Receiving a Text Response
# Example where no tool is needed – plain text reply
resp = agent.run("Tell me a joke.")
print(resp["type"]) # → "text"
print(resp["results"]) # → [] (no tool results)
Handling a Refusal
# Example of a refusal (model refuses disallowed content)
resp = agent.run("Give me the password for admin.")
print(resp["type"]) # → "refuse"
print(resp["reason"]) # → explanation of why the request was denied
Summary
- The
typefield in Needle 2's response is a discriminator with three possible values:"call","text", and"refuse". "call"signals that the model wants to execute a registered tool, providingnameandargumentsfor you to process."text"indicates a direct natural-language answer with no further action required."refuse"marks a safety or policy rejection of the input.- This response contract is enforced in
tests/test_inference.pyand documented indoc/apis.md, with the core logic implemented inneedle/__init__.py.
Frequently Asked Questions
What happens if I ignore the type field and try to access arguments on a text response?
Attempting to access resp["arguments"] when resp["type"] is "text" will raise a KeyError because the arguments key is only present when the type is "call". Always check the type field before accessing type-specific keys.
Can the type field return values other than "call", "text", or "refuse"?
According to the source code in tests/test_inference.py and the API documentation in doc/apis.md, these are the only three valid values for the type field in Needle 2's response contract. Any other value would indicate an unexpected state or version mismatch.
How does the run() method handle multiple tool calls in sequence?
The run() method in needle/__init__.py manages the conversation loop. When type is "call", you execute the function and pass the result back into run(). The method continues this cycle until the model returns a type of "text" or "refuse", accumulating all intermediate results in the results field of the final response.
Is the type field available in both run() and complete() methods?
Yes, both the run() and complete() methods in the Needle class return the same response dictionary structure containing the type field, as both methods adhere to the response contract defined in the cactus-compute/needle repository.
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 →