Spaces:
Running on Zero
fix: Unpin the Space's transformers -- the pin made the build unsolvable
Browse filesThe Space build failed with ResolutionImpossible. The platform appends its own
gradio[oauth,mcp]==6.25.0 to whatever requirements.txt asks for, gradio 6.x
requires huggingface-hub>=1.16, and every transformers<4.56 requires <1.0. The
only reason for that pin was engine_torch passing torch_dtype=, which
transformers renamed to dtype= in 4.56.
dtype_kwarg() picks the spelling from the installed version instead, so nothing
needs pinning; embeddings.py carries the same two-line check rather than
importing it, to keep controlai_rag from depending on controlai_agent. gradio,
spaces and huggingface-hub are dropped from the file entirely -- the platform
injects all three, and listing them only adds constraints to conflict with.
Since the file no longer pins transformers at all, _align_cache now tolerates a
DynamicCache without crop(): it re-prefills the whole prompt instead, losing the
prefix reuse but not correctness.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- CLAUDE.md +8 -0
- controlai_agent/engine_torch.py +25 -3
- controlai_rag/embeddings.py +8 -1
- requirements-space.txt +8 -5
|
@@ -207,6 +207,14 @@ and silently offloads to CPU.
|
|
| 207 |
with `_share_cuda_: only available on CUDA` after emitting nothing — which reads exactly like
|
| 208 |
"just slow". Reach the agent through the module global.
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
The Space needs `HF_TOKEN` as a secret: the retrieval index is in a private dataset repo and
|
| 211 |
`app_space.py::_fetch_index` pulls it at startup. Without it the Space still boots, and answers
|
| 212 |
from model knowledge alone.
|
|
|
|
| 207 |
with `_share_cuda_: only available on CUDA` after emitting nothing — which reads exactly like
|
| 208 |
"just slow". Reach the agent through the module global.
|
| 209 |
|
| 210 |
+
**Do not put an upper bound in `requirements-space.txt`.** The platform appends its own
|
| 211 |
+
`gradio[oauth,mcp]`, `spaces`, `uvicorn` and a `torch` ceiling to whatever that file asks for, and
|
| 212 |
+
one extra constraint can make the resolve impossible. Pinning `transformers<4.56` — to keep using
|
| 213 |
+
the `torch_dtype=` kwarg it renamed — failed the build outright, because gradio 6.x requires
|
| 214 |
+
`huggingface-hub>=1.16` and every `transformers<4.56` requires `<1.0`. `engine_torch.dtype_kwarg()`
|
| 215 |
+
detects the spelling instead, and `_align_cache` falls back to a full re-prefill if `DynamicCache`
|
| 216 |
+
has no `crop()`, so an unpinned transformers costs speed rather than correctness.
|
| 217 |
+
|
| 218 |
The Space needs `HF_TOKEN` as a secret: the retrieval index is in a private dataset repo and
|
| 219 |
`app_space.py::_fetch_index` pulls it at startup. Without it the Space still boots, and answers
|
| 220 |
from model knowledge alone.
|
|
@@ -34,6 +34,22 @@ from typing import Any, Generator, Iterable, Sequence
|
|
| 34 |
|
| 35 |
from controlai_agent.engine import Chunk, SamplingConfig, Stats
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
# The MLX default is a 4-bit MLX conversion, which transformers cannot read.
|
| 38 |
# This is the same weights in a format it can, already quantised to NF4: ~9GB to
|
| 39 |
# download rather than the ~28GB of the bf16 Qwen/Qwen3-14B, and no quantisation
|
|
@@ -67,10 +83,8 @@ class TorchEngine:
|
|
| 67 |
# module docstring. The CPU branch exists only so the decode loop can be
|
| 68 |
# exercised on a small model off a GPU box; it is far too slow to serve.
|
| 69 |
cuda = torch.cuda.is_available()
|
| 70 |
-
# `torch_dtype`, not `dtype`: the newer spelling only exists from
|
| 71 |
-
# transformers 4.56, and requirements-space.txt pins older than that.
|
| 72 |
kwargs: dict[str, Any] = {
|
| 73 |
-
|
| 74 |
"device_map": {"": 0} if cuda else "cpu",
|
| 75 |
}
|
| 76 |
if load_in_4bit and not cuda:
|
|
@@ -203,6 +217,14 @@ class TorchEngine:
|
|
| 203 |
return list(tokens)
|
| 204 |
|
| 205 |
if shared < len(self._cache_tokens):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 206 |
self._cache.crop(shared)
|
| 207 |
self._cache_tokens = list(tokens[:shared])
|
| 208 |
return list(tokens[shared:])
|
|
|
|
| 34 |
|
| 35 |
from controlai_agent.engine import Chunk, SamplingConfig, Stats
|
| 36 |
|
| 37 |
+
|
| 38 |
+
def dtype_kwarg(dtype: Any) -> dict[str, Any]:
|
| 39 |
+
"""`{"dtype": ...}` or `{"torch_dtype": ...}`, whichever this release takes.
|
| 40 |
+
|
| 41 |
+
transformers renamed the argument in 4.56 and the old spelling is gone in
|
| 42 |
+
recent releases. Pinning below 4.56 to keep using it is what broke the Space
|
| 43 |
+
build: the platform force-installs gradio 6.x, which requires
|
| 44 |
+
huggingface-hub >= 1.16, while every transformers < 4.56 requires < 1.0.
|
| 45 |
+
Detecting the spelling costs two lines and pins nothing.
|
| 46 |
+
"""
|
| 47 |
+
import transformers
|
| 48 |
+
|
| 49 |
+
major, minor = (int(x) for x in transformers.__version__.split(".")[:2])
|
| 50 |
+
key = "dtype" if (major, minor) >= (4, 56) else "torch_dtype"
|
| 51 |
+
return {key: dtype}
|
| 52 |
+
|
| 53 |
# The MLX default is a 4-bit MLX conversion, which transformers cannot read.
|
| 54 |
# This is the same weights in a format it can, already quantised to NF4: ~9GB to
|
| 55 |
# download rather than the ~28GB of the bf16 Qwen/Qwen3-14B, and no quantisation
|
|
|
|
| 83 |
# module docstring. The CPU branch exists only so the decode loop can be
|
| 84 |
# exercised on a small model off a GPU box; it is far too slow to serve.
|
| 85 |
cuda = torch.cuda.is_available()
|
|
|
|
|
|
|
| 86 |
kwargs: dict[str, Any] = {
|
| 87 |
+
**dtype_kwarg(torch.bfloat16 if cuda else torch.float32),
|
| 88 |
"device_map": {"": 0} if cuda else "cpu",
|
| 89 |
}
|
| 90 |
if load_in_4bit and not cuda:
|
|
|
|
| 217 |
return list(tokens)
|
| 218 |
|
| 219 |
if shared < len(self._cache_tokens):
|
| 220 |
+
# crop() is what makes prefix reuse possible. It has moved around
|
| 221 |
+
# between transformers releases and this file no longer pins a
|
| 222 |
+
# version, so losing it costs speed, not correctness: fall back to
|
| 223 |
+
# re-prefilling the whole prompt.
|
| 224 |
+
if not hasattr(self._cache, "crop"):
|
| 225 |
+
self._cache = DynamicCache()
|
| 226 |
+
self._cache_tokens = []
|
| 227 |
+
return list(tokens)
|
| 228 |
self._cache.crop(shared)
|
| 229 |
self._cache_tokens = list(tokens[:shared])
|
| 230 |
return list(tokens[shared:])
|
|
@@ -60,9 +60,16 @@ class Embedder:
|
|
| 60 |
from transformers import AutoModel, AutoTokenizer
|
| 61 |
|
| 62 |
self._tokenizer = AutoTokenizer.from_pretrained(self.model_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
self._model = AutoModel.from_pretrained(
|
| 64 |
self.model_id,
|
| 65 |
-
|
| 66 |
)
|
| 67 |
self._model = self._model.to("cuda" if torch.cuda.is_available() else "cpu")
|
| 68 |
self._model.eval()
|
|
|
|
| 60 |
from transformers import AutoModel, AutoTokenizer
|
| 61 |
|
| 62 |
self._tokenizer = AutoTokenizer.from_pretrained(self.model_id)
|
| 63 |
+
# transformers renamed torch_dtype -> dtype in 4.56; the Space
|
| 64 |
+
# resolves to whatever gradio's huggingface-hub floor allows, so
|
| 65 |
+
# detect rather than pin. See engine_torch.dtype_kwarg.
|
| 66 |
+
import transformers
|
| 67 |
+
|
| 68 |
+
_v = tuple(int(x) for x in transformers.__version__.split(".")[:2])
|
| 69 |
+
_key = "dtype" if _v >= (4, 56) else "torch_dtype"
|
| 70 |
self._model = AutoModel.from_pretrained(
|
| 71 |
self.model_id,
|
| 72 |
+
**{_key: torch.float16 if torch.cuda.is_available() else torch.float32},
|
| 73 |
)
|
| 74 |
self._model = self._model.to("cuda" if torch.cuda.is_available() else "cpu")
|
| 75 |
self._model.eval()
|
|
@@ -4,16 +4,19 @@
|
|
| 4 |
# through controlai_agent/engine_torch.py instead. Do NOT install this file
|
| 5 |
# locally: requirements.txt is the Apple Silicon runtime and is MLX-only.
|
| 6 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
torch>=2.4.0
|
| 8 |
-
|
| 9 |
-
transformers>=4.51.0,<4.56
|
| 10 |
accelerate>=0.30.0
|
| 11 |
bitsandbytes>=0.43.0 # 4-bit NF4; CUDA-only
|
| 12 |
sentencepiece>=0.2.0
|
| 13 |
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
huggingface-hub>=0.23.0
|
| 17 |
|
| 18 |
# Everything below is shared with requirements.txt (minus mlx-lm).
|
| 19 |
numpy>=1.24.0
|
|
|
|
| 4 |
# through controlai_agent/engine_torch.py instead. Do NOT install this file
|
| 5 |
# locally: requirements.txt is the Apple Silicon runtime and is MLX-only.
|
| 6 |
|
| 7 |
+
# Deliberately unpinned above the floor. The Space platform force-installs its
|
| 8 |
+
# own gradio, spaces, uvicorn and a torch ceiling on top of this file, and any
|
| 9 |
+
# upper bound here can make the resolve impossible -- pinning transformers <4.56
|
| 10 |
+
# did exactly that, because gradio 6.x needs huggingface-hub >=1.16 and every
|
| 11 |
+
# transformers <4.56 needs <1.0.
|
| 12 |
torch>=2.4.0
|
| 13 |
+
transformers>=4.51.0
|
|
|
|
| 14 |
accelerate>=0.30.0
|
| 15 |
bitsandbytes>=0.43.0 # 4-bit NF4; CUDA-only
|
| 16 |
sentencepiece>=0.2.0
|
| 17 |
|
| 18 |
+
# gradio, spaces and huggingface-hub are injected by the platform at build
|
| 19 |
+
# time; listing them here only adds constraints that can conflict with it.
|
|
|
|
| 20 |
|
| 21 |
# Everything below is shared with requirements.txt (minus mlx-lm).
|
| 22 |
numpy>=1.24.0
|