# /// script # dependencies = ["huggingface_hub>=0.35", "requests"] # /// """Daily radar: transformers-related issues + monkey patches in downstream repos -> static Space. Run: HF_TOKEN=... GITHUB_TOKEN=... uv run tracker.py (DRY=1 to write index.html locally instead of pushing) Schedule: hf jobs scheduled uv run daily https://huggingface.co/spaces/$SPACE/resolve/main/tracker.py --secrets HF_TOKEN (GITHUB_TOKEN optional: 3x faster search) """ import json import os import re import subprocess import tempfile import time from collections import defaultdict from datetime import date, timedelta from html import escape from pathlib import Path import requests from huggingface_hub import HfApi, InferenceClient, hf_hub_download # Heavy transformers users, ordered by GitHub stars (2026-11). Picked from stars >5k or pypi >300k/month. REPOS = [ "ggml-org/llama.cpp", "vllm-project/vllm", "unslothai/unsloth", "hiyouga/LlamaFactory", "deepspeedai/DeepSpeed", "hpcaitech/ColossalAI", "sgl-project/sglang", "huggingface/diffusers", "huggingface/lerobot", "huggingface/open-r1", "m-bain/whisperX", "verl-project/verl", "huggingface/peft", "huggingface/trl", "kvcache-ai/ktransformers", "huggingface/sentence-transformers", "NVIDIA-NeMo/Automodel", "modelscope/ms-swift", "dottxt-ai/outlines", "NVIDIA/TensorRT-LLM", "flairNLP/flair", "EleutherAI/lm-evaluation-harness", "axolotl-ai-cloud/axolotl", "FlagOpen/FlagEmbedding", "OpenRLHF/OpenRLHF", "huggingface/accelerate", "THUDM/slime", "bitsandbytes-foundation/bitsandbytes", "ml-explore/mlx-lm", "arcee-ai/mergekit", "linkedin/Liger-Kernel", "Blaizzy/mlx-vlm", "EvolvingLMMs-Lab/lmms-eval", "urchade/GLiNER", "vllm-project/llm-compressor", "allenai/open-instruct", "huggingface/optimum", "embeddings-benchmark/mteb", "alibaba/ROLL", "PrimeIntellect-ai/prime-rl", "intel/auto-round", "ModelCloud/GPTQModel", "huggingface/optimum-quanto", "unslothai/unsloth-zoo", ] # fmt: skip SPACE = os.environ.get("SPACE", "ModelAdders/transformers-downstream-tracker") MODEL = os.environ.get("MODEL", "Qwen/Qwen3-235B-A22B-Instruct-2507") DAYS = int(os.environ.get("DAYS", 2)) # ponytail: overlap between daily runs is fine DRY = os.environ.get("DRY") == "1" # ponytail: regex heuristic, catches `transformers.x.y = ...`, `modeling_llama.Foo.forward = ...`, setattr on # transformers modules, and `LlamaAttention.forward = ...`. Misses aliased imports; AST pass if that matters. PATCH_RE = re.compile( r"^\s*(transformers(\.\w+)+|modeling_\w+(\.\w+)+" r"|[A-Z]\w*(Attention|MLP|Model|ForCausalLM|DecoderLayer|RMSNorm|PreTrainedModel|Embedding)\w*\.\w+)\s*=[^=]" r"|setattr\(\s*(transformers|modeling_)" ) MODEL_CLS = re.compile( r"^(?!PreTrainedModel)[A-Z]\w*?(?=(ForCausalLM|ForConditionalGeneration|SdpaAttention|FlashAttention2|Attention" r"|MLP|DecoderLayer|RMSNorm|RotaryEmbedding|SparseMoeBlock|Experts|Model)\b)" ) def issues(): # GitHub search, not GH Archive: the public events feed is heavily sampled (~40 of ~650 daily vllm events). since = (date.today() - timedelta(days=DAYS)).isoformat() headers = {"Authorization": f"Bearer {os.environ['GITHUB_TOKEN']}"} if "GITHUB_TOKEN" in os.environ else {} rows = [] for i, repo in enumerate(REPOS, 1): q = f"repo:{repo} transformers in:title,body,comments updated:>={since}" r = requests.get( "https://api.github.com/search/issues", params={"q": q, "per_page": 100, "sort": "updated"}, headers=headers, timeout=60, ) # fmt: skip if not r.ok: # renamed/private repo shouldn't kill the whole report print(f"[{i}/{len(REPOS)}] {repo}: search failed {r.status_code}", flush=True) continue # ponytail: first 100 most recently updated only; vllm hits the cap, paginate if the tail matters items = r.json()["items"] rows += [ {"repo_name": repo, "number": it["number"], "t": it["title"], "b": it["body"], "comments": it["comments"], "is_pr": "pull_request" in it} for it in items ] # fmt: skip print(f"[{i}/{len(REPOS)}] {repo}: {len(items)} threads", flush=True) time.sleep(2.1 if headers else 6.5) # search API: 30 req/min authenticated, 10 anonymous return sorted(rows, key=lambda r: -r["comments"]) def patches(): found = set() for i, repo in enumerate(REPOS, 1): with tempfile.TemporaryDirectory() as dst: # one at a time, keeps job disk small clone = ["git", "clone", "-q", "--depth", "1", "--filter=blob:limit=1m", f"https://github.com/{repo}", dst] if subprocess.run(clone).returncode: print(f"[{i}/{len(REPOS)}] {repo}: clone failed", flush=True) continue files = subprocess.run(["git", "ls-files", "*.py"], cwd=dst, capture_output=True, text=True).stdout # key on file + stripped line so line-number churn doesn't count as a new patch hits = { f"{repo}:{f}: {line.strip()}" for f in files.split() if "test" not in f and Path(dst, f).exists() for line in Path(dst, f).read_text(errors="ignore").splitlines() if PATCH_RE.search(line) } found |= hits print(f"[{i}/{len(REPOS)}] {repo}: {len(hits)} patches", flush=True) return found def target(key): """`repo:file: modeling_llama.LlamaAttention.forward = f` -> `*Attention.forward` (what transformers symbol is patched).""" code = key.split(": ", 1)[1] m = re.search(r"setattr\(\s*([\w.]+)\s*,\s*['\"](\w+)", code) sym = f"{m[1]}.{m[2]}" if m else code.split("=")[0].strip() sym = re.sub(r"^(transformers\.)?(models\.\w+\.)?(\w*modeling_\w+\.?)?", "", sym) or "" return MODEL_CLS.sub("*", sym) def triage(rows): """LLM groups threads by root cause and says what transformers should do. Returns list of dicts or None.""" listing = "\n".join( f"- {r['repo_name']}#{r['number']} ({'PR' if r['is_pr'] else 'issue'}, {r['comments']} comments): " f"{r['t']}\n {(r['b'] or '')[:300]!r}" for r in rows[:200] ) prompt = ( "You triage downstream breakage for the huggingface/transformers maintainers. Below are recent issues/PRs from " "libraries that depend on transformers. Group them by root cause. Drop anything not caused by or about " "transformers (env dumps that merely list a version do not count). Reply with ONLY a JSON array, most urgent " 'first, items: {"severity": "high|medium|low", "action": "fix in transformers|reply/guide users|watch", ' '"component": "e.g. tokenizers, generate, from_pretrained, attention, model:, trainer", ' '"summary": "one line, in transformers terms", "refs": ["owner/repo#N", ...]}\n\n' + listing ) try: out = InferenceClient().chat_completion([{"role": "user", "content": prompt}], model=MODEL, max_tokens=4000) return json.loads(re.search(r"\[.*\]", out.choices[0].message.content, re.S)[0]) except Exception as e: # LLM is a nicety; raw table still rendered print(f"triage failed: {e}", flush=True) return None def link(ref): repo, n = ref.split("#") return f'{escape(ref)}' def patch_link(key): repo, rest = key.split(":", 1) f, code = rest.split(": ", 1) return f'{escape(repo)}/{escape(f)}', f"{escape(code)}" def table(head, rows): th = "".join(f"{h}" for h in head) return f"{th}" + "".join("" + "".join(f"" for c in r) + "" for r in rows) + "
{c}
" def render(rows, groups, now, new, gone): sev = {"high": "🔴", "medium": "🟠", "low": "⚪"} h = [f"

transformers downstream radar · {date.today()}

", f"

{len(REPOS)} repos · last {DAYS} days of GitHub activity · {len(now)} monkey patches tracked

"] # fmt: skip h.append("

Act on these

") if groups is not None: groups = sorted(groups, key=lambda g: ["high", "medium", "low"].index(g.get("severity", "low"))) h.append(table(["", "action", "component", "what", "threads"], [ [sev.get(g.get("severity"), ""), escape(g.get("action", "")), escape(g.get("component", "")), escape(g.get("summary", "")), " ".join(link(r) for r in g.get("refs", []) if "#" in r)] for g in groups if g.get("action") != "watch" ])) # fmt: skip h.append(f"
All {len(rows)} matching threads") h.append(table(["thread", "comments", "title"], [ [link(f"{r['repo_name']}#{r['number']}"), r["comments"], escape(r["t"] or "")] for r in rows ])) # fmt: skip h.append("
") h.append(f"

New monkey patches since last run ({len(new)})

") h.append("

Something changed on their side or ours: check whether a transformers change forced it.

") h.append(table(["where", "patch"], [patch_link(k) for k in new]) if new else "

None.

") if gone: h.append(f"
Removed since last run ({len(gone)})") h.append(table(["where", "patch"], [patch_link(k) for k in gone]) + "
") by_target = defaultdict(set) for k in now: by_target[target(k)].add(k.split(":", 1)[0]) top = sorted(by_target.items(), key=lambda kv: (-len(kv[1]), kv[0]))[:40] h.append("

Most-patched transformers internals

") h.append("

Patched by several repos = missing extension point (kernel hub / attention interface / hook).

") h.append(table(["symbol", "#repos", "repos"], [ [f"{escape(t)}", len(rs), ", ".join(r.split("/")[1] for r in sorted(rs))] for t, rs in top ])) # fmt: skip threads = defaultdict(int) for r in rows: threads[r["repo_name"]] += 1 count = lambda keys, repo: sum(k.startswith(repo + ":") for k in keys) h.append("

Per repo

") h.append(table(["repo", "threads", "patches", "new patches"], [ [f'{r}', threads[r], count(now, r), count(new, r)] for r in REPOS ])) # fmt: skip h.append(f"
All {len(now)} patches") h.append(table(["where", "patch"], [patch_link(k) for k in sorted(now)]) + "
") css = ( "body{max-width:1200px;margin:auto;padding:1em;font-family:system-ui}table{border-collapse:collapse;width:100%}" "td,th{border-bottom:1px solid #ddd;padding:4px 8px;text-align:left;vertical-align:top}code{font-size:85%}" ) return f"transformers radar" + "\n".join(h) def main(): rows = issues() print(f"{len(rows)} transformers-related threads in last {DAYS}d", flush=True) groups = triage(rows) if rows else [] print(f"triaged into {len(groups) if groups is not None else '?'} groups", flush=True) now = patches() try: before = set(json.load(open(hf_hub_download(SPACE, "patches.json", repo_type="space")))) except Exception: # first run: nothing to diff against before = now new, gone = sorted(now - before), sorted(before - now) html = render(rows, groups, now, new, gone) if DRY: Path("index.html").write_text(html) print("wrote index.html", flush=True) return api = HfApi() api.create_repo(SPACE, repo_type="space", space_sdk="static", exist_ok=True) with tempfile.TemporaryDirectory() as tmp: Path(tmp, "index.html").write_text(html) Path(tmp, "patches.json").write_text(json.dumps(sorted(now), indent=1)) Path(tmp, "reports").mkdir() Path(tmp, f"reports/{date.today()}.json").write_text(json.dumps({"threads": rows, "groups": groups}, indent=1)) api.upload_folder(folder_path=tmp, repo_id=SPACE, repo_type="space", commit_message=f"radar {date.today()}") print(f"pushed https://huggingface.co/spaces/{SPACE}", flush=True) if __name__ == "__main__": main()