atakan Claude Opus 5 commited on
Commit
e384d86
·
1 Parent(s): 0f20891

fix: Unpin the Space's transformers -- the pin made the build unsolvable

Browse files

The 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 CHANGED
@@ -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.
controlai_agent/engine_torch.py CHANGED
@@ -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
- "torch_dtype": torch.bfloat16 if cuda else torch.float32,
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:])
controlai_rag/embeddings.py CHANGED
@@ -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
- torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
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()
requirements-space.txt CHANGED
@@ -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
- # <4.56: engine_torch passes `torch_dtype=`, which the newer releases renamed.
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
- gradio>=4.44.0 # only for the ZeroGPU probe
15
- spaces>=0.30.0
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