JSON Envelope Returned by Needle 2 complete(): Structure and Fields
Needle 2's complete() method returns a JSON envelope containing fields like type, text (or content), function_calls for tool invocations, and a confidence field injected by the Python wrapper.
The cactus-compute/needle repository provides a lightweight inference engine that exposes a Python API for text completion and tool calling. Understanding the JSON envelope returned by Needle 2's complete() function is essential for parsing model responses, handling tool calls, and integrating the engine into production applications.
JSON Envelope Structure
When you invoke Needle.complete(), the underlying C library (needle_complete) writes a JSON-encoded envelope into a pre-allocated buffer. The Python wrapper decodes this buffer into a dictionary with the following optional fields:
Response Type and Content Fields
The envelope always includes a type field that describes the response category:
"answer"– Standard text generation with no tool invocation"call"– The model has decided to invoke one or more tools- Custom strings depending on the engine configuration
The generated prose appears in either text or content (the exact key varies by engine version). This field contains the raw model output when type is not "call".
Tool Invocation Fields
When type equals "call", the envelope includes a function_calls array. Each object in this array contains:
name– The tool identifier (string)arguments– A JSON object containing the parameters for the tool call
These objects map directly to the schemas defined in needle/agent/tools.py.
Confidence Calibration Field
The Python wrapper adds a confidence field (float or null) only when a fine-tuned weight file is loaded. Because the confidence head is not calibrated for tuned models, the wrapper explicitly sets this value to null in Needle._complete.
Additional Metadata
The engine may pass through other keys (e.g., model, usage) unchanged. The wrapper does not modify these custom fields.
How the Envelope Is Built in the Source Code
The construction of the JSON envelope follows a specific path through the codebase:
-
Needle.complete()forwards the request to the private method_complete()(lines 19-22 ofneedle/__init__.py) -
_complete()calls the low-level C library functionneedle_completeand decodes the buffer as JSON (lines 24-31) -
Confidence injection occurs when
self._weightsis present (lines 35-37), where the wrapper addsresponse["confidence"] = None
The same envelope structure propagates through needle/playground/server.py (lines 30-39), where the server calls engine.complete() and returns the result to HTTP clients.
Practical Code Examples
Basic Text Completion
For standard generation without tools, the envelope contains the generated text and a null confidence score:
from needle import Needle
agent = Needle()
result = agent.complete("Tell me a short joke.")
print(result["text"]) # → "Why did the scarecrow win an award?"
print(result["type"]) # → "answer"
print(result["confidence"]) # → null
Tool-Calling Completion
When the model invokes tools, the envelope contains the function_calls array:
from needle import Needle, tool
@tool
def get_weather(city: str) -> dict:
return {"city": city, "temp_c": 22}
agent = Needle(tools=[get_weather])
result = agent.complete("What's the weather in Paris?")
print(result["type"]) # → "call"
print(result["function_calls"]) # → [{"name": "get_weather", "arguments": {"city": "Paris"}}]
Multi-Step Agent Execution
When using the higher-level run() method, the system collects intermediate results and adds them to the final envelope:
agent = Needle(tools=[get_weather])
out = agent.run("Plan a picnic in Paris.")
# The envelope includes final response plus execution history
print(out["results"]) # → List of function call results collected during the run
Summary
- The JSON envelope returned by
Needle.complete()containstype,text(orcontent), and optionallyfunction_callsandconfidence - The
typefield distinguishes between direct answers ("answer") and tool invocations ("call") function_callsprovides structured tool invocation data when the model decides to use external functions- The
confidencefield is injected by the Python wrapper inneedle/__init__.pyonly when fine-tuned weights are loaded, always set tonullfor tuned models - The underlying C library (
needle_complete) generates the raw JSON, which the Python wrapper decodes and augments before returning to the caller
Frequently Asked Questions
What is the difference between the text and content fields in the Needle 2 JSON envelope?
The envelope may use either text or content as the key for generated prose depending on the specific engine version you are running. Both keys serve the same purpose: they contain the raw text generated by the model when no tool call is required. Your application should check for both keys or consult the engine documentation for your specific version.
Why is the confidence field always null in my Needle 2 responses?
According to the source code in needle/__init__.py (lines 35-37), the Python wrapper adds the confidence field only when a fine-tuned weight file is loaded via self._weights. Because the confidence head is not calibrated for fine-tuned models, the wrapper explicitly sets this value to null to indicate that the confidence score is unavailable or unreliable.
How does Needle 2 handle multiple tool calls in a single completion?
When the model decides to invoke multiple tools simultaneously, the type field is set to "call" and the function_calls array contains multiple objects. Each object includes a name string identifying the tool and an arguments object containing the parameters. Your application must iterate through this array to execute all requested tool calls.
Where in the source code is the JSON envelope actually constructed?
The envelope originates in the low-level C library function needle_complete, which writes JSON into a pre-allocated buffer. The Python wrapper in needle/__init__.py (specifically the _complete method at lines 19-38) decodes this buffer and conditionally adds the confidence field before returning the final dictionary to the caller.
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 →