[teamai] Push 87 resource(s) from XingfenD

This commit is contained in:
2026-09-10 16:10:45 +08:00
parent 425c9c078a
commit 65c04def51
1314 changed files with 211681 additions and 0 deletions
@@ -0,0 +1 @@
"""model-support-checker package: SGLang/vLLM model support checker."""
@@ -0,0 +1,59 @@
"""Step 1: resolve a model's architecture name from its config.json."""
import json
from .http_utils import _get, _get_json
def get_architecture(model_id, source="modelscope", arch_override=None):
"""Return (architectures: list[str], source_used: str).
If *arch_override* is given (comma-separated architecture string), return it
directly without fetching config.json. This allows the caller to bypass
the network lookup when the config is unavailable or the user already knows
the architecture name.
"""
if arch_override:
archs = [a.strip() for a in arch_override.split(",") if a.strip()]
if archs:
return archs, "manual"
if source in ("auto", "hf"):
url = f"https://huggingface.co/{model_id}/resolve/main/config.json"
try:
body, _ = _get(url)
except RuntimeError:
body = None
if body:
try:
data = json.loads(body)
if data.get("architectures"):
return data["architectures"], "huggingface"
except json.JSONDecodeError:
pass
if source in ("auto", "modelscope"):
url = f"https://modelscope.cn/models/{model_id}/resolve/master/config.json"
try:
body, _ = _get(url)
except RuntimeError:
body = None
if body:
try:
data = json.loads(body)
if data.get("architectures"):
return data["architectures"], "modelscope"
except json.JSONDecodeError:
pass
api = f"https://modelscope.cn/api/v1/models/{model_id}"
data = _get_json(api)
if data:
arch = data.get("Architectures") or data.get("architectures")
if arch:
return [arch] if isinstance(arch, str) else arch, "modelscope-api"
raise RuntimeError(
f"Could not fetch config.json for '{model_id}' from HuggingFace or ModelScope.\n"
f"Try: --source hf | --source modelscope (pick a specific platform)\n"
f" or: --arch <ArchitectureName> (e.g. --arch LlamaForCausalLM)"
)
+217
View File
@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""Check whether a HuggingFace / ModelScope model is supported by SGLang, vLLM, or vLLM-Ascend,
and since which version.
Usage:
python3 main.py --setup local # first run: clone repos into .state/repos/ (recommended)
python3 main.py --setup token # first run: use GitHub API (GITHUB_TOKEN per run)
python3 main.py --doctor # check setup state and local checkouts
GITHUB_TOKEN=xxx python3 main.py --framework sglang Qwen/Qwen3.6-35B-A3B
python3 main.py --framework vllm deepseek-ai/DeepSeek-V3 # after setup
python3 main.py --framework vllm-ascend deepseek-ai/DeepSeek-V3
python3 main.py --arch LlamaForCausalLM # manual architecture (skip config.json fetch)
"""
import argparse
import os
import sys
import time
from . import state
from .architecture import get_architecture
from .framework_strategies import STRATEGIES
# Max seconds to wait for background checkout refreshes before exiting.
_REFRESH_JOIN_SECONDS = 15
# Framework names that can be used with --framework
FRAMEWORK_CHOICES = ["sglang", "vllm", "vllm-ascend", "all"]
def main():
ap = argparse.ArgumentParser(description="Check SGLang/vLLM/vLLM-Ascend model support.")
ap.add_argument("model_id", nargs="?", help="e.g. Qwen/Qwen3.6-35B-A3B (optional with --arch)")
ap.add_argument("--framework", choices=FRAMEWORK_CHOICES, default="all",
help="which framework to check (default: all)")
ap.add_argument("--source", choices=["auto", "hf", "modelscope"],
default="modelscope", help="where to read config.json")
ap.add_argument("--arch", default=None,
help="manually specify architecture name(s), comma-separated "
"(e.g. LlamaForCausalLM). Skips config.json fetch.")
ap.add_argument("--token", default=os.environ.get("GITHUB_TOKEN"),
help="GitHub token (or set GITHUB_TOKEN env)")
ap.add_argument("--no-docs", action="store_true", help="skip docs check")
ap.add_argument("--vllm-ref", default=None,
help="vLLM git ref (branch/tag) for registry check (default: main)")
ap.add_argument("--vllm-path", default=None,
help="local vllm repo checkout path (skip GitHub API)")
ap.add_argument("--sglang-path", default=None,
help="local sglang repo checkout path (skip GitHub API)")
ap.add_argument("--vllm-ascend-path", default=None,
help="local vllm-ascend repo checkout path (skip GitHub API)")
ap.add_argument("--setup", choices=["local", "token"], default=None,
help="first-run setup: 'local' clones repos (recommended), "
"'token' uses the GitHub API. Saved to .state/state.json.")
ap.add_argument("--reset-state", action="store_true",
help="forget saved setup state")
ap.add_argument("--doctor", action="store_true",
help="check setup state and exit")
ap.add_argument("-v", "--verbose", action="store_true")
args = ap.parse_args()
if args.reset_state:
state.reset()
if not args.setup:
return
if args.setup:
state.ensure_setup(args.setup, args)
return
# Resolve setup state: first run asks the user (TTY menu) or tells the
# caller to run --setup. With --doctor we skip the interactive menu and
# just report whatever is (or isn't) on disk.
st = state.load()
if st is None and args.doctor:
has_errors = state.print_report(state.doctor(st, args, framework=args.framework))
sys.exit(1 if has_errors else 0)
if st is None:
if sys.stdin.isatty():
state.ensure_setup(state.first_run_menu(), args)
st = state.load()
else:
raise RuntimeError(
"First run: no setup found (.state/state.json missing). Ask the "
"user to choose, then run one of:\n"
" python3 main.py --setup local # recommended\n"
" python3 main.py --setup local --vllm-path P1 --sglang-path P2 --vllm-ascend-path P3\n"
" python3 main.py --setup token # needs GITHUB_TOKEN"
)
# The agent is expected to run `python3 main.py --doctor` explicitly
# before any model check (see SKILL.md workflow). When --doctor is passed
# directly, we inspect state and exit without touching a model.
if args.doctor:
issues = state.doctor(st, args, framework=args.framework)
has_errors = state.print_report(issues)
sys.exit(1 if has_errors else 0)
# Build path mapping: framework name -> local path
paths = {
"vllm": args.vllm_path or st.get("vllm_path"),
"sglang": args.sglang_path or st.get("sglang_path"),
"vllm-ascend": args.vllm_ascend_path or st.get("vllm_ascend_path"),
}
if not args.model_id and not args.arch:
ap.error("model_id is required (unless --arch is specified)")
frameworks = list(STRATEGIES) if args.framework == "all" else [args.framework]
# Local mode: refresh checkouts in the background while checking runs;
# failures/staleness are only reported at the very end, never blocking.
local_paths = {}
for fw_name in frameworks:
lp = paths.get(fw_name)
if lp and os.path.isdir(os.path.join(lp, ".git")):
local_paths[fw_name] = lp
freshness, refresh_threads = state.start_refresh(local_paths)
# Step 1 (framework-independent): architecture name.
archs, src = get_architecture(args.model_id or "", args.source,
arch_override=args.arch)
arch = archs[0]
model_display = args.model_id or "(manual)"
print(f"Model: {model_display}")
print(f"[1] Architecture(s): {', '.join(archs)} (source: {src})\n")
results = {}
for fw_name in frameworks:
local_path = paths.get(fw_name)
strategy = STRATEGIES[fw_name]
ctx = strategy.make_context(local_path)
print(f"========== {strategy.label} ==========")
if ctx.is_local:
print(f" (using local checkout: {ctx.local_dir})")
# Step 3 (authoritative)
print("[3] GitHub source check (authoritative)...")
supported, file_path = strategy.check_support(arch, ctx, args.token, args.verbose)
print(f" Supported in source: {'YES' if supported else 'NO'}"
+ (f" ({file_path})" if file_path else ""))
# Framework-specific extra checks (e.g. vLLM registry)
extra = strategy.extra_checks(arch, ctx, args.token, args.verbose, ref=args.vllm_ref)
# Step 2 (docs, supplementary)
docs = "skipped"
if not args.no_docs:
print("[2] Official docs check...")
docs = strategy.check_docs(arch, args.verbose)
print(f" Docs mention: {docs}")
# Step 4 (version)
version = None
if supported:
print(f"[4] Determining first supporting {strategy.label} version...")
version = strategy.get_version(strategy.version_path(file_path), ctx, args.token, args.verbose)
print(f" First version: {version}")
else:
print("[4] Skipped (not found in source).")
results[fw_name] = (supported, file_path, version, docs, extra, strategy)
print()
# Final combined summary.
print("=== Summary ===")
print(f" Model : {model_display}")
print(f" Architecture : {arch}")
for fw_name in frameworks:
supported, file_path, version, docs, extra, strategy = results[fw_name]
line = f" {strategy.label:12} supported : {'YES' if supported else 'NO'}"
if supported:
line += f" | since {version} | {file_path}"
print(line)
strategy.format_summary_extra(extra)
print("\nNote: GitHub source is the authoritative signal for all frameworks.")
print("The 'since version' is approximated from the implementation file's first")
print("commit date and may be off by a release or two; it needs GITHUB_TOKEN")
print("on rate-limited IPs.")
_print_refresh_notes(freshness, refresh_threads, args.verbose)
def _print_refresh_notes(freshness, threads, verbose=False):
"""Report background checkout refresh results after the main flow.
Waits at most _REFRESH_JOIN_SECONDS total so a slow fetch never blocks
the exit for long; unfinished workers are simply not reported.
"""
deadline = time.monotonic() + _REFRESH_JOIN_SECONDS
for t in threads:
t.join(timeout=max(0.0, deadline - time.monotonic()))
notes = []
for fw_name, info in sorted(freshness.items()):
label = STRATEGIES[fw_name].label
if "error" in info:
notes.append(f"{label}: checkout refresh failed ({info['error']}); "
f"results reflect the checkout as-is.")
elif info.get("behind"):
notes.append(f"{label}: checkout is {info['behind']} commit(s) behind "
f"its upstream — update with: git -C {info['path']} pull")
elif verbose and not info.get("no_upstream"):
notes.append(f"{label}: checkout is up to date.")
if notes:
print("\n=== Checkout freshness ===")
for n in notes:
print(f" NOTE: {n}")
if __name__ == "__main__":
try:
main()
except RuntimeError as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
@@ -0,0 +1,67 @@
"""Execution context for framework checks.
Replaces the global mutable state in config.py. Each check runs with its own
Context, making the code concurrency-safe and easier to test.
"""
import os
from dataclasses import dataclass
from typing import Optional
from .http_utils import _get
@dataclass
class Context:
"""Immutable context for a single framework check."""
repo: str
branch: str
models_dir: str
docs_url: str
label: str
local_dir: Optional[str] = None
@property
def api(self) -> str:
return f"https://api.github.com/repos/{self.repo}"
@property
def raw(self) -> str:
return f"https://raw.githubusercontent.com/{self.repo}/{self.branch}"
@property
def is_local(self) -> bool:
return self.local_dir is not None
def read_source(self, rel_path: str) -> Optional[str]:
"""Read a repository-relative file.
Local mode: read from disk.
Remote mode: fetch from GitHub raw CDN.
Returns None on failure.
"""
if self.is_local:
p = os.path.join(self.local_dir, rel_path)
try:
with open(p, encoding="utf-8") as f:
return f.read()
except OSError:
return None
try:
body, _ = _get(f"{self.raw}/{rel_path}")
except RuntimeError:
return None
return body
@classmethod
def from_strategy(cls, strategy, local_dir: Optional[str] = None) -> "Context":
"""Create a Context from a strategy instance."""
return cls(
repo=strategy.repo,
branch=strategy.branch,
models_dir=strategy.models_dir,
docs_url=strategy.docs_url,
label=strategy.label,
local_dir=os.path.expanduser(local_dir) if local_dir else None,
)
@@ -0,0 +1,10 @@
"""Framework strategies: each framework is a strategy instance."""
from .base import FrameworkStrategy
from .sglang import SglangStrategy
from .vllm import VllmStrategy
from .vllm_ascend import VllmAscendStrategy
STRATEGIES = {s.name: s() for s in (VllmStrategy, SglangStrategy, VllmAscendStrategy)}
__all__ = ["FrameworkStrategy", "STRATEGIES"]
@@ -0,0 +1,249 @@
"""Base strategy class for framework-specific behavior."""
import json
import os
import re
import subprocess
import urllib.parse
from typing import Optional, Tuple
from ..context import Context
from ..http_utils import BROWSER_UA, _get, _get_json
class FrameworkStrategy:
name = None
label = None
repo = None
branch = None
models_dir = None
docs_url = None
def make_context(self, local_dir: Optional[str] = None) -> Context:
return Context.from_strategy(self, local_dir)
def check_docs(self, arch: str, verbose: bool = False) -> str:
body, _ = _get(self.docs_url)
if not body:
if verbose:
print(f" [docs] could not fetch {self.docs_url} (may be JS-rendered).")
return "unknown"
if arch in body or arch.lower() in body.lower():
return "yes"
family = re.split(r"(?=[A-Z])", arch)[0].lower()
if family and family in body.lower():
return "maybe"
return "no"
def check_support(
self, arch: str, ctx: Context, token: Optional[str] = None, verbose: bool = False
) -> Tuple[bool, Optional[str]]:
if ctx.is_local:
return self._check_local(arch, ctx, verbose)
if token:
inner = "^" + ctx.models_dir.replace("/", r"\/") + r"\/"
q = f"{arch} repo:{ctx.repo} path:/{inner}/"
url = f"{ctx.api}/search/code?q={urllib.parse.quote(q)}&per_page=20"
data = _get_json(url, token)
if data:
for item in data.get("items", []):
if item["path"].startswith(ctx.models_dir) and item["path"].endswith(".py"):
if verbose:
print(f" [github] code-search hit: {item['path']}")
return True, item["path"]
elif verbose:
print(" [github] code search returned nothing / was rate-limited.")
if not token and verbose:
print(" [github] no token: using best-effort tree scrape "
"(may be incomplete; set GITHUB_TOKEN for a definitive answer).")
files = self.list_model_files(ctx, verbose)
candidates = self.match_files(arch, files) if files else []
if verbose:
print(" [github] fallback candidates: " + ", ".join(candidates) or "(none)")
for fname in candidates:
path = f"{ctx.models_dir}/{fname}"
body = ctx.read_source(path)
if body and arch in body:
if verbose:
print(f" [github] '{arch}' found in {path}")
return True, path
return False, None
def get_version(
self, file_path: str, ctx: Context, token: Optional[str] = None, verbose: bool = False
) -> Optional[str]:
if not file_path:
return None
if ctx.is_local:
return self._get_version_local(file_path, ctx, verbose)
try:
date = self._earliest_commit_date(file_path, ctx, token)
except RuntimeError as e:
return f"unknown ({e}; try GITHUB_TOKEN)"
if verbose:
print(f" [version] earliest commit touching {file_path}: {date}")
if not date:
return "unknown"
try:
return self._first_release_after(date, ctx, token)
except RuntimeError as e:
return f"unknown ({e}; try GITHUB_TOKEN)"
def version_path(self, file_path: Optional[str]) -> Optional[str]:
return file_path
def extra_checks(self, arch: str, ctx: Context, token: Optional[str], verbose: bool, ref: Optional[str] = None):
return None
def format_summary_extra(self, info) -> None:
pass
def list_model_files(self, ctx: Context, verbose: bool = False) -> Optional[set]:
if ctx.is_local:
d = os.path.join(ctx.local_dir, ctx.models_dir)
try:
names = {f for f in os.listdir(d) if f.endswith(".py")}
except OSError:
if verbose:
print(f" [local] could not list models directory {d}.")
return None
names.discard("__init__.py")
if names:
if verbose:
print(f" [local] listed {len(names)} model files from {d}.")
return names
return None
url = f"{ctx.api}/contents/{ctx.models_dir}"
data = _get_json(url)
if data:
names = {
e["name"]
for e in data
if e.get("type") == "file" and e["name"].endswith(".py")
}
names.discard("__init__.py")
if names:
if verbose:
print(f" [github] listed {len(names)} model files via Contents API.")
return names
if verbose:
print(" [github] Contents API unavailable; scraping tree page.")
turl = f"https://github.com/{ctx.repo}/tree/{ctx.branch}/{ctx.models_dir}"
try:
body, _ = _get(turl, ua=BROWSER_UA)
except RuntimeError:
body = None
if not body:
if verbose:
print(" [github] could not fetch models directory listing.")
return None
names = set(re.findall(r'"name":"([a-zA-Z0-9_]+\.py)"', body))
names.discard("__init__.py")
return names
@staticmethod
def match_files(arch: str, files: set) -> list:
a = arch.lower().replace("_", "")
fam = re.match(r"[A-Za-z]+", arch)
fam = fam.group(0).lower() if fam else ""
out = []
for f in files:
if not f.endswith(".py"):
continue
stem = f[:-3].lower().replace("_", "")
if (
a.startswith(stem)
or stem.startswith(a)
or (fam and (stem.startswith(fam) or fam.startswith(stem)))
):
out.append(f)
return sorted(out, key=len)
def _check_local(self, arch: str, ctx: Context, verbose: bool = False) -> Tuple[bool, Optional[str]]:
files = self.list_model_files(ctx, verbose)
candidates = self.match_files(arch, files) if files else []
if verbose:
print(" [local] candidates: " + (", ".join(candidates) or "(none)"))
for fname in candidates:
path = f"{ctx.models_dir}/{fname}"
body = ctx.read_source(path)
if body and arch in body:
if verbose:
print(f" [local] '{arch}' found in {path}")
return True, path
return False, None
def _earliest_commit_date(self, path: str, ctx: Context, token: Optional[str]) -> Optional[str]:
headers = {"Authorization": f"Bearer {token}"} if token else {}
url = f"{ctx.api}/commits?path={urllib.parse.quote(path)}&per_page=1"
try:
body, hdrs = _get(url, headers)
except RuntimeError as e:
raise RuntimeError(str(e)) from e
if not body:
return None
link = hdrs.get("Link", "")
last_page = 1
for part in link.split(","):
if 'rel="last"' in part:
m = re.search(r"[?&]page=(\d+)", part)
if m:
last_page = int(m.group(1))
if last_page > 1:
try:
body, _ = _get(f"{url}&page={last_page}", headers)
except RuntimeError:
body = None
if not body:
return None
commits = json.loads(body)
if not commits:
return None
commit = commits[-1]["commit"]
return commit.get("committer", {}).get("date") or commit.get("author", {}).get("date")
def _first_release_after(self, date_iso: str, ctx: Context, token: Optional[str]) -> str:
rels = _get_json(f"{ctx.api}/releases?per_page=100", token) or []
picked = None
for r in rels:
pub = r.get("published_at")
if not pub:
continue
if pub >= date_iso and (picked is None or pub < picked["published_at"]):
picked = r
return picked["tag_name"] if picked else "unreleased (main)"
def _get_version_local(self, file_path: str, ctx: Context, verbose: bool = False) -> str:
repo = ctx.local_dir
log = subprocess.run(
["git", "-C", repo, "log", "--reverse", "--format=%aI", "--", file_path],
capture_output=True, text=True,
)
if log.returncode != 0 or not log.stdout.strip():
if verbose:
print(f" [version] no git history for {file_path}.")
return "unknown"
first_date = log.stdout.strip().splitlines()[0]
if verbose:
print(f" [version] earliest commit touching {file_path}: {first_date}")
tags = subprocess.run(
["git", "-C", repo, "for-each-ref", "--sort=creatordate",
"--format=%(creatordate:iso-strict) %(refname:short)", "refs/tags"],
capture_output=True, text=True,
)
if tags.returncode != 0:
return "unreleased (main)"
picked = None
for line in tags.stdout.splitlines():
line = line.strip()
if not line:
continue
date, tag = line.split(" ", 1)
if date >= first_date and (picked is None or date < picked[0]):
picked = (date, tag)
return picked[1] if picked else "unreleased (main)"
@@ -0,0 +1,12 @@
"""SGLang strategy."""
from .base import FrameworkStrategy
class SglangStrategy(FrameworkStrategy):
name = "sglang"
label = "SGLang"
repo = "sgl-project/sglang"
branch = "main"
models_dir = "python/sglang/srt/models"
docs_url = "https://docs.sglang.io/docs/supported-models"
@@ -0,0 +1,10 @@
"""vLLM framework strategy."""
from .registry import (
check_vllm_registry,
fetch_vllm_registry,
parse_vllm_registry,
)
from .strategy import VllmStrategy
__all__ = ["VllmStrategy", "fetch_vllm_registry", "parse_vllm_registry", "check_vllm_registry"]
@@ -0,0 +1,203 @@
"""vLLM registry.py source-level parsing (category, module, class, etc.)."""
import os
import re
from typing import Optional
from ...context import Context
from ...http_utils import _get
_REGISTRY_PATH = "vllm/model_executor/models/registry.py"
_CATEGORY_MAP = {
"_TEXT_GENERATION_MODELS": "text_generation",
"_EMBEDDING_MODELS": "embedding",
"_LATE_INTERACTION_MODELS": "late_interaction",
"_REWARD_MODELS": "reward",
"_TOKEN_CLASSIFICATION_MODELS": "token_classification",
"_SEQUENCE_CLASSIFICATION_MODELS": "sequence_classification",
"_MULTIMODAL_MODELS": "multimodal",
"_SPECULATIVE_DECODING_MODELS": "speculative_decoding",
"_TRANSFORMERS_SUPPORTED_MODELS": "transformers_supported",
"_TRANSFORMERS_BACKEND_MODELS": "transformers_backend",
}
_BROWSER_UA = {
"User-Agent": (
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0 Safari/537.36"
)
}
def _parse_dict_entries(source, dict_name):
"""Extract architecture keys from a Python dict literal in source.
Returns dict[arch_name] = (module_str, class_str).
"""
pattern = rf"^{re.escape(dict_name)}\s*=\s*\{{"
match = re.search(pattern, source, re.MULTILINE)
if not match:
return {}
start = match.end()
depth = 1
i = start
while i < len(source) and depth > 0:
ch = source[i]
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
elif ch in ("'", '"'):
quote = ch
i += 1
while i < len(source):
if source[i] == "\\":
i += 2
continue
if source[i] == quote:
break
i += 1
i += 1
body = source[start : i - 1]
entry_re = re.compile(
r'''["'](\w+)["']\s*:\s*\(\s*["']([^"']+)["']\s*,\s*["']([^"']+)["']\s*,?\s*\)'''
)
result = {}
for m in entry_re.finditer(body):
result[m.group(1)] = (m.group(2), m.group(3))
return result
def _parse_simple_dict(source, dict_name):
"""Extract entries from a simple dict: "Key": "Value"."""
pattern = rf"^{re.escape(dict_name)}\s*=\s*\{{"
match = re.search(pattern, source, re.MULTILINE)
if not match:
return {}
start = match.end()
depth = 1
i = start
while i < len(source) and depth > 0:
ch = source[i]
if ch == "{":
depth += 1
elif ch == "}":
depth -= 1
elif ch in ("'", '"'):
quote = ch
i += 1
while i < len(source):
if source[i] == "\\":
i += 2
continue
if source[i] == quote:
break
i += 1
i += 1
body = source[start : i - 1]
entry_re = re.compile(r'''["'](\w+)["']\s*:\s*["']([^"']+)["']''')
result = {}
for m in entry_re.finditer(body):
result[m.group(1)] = m.group(2)
return result
def fetch_vllm_registry(ctx: Context, ref: Optional[str] = None, verbose: bool = False) -> str:
"""Fetch vLLM registry.py source.
In local mode (ctx.is_local) the file is read from disk; otherwise
it is fetched from the GitHub raw CDN.
"""
if ctx.is_local:
p = os.path.join(ctx.local_dir, _REGISTRY_PATH)
if verbose:
print(f" [registry] reading local {p}")
try:
with open(p, encoding="utf-8") as f:
body = f.read()
except OSError:
raise RuntimeError(f"Could not read local registry.py at {p}")
if not body:
raise RuntimeError(f"Empty local registry.py at {p}")
return body
ref = ref or ctx.branch
url = f"https://raw.githubusercontent.com/{ctx.repo}/{ref}/{_REGISTRY_PATH}"
if verbose:
print(f" [registry] fetching {url}")
body, _ = _get(url, ua=_BROWSER_UA)
if not body:
raise RuntimeError(f"Could not fetch registry.py from {url}")
return body
def parse_vllm_registry(source, verbose: bool = False):
"""Parse registry.py source and return structured info.
Returns:
supported: dict[arch] -> {category, module, class_name}
previously: dict[arch] -> version_str
oot: dict[arch] -> plugin_url
"""
supported = {}
for dict_name, category in _CATEGORY_MAP.items():
entries = _parse_dict_entries(source, dict_name)
for arch, (mod, cls) in entries.items():
supported[arch] = {
"category": category,
"module": mod,
"class_name": cls,
}
if verbose and entries:
print(f" [registry] {dict_name}: {len(entries)} entries")
previously = _parse_simple_dict(source, "_PREVIOUSLY_SUPPORTED_MODELS")
if verbose and previously:
print(f" [registry] _PREVIOUSLY_SUPPORTED_MODELS: {len(previously)} entries")
oot = _parse_simple_dict(source, "_OOT_SUPPORTED_MODELS")
if verbose and oot:
print(f" [registry] _OOT_SUPPORTED_MODELS: {len(oot)} entries")
return supported, previously, oot
def check_vllm_registry(arch, supported, previously, oot):
"""Check an architecture against parsed vLLM registry data.
Returns a dict with status details.
"""
if arch in supported:
info = supported[arch]
mod = info["module"]
if mod.startswith("vllm."):
full_module = mod
else:
full_module = f"vllm.model_executor.models.{mod}"
return {
"status": "supported",
"category": info["category"],
"module": full_module,
"class_name": info["class_name"],
}
if arch in previously:
return {
"status": "previously_supported",
"last_version": previously[arch],
}
if arch in oot:
return {
"status": "oot_plugin",
"plugin_url": oot[arch],
}
return {"status": "unsupported"}
@@ -0,0 +1,119 @@
"""vLLM strategy: registry.py parsing, version path, summary formatting."""
import os
from typing import Optional, Tuple
from ...context import Context
from .registry import (
check_vllm_registry,
fetch_vllm_registry,
parse_vllm_registry,
)
from ..base import FrameworkStrategy
_NEW_MODELS_DIR = "vllm/models"
class VllmStrategy(FrameworkStrategy):
name = "vllm"
label = "vLLM"
repo = "vllm-project/vllm"
branch = "main"
models_dir = "vllm/model_executor/models"
docs_url = "https://docs.vllm.ai/en/stable/models/supported_models/"
def __init__(self):
super().__init__()
self._registry_file_path = None
def check_support(
self, arch: str, ctx: Context, token: Optional[str] = None, verbose: bool = False
) -> Tuple[bool, Optional[str]]:
supported, file_path = super().check_support(arch, ctx, token, verbose)
if supported:
return True, file_path
try:
reg_source = fetch_vllm_registry(ctx=ctx, ref=self.branch, verbose=verbose)
reg_supported, _, _ = parse_vllm_registry(reg_source, verbose=verbose)
except RuntimeError as e:
if verbose:
print(f" [registry-fallback] skipped: {e}")
return False, None
if arch not in reg_supported:
return False, None
module = reg_supported[arch]["module"]
if not module.startswith("vllm.models."):
return False, None
resolved = self._resolve_new_style_path(module, arch, ctx, verbose)
if resolved:
self._registry_file_path = resolved
if verbose:
print(f" [registry-fallback] found via registry: {resolved}")
return True, resolved
return False, None
def _resolve_new_style_path(self, module, arch, ctx, verbose):
pkg_rel = module.replace(".", os.sep)
candidates = [
f"{pkg_rel}/__init__.py",
f"{pkg_rel}.py",
]
for rel in candidates:
body = ctx.read_source(rel)
if body and arch in body:
return rel
if ctx.is_local:
pkg_dir = os.path.join(ctx.local_dir, pkg_rel)
if os.path.isdir(pkg_dir):
for fname in sorted(os.listdir(pkg_dir)):
if fname.endswith(".py") and fname != "__init__.py":
fpath = os.path.join(pkg_dir, fname)
try:
with open(fpath, encoding="utf-8") as f:
body = f.read()
except OSError:
continue
if arch in body:
return f"{pkg_rel}/{fname}"
return None
def extra_checks(self, arch: str, ctx: Context, token: Optional[str], verbose: bool, ref: Optional[str] = None):
"""Parse registry.py for detailed vLLM model info."""
try:
reg_source = fetch_vllm_registry(ctx=ctx, ref=ref or self.branch, verbose=verbose)
reg_supported, reg_previously, reg_oot = parse_vllm_registry(
reg_source, verbose=verbose
)
print(f" Registry parsed: {len(reg_supported)} architectures registered")
info = check_vllm_registry(arch, reg_supported, reg_previously, reg_oot)
status = info["status"]
if status == "supported":
print(f" Category : {info['category']}")
print(f" Module : {info['module']}")
print(f" Class : {info['class_name']}")
elif status == "previously_supported":
print(f" PREVIOUSLY SUPPORTED (removed)")
print(f" Last version: v{info['last_version']}")
elif status == "oot_plugin":
print(f" OUT-OF-TREE PLUGIN REQUIRED")
print(f" Plugin: {info['plugin_url']}")
return info
except RuntimeError as e:
if verbose:
print(f" [registry] skipped: {e}")
return None
def version_path(self, file_path: Optional[str]) -> Optional[str]:
"""Prefer registry-resolved path, then file_path, then registry.py."""
return self._registry_file_path or file_path or f"{self.models_dir}/registry.py"
def format_summary_extra(self, info) -> None:
if not info:
return
status = info["status"]
if status == "previously_supported":
print(f" NOTE: removed after v{info['last_version']}")
elif status == "oot_plugin":
print(f" NOTE: requires plugin {info['plugin_url']}")
elif status == "supported":
print(f" Category: {info['category']}")
@@ -0,0 +1,15 @@
"""vLLM-Ascend framework strategy."""
from .registry import (
check_vllm_ascend_registry,
fetch_vllm_ascend_registry,
parse_vllm_ascend_registry,
)
from .strategy import VllmAscendStrategy
__all__ = [
"VllmAscendStrategy",
"fetch_vllm_ascend_registry",
"parse_vllm_ascend_registry",
"check_vllm_ascend_registry",
]
@@ -0,0 +1,104 @@
"""vLLM-Ascend __init__.py parsing for registered models.
vLLM-Ascend uses ModelRegistry.register_model() calls in __init__.py
to register model architectures, unlike vLLM which uses a dict-based registry.
"""
import os
import re
from typing import Optional
from ...context import Context
from ...http_utils import _get
_INIT_PATH = "vllm_ascend/models/__init__.py"
_BROWSER_UA = {
"User-Agent": (
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0 Safari/537.36"
)
}
def fetch_vllm_ascend_registry(ctx: Context, ref: Optional[str] = None, verbose: bool = False) -> str:
"""Fetch vLLM-Ascend models/__init__.py source.
In local mode (ctx.is_local) the file is read from disk; otherwise
it is fetched from the GitHub raw CDN.
"""
if ctx.is_local:
p = os.path.join(ctx.local_dir, _INIT_PATH)
if verbose:
print(f" [registry] reading local {p}")
try:
with open(p, encoding="utf-8") as f:
body = f.read()
except OSError:
raise RuntimeError(f"Could not read local __init__.py at {p}")
if not body:
raise RuntimeError(f"Empty local __init__.py at {p}")
return body
ref = ref or ctx.branch
url = f"https://raw.githubusercontent.com/{ctx.repo}/{ref}/{_INIT_PATH}"
if verbose:
print(f" [registry] fetching {url}")
body, _ = _get(url, ua=_BROWSER_UA)
if not body:
raise RuntimeError(f"Could not fetch __init__.py from {url}")
return body
def parse_vllm_ascend_registry(source: str, verbose: bool = False):
"""Parse __init__.py source and extract registered models.
Looks for ModelRegistry.register_model() calls and extracts:
- arch_name: the architecture name (first argument)
- class_path: the module:class path (second argument)
Returns:
registered: dict[arch_name] = class_path
"""
# Match: ModelRegistry.register_model("ArchName", "module.path:ClassName")
# Handles multi-line calls with various whitespace
pattern = re.compile(
r'ModelRegistry\.register_model\s*\(\s*'
r'["\'](\w+)["\']\s*,\s*'
r'["\']([^"\']+)["\']',
re.MULTILINE
)
registered = {}
for m in pattern.finditer(source):
arch_name = m.group(1)
class_path = m.group(2)
registered[arch_name] = class_path
if verbose and registered:
print(f" [registry] found {len(registered)} registered models")
return registered
def check_vllm_ascend_registry(arch: str, registered: dict) -> dict:
"""Check an architecture against parsed vLLM-Ascend registry data.
Returns a dict with status details.
"""
if arch in registered:
class_path = registered[arch]
# Parse "module.path:ClassName" format
if ":" in class_path:
module_path, class_name = class_path.rsplit(":", 1)
else:
module_path = class_path
class_name = class_path.split(".")[-1]
return {
"status": "supported",
"module": module_path,
"class_name": class_name,
}
return {"status": "unsupported"}
@@ -0,0 +1,108 @@
"""vLLM-Ascend strategy: __init__.py parsing for registered models."""
import os
from typing import Optional, Tuple
from ...context import Context
from .registry import (
check_vllm_ascend_registry,
fetch_vllm_ascend_registry,
parse_vllm_ascend_registry,
)
from ..base import FrameworkStrategy
class VllmAscendStrategy(FrameworkStrategy):
name = "vllm-ascend"
label = "vLLM-Ascend"
repo = "vllm-project/vllm-ascend"
branch = "main"
models_dir = "vllm_ascend/models"
docs_url = "https://docs.vllm.ai/projects/ascend/en/latest/"
def __init__(self):
super().__init__()
self._registry_file_path = None
def check_support(
self, arch: str, ctx: Context, token: Optional[str] = None, verbose: bool = False
) -> Tuple[bool, Optional[str]]:
supported, file_path = super().check_support(arch, ctx, token, verbose)
if supported:
return True, file_path
try:
init_source = fetch_vllm_ascend_registry(ctx=ctx, ref=self.branch, verbose=verbose)
registered = parse_vllm_ascend_registry(init_source, verbose=verbose)
except RuntimeError as e:
if verbose:
print(f" [registry-fallback] skipped: {e}")
return False, None
if arch not in registered:
return False, None
class_path = registered[arch]
if ":" in class_path:
module_path = class_path.rsplit(":", 1)[0]
else:
module_path = class_path
if not module_path.startswith("vllm_ascend.models."):
return False, None
resolved = self._resolve_new_style_path(module_path, arch, ctx, verbose)
if resolved:
self._registry_file_path = resolved
if verbose:
print(f" [registry-fallback] found via registry: {resolved}")
return True, resolved
return False, None
def _resolve_new_style_path(self, module, arch, ctx, verbose):
pkg_rel = module.replace(".", os.sep)
candidates = [
f"{pkg_rel}/__init__.py",
f"{pkg_rel}.py",
]
for rel in candidates:
body = ctx.read_source(rel)
if body and arch in body:
return rel
if ctx.is_local:
pkg_dir = os.path.join(ctx.local_dir, pkg_rel)
if os.path.isdir(pkg_dir):
for fname in sorted(os.listdir(pkg_dir)):
if fname.endswith(".py") and fname != "__init__.py":
fpath = os.path.join(pkg_dir, fname)
try:
with open(fpath, encoding="utf-8") as f:
body = f.read()
except OSError:
continue
if arch in body:
return f"{pkg_rel}/{fname}"
return None
def extra_checks(self, arch: str, ctx: Context, token: Optional[str], verbose: bool, ref: Optional[str] = None):
"""Parse __init__.py for registered model info."""
try:
init_source = fetch_vllm_ascend_registry(ctx=ctx, ref=ref or self.branch, verbose=verbose)
registered = parse_vllm_ascend_registry(init_source, verbose=verbose)
print(f" Registry parsed: {len(registered)} architectures registered")
info = check_vllm_ascend_registry(arch, registered)
status = info["status"]
if status == "supported":
print(f" Module : {info['module']}")
print(f" Class : {info['class_name']}")
return info
except RuntimeError as e:
if verbose:
print(f" [registry] skipped: {e}")
return None
def version_path(self, file_path: Optional[str]) -> Optional[str]:
"""Prefer registry-resolved path, then file_path, then __init__.py."""
return self._registry_file_path or file_path or f"{self.models_dir}/__init__.py"
def format_summary_extra(self, info) -> None:
if not info:
return
status = info["status"]
if status == "supported":
print(f" Module: {info['module']}")
@@ -0,0 +1,41 @@
"""Minimal HTTP helpers (standard library only)."""
import json
import urllib.error
import urllib.request
UA = {"User-Agent": "model-support-check/1.0"}
BROWSER_UA = {
"User-Agent": (
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0 Safari/537.36"
)
}
def _get(url, headers=None, timeout=25, ua=None):
h = dict(ua or UA)
if headers:
h.update(headers)
req = urllib.request.Request(url, headers=h)
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.read().decode("utf-8", "replace"), r.headers
except urllib.error.HTTPError as e:
if e.code in (403, 429):
raise RuntimeError(f"GitHub rate limit / forbidden ({e.code})")
if e.code in (401, 404):
return None, e.headers
raise
def _get_json(url, token=None):
headers = {"Authorization": f"Bearer {token}"} if token else {}
try:
body, _ = _get(url, headers)
except RuntimeError:
return None
if body is None:
return None
return json.loads(body)
@@ -0,0 +1,22 @@
"""State management for model-support-checker.
State lives in <skill root>/.state/ (gitignored via .gitignore) so the
first-run choice (GitHub PAT vs local clone) survives across runs without
being tracked by git. The GitHub token itself is NEVER stored here.
"""
from .doctor import doctor, print_report
from .persistence import load, save, reset
from .setup import first_run_menu, ensure_setup
from .refresh import start_refresh
__all__ = [
"load",
"save",
"reset",
"first_run_menu",
"ensure_setup",
"start_refresh",
"doctor",
"print_report",
]
@@ -0,0 +1,40 @@
"""Repository cloning and validation."""
import os
import subprocess
from ..framework_strategies import STRATEGIES
from .constants import REPOS_DIR
def clone(url, target):
"""Clone url into target (full history -- shallow clones break step 4)."""
if os.path.isdir(os.path.join(target, ".git")):
print(f" reusing existing clone: {target}")
return target
os.makedirs(os.path.dirname(target), exist_ok=True)
print(f" cloning {url} -> {target} (full history, may take a while)...")
r = subprocess.run(["git", "clone", url, target])
if r.returncode != 0:
raise RuntimeError(f"git clone failed for {url}")
return target
def validate_checkout(path, fw_name):
"""Validate that a path looks like a valid framework checkout."""
strategy = STRATEGIES[fw_name]
if not os.path.isfile(os.path.join(path, strategy.models_dir, "__init__.py")):
print(
f" WARNING: {strategy.models_dir} not found under {path}; "
f"is this really a {strategy.label} checkout?"
)
def get_clone_url(fw_name):
"""Get the clone URL for a framework."""
return f"https://github.com/{STRATEGIES[fw_name].repo}"
def get_default_clone_path(fw_name):
"""Get the default clone path for a framework."""
return os.path.join(REPOS_DIR, fw_name)
@@ -0,0 +1,8 @@
"""State constants."""
import os
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
STATE_DIR = os.path.join(ROOT, ".state")
REPOS_DIR = os.path.join(STATE_DIR, "repos")
STATE_FILE = os.path.join(STATE_DIR, "state.json")
@@ -0,0 +1,169 @@
"""Health checks for persisted setup state.
The `doctor()` function inspects `.state/state.json` and the configured
framework checkouts, returning a list of actionable issues. It is run
automatically on every invocation so callers (human or agent) do not need
to manually inspect `.state/` with `ls` or `cat`.
"""
import os
from ..framework_strategies import STRATEGIES
from .constants import STATE_FILE
class Issue:
"""A single doctor issue with severity and an actionable message."""
def __init__(self, severity, message, framework=None):
self.severity = severity # "error" | "warning"
self.message = message
self.framework = framework
def __str__(self):
prefix = "ERROR" if self.severity == "error" else "WARN"
if self.framework:
return f"[{prefix} {self.framework}] {self.message}"
return f"[{prefix}] {self.message}"
def doctor(st, args=None, framework=None):
"""Check setup state and local checkouts.
Args:
st: The loaded state dict, or None if no state file exists.
args: Optional argparse namespace with path overrides.
framework: Framework name to limit the check to, or None/'all' to check
every configured framework.
Returns:
A list of Issue objects. An empty list means the configuration looks
healthy enough to proceed.
"""
issues = []
if st is None:
issues.append(
Issue(
"error",
f"No setup state found ({STATE_FILE} missing). "
"Run: python3 main.py --setup local",
)
)
return issues
mode = st.get("mode")
if mode not in ("local", "token"):
issues.append(
Issue(
"error",
f"Invalid mode '{mode}' in state. Run: python3 main.py --setup local",
)
)
return issues
if mode == "token":
token = _get_token(args)
if not token:
issues.append(
Issue(
"warning",
"GitHub token mode but no GITHUB_TOKEN set. "
"Code search results will be best-effort only.",
)
)
return issues
# Local mode: validate the requested framework path(s).
frameworks = list(STRATEGIES) if framework in (None, "all") else [framework]
for fw_name in frameworks:
if fw_name not in STRATEGIES:
issues.append(Issue("error", f"Unknown framework: {fw_name}"))
continue
strategy = STRATEGIES[fw_name]
path_key = f"{fw_name.replace('-', '_')}_path"
configured_path = st.get(path_key)
override_path = _get_override_path(args, fw_name)
path = override_path or configured_path
if not configured_path and not override_path:
issues.append(
Issue(
"error",
f"No local checkout configured. Run: python3 main.py --setup local --{fw_name}-path /path/to/{fw_name}",
framework=strategy.label,
)
)
continue
if override_path and not configured_path:
issues.append(
Issue(
"warning",
f"Using one-time override {override_path}; state is missing a saved path.",
framework=strategy.label,
)
)
if not os.path.isdir(path):
issues.append(
Issue(
"error",
f"Configured path does not exist: {path}",
framework=strategy.label,
)
)
continue
if not os.path.isdir(os.path.join(path, ".git")):
issues.append(
Issue(
"error",
f"Path is not a git repository: {path}",
framework=strategy.label,
)
)
continue
init_file = os.path.join(path, strategy.models_dir, "__init__.py")
if not os.path.isfile(init_file):
issues.append(
Issue(
"warning",
f"{strategy.models_dir}/__init__.py not found under {path}; "
"is this really a checkout?",
framework=strategy.label,
)
)
return issues
def _get_token(args):
if args and getattr(args, "token", None):
return args.token
return os.environ.get("GITHUB_TOKEN")
def _get_override_path(args, fw_name):
if args is None:
return None
attr = f"{fw_name.replace('-', '_')}_path"
return getattr(args, attr, None)
def print_report(issues):
"""Print doctor issues in a consistent format.
Returns True if any errors were reported.
"""
has_errors = any(i.severity == "error" for i in issues)
if not issues:
print("doctor: setup state looks healthy.")
return False
print("=== doctor ===")
for issue in issues:
print(f" {issue}")
print()
return has_errors
@@ -0,0 +1,33 @@
"""State persistence: load, save, reset."""
import json
import os
from .constants import STATE_DIR, STATE_FILE, REPOS_DIR
def load():
"""Return the saved state dict, or None if not set up yet."""
try:
with open(STATE_FILE, encoding="utf-8") as f:
st = json.load(f)
return st if isinstance(st, dict) and st.get("mode") else None
except (OSError, ValueError):
return None
def save(st):
os.makedirs(STATE_DIR, exist_ok=True)
with open(STATE_FILE, "w", encoding="utf-8") as f:
json.dump(st, f, indent=2)
return st
def reset():
"""Forget setup state. Cloned repos under .state/repos/ are kept and will
be reused automatically by a later `--setup local`."""
try:
os.remove(STATE_FILE)
print(f"Removed {STATE_FILE} (cloned repos kept at {REPOS_DIR}).")
except FileNotFoundError:
print("No saved state found.")
@@ -0,0 +1,68 @@
"""Background checkout refresh."""
import subprocess
import threading
def fetch_status(path, result, key):
"""Background worker: `git fetch` a local checkout and count how far
behind its upstream it is. Writes into result[key]; NEVER raises — any
failure is recorded as {"error": ...} so the main flow is never blocked."""
info = {"path": path}
try:
remotes = subprocess.run(
["git", "-C", path, "remote"],
capture_output=True, text=True,
).stdout.strip()
if not remotes:
info["no_upstream"] = True
result[key] = info
return
f = subprocess.run(
["git", "-C", path, "fetch", "--quiet", "origin"],
capture_output=True, text=True, timeout=300,
)
if f.returncode != 0:
lines = [ln for ln in f.stderr.strip().splitlines() if ln.strip()]
info["error"] = lines[-1] if lines else "git fetch failed"
else:
up = subprocess.run(
["git", "-C", path, "rev-parse", "--abbrev-ref",
"--symbolic-full-name", "@{upstream}"],
capture_output=True, text=True,
)
head = subprocess.run(
["git", "-C", path, "rev-parse", "--abbrev-ref", "HEAD"],
capture_output=True, text=True,
).stdout.strip()
if up.returncode != 0 or head in ("", "HEAD"):
info["no_upstream"] = True
else:
cnt = subprocess.run(
["git", "-C", path, "rev-list", "--count",
f"HEAD..{up.stdout.strip()}"],
capture_output=True, text=True,
)
if cnt.returncode == 0 and cnt.stdout.strip().isdigit():
info["behind"] = int(cnt.stdout.strip())
else:
info["no_upstream"] = True
except (subprocess.SubprocessError, OSError, ValueError) as e:
# ponytail: broad catch is the point — refresh must never be fatal
info["error"] = str(e)
result[key] = info
def start_refresh(framework_paths):
"""Spawn daemon threads to refresh local checkouts concurrently.
Returns (results_dict, threads); results are filled in as workers finish.
"""
results = {}
threads = []
for key, path in framework_paths.items():
t = threading.Thread(target=fetch_status, args=(path, results, key),
daemon=True)
t.start()
threads.append(t)
return results, threads
@@ -0,0 +1,95 @@
"""Interactive setup and first-run menu."""
import os
import sys
from ..framework_strategies import STRATEGIES
from .clone import clone, validate_checkout, get_clone_url, get_default_clone_path
from .constants import REPOS_DIR, STATE_FILE
from .persistence import save
def print_tradeoffs():
"""Print the tradeoffs between local clone and GitHub PAT modes."""
print(
"First-run setup: choose how to access vLLM/SGLang sources.\n"
"\n"
" 1) Local clone (recommended)\n"
" + definitive results: files grepped on disk, no rate limits\n"
" + fast repeat checks; version detection from full git history\n"
" + works offline after the initial clone\n"
" - one-time download (vLLM full history ~1 GB+, SGLang smaller)\n"
" - needs occasional 'git pull' or answers go stale\n"
"\n"
" 2) GitHub PAT\n"
" + no disk usage; always reflects remote main\n"
" - code search 403s without a token; anonymous results are\n"
" best-effort only\n"
" - API rate limits can break batch/version checks\n"
" - GITHUB_TOKEN must be provided every run (never stored here)"
)
def first_run_menu():
"""Interactive TTY menu. Returns the chosen mode ('local' | 'token')."""
print_tradeoffs()
while True:
choice = input("Choose [1/2] (default 1): ").strip()
if choice in ("", "1"):
return "local"
if choice == "2":
return "token"
print("Please enter 1 or 2.")
def ensure_setup(mode, args):
"""Create and persist setup state. Returns the new state dict."""
st = {"mode": mode}
if mode == "local":
vllm_path = args.vllm_path
sglang_path = args.sglang_path
vllm_ascend_path = getattr(args, "vllm_ascend_path", None)
if sys.stdin.isatty():
if not vllm_path:
raw = input(
f"vLLM checkout path [Enter = clone into {REPOS_DIR}/vllm]: "
).strip()
vllm_path = raw or None
if not sglang_path:
raw = input(
f"SGLang checkout path [Enter = clone into {REPOS_DIR}/sglang]: "
).strip()
sglang_path = raw or None
if not vllm_ascend_path:
raw = input(
f"vLLM-Ascend checkout path [Enter = clone into {REPOS_DIR}/vllm-ascend]: "
).strip()
vllm_ascend_path = raw or None
if not vllm_path:
vllm_path = clone(get_clone_url("vllm"), get_default_clone_path("vllm"))
if not sglang_path:
sglang_path = clone(get_clone_url("sglang"), get_default_clone_path("sglang"))
if not vllm_ascend_path:
vllm_ascend_path = clone(get_clone_url("vllm-ascend"), get_default_clone_path("vllm-ascend"))
st["vllm_path"] = os.path.abspath(os.path.expanduser(vllm_path))
st["sglang_path"] = os.path.abspath(os.path.expanduser(sglang_path))
st["vllm_ascend_path"] = os.path.abspath(os.path.expanduser(vllm_ascend_path))
validate_checkout(st["vllm_path"], "vllm")
validate_checkout(st["sglang_path"], "sglang")
validate_checkout(st["vllm_ascend_path"], "vllm-ascend")
elif mode == "token":
if not args.token and not os.environ.get("GITHUB_TOKEN"):
print(
"NOTE: no GITHUB_TOKEN set. Code search needs it; export "
"GITHUB_TOKEN per run (it is never stored in .state/)."
)
else:
raise RuntimeError(f"Unknown setup mode: {mode}")
save(st)
print(f"Setup saved ({mode}) -> {STATE_FILE}")
return st