needle-openai
An OpenAI-compatible HTTP API in front of Needle 2 — Cactus Compute's 45M-parameter model for tool calling, device use and structured extraction. Point any OpenAI client at it and get function calls back from a 14MB model that runs on CPU in ~100MB of RAM.
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="not-needed")
response = client.chat.completions.create(
model="needle-2",
messages=[{"role": "user", "content": "what's it like in Lagos right now?"}],
tools=[
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}
],
)
print(response.choices[0].message.tool_calls[0].function)
# Function(arguments='{"city": "Lagos"}', name='get_weather')
[!IMPORTANT] Needle 2 is not a chat model. It emits tool calls or nothing at all — it has no free-form generation head. Read the fidelity notes before building on this; they list every place the OpenAI mapping is lossy and the two failure modes worth guarding against.
Quickstart
docker run -d -p 8000:8000 -v needle-cache:/cache ghcr.io/sirmmo/needle-openai:latest
curl -s localhost:8000/health
Or from a clone:
docker compose up -d
Or as a Python package (needs Python ≥3.10):
pip install needle-openai
pip install --no-deps cactus-needle==2.0.3 # see "Why --no-deps" in the docs
needle-openai --port 8000
First start downloads the native engine and weights from HuggingFace into
/cache — a few tens of MB, ~6s on a warm connection, cached across restarts.
Runnable examples: examples/openai_client.py and
examples/curl.sh.
What works
| Tool calling | tools / functions, parallel calls, the full agent loop. |
| Structured extraction | response_format with a JSON Schema → typed objects. |
| Streaming | SSE chunks, synthesized from the finished result. |
| Confidence gating | Calibrated 0–1 score on every response via x_needle. |
| Tuned weights | Serve a fine-tuned .cact with NEEDLE_WEIGHTS. |
| Auth | Optional bearer token; /health stays open. |
Endpoints
| Endpoint | Notes |
|---|---|
POST /v1/chat/completions |
Tools, streaming, structured output. |
POST /v1/completions |
Legacy text completion. |
GET /v1/models, GET /v1/models/{id} |
Model discovery. |
POST /v1/needle/extract |
Native extraction: text + JSON Schema → object. |
POST /v1/needle/complete |
Passthrough returning the engine's raw response. |
GET /health |
Readiness, queue depth, token-count mode. |
Full details in the API reference.
Key things to know
A short version of the fidelity notes:
- No free-form text. When no tool is called, the model's
reasoningtrace is returned ascontent. Asked"hello, who are you?"it replies "No tool available to query location or contact info." - Deterministic.
temperature,top_p,seedandnare accepted, ignored, and reported inx_needle.warnings. - One request at a time per container. The native engine is a single global session that segfaults under concurrent use, so everything serializes through one thread. 24 concurrent requests complete correctly in ~4.2s; scale by running more containers.
- Long inputs truncate silently and return a confident-looking wrong answer
with
confidence: 0.0. Gate onconfidence. response_format: {"type": "json_object"}returns 400 — Needle needs an explicit schema.
Development
pip install -r requirements.txt pytest httpx ruff
pytest # 57 tests, ~1s, no model download (fake engine)
docker compose up -d # live suite against the real engine
NEEDLE_TEST_BASE_URL=http://127.0.0.1:8000 pytest -m live
See Development and CONTRIBUTING.md.
License
MIT — see LICENSE. Needle 2 and its weights are licensed by Cactus Compute.
Metadata
Release files for needle-openai 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| needle_openai-0.1.1.tar.gz | 30.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| needle_openai-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.5 kB
Release files / needle_openai-0.1.1.tar.gz
| Download URL | needle_openai-0.1.1.tar.gz |
|---|---|
| Size | 30.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cb05784380564218a5e6b5e11b1fb0c651b522c1d0743c6a12edb3189c95cae0
|
|
BLAKE2b-256 checksum How to use checksums |
8bb5657607a8e0de3ab2e2b36ee59042ef56ea339c2963d9f963d94cee242502
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / needle_openai-0.1.1-py3-none-any.whl
| Download URL | needle_openai-0.1.1-py3-none-any.whl |
|---|---|
| Size | 25.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
79eff434e7850b772423bc90c26d4065910bea2382089d466b87020a56e08971
|
|
BLAKE2b-256 checksum How to use checksums |
960620c7956c03c5c32445feace007fa56a6060ecb6f2334285e6d44729fd9bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency log