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:

  1. Needle.complete() forwards the request to the private method _complete() (lines 19-22 of needle/__init__.py)

  2. _complete() calls the low-level C library function needle_complete and decodes the buffer as JSON (lines 24-31)

  3. Confidence injection occurs when self._weights is present (lines 35-37), where the wrapper adds response["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() contains type, text (or content), and optionally function_calls and confidence
  • The type field distinguishes between direct answers ("answer") and tool invocations ("call")
  • function_calls provides structured tool invocation data when the model decides to use external functions
  • The confidence field is injected by the Python wrapper in needle/__init__.py only when fine-tuned weights are loaded, always set to null for 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:

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 →