build: the agent installs one CUDA-13 stack instead of two, the web image drops ML packages it never imported, and Redis moves to 8 (1451, 1452)
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
extension / lint (push) Successful in 16s
CI and images / frontend-build (push) Successful in 19s
CI and images / backend-lint-and-test (push) Successful in 31s
CI and images / integration (push) Successful in 2m22s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-web (push) Successful in 3m7s
CI and images / smoke-web (push) Successful in 59s
CI and images / build-agent (push) Successful in 6m41s
CI and images / promote (push) Successful in 2s

Agent:
- The image ran PyPI's CUDA-13 torch 2.14 and onnxruntime-gpu 1.30 on a
  CUDA 12.9 cudnn-runtime base. requirements.txt had silently replaced the
  Dockerfile's torch 2.6+cu124, because ultralytics pulls torchvision, which
  pulls its own torch. That left ~3 GB of base libraries and a ~3 GB torch
  nothing loaded: 10 GB compressed.
- Now: an nvidia/cuda 13.0.3 `base` image, with torch and torchvision
  installed together from cu130. CUDA and cuDNN come from the nvidia-* pip
  packages; onnxruntime-gpu declares its [cuda,cudnn] extras.
- fc_agent/accel.py preloads those libraries for onnxruntime. It then logs,
  and reports in /status, whether torch and the ONNX CUDA provider actually
  got the GPU, since both fall back to the CPU silently.

Web image:
- Drop opencv-python-headless and onnxruntime, plus the opencv-only apt libs.
  Both have been listed since the scaffold and nothing in backend/ imports
  them.
- torch/torchvision move to 2.14/0.29, and the unexplained caps are lifted
  (rule 154).

Redis: 8-alpine in both compose files and both CI service containers. That
gives an AGPLv3 licence option, where 7.4 was RSAL/SSPL only. The client
moves to >=8.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
This commit is contained in:
2026-09-24 17:45:39 -04:00
co-authored by Claude Opus 5.5
parent 2587421f5b
commit 7a09dc3cda
12 changed files with 220 additions and 41 deletions
+75
View File
@@ -0,0 +1,75 @@
"""The agent's startup report of which runtime landed on the GPU (#1451).
Both runtimes fall back to the CPU without raising, so the report is the only
thing that says so. These pin the distinction it exists for: onnxruntime
listing the CUDA provider is not the same as the provider being able to load
its libraries.
"""
from __future__ import annotations
import types
from agent.fc_agent import accel
def _ort(providers, preload=None):
mod = types.SimpleNamespace(
__version__="1.30.0",
__file__="/site/onnxruntime/__init__.py",
get_available_providers=lambda: providers,
)
if preload is not None:
mod.preload_dlls = preload
return mod
def _imp(mod):
return lambda name: mod
def test_onnx_on_gpu_when_the_cuda_provider_loads():
calls = []
s = accel.onnx_status(
_imp(_ort(["CUDAExecutionProvider", "CPUExecutionProvider"], lambda: calls.append("preload"))),
load=lambda path, mode=0: calls.append(path),
)
assert s["device"] == "cuda"
assert calls[0] == "preload"
assert calls[-1].endswith("capi/libonnxruntime_providers_cuda.so")
def test_onnx_listed_but_unloadable_reports_cpu_with_the_reason():
def load(path, mode=0):
if path.endswith("providers_cuda.so"):
raise OSError("libcudart.so.13: cannot open shared object file")
s = accel.onnx_status(_imp(_ort(["CUDAExecutionProvider", "CPUExecutionProvider"])), load=load)
assert s["device"] == "cpu"
assert "libcudart.so.13" in s["error"]
def test_onnx_cpu_build_never_tries_the_cuda_library():
def load(path, mode=0):
raise AssertionError("a CPU build has no CUDA provider to load")
s = accel.onnx_status(_imp(_ort(["CPUExecutionProvider"])), load=load)
assert s["device"] == "cpu"
def test_torch_reports_cpu_when_cuda_is_unavailable():
torch = types.SimpleNamespace(
__version__="2.14.0+cu130",
version=types.SimpleNamespace(cuda="13.0"),
cuda=types.SimpleNamespace(is_available=lambda: False),
)
s = accel.torch_status(_imp(torch))
assert s == {"version": "2.14.0+cu130", "cuda_build": "13.0", "device": "cpu"}
def test_a_missing_runtime_is_reported_not_raised():
def imp(name):
raise ImportError(f"No module named {name!r}")
assert accel.torch_status(imp)["device"] == "unavailable"
assert accel.onnx_status(imp)["device"] == "unavailable"