SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
23.4 KB · 376 lines python
Raw Blame History
1"""Model identity ontology — the rules that separate a MODEL (release) from its ARTIFACTS (checkpoints, conversions, quantisations),2its EVALUATION VARIANTS (reasoning-effort settings of the same weights) and its FAMILY.34    MODEL FAMILY   Llama 4 · Qwen3.6 · Claude · Gemini5      └ MODEL      Llama 4 Maverick · Qwen3.6-35B-A3B · Claude Fable 5.16          └ ARTIFACT  meta-llama/Llama-4-Maverick-17B-128E-Instruct (official checkpoint) · unsloth/…-GGUF (third-party quantisation)7              └ DEPLOYMENT  OpenRouter meta-llama/llama-4-maverick · Together meta-llama/Llama-4-Maverick  (= prices rows)89Everything here is deterministic string analysis. It never *asserts* a relation on its own: the resolution service uses these10signals together with identifiers, organisations, `base_model` metadata and dates, and parks anything ambiguous in the review queue.11"""12from __future__ import annotations1314import re15from dataclasses import dataclass, field1617# ---------------------------------------------------------------------------------------------- quantisation / precision formats18QUANT_FORMATS: dict[str, str] = {19    # token (lowercase, matched on word boundaries) → canonical format20    "gguf": "gguf", "ggml": "gguf", "q2_k": "gguf", "q3_k_m": "gguf", "q4_k_m": "gguf", "q4_k_s": "gguf", "q5_k_m": "gguf", "q6_k": "gguf", "q8_0": "gguf",21    "q4_0": "gguf", "q4_1": "gguf", "q5_0": "gguf", "iq4_xs": "gguf", "iq3_m": "gguf", "iq2_m": "gguf", "ud-q4_k_xl": "gguf",22    "awq": "awq", "w4a16": "awq", "gptq": "gptq", "exl2": "exl2", "exl3": "exl3", "mlx": "mlx", "onnx": "onnx", "openvino": "openvino", "coreml": "coreml",23    "tensorrt": "tensorrt", "trt": "tensorrt", "trt-llm": "tensorrt", "bnb": "bnb", "bitsandbytes": "bnb", "nf4": "bnb", "4bit": "int4", "8bit": "int8",24    "int4": "int4", "int8": "int8", "w8a8": "int8", "w8a16": "int8", "fp8": "fp8", "fp8-kv": "fp8", "e4m3": "fp8", "nvfp4": "nvfp4", "mxfp4": "mxfp4",25    "mxfp8": "mxfp8", "fp4": "fp4", "quark": "quark", "quantized": "quantized", "quant": "quantized", "qat": "qat", "hqq": "hqq", "aqlm": "aqlm", "eetq": "eetq",26    "smoothquant": "smoothquant", "compressed-tensors": "compressed-tensors", "marlin": "gptq", "gptq-int4": "gptq", "autoround": "autoround",27    "2bit": "int2", "3bit": "int3", "5bit": "int5", "6bit": "int6", "2-bit": "int2", "3-bit": "int3", "4-bit": "int4", "5-bit": "int5", "6-bit": "int6", "8-bit": "int8",28}29# Full-precision dtype tokens: a "-BF16" or "-FP16" repo is a *conversion/packaging* of the same weights, not a quantisation.30PRECISION_FORMATS = {"bf16", "fp16", "fp32", "f16", "f32", "float16", "bfloat16", "half"}31ARTIFACT_PACKAGING = {"safetensors", "pytorch", "pth", "ckpt", "jax", "flax", "tf", "tflite", "litert", "gguf", "mlx", "onnx", "coreml", "openvino", "tensorrt"}3233# Third-party organisations that (almost) only publish conversions/quantisations of other people's models.34CONVERTER_ORGS = {35    "unsloth", "bartowski", "mlx-community", "thebloke", "lmstudio-community", "qwen-community", "mradermacher", "quantfactory", "nousresearch-quant",36    "mistral-community", "turboderp", "casperhansen", "neuralmagic", "redhatai", "amd", "intel", "nvidia-quant", "ggml-org", "second-state",37    "mlx-vision", "cortexso", "gaianet", "bunnycore", "dranger003", "ubergarm", "anthracite-org", "modelcloud", "jinaai-quant", "ai-forever-quant",38    "lmstudio", "ollama", "ggerganov", "mlc-ai", "onnx-community", "onnxmodelzoo", "kaitchup", "thedrummer-quant",39}4041# ---------------------------------------------------------------------------------------------- evaluation-effort variants (same weights, different setting)42# Suffixes appended by evaluators (Artificial Analysis, LiveBench…) to a model slug to denote a *configuration* of the model.43EFFORT_SUFFIXES: dict[str, dict[str, str]] = {44    "xhigh": {"reasoning_effort": "xhigh"}, "x-high": {"reasoning_effort": "xhigh"}, "extra-high": {"reasoning_effort": "xhigh"},45    "high": {"reasoning_effort": "high"}, "medium": {"reasoning_effort": "medium"}, "low": {"reasoning_effort": "low"}, "minimal": {"reasoning_effort": "minimal"},46    "max-effort": {"reasoning_effort": "max"}, "high-effort": {"reasoning_effort": "high"}, "low-effort": {"reasoning_effort": "low"},47    "medium-effort": {"reasoning_effort": "medium"}, "xhigh-effort": {"reasoning_effort": "xhigh"},48    "thinking": {"reasoning": "on"}, "reasoning": {"reasoning": "on"}, "think": {"reasoning": "on"}, "thinking-on": {"reasoning": "on"},49    "non-reasoning": {"reasoning": "off"}, "no-reasoning": {"reasoning": "off"}, "non-thinking": {"reasoning": "off"}, "nothink": {"reasoning": "off"},50    "no-think": {"reasoning": "off"}, "no-thinking": {"reasoning": "off"}, "thinking-off": {"reasoning": "off"}, "without-thinking": {"reasoning": "off"},51    "with-thinking": {"reasoning": "on"},52    "adaptive": {"reasoning": "adaptive"}, "adaptive-reasoning": {"reasoning": "adaptive"},53    # NOT effort suffixes although evaluators sometimes use them: "max" (Qwen3-Max, GPT-5.1-Codex-Max are models), "fast" (Grok 4.1 Fast),54    # "instant" (Claude Instant) — they name a model tier, so they are only recognised in the explicit "-max-effort" form above.55    "thinking-16k": {"reasoning": "on", "thinking_budget": "16k"}, "thinking-32k": {"reasoning": "on", "thinking_budget": "32k"},56    "thinking-64k": {"reasoning": "on", "thinking_budget": "64k"}, "thinking-128k": {"reasoning": "on", "thinking_budget": "128k"},57    "thinking-8k": {"reasoning": "on", "thinking_budget": "8k"}, "thinking-4k": {"reasoning": "on", "thinking_budget": "4k"}, "thinking-1k": {"reasoning": "on", "thinking_budget": "1k"},58}59# order matters: try the longest compound suffixes first60_EFFORT_ORDERED = sorted(EFFORT_SUFFIXES, key=len, reverse=True)61_EFFORT_RE = re.compile(r"[-_ ](" + "|".join(re.escape(s) for s in _EFFORT_ORDERED) + r")$", re.I)62# LiveBench-style budgets: "32k-thinking", "24k-think", "default-think(ing)"63_BUDGET_RE = re.compile(r"[-_ ]((\d+)k)[-_ ]?(thinking|think)$", re.I)64_DEFAULT_THINK_RE = re.compile(r"[-_ ](default[-_ ]?(thinking|think))$", re.I)65_MAX_EFFORT_SUFFIXES = 3     # "claude-opus-4-5-20251101-thinking-64k-high-effort" → thinking-64k + high-effort66# Words that are *part of a model name*, never an effort suffix, when they precede the suffix (e.g. "Kimi K2 Thinking" is a distinct release).67OFFICIAL_THINKING_RELEASES = {"kimi-k2-thinking", "qwen3-235b-a22b-thinking-2507", "qwen3-30b-a3b-thinking-2507", "qwen3-4b-thinking-2507", "glm-4.5-air-thinking",68                              "gemini-2.5-flash-thinking", "grok-3-mini-thinking", "gemini-2-0-flash-thinking-exp-1219", "gemini-2-0-flash-thinking-exp-01-21",69                              "qwen3-next-80b-a3b-thinking", "trinity-large-thinking", "trinity-mini-thinking", "kimi-k2-thinking-turbo", "devstral-medium",70                              "mistral-medium", "codestral-medium", "magistral-medium", "mistral-small", "mistral-large"}71# families whose "Thinking" checkpoints are separate weights (own hub repo), never an evaluation setting72_OFFICIAL_THINKING_PATTERNS = [re.compile(p) for p in (r"^qwen3-vl-.*-thinking$", r"^qwen3(\.\d+)?-.*-thinking-\d{4}$", r"^qwen3-next-.*-thinking$",73                                                        r"^glm-4\.[1-9]v?-.*thinking$", r"^deepseek-v3\.1-terminus-thinking$", r"^trinity-.*-thinking$")]74# tier words that are only an *effort* when the stem carries a version or size digit ("claude-opus-5-medium", "o3-mini-high", "gpt-5-4-mini-low")75# — never on a bare product name ("devstral-medium", "mistral-medium" are model tiers)76_DIGIT_GATED_SUFFIXES = {"medium", "low", "high", "minimal"}777879def is_official_thinking_release(low: str) -> bool:80    return low in OFFICIAL_THINKING_RELEASES or any(p.match(low) for p in _OFFICIAL_THINKING_PATTERNS)8182# ---------------------------------------------------------------------------------------------- name analysis83_SIZE_RE = re.compile(r"(?<![a-z0-9])(\d+(?:\.\d+)?)\s?([bmt])(?![a-z])", re.I)          # 70B 3.8B 235B 1.5T 350M84_ACTIVE_RE = re.compile(r"(?<![a-z0-9])(\d+(?:\.\d+)?)\s?[bmt]\s?-?a(\d+(?:\.\d+)?)\s?([bmt])(?![a-z])", re.I)   # 35B-A3B85_DATE_RE = re.compile(r"(?<!\d)(20\d{2})[-_.]?(0[1-9]|1[0-2])[-_.]?(0[1-9]|[12]\d|3[01])(?!\d)")   # 2024062086_MMDD_RE = re.compile(r"(?<![0-9])(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])(?![0-9])")                   # 0905 / 0324 (release snapshots)87_YYMM_RE = re.compile(r"(?<![0-9])(2[3-9])(0[1-9]|1[0-2])(?![0-9])")                                 # 2507 (Qwen-style)88_TRAILING_VARIANT_WORDS = {"instruct", "it", "chat", "base", "sft", "dpo", "rl", "hf", "preview", "exp", "experimental", "latest", "beta", "alpha", "v1", "v2", "v3",89                           "mtp", "distill", "distilled", "uncensored", "abliterated", "heretic", "merge"}90_TOKEN_SPLIT = re.compile(r"[\s_/]+|(?<=[a-z])(?=[A-Z][a-z])")919293@dataclass94class NameAnalysis:95    raw: str96    repo_org: str | None = None                    # "unsloth" in "unsloth/Qwen3.6-35B-A3B-GGUF"97    repo_name: str | None = None                   # "Qwen3.6-35B-A3B-GGUF"98    base_key: str = ""                             # normalised key with quant/precision/effort tokens removed: "qwen3.6-35b-a3b"99    quant_formats: list[str] = field(default_factory=list)     # ["gguf"]100    precision: str | None = None                   # "bf16" when only a precision tag is present101    is_quantized: bool = False102    is_conversion: bool = False                    # packaging/precision conversion without quantisation (BF16 repack, MLX fp16, ONNX)103    from_converter_org: bool = False104    effort: dict[str, str] = field(default_factory=dict)       # {"reasoning_effort": "xhigh"} when an evaluator suffix was stripped105    effort_suffix: str | None = None106    parameter_count: int | None = None107    active_parameter_count: int | None = None108    snapshot_date: str | None = None               # "2024-06-20" / "2025-09" style date embedded in the name109    family_hint: str | None = None                 # "Qwen3.6", "Llama 4", "Claude", "Gemini 2.5"110111    @property112    def is_artifact(self) -> bool:113        return self.is_quantized or self.is_conversion114115    @property116    def is_effort_variant(self) -> bool:117        return bool(self.effort)118119120def _to_count(num: str, unit: str) -> int:121    mult = {"m": 1e6, "b": 1e9, "t": 1e12}[unit.lower()]122    return int(round(float(num) * mult))123124125def analyze_model_name(raw: str) -> NameAnalysis:126    """Deterministic analysis of a model / repository name."""127    a = NameAnalysis(raw=raw.strip())128    name = a.raw129    if "/" in name and " " not in name.split("/")[0]:130        org, _, rest = name.partition("/")131        a.repo_org, a.repo_name = org.strip(), rest.strip()132        name = rest133        a.from_converter_org = org.strip().lower() in CONVERTER_ORGS134    low = re.sub(r"[\s_]+", "-", name.lower().strip())135    low = re.sub(r"[()\[\]]+", "-", low).strip("-")136    low = re.sub(r"-{2,}", "-", low)137138    # evaluator effort suffixes (up to three, e.g. "-thinking-64k-high-effort"), only when the stem is not itself an official "Thinking" release139    stripped: list[str] = []140    for _ in range(_MAX_EFFORT_SUFFIXES):141        if is_official_thinking_release(low):142            break143        m = _BUDGET_RE.search(low)              # "-32k-thinking" before the bare "-thinking"144        if m:145            a.effort = {"reasoning": "on", "thinking_budget": m.group(1).lower(), **a.effort}146            stripped.insert(0, m.group(0)[1:].lower())147            low = low[: m.start()]148            continue149        m = _DEFAULT_THINK_RE.search(low)150        if m:151            a.effort = {"reasoning": "on", **a.effort}152            stripped.insert(0, m.group(1).lower())153            low = low[: m.start()]154            continue155        m = _EFFORT_RE.search(low)156        if m:157            suffix = m.group(1).lower()158            if suffix in _DIGIT_GATED_SUFFIXES and not re.search(r"\d", low[: m.start()]):159                break160            a.effort = {**EFFORT_SUFFIXES[suffix], **a.effort}161            stripped.insert(0, suffix)162            low = low[: m.start()]163            continue164        break165    if stripped:166        a.effort_suffix = "-".join(stripped)167168    # sizes169    am = _ACTIVE_RE.search(low)170    if am:171        a.parameter_count = _to_count(am.group(1), low[am.start(1) + len(am.group(1)):].strip()[0])172        a.active_parameter_count = _to_count(am.group(2), am.group(3))173    else:174        sizes = _SIZE_RE.findall(low)175        if sizes:176            counts = [_to_count(n, u) for n, u in sizes]177            a.parameter_count = max(counts)178179    # dates embedded in the name180    dm = _DATE_RE.search(low)181    if dm:182        a.snapshot_date = f"{dm.group(1)}-{dm.group(2)}-{dm.group(3)}"183    else:184        ym = _YYMM_RE.search(low)185        if ym and not _SIZE_RE.search(ym.group(0)):186            a.snapshot_date = f"20{ym.group(1)}-{ym.group(2)}"187188    # quantisation / precision tokens189    tokens = [t for t in re.split(r"[-_\s./()\[\]]+", low) if t]190    quant: list[str] = []191    precision = None192    kept: list[str] = []193    for t in tokens:194        if t in QUANT_FORMATS:195            quant.append(QUANT_FORMATS[t])196            continue197        if t in PRECISION_FORMATS:198            precision = t199            continue200        if re.fullmatch(r"(w\d+a\d+|q\d(_[a-z0-9]+)*|iq\d(_[a-z0-9]+)*|\d-?bit|int\d|fp\d|nvfp\d|mxfp\d)", t):201            quant.append(QUANT_FORMATS.get(t, "quantized"))202            continue203        kept.append(t)204    # "GGUF" / "MLX" packaging counts as artifact even without a bit-width; "MLX-8bit" is quantised205    a.quant_formats = sorted(set(quant))206    a.precision = precision207    a.is_quantized = any(q not in ("onnx", "coreml", "openvino", "tensorrt", "mlx", "gguf") for q in a.quant_formats) or "gguf" in a.quant_formats208    a.is_conversion = (not a.is_quantized) and (bool(a.quant_formats) or precision is not None or (a.from_converter_org and bool(a.repo_org)))209    if "mlx" in a.quant_formats and any(q.startswith("int") for q in a.quant_formats):210        a.is_quantized = True211212    a.base_key = "-".join(kept).strip("-")213    a.family_hint = family_hint(name)214    return a215216217# ---------------------------------------------------------------------------------------------- family inference218_FAMILY_PATTERNS: list[tuple[re.Pattern[str], str]] = [219    (re.compile(r"\bclaude\b", re.I), "Claude"),220    (re.compile(r"\bgpt[- ]?(oss)\b", re.I), "gpt-oss"),221    (re.compile(r"\b(chat)?gpt[- ]?\d", re.I), "GPT"),222    (re.compile(r"\bo[1-9](-| |$|mini|pro)", re.I), "OpenAI o-series"),223    (re.compile(r"\bgemini\b", re.I), "Gemini"),224    (re.compile(r"\bgemma(?=\d|\b)", re.I), "Gemma"),225    (re.compile(r"\bpalm\b", re.I), "PaLM"),226    (re.compile(r"\bllama(?=\d|\b)", re.I), "Llama"),227    (re.compile(r"\bmistral\b", re.I), "Mistral"),228    (re.compile(r"\bmixtral\b", re.I), "Mixtral"),229    (re.compile(r"\bministral\b", re.I), "Ministral"),230    (re.compile(r"\b(codestral|devstral|magistral|pixtral|voxtral)\b", re.I), None),  # own families, name = family231    (re.compile(r"\bqwen(?=\d|\b)|\bqwq\b|\bqvq\b", re.I), "Qwen"),232    (re.compile(r"\bdeepseek\b", re.I), "DeepSeek"),233    (re.compile(r"\bkimi\b", re.I), "Kimi"),234    (re.compile(r"\bglm(?=\d|\b)|\bchatglm\b", re.I), "GLM"),235    (re.compile(r"\bgrok\b", re.I), "Grok"),236    (re.compile(r"\bcommand\b", re.I), "Command"),237    (re.compile(r"\baya\b", re.I), "Aya"),238    (re.compile(r"\bphi(?=\d|\b)", re.I), "Phi"),239    (re.compile(r"\bnemotron\b", re.I), "Nemotron"),240    (re.compile(r"\bgranite\b", re.I), "Granite"),241    (re.compile(r"\bolmo(?=\d|\b)", re.I), "OLMo"),242    (re.compile(r"\bmolmo\b", re.I), "Molmo"),243    (re.compile(r"\bfalcon\b", re.I), "Falcon"),244    (re.compile(r"\byi\b", re.I), "Yi"),245    (re.compile(r"\bminimax\b", re.I), "MiniMax"),246    (re.compile(r"\bhunyuan\b", re.I), "Hunyuan"),247    (re.compile(r"\bernie\b", re.I), "ERNIE"),248    (re.compile(r"\bseed\b", re.I), "Seed"),249    (re.compile(r"\bdoubao\b", re.I), "Doubao"),250    (re.compile(r"\bstep\b", re.I), "Step"),251    (re.compile(r"\binternlm(?=\d|\b)|\binternvl(?=\d|\b)", re.I), "InternLM"),252    (re.compile(r"\bjamba\b", re.I), "Jamba"),253    (re.compile(r"\blfm(?=\d|\b)", re.I), "LFM"),254    (re.compile(r"\bexaone(?=\d|\b)", re.I), "EXAONE"),255    (re.compile(r"\bsolar\b", re.I), "Solar"),256    (re.compile(r"\bnova\b", re.I), "Nova"),257    (re.compile(r"\btitan\b", re.I), "Titan"),258    (re.compile(r"\bsonar\b", re.I), "Sonar"),259    (re.compile(r"\bstable[- ]?diffusion\b|\bsdxl\b|\bsd3\b", re.I), "Stable Diffusion"),260    (re.compile(r"\bflux\b", re.I), "FLUX"),261    (re.compile(r"\bwhisper\b", re.I), "Whisper"),262    (re.compile(r"\bdall[- ]?e\b", re.I), "DALL·E"),263    (re.compile(r"\bsora\b", re.I), "Sora"),264    (re.compile(r"\bveo\b", re.I), "Veo"),265    (re.compile(r"\bimagen\b", re.I), "Imagen"),266    (re.compile(r"\bcogito\b", re.I), "Cogito"),267    (re.compile(r"\bhermes\b", re.I), "Hermes"),268    (re.compile(r"\bsmol(lm|vlm)\b", re.I), "SmolLM"),269    (re.compile(r"\bbert\b", re.I), "BERT"),270    (re.compile(r"\bt5\b", re.I), "T5"),271    (re.compile(r"\bclip\b", re.I), "CLIP"),272    (re.compile(r"\bembed(ding)?\b", re.I), None),273    (re.compile(r"\brerank\b", re.I), None),274]275_FAMILY_VERSION_RE = re.compile(r"^(?P<fam>[A-Za-z][A-Za-z·\-]*?)[\s\-]?(?P<ver>\d+(?:\.\d+)?)", re.I)276277278def family_hint(name: str) -> str | None:279    """Family label without a version ("Qwen", "Llama", "Claude"). Versioned families ("Llama 3.1") are `family_release_hint`."""280    n = name.split("/")[-1]281    for pat, fam in _FAMILY_PATTERNS:282        if pat.search(n):283            if fam is None:284                m = pat.search(n)285                return m.group(0).title() if m else None286            return fam287    return None288289290def family_release_hint(name: str) -> str | None:291    """Versioned family ("Llama 3.1", "Qwen3.6", "Gemini 2.5", "Claude 4") when the name carries a version right after the family word."""292    fam = family_hint(name)293    if not fam:294        return None295    n = name.split("/")[-1]296    # version = digits right after the family word, optionally ".minor" or "-minor" (AA/OpenRouter slugs write 5.4 as 5-4);297    # a number followed by a size unit (38B, 235B, 1.5T) is a parameter count, never a version.298    m = re.search(re.escape(fam.split(" ")[0]) + r"[\s\-]?(\d+)(?![0-9]*\.?\d*[bmt](?![a-z]))(?:[.\-](\d+)(?![0-9]*[bmt](?![a-z])))?(?![0-9])", n, re.I)299    if m:300        version = m.group(1) + (f".{m.group(2)}" if m.group(2) else "")301        joined = fam in ("Qwen", "GLM", "Phi", "Yi", "Step") or re.search(re.escape(fam) + r"\d", n, re.I)302        return f"{fam}{version}" if joined else f"{fam} {version}"303    return fam304305306def variant_key(name: str) -> str:307    """Grouping key for near-duplicates: analysed base key + parameter count, ignoring org prefixes, quant/precision/effort tokens,308    separators and trailing 'instruct/chat/it' words. `Qwen3.6-35B-A3B`, `unsloth/Qwen3.6-35B-A3B-GGUF`, `Qwen3.6 35B A3B FP8` → same key."""309    a = analyze_model_name(name)310    toks = [t for t in a.base_key.split("-") if t and t not in _TRAILING_VARIANT_WORDS]311    return "-".join(toks)312313314# ---------------------------------------------------------------------------------------------- official organisations per family315# family root (lowercase `family_hint`) → organisation slugs / hub org names (lowercase) that publish the *official* checkpoints.316# A repository under one of these orgs is the model (or its official checkpoint), never a third-party artifact.317FAMILY_ORGS: dict[str, tuple[str, ...]] = {318    "llama": ("meta-llama", "meta", "meta-ai", "facebook"), "qwen": ("qwen", "alibaba", "alibaba-cloud", "alibaba-qwen"), "gemma": ("google", "google-deepmind"),319    "gemini": ("google", "google-deepmind"), "palm": ("google",), "claude": ("anthropic",), "gpt": ("openai",), "gpt-oss": ("openai",), "openai o-series": ("openai",),320    "whisper": ("openai",), "dall·e": ("openai",), "sora": ("openai",), "deepseek": ("deepseek-ai", "deepseek"), "kimi": ("moonshotai", "moonshot-ai", "moonshot"),321    "glm": ("zai-org", "thudm", "zhipu-ai", "z-ai", "zhipu"), "mistral": ("mistralai", "mistral-ai", "mistral"), "mixtral": ("mistralai", "mistral-ai", "mistral"),322    "ministral": ("mistralai", "mistral-ai", "mistral"), "codestral": ("mistralai", "mistral-ai", "mistral"), "devstral": ("mistralai", "mistral-ai", "mistral"),323    "magistral": ("mistralai", "mistral-ai", "mistral"), "pixtral": ("mistralai", "mistral-ai", "mistral"), "voxtral": ("mistralai", "mistral-ai", "mistral"),324    "phi": ("microsoft",), "grok": ("xai", "x-ai", "xai-org"), "command": ("cohereforai", "cohere", "coherelabs", "cohere-labs"), "aya": ("cohereforai", "cohere", "coherelabs"),325    "nemotron": ("nvidia",), "granite": ("ibm-granite", "ibm"), "olmo": ("allenai", "ai2"), "molmo": ("allenai", "ai2"), "falcon": ("tiiuae", "tii"), "yi": ("01-ai",),326    "minimax": ("minimaxai", "minimax"), "hunyuan": ("tencent", "tencent-hunyuan"), "ernie": ("baidu",), "seed": ("bytedance-seed", "bytedance"), "doubao": ("bytedance",),327    "step": ("stepfun-ai", "stepfun"), "internlm": ("internlm", "shanghai-ai-laboratory", "opengvlab"), "jamba": ("ai21labs", "ai21"), "lfm": ("liquidai", "liquid-ai"),328    "exaone": ("lgai-exaone", "lg-ai-research"), "solar": ("upstage",), "nova": ("amazon", "aws"), "titan": ("amazon", "aws"), "sonar": ("perplexity-ai", "perplexity"),329    "stable diffusion": ("stabilityai", "stability-ai"), "flux": ("black-forest-labs",), "veo": ("google",), "imagen": ("google",), "cogito": ("deepcogito",),330    "hermes": ("nousresearch",), "smollm": ("huggingfacetb", "hugging-face"), "bert": ("google", "google-bert"), "t5": ("google", "google-t5"), "clip": ("openai",),331}332333334def official_orgs(name: str) -> tuple[str, ...]:335    """Official organisation slugs for the family the name belongs to (empty when unknown)."""336    fam = family_hint(name)337    return FAMILY_ORGS.get(fam.lower(), ()) if fam else ()338339340def is_official_org(repo_org: str | None, name: str) -> bool:341    return bool(repo_org) and repo_org.lower() in official_orgs(name)342343344def effort_config(name: str, config: dict | None) -> dict:345    """Result configuration for an evaluation-effort variant: the effort dict (`reasoning_effort`, `reasoning`, `thinking_budget`) is merged346    into the config and the evaluator's variant slug is kept as `aa_variant_slug` so folded results stay distinguishable. Names that are347    not effort variants return the config unchanged."""348    cfg = dict(config or {})349    a = analyze_model_name(name)350    if not a.is_effort_variant:351        return cfg352    for k, v in a.effort.items():353        cfg.setdefault(k, v)354    slug = cfg.get("aa_slug") or a.raw.split("/")[-1].strip().lower().replace(" ", "-")355    cfg.setdefault("aa_variant_slug", slug)356    return cfg357358359def base_name(name: str) -> str:360    """The name with the evaluator effort suffix removed ("gpt-5-4-mini-medium" → "gpt-5-4-mini", "Claude Sonnet 4 (no thinking)" →361    "Claude Sonnet 4"); unchanged when not a variant."""362    a = analyze_model_name(name)363    if not a.is_effort_variant or not a.effort_suffix:364        return name.strip()365    n = name.strip()366    # the suffix was detected on a normalised form (spaces/underscores/parentheses → "-"): strip it from the raw name with the same tolerance367    tokens = [re.escape(t) for t in a.effort_suffix.split("-") if t]368    pattern = r"[\s\-_(]+" + r"[\s\-_]*".join(tokens) + r"[)\s]*$"369    out = re.sub(pattern, "", n, flags=re.I)370    return out.strip().rstrip("-_ (").strip() or n371372373__all__ = ["ARTIFACT_PACKAGING", "CONVERTER_ORGS", "EFFORT_SUFFIXES", "FAMILY_ORGS", "OFFICIAL_THINKING_RELEASES", "NameAnalysis", "PRECISION_FORMATS", "QUANT_FORMATS",374           "analyze_model_name", "base_name", "effort_config", "family_hint", "family_release_hint", "is_official_org", "is_official_thinking_release", "official_orgs",375           "variant_key"]376