HTML 77.2%
TypeScript 10.5%
Python 9.6%
JavaScript 2.5%
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