needle / Dockerfile
Leon4gr45's picture
Upload folder using huggingface_hub
9af7d99 verified
Raw History Blame Contribute Delete
3.88 kB
FROM python:3.11-slim AS dependencies
ENV PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
NEEDLE_TELEMETRY=0 \
DO_NOT_TRACK=1 \
NEEDLE_INFERENCE_CONCURRENCY=1 \
NEEDLE_MAX_QUEUE_SIZE=16 \
NEEDLE_BODY_CONCURRENCY=16 \
NEEDLE_CONTEXT_BUDGET=2048 \
NEEDLE_STATE_BYTES=4194304
# Official Python slim already includes CA roots; verify them rather than
# adding a redundant network-dependent apt layer. Never disable TLS validation.
RUN python -c "import ssl; assert ssl.create_default_context().cert_store_stats()['x509_ca'] > 0"
WORKDIR /srv
COPY requirements.txt /srv/requirements.txt
# Optional cloud proxy CA bundle is mounted only for this build step. It is
# never baked into the image and verification remains enabled.
RUN --mount=type=secret,id=cloud_ca \
if [ -f /run/secrets/cloud_ca ]; then \
export PIP_CERT=/run/secrets/cloud_ca SSL_CERT_FILE=/run/secrets/cloud_ca; \
fi; \
pip install --no-cache-dir -r requirements.txt
# Local CPU regression target, independent of model download availability.
FROM dependencies AS tests
COPY requirements-dev.txt /srv/requirements-dev.txt
RUN --mount=type=secret,id=cloud_ca \
if [ -f /run/secrets/cloud_ca ]; then export PIP_CERT=/run/secrets/cloud_ca; fi; \
pip install --no-cache-dir -r requirements-dev.txt
COPY gateway.py models.py registry.py laya.py context_adapter.py decision_policy.py request_limits.py intent_guard.py payload_transport.py native_schema.py headroom_evaluation.py /srv/
COPY tests /srv/tests
COPY benchmarks/intent/development.json /srv/benchmarks/intent/development.json
COPY benchmarks/coverage/development.json /srv/benchmarks/coverage/development.json
COPY pytest.ini /srv/pytest.ini
ENV NEEDLE3_LIB_PATH=/nonexistent/needle3.so HF_HUB_OFFLINE=1
CMD ["python", "-m", "pytest", "-q", "tests"]
FROM dependencies AS runtime
# Bake the Needle 3 engine library and base needle3.cact weights into the
# image at Needle's own default cache-directory convention
# (~/.cache/cactus-needle/v3/<engine-version>/), so `needle.Needle(...)`
# resolves both locally with no network call at container start/restart.
#
# We deliberately do NOT pass an explicit weights= path to Needle() at
# runtime (see gateway.py): cactus-needle==3.0.1 treats any explicit
# `weights=` as a tuned checkpoint and permanently disables the calibrated
# confidence head, which this service's routing policy depends on. Baking
# into the default cache dir keeps both "no network at runtime" and a
# calibrated confidence score. The Dockerfile stays root/HOME=/root for
# the whole build and the running container so this cache path is the
# same one Needle looks up at request time.
RUN --mount=type=secret,id=cloud_ca \
if [ -f /run/secrets/cloud_ca ]; then \
export SSL_CERT_FILE=/run/secrets/cloud_ca REQUESTS_CA_BUNDLE=/run/secrets/cloud_ca; \
fi; \
NEEDLE_CACHE_DIR="$(python -c 'from needle.agent import fetch; print(fetch.cache_dir(3))')" \
&& mkdir -p "$NEEDLE_CACHE_DIR" \
&& needle fetch --generation 3 \
&& needle download needle3 --generation 3 --out "$NEEDLE_CACHE_DIR"
# HF_HUB_OFFLINE=1 makes a missing/misconfigured cache fail fast at
# startup instead of silently reaching the network.
ENV HF_HUB_OFFLINE=1
# Keep the exact official base assets used for the baseline comparison. An
# upstream asset change fails the build rather than silently changing Needle.
COPY needle-assets.sha256 /srv/needle-assets.sha256
RUN NEEDLE_CACHE_DIR="$(python -c 'from needle.agent import fetch; print(fetch.cache_dir(3))')" \
&& cd "$NEEDLE_CACHE_DIR" \
&& sha256sum --check /srv/needle-assets.sha256
COPY gateway.py models.py registry.py laya.py context_adapter.py decision_policy.py request_limits.py intent_guard.py payload_transport.py native_schema.py start.sh /srv/
RUN chmod +x /srv/start.sh
EXPOSE 7860
ENTRYPOINT ["/srv/start.sh"]