Files
club-3090/scripts/lib/profiles/deriver.py
T
noonghunnaandClaude Opus 4.7 344ab87dd3 fix(deriver): correct stale "GGUF not supported until v0.8.1" message — now misleading post-v0.8.1-ship
deriver.py:343 and :743 told users GGUF/.bin is "not supported until
v0.8.1". v0.8.1 has shipped (the fix/docs-fidelity stack) and GGUF was
deliberately de-scoped from the v0.8.2 feature work too (cross-engine
serving = a deferred §2/§9 design-unlock, not a near-term version). The
strings actively mislead users on master ("wait for v0.8.1" — which
exists and won't add it). Re-anchored both to accurate, version-free
wording: GGUF/.bin not supported — this path is vLLM + safetensors only.
String-only; zero decision-logic change. Surfaced by the v0.8.2 brief
r1 review (Major finding). Same docs-fidelity class as the v0.8.1 stack.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
2026-05-18 11:38:12 +00:00

858 lines
32 KiB
Python

"""v0.8.0 Pull-Gate — `[A]` transformers deriver.
Given an HF repo slug, derive a ModelProfile-shaped spec from the repo's own
`config.json` + HF Hub model API (`?blobs=true` for LFS-resolved sizes) +
a bounded, pre-download safetensors-header probe. This is the `[A]` slice
that produces the spec P1's generic-dense `[B]` branch consumes.
Public API (stable for P3/P4):
from scripts.lib.profiles import deriver
res = deriver.derive(slug, *, hf_token=None, hf_home=None, fetcher=None,
profiles=None)
# res: DeriveResult
# .error -> DeriverError | None (stratum-1 structured error)
# .tier1 -> Tier1Match | None (curated lookup hit)
# .confidence -> Confidence enum
# .generic_dense_eligible -> bool | None
# .spec -> dict | None (kv-calc generic-dense spec shape)
# .profile -> dict | None (derived ModelProfile-shaped dict)
P2 ONLY classifies. The stratum-5 `no-fit-model` abort, `[C0]`/`[C2a]`/`[C1]`
and the orchestrator are P3/P4 — this module never raises a traceback for a
stratum-1 condition; it returns a structured `DeriverError`.
Network: all HTTP goes through an injectable `fetcher` (see `HttpFetcher`).
Tests pass a recorded-fixture fetcher so there is NO live network and NO
weight file is ever downloaded — the header probe is range-bounded.
How P1's kv-calc is imported (per the in-file import contract at
`tools/kv-calc.py` ~line 645): via importlib, registering the module in
`sys.modules["kv_calc"]` BEFORE `exec_module` so `@dataclass` resolves
`cls.__module__`. See `_load_kv_calc()`.
"""
from __future__ import annotations
import importlib.util
import json
import os
import struct
import sys
import urllib.error
import urllib.request
from dataclasses import dataclass, field
from enum import Enum
from pathlib import Path
from typing import Any, Callable, Optional
REPO_ROOT = Path(__file__).resolve().parents[3]
_HF_API = "https://huggingface.co/api/models"
_HF_RESOLVE = "https://huggingface.co"
_NET_TIMEOUT = 30 # seconds (per brief)
_MAX_HEADER_BYTES = 16 * 1024 * 1024 # 16 MiB safetensors-header ceiling
# Name patterns that mark a *.safetensors blob as an adapter/LoRA, not a
# complete weight set. Matched case-insensitively on the basename.
_ADAPTER_PATTERNS = (
"adapter_model",
"adapter-model",
"lora",
"/adapter",
)
# ---------------------------------------------------------------------------
# Structured stratum-1 errors (NEVER raised as raw tracebacks)
# ---------------------------------------------------------------------------
class DeriverErrorKind(str, Enum):
REPO_NOT_FOUND = "repo-not-found"
GATED_NO_TOKEN = "gated-no-token"
UNSUPPORTED_FORMAT = "unsupported-format"
AMBIGUOUS_WEIGHT_SET = "ambiguous-weight-set"
QUANT_DTYPE_UNKNOWN = "quant-dtype-unknown"
@dataclass(frozen=True)
class DeriverError:
"""A stratum-1 structured error. Returned, never raised."""
kind: DeriverErrorKind
detail: str = ""
def __str__(self) -> str: # pragma: no cover - cosmetic
return f"{self.kind.value}: {self.detail}" if self.detail else self.kind.value
class Confidence(str, Enum):
"""§4 confidence tiers. `DERIVED` is RESERVED for the future
override-registry phase and unused in v0.8.0."""
EXACT = "exact"
ESTIMATED_LOWER_BOUND = "estimated-lower-bound"
DERIVED = "derived" # RESERVED — not assigned this phase
NOT_ELIGIBLE = "not-generic-dense-eligible"
@dataclass(frozen=True)
class Tier1Match:
"""A curated lookup hit: slug ∈ a curated model variant's `hf_repos`."""
model_id: str
weights_variant: str
slug: str
@dataclass
class DeriveResult:
slug: str
error: Optional[DeriverError] = None
tier1: Optional[Tier1Match] = None
confidence: Optional[Confidence] = None
generic_dense_eligible: Optional[bool] = None
spec: Optional[dict[str, Any]] = None
profile: Optional[dict[str, Any]] = None
diagnostics: dict[str, Any] = field(default_factory=dict)
# ---------------------------------------------------------------------------
# HTTP fetcher abstraction (injectable for fixture-driven tests)
# ---------------------------------------------------------------------------
@dataclass
class FetchResponse:
status: int
body: bytes
class HttpFetcher:
"""Real-network fetcher. Tests inject a recorded-fixture replacement.
`get(url, headers=None, range_=None)` returns a FetchResponse. HTTP errors
surface as the response's status (not exceptions) where the caller maps
them to structured stratum-1 errors; only true network failures raise
`NetworkError`.
"""
timeout = _NET_TIMEOUT
def get(
self,
url: str,
headers: Optional[dict[str, str]] = None,
range_: Optional[tuple[int, int]] = None,
) -> FetchResponse:
req_headers = dict(headers or {})
if range_ is not None:
lo, hi = range_
req_headers["Range"] = f"bytes={lo}-{hi}"
req = urllib.request.Request(url, headers=req_headers, method="GET")
try:
with urllib.request.urlopen(req, timeout=self.timeout) as resp:
return FetchResponse(status=resp.status, body=resp.read())
except urllib.error.HTTPError as exc: # 4xx/5xx — surface status
try:
body = exc.read()
except Exception: # pragma: no cover - defensive
body = b""
return FetchResponse(status=exc.code, body=body)
except (urllib.error.URLError, TimeoutError, OSError) as exc:
raise NetworkError(str(exc)) from exc
class NetworkError(RuntimeError):
"""True transport failure (timeout / DNS / connection). Distinct from an
HTTP status code, which the fetcher returns as a FetchResponse."""
Fetcher = HttpFetcher # type alias for callers
# ---------------------------------------------------------------------------
# kv-calc import (per the documented sys.modules contract)
# ---------------------------------------------------------------------------
_KV_CALC = None
def _load_kv_calc():
"""Load tools/kv-calc.py via importlib, registering it in sys.modules
BEFORE exec_module (required: kv-calc.py uses @dataclass, which resolves
cls.__module__ via sys.modules during class creation)."""
global _KV_CALC
if _KV_CALC is not None:
return _KV_CALC
if "kv_calc" in sys.modules:
_KV_CALC = sys.modules["kv_calc"]
return _KV_CALC
kv_path = REPO_ROOT / "tools" / "kv-calc.py"
spec = importlib.util.spec_from_file_location("kv_calc", kv_path)
mod = importlib.util.module_from_spec(spec)
sys.modules["kv_calc"] = mod # MUST precede exec_module
spec.loader.exec_module(mod)
_KV_CALC = mod
return _KV_CALC
# ---------------------------------------------------------------------------
# HF_HOME resolution (--hf-home > $HF_HOME > $XDG_CACHE_HOME/huggingface > ~)
# ---------------------------------------------------------------------------
def resolve_hf_home(hf_home: Optional[str] = None) -> Path:
if hf_home:
return Path(hf_home).expanduser()
env = os.environ.get("HF_HOME")
if env:
return Path(env).expanduser()
xdg = os.environ.get("XDG_CACHE_HOME")
if xdg:
return Path(xdg).expanduser() / "huggingface"
return Path.home() / ".cache" / "huggingface"
# v0.8.0 [E] E2 (additive): the canonical fetcher E1's deferred dtype
# header-probe step (2) uses. E1's `_resolve_compute_dtype()` calls the
# deriver's existing `probe_safetensors_dtype()` ONLY when a usable fetcher
# is present at `einput.diagnostics["fetcher"]`. E2 standardizes the SOURCE
# of that fetcher here (a real range-bounded `HttpFetcher`) so E4 can wire
# `diagnostics["fetcher"]` deterministically and tests can inject a fixture.
# This does NOT change E1's resolution ORDER/semantics — it only makes the
# probe path live by supplying the fetcher E1 already looks for.
def default_probe_fetcher() -> "HttpFetcher":
"""The canonical real bounded-header-probe fetcher (range-GET only;
never downloads a full weight). Tests inject a recorded fixture
instead."""
return HttpFetcher()
# ---------------------------------------------------------------------------
# Tier-1 curated lookup
# ---------------------------------------------------------------------------
def _tier1_lookup(slug: str, profiles) -> Optional[Tier1Match]:
"""slug ∈ a curated model variant's `hf_repos` → that (model, variant).
Matched case-insensitively (per brief: `hf_repos` entries are full HF
slugs, matched case-insensitively)."""
needle = slug.strip().lower()
for model in profiles.models.values():
for variant, meta in model.weights.items():
for repo in meta.get("hf_repos", []) or []:
if str(repo).strip().lower() == needle:
return Tier1Match(
model_id=model.id, weights_variant=variant, slug=str(repo)
)
return None
# ---------------------------------------------------------------------------
# HF fetch helpers
# ---------------------------------------------------------------------------
def _auth_headers(hf_token: Optional[str]) -> dict[str, str]:
return {"Authorization": f"Bearer {hf_token}"} if hf_token else {}
def _fetch_model_api(
slug: str, fetcher: HttpFetcher, hf_token: Optional[str]
) -> tuple[Optional[dict], Optional[DeriverError]]:
url = f"{_HF_API}/{slug}?blobs=true"
resp = fetcher.get(url, headers=_auth_headers(hf_token))
if resp.status == 404:
return None, DeriverError(DeriverErrorKind.REPO_NOT_FOUND, slug)
if resp.status in (401, 403):
if not hf_token:
return None, DeriverError(DeriverErrorKind.GATED_NO_TOKEN, slug)
# token present but still denied → treat as not-found (no access)
return None, DeriverError(DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (auth denied)")
if resp.status != 200:
return None, DeriverError(
DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (HF API status {resp.status})"
)
try:
return json.loads(resp.body.decode("utf-8")), None
except (ValueError, UnicodeDecodeError) as exc:
return None, DeriverError(
DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (malformed HF API: {exc})"
)
def _fetch_config_json(
slug: str, fetcher: HttpFetcher, hf_token: Optional[str]
) -> tuple[Optional[dict], Optional[DeriverError]]:
url = f"{_HF_RESOLVE}/{slug}/resolve/main/config.json"
resp = fetcher.get(url, headers=_auth_headers(hf_token))
if resp.status == 404:
return None, DeriverError(
DeriverErrorKind.UNSUPPORTED_FORMAT, f"{slug} (no config.json)"
)
if resp.status in (401, 403):
if not hf_token:
return None, DeriverError(DeriverErrorKind.GATED_NO_TOKEN, slug)
return None, DeriverError(DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (auth denied)")
if resp.status != 200:
return None, DeriverError(
DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (config.json status {resp.status})"
)
try:
return json.loads(resp.body.decode("utf-8")), None
except (ValueError, UnicodeDecodeError) as exc:
return None, DeriverError(
DeriverErrorKind.QUANT_DTYPE_UNKNOWN, f"{slug} (malformed config.json: {exc})"
)
# ---------------------------------------------------------------------------
# File selection
# ---------------------------------------------------------------------------
def _is_adapter(name: str) -> bool:
low = name.lower()
return any(p in low for p in _ADAPTER_PATTERNS)
def _siblings(api: dict) -> list[dict]:
out = []
for s in api.get("siblings", []) or []:
if isinstance(s, dict) and s.get("rfilename"):
out.append(s)
return out
def select_weight_files(
api: dict,
) -> tuple[Optional[list[str]], Optional[DeriverError]]:
"""Per brief file selection:
- `*.safetensors.index.json` present → the shard set in its weight_map.
(The index itself must be fetched separately to read weight_map; here
we only need the shard filenames the index points to, which equal the
set of top-level shard *.safetensors. We resolve the shard set from
the siblings list filtered to non-adapter *.safetensors.)
- Else → after excluding adapter/LoRA patterns, accept EXACTLY ONE
top-level *.safetensors regardless of basename; multiple plausible
complete sets → `ambiguous-weight-set`.
- No *.safetensors → `unsupported-format`.
"""
sibs = _siblings(api)
names = [s["rfilename"] for s in sibs]
safet = [
n
for n in names
if n.endswith(".safetensors") and "/" not in n and not _is_adapter(n)
]
if not safet:
return None, DeriverError(
DeriverErrorKind.UNSUPPORTED_FORMAT,
"no top-level *.safetensors (GGUF/.bin not supported — this path is vLLM + safetensors only)",
)
index_files = [
n
for n in names
if n.endswith(".safetensors.index.json") and "/" not in n
]
if index_files:
# Sharded set: the shards are the non-adapter top-level *.safetensors.
# A single complete sharded set is unambiguous; >1 distinct index
# implies >1 plausible complete set.
if len(index_files) > 1:
return None, DeriverError(
DeriverErrorKind.AMBIGUOUS_WEIGHT_SET,
f"multiple safetensors index files: {sorted(index_files)}",
)
shards = sorted(
n for n in safet if "-of-" in n or n.startswith("model-")
)
if not shards:
# Index present but no obvious shard naming — fall back to all
# non-adapter top-level safetensors as the set.
shards = sorted(safet)
return shards, None
# No index: must be exactly one complete set.
if len(safet) == 1:
return safet, None
# Multiple top-level safetensors with no index → ambiguous.
return None, DeriverError(
DeriverErrorKind.AMBIGUOUS_WEIGHT_SET,
f"{len(safet)} top-level *.safetensors and no index.json: {sorted(safet)}",
)
def _sum_blob_gb(api: dict, selected: list[str]) -> float:
by_name = {}
for s in _siblings(api):
size = s.get("size")
if size is None and isinstance(s.get("lfs"), dict):
size = s["lfs"].get("size")
if size is not None:
by_name[s["rfilename"]] = size
total = 0
wanted = set(selected) | {"config.json"}
for name, size in by_name.items():
base = name
if name in wanted or (
name.endswith("config.json") and "/" not in name
) or any(name == w for w in selected):
total += int(size)
continue
# tokenizer files (required) count toward footprint
if base in (
"tokenizer.json",
"tokenizer.model",
"tokenizer_config.json",
"special_tokens_map.json",
"vocab.json",
"merges.txt",
):
total += int(size)
# weights authority is the summed selected blobs (config/tokenizer are
# negligible but included for footprint completeness).
return round(total / (1024 ** 3), 4)
def _selected_weight_gb(api: dict, selected: list[str]) -> float:
by_name = {}
for s in _siblings(api):
size = s.get("size")
if size is None and isinstance(s.get("lfs"), dict):
size = s["lfs"].get("size")
if size is not None:
by_name[s["rfilename"]] = int(size)
total = sum(by_name.get(n, 0) for n in selected)
return round(total / (1024 ** 3), 4)
# ---------------------------------------------------------------------------
# v0.8.0 [E] CONTRACT-3 — the SINGLE shared download allowlist.
#
# `select_weight_files()` returns only `*.safetensors`; vLLM also needs the
# config/tokenizer/template assets. CONTRACT-3 reconciles v2's `*.jinja`
# addition with the legacy `[C2a]` footprint's `vocab.json`/`merges.txt` into
# ONE union, used identically by `[C2a]` sizing (gates.c2a_disk), E2 download
# (downloader.download_model -> snapshot_download allow_patterns), and E3
# smoke. There is exactly ONE function — no parallel lists that can drift.
# ---------------------------------------------------------------------------
# Exact non-glob metadata basenames (the brief's REQUIRED_METADATA, minus the
# `*.jinja` glob which is matched separately). "those that exist in siblings".
REQUIRED_METADATA = (
"config.json",
"generation_config.json",
"tokenizer.json",
"tokenizer_config.json",
"tokenizer.model",
"special_tokens_map.json",
"vocab.json",
"merges.txt",
)
def download_set(api: dict) -> list[str]:
"""CONTRACT-3 reconciled union — the ONE allowlist:
select_weight_files(api) # *.safetensors (no adapters)
+ the *.safetensors.index.json if present
+ REQUIRED_METADATA siblings that exist # config/tokenizer/...
+ every top-level *.jinja sibling # chat templates
Deterministic ordering: weights (as `select_weight_files` returns them),
then the index, then metadata in REQUIRED_METADATA order, then sorted
`*.jinja`. Only siblings that ACTUALLY EXIST are included ("those that
exist in siblings"). On an unselectable weight set this returns `[]`
(the caller already surfaced the structured `select_weight_files` error;
`download_set` never raises — it is a pure projection of `api`).
This is the literal list E2 passes as `snapshot_download(...,
allow_patterns=...)` and the exact set `[C2a]` sizes — a test asserts
fetched-set == sized-set.
"""
selected, err = select_weight_files(api or {})
if err is not None or not selected:
return []
names = {s["rfilename"] for s in _siblings(api or {})}
out: list[str] = list(selected)
# the *.safetensors.index.json (top-level) if present
for n in sorted(names):
if n.endswith(".safetensors.index.json") and "/" not in n:
out.append(n)
# REQUIRED_METADATA — exact basenames that exist (top-level)
for meta in REQUIRED_METADATA:
if meta in names:
out.append(meta)
# every top-level *.jinja (chat templates)
for n in sorted(names):
if n.endswith(".jinja") and "/" not in n and n not in out:
out.append(n)
# de-dup while preserving first-seen order (a weight is never metadata,
# but be defensive against an index/metadata name collision).
seen: set[str] = set()
deduped: list[str] = []
for n in out:
if n not in seen:
seen.add(n)
deduped.append(n)
return deduped
def sized_download_gb(api: dict) -> float:
"""Σ size of EXACTLY `download_set(api)` (LFS-resolved), GiB.
This is the CONTRACT-3 footprint: `[C2a]` sizes precisely the set E2
fetches, so `[C2a]`/E2/E3 cannot drift. Replaces the legacy
`_sum_blob_gb` heuristic (which approximated the same union but with a
hand-listed metadata set that omitted `*.jinja`); behaviour-equivalent
to within KB on any real model (metadata is negligible vs multi-GB
weights) and now provably == the fetched set."""
by_name = {}
for s in _siblings(api or {}):
size = s.get("size")
if size is None and isinstance(s.get("lfs"), dict):
size = s["lfs"].get("size")
if size is not None:
by_name[s["rfilename"]] = int(size)
total = sum(by_name.get(n, 0) for n in download_set(api or {}))
return round(total / (1024 ** 3), 4)
# ---------------------------------------------------------------------------
# Bounded safetensors-header probe (pre-download, range-bounded)
# ---------------------------------------------------------------------------
def probe_safetensors_dtype(
slug: str,
weight_file: str,
fetcher: HttpFetcher,
hf_token: Optional[str],
) -> Optional[str]:
"""Range-bounded header probe. NEVER downloads a full weight file.
1. Range-GET bytes=0-7 → little-endian u64 = header length N.
2. if N > 16 MiB → None (caller maps to quant-dtype-unknown).
3. Range-GET bytes=8-(8+N-1) [HTTP ranges inclusive; read exactly N].
4. parse JSON; read __metadata__ / first tensor dtype.
Any failure/malformed → None.
"""
url = f"{_HF_RESOLVE}/{slug}/resolve/main/{weight_file}"
try:
r1 = fetcher.get(url, headers=_auth_headers(hf_token), range_=(0, 7))
except NetworkError:
return None
if r1.status not in (200, 206) or len(r1.body) < 8:
return None
n = struct.unpack("<Q", r1.body[:8])[0]
if n <= 0 or n > _MAX_HEADER_BYTES:
return None
# bytes 8 .. 8+N-1 inclusive == exactly N bytes from offset 8.
try:
r2 = fetcher.get(
url, headers=_auth_headers(hf_token), range_=(8, 8 + n - 1)
)
except NetworkError:
return None
if r2.status not in (200, 206):
return None
blob = r2.body[:n]
if len(blob) < n:
return None
try:
hdr = json.loads(blob.decode("utf-8"))
except (ValueError, UnicodeDecodeError):
return None
if not isinstance(hdr, dict):
return None
meta = hdr.get("__metadata__")
if isinstance(meta, dict):
for k in ("dtype", "torch_dtype", "format"):
if isinstance(meta.get(k), str):
return meta[k]
for key, tinfo in hdr.items():
if key == "__metadata__":
continue
if isinstance(tinfo, dict) and isinstance(tinfo.get("dtype"), str):
return tinfo["dtype"]
return None
# ---------------------------------------------------------------------------
# Quant / dtype chain + effective bits-per-weight
# ---------------------------------------------------------------------------
_DTYPE_BPW = {
"BF16": 16.0,
"F16": 16.0,
"FP16": 16.0,
"FLOAT16": 16.0,
"BFLOAT16": 16.0,
"F32": 32.0,
"FP32": 32.0,
"FLOAT32": 32.0,
"F8_E5M2": 8.0,
"F8_E4M3": 8.0,
"FLOAT8_E5M2": 8.0,
"FLOAT8_E4M3FN": 8.0,
"I8": 8.0,
"INT8": 8.0,
"U8": 8.0,
"I4": 4.0,
"INT4": 4.0,
}
def _quant_bpw(quant_cfg: dict) -> Optional[float]:
bits = quant_cfg.get("bits") or quant_cfg.get("w_bit") or quant_cfg.get(
"weight_bits"
)
if isinstance(bits, (int, float)) and bits > 0:
return float(bits)
method = str(
quant_cfg.get("quant_method")
or quant_cfg.get("method")
or quant_cfg.get("quant_algo")
or ""
).lower()
if any(k in method for k in ("awq", "gptq", "autoround", "int4", "4bit")):
return 4.0
if "fp8" in method or "8bit" in method or "int8" in method:
return 8.0
return None
def resolve_quant_dtype(
slug: str,
config: dict,
selected: list[str],
fetcher: HttpFetcher,
hf_token: Optional[str],
) -> tuple[Optional[str], Optional[float], Optional[DeriverError]]:
"""`quantization_config` → `torch_dtype` → bounded header probe →
else `quant-dtype-unknown`. Returns (weight_format, bpw, error)."""
qcfg = config.get("quantization_config")
if isinstance(qcfg, dict) and qcfg:
method = str(
qcfg.get("quant_method") or qcfg.get("method") or "quantized"
).lower()
bpw = _quant_bpw(qcfg)
if bpw is not None:
return method, bpw, None
# known method, undeterminable bits
return None, None, DeriverError(
DeriverErrorKind.QUANT_DTYPE_UNKNOWN,
f"{slug} (quantization_config method={method!r} bits undeterminable)",
)
td = config.get("torch_dtype") or config.get("dtype")
if isinstance(td, str) and td.strip():
bpw = _DTYPE_BPW.get(td.strip().upper())
if bpw is not None:
return td.strip(), bpw, None
# bounded header probe (sharded → first shard only)
if selected:
dtype = probe_safetensors_dtype(
slug, sorted(selected)[0], fetcher, hf_token
)
if dtype:
bpw = _DTYPE_BPW.get(dtype.strip().upper())
if bpw is not None:
return dtype.strip(), bpw, None
return None, None, DeriverError(
DeriverErrorKind.QUANT_DTYPE_UNKNOWN,
f"{slug} (no quantization_config / torch_dtype / probeable header dtype)",
)
# ---------------------------------------------------------------------------
# Spec / profile assembly
# ---------------------------------------------------------------------------
def _int(config: dict, key: str) -> Optional[int]:
v = config.get(key)
return v if isinstance(v, int) and not isinstance(v, bool) else None
def _build_generic_dense_spec(
slug: str, config: dict, weight_gb: float
) -> dict[str, Any]:
hidden = _int(config, "hidden_size")
n_layers = _int(config, "num_hidden_layers")
n_heads = _int(config, "num_attention_heads")
n_kv = _int(config, "num_key_value_heads")
head_dim = _int(config, "head_dim")
if head_dim is None and hidden and n_heads and hidden % n_heads == 0:
head_dim = hidden // n_heads
arch_list = config.get("architectures") or []
arch = str(arch_list[0]) if arch_list else None
return {
"model_id": slug,
"model_family": "generic-dense",
"arch": arch,
"hidden_size": hidden,
"num_hidden_layers": n_layers,
"num_attn_heads": n_heads,
"num_kv_heads": n_kv,
"head_dim_attn": head_dim,
"weights_total_gb": weight_gb,
"valid_tp": [1, 2],
"max_ctx_supported": _int(config, "max_position_embeddings") or 131072,
}
# ---------------------------------------------------------------------------
# Public entry point
# ---------------------------------------------------------------------------
def derive(
slug: str,
*,
hf_token: Optional[str] = None,
hf_home: Optional[str] = None,
fetcher: Optional[HttpFetcher] = None,
profiles=None,
) -> DeriveResult:
"""Derive a ModelProfile-shaped result for an HF repo slug.
Resolution order (§4):
1. Tier-1 curated lookup (slug ∈ a curated variant's hf_repos) →
confidence EXACT, no network for the spec (curated profile is
authoritative). Stratum-1 file/quant checks are NOT run for a
curated hit (the curated profile already encodes them); P3/P4 do
the Path-A weights_variant compat check.
2. else fetch config.json + HF siblings; run stratum-1 deriver checks;
if is_generic_dense_eligible → confidence ESTIMATED_LOWER_BOUND.
3. else → NOT_ELIGIBLE (P4 wires the stratum-5 abort; P2 only marks).
"""
res = DeriveResult(slug=slug)
if fetcher is None:
fetcher = HttpFetcher()
if profiles is None:
from .compat import load_profiles
profiles = load_profiles()
hf_token = hf_token or os.environ.get("HF_TOKEN") or None
# --- §4 Tier-1 curated lookup ------------------------------------------
t1 = _tier1_lookup(slug, profiles)
if t1 is not None:
model = profiles.models[t1.model_id]
variant_meta = model.weights.get(t1.weights_variant, {})
# Schema invariant: hf_repos must only attach to safetensors-compatible
# variants. If a curated slug somehow resolves to a gguf / non-
# safetensors variant, surface stratum-1 unsupported-format honestly
# rather than a silent mismatch (Codex-r5 Med-3).
fmt = str(variant_meta.get("format", "")).lower()
if fmt in ("gguf",):
res.error = DeriverError(
DeriverErrorKind.UNSUPPORTED_FORMAT,
f"{slug} resolves to {t1.model_id}.{t1.weights_variant} "
f"(format={fmt!r}); GGUF not supported — vLLM + safetensors only",
)
return res
res.tier1 = t1
res.confidence = Confidence.EXACT
res.profile = {
"model_id": model.id,
"weights_variant": t1.weights_variant,
"arch": None,
"family": model.family,
"hidden_size": model.hidden_size,
"num_hidden_layers": model.num_hidden_layers,
"num_attn_heads": model.num_attn_heads,
"num_kv_heads": model.num_kv_heads,
"weight_format": variant_meta.get("format"),
"weights_variant_size_gb": variant_meta.get("size_gb"),
}
res.diagnostics["resolution"] = "tier1-curated"
return res
# --- stratum-1: HF model API first (repo existence / gating) -----------
# Order matters: the HF model API is the authority for repo-not-found
# (404) and gated-no-token (401/403 w/o token). config.json 404 on an
# existing repo means "no transformers config" -> unsupported-format.
try:
api, err = _fetch_model_api(slug, fetcher, hf_token)
except NetworkError as exc:
res.error = DeriverError(
DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (network error: {exc})"
)
return res
if err is not None:
res.error = err
return res
try:
config, err = _fetch_config_json(slug, fetcher, hf_token)
except NetworkError as exc:
res.error = DeriverError(
DeriverErrorKind.REPO_NOT_FOUND, f"{slug} (network error: {exc})"
)
return res
if err is not None:
res.error = err
return res
selected, err = select_weight_files(api or {})
if err is not None:
res.error = err
return res
weight_format, bpw, err = resolve_quant_dtype(
slug, config or {}, selected or [], fetcher, hf_token
)
if err is not None:
res.error = err
return res
weight_gb = _selected_weight_gb(api or {}, selected or [])
# v0.8.0 [E] CONTRACT-3: footprint sizes EXACTLY the shared download_set
# (the same union E2 fetches + [C2a] gates on) — single source, no drift.
# (`_sum_blob_gb` kept above as append-only history; superseded here.)
footprint_gb = sized_download_gb(api or {})
# --- §4 generic-dense eligibility (reuse P1's predicate) ---------------
kv = _load_kv_calc()
eligible = bool(kv.is_generic_dense_eligible(config or {}))
res.generic_dense_eligible = eligible
arch_list = (config or {}).get("architectures") or []
arch = str(arch_list[0]) if arch_list else None
has_auto_map = bool((config or {}).get("auto_map"))
# v0.8.0 [E] CONTRACT-2 — scoped ADDITIVE surface: expose config.json's
# raw `torch_dtype` (or its `dtype` alias) so [E]'s derived-vllm template
# can resolve `--dtype` for quantized rows (resolve_quant_dtype()
# short-circuits at quantization_config and never records it). Additive
# field ONLY — every existing field is byte-unchanged; no behaviour
# depends on it inside the deriver. None when config.json omits it.
_raw_td = (config or {}).get("torch_dtype") or (config or {}).get("dtype")
config_torch_dtype = _raw_td.strip() if isinstance(_raw_td, str) and _raw_td.strip() else None
res.profile = {
"model_id": slug,
"weights_variant": None,
"arch": arch,
"family": "generic-dense" if eligible else None,
"auto_map": has_auto_map,
"weight_format": weight_format,
"torch_dtype": config_torch_dtype,
"effective_bpw": bpw,
"weights_total_gb": weight_gb,
"footprint_gb": footprint_gb,
"selected_weight_files": selected,
# v0.8.0 [E] CONTRACT-3 (additive): the raw HF siblings API so
# gates.c2a_disk can size the SHARED download_set() directly (single
# function, [C2a]/E2/E3 cannot drift). Additive field ONLY — no
# existing field/behaviour changes; absent for a tier-1 curated hit
# (curated footprint comes from the variant size_gb, not the API).
"_hf_api": api or {},
"download_set": download_set(api or {}),
"config_hidden_size": _int(config or {}, "hidden_size"),
"config_num_hidden_layers": _int(config or {}, "num_hidden_layers"),
"config_num_attention_heads": _int(config or {}, "num_attention_heads"),
"config_num_key_value_heads": _int(config or {}, "num_key_value_heads"),
}
res.diagnostics["resolution"] = "derived"
if eligible:
res.confidence = Confidence.ESTIMATED_LOWER_BOUND
res.spec = _build_generic_dense_spec(slug, config or {}, weight_gb)
else:
res.confidence = Confidence.NOT_ELIGIBLE # P4 wires stratum-5 abort
return res