FROM python:3.12-slim

ENV PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1 \
    UV_HTTP_RETRIES=8 \
    UV_HTTP_TIMEOUT=180

WORKDIR /app

RUN apt-get update && \
    apt-get install -y --no-install-recommends libgl1 libglib2.0-0 && \
    rm -rf /var/lib/apt/lists/*

RUN pip install --upgrade pip setuptools wheel uv

# Install dependencies declared by the local packages before copying their
# frequently-changing source. This keeps the expensive policy stack cached when
# only Armnet runtime code changes.
COPY armnet-package-requirements.txt /tmp/armnet-package-requirements.txt
RUN uv pip install --system -r /tmp/armnet-package-requirements.txt

RUN printf 'pynput>=0.0.0; sys_platform == "never"\nevdev>=0.0.0; sys_platform == "never"\ntorch==2.8.0\ntorchvision==0.23.0\ntransformers==5.3.0\n' > /tmp/overrides.txt

RUN uv pip install --system \
        --override /tmp/overrides.txt \
        --extra-index-url https://download.pytorch.org/whl/cu129 \
        --index-strategy unsafe-best-match \
        torch==2.8.0 torchvision==0.23.0

RUN uv pip install --system \
        --override /tmp/overrides.txt \
        --extra-index-url https://download.pytorch.org/whl/cu129 \
        --index-strategy unsafe-best-match \
        'transformers[vision]==5.3.0'

RUN uv pip install --system \
        --override /tmp/overrides.txt \
        --extra-index-url https://download.pytorch.org/whl/cu129 \
        --index-strategy unsafe-best-match \
        'lerobot[feetech,smolvla]==0.5.1' \
        accelerate numpy pillow opencv-python-headless safetensors scipy && \
    python -c "import torch, torchvision; from transformers.models.auto.processing_auto import AutoProcessor; print(torch.__version__, torchvision.__version__)"

# Install the armnet packages after the stable third-party dependency layers.
# A build from a checkout stages their source here and installs it; a build from
# a published armnet-client stages nothing, having named the wheels in the
# requirements file above. armnet-busybox — which reads the instrumented task box
# over MQTT, and is not in runtime/, which stays pydantic-only — only exists in
# the monorepo, so a customer's image simply goes without it and the runtime
# falls back to the operator for scoring and resets.
COPY armnet-packages /app/armnet-packages
COPY install-armnet-packages.sh /app/install-armnet-packages.sh
RUN sh /app/install-armnet-packages.sh

# Patch the installed LeRobot diffusion policy to accept heterogeneous camera resolutions
# (same patch used to train these policies). Must run after lerobot is installed and before
# the runtime imports it. Fails the build loudly on lerobot version drift.
COPY diffusion_resolution_patch.py /app/diffusion_resolution_patch.py
RUN python /app/diffusion_resolution_patch.py

# Install MolmoAct2 as a 3rd-party lerobot plugin (it only ships in lerobot `main`, not 0.5.1).
# Vendors policies/molmoact2 (+ hf_model) from a pinned lerobot commit and registers it.
# Must run after lerobot is installed; fails the build loudly on lerobot version drift.
COPY install_molmoact2_plugin.py /app/install_molmoact2_plugin.py
RUN python /app/install_molmoact2_plugin.py

COPY armnet_client /app/armnet_client
COPY lerobot_eval_runtime.py /app/lerobot_eval_runtime.py

CMD ["armnet-runtime", "/app/lerobot_eval_runtime.py"]
