use std::collections::HashMap;
use std::sync::{OnceLock, RwLock};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ArchFamily {
BertEncoder,
NomicBertEncoder,
VisionEncoder,
Segmenter,
CausalLLM,
SpeechEncoder,
Diffusion,
Other,
}
#[derive(Debug, Clone)]
pub struct ArchSpec {
pub name: &'static str,
pub family: ArchFamily,
pub description: &'static str,
}
struct Registry {
map: RwLock<HashMap<&'static str, ArchSpec>>,
}
fn registry() -> &'static Registry {
static R: OnceLock<Registry> = OnceLock::new();
R.get_or_init(|| Registry {
map: RwLock::new(HashMap::new()),
})
}
pub fn register(spec: ArchSpec) {
let r = registry();
let mut m = r.map.write().expect("arch registry poisoned");
m.insert(spec.name, spec);
}
pub fn lookup(name: &str) -> Option<ArchSpec> {
let r = registry();
let m = r.map.read().expect("arch registry poisoned");
m.get(name).cloned()
}
pub fn registered() -> Vec<ArchSpec> {
let r = registry();
let m = r.map.read().expect("arch registry poisoned");
let mut v: Vec<ArchSpec> = m.values().cloned().collect();
v.sort_by_key(|s| s.name);
v
}
pub fn register_all() {
register(ArchSpec {
name: "bert",
family: ArchFamily::BertEncoder,
description: "BERT-style encoder (MiniLM / BGE / mpnet).",
});
register(ArchSpec {
name: "nomic-bert",
family: ArchFamily::NomicBertEncoder,
description: "NomicBERT encoder with RoPE + SwiGLU FFN.",
});
register(ArchSpec {
name: "nomic-vision",
family: ArchFamily::VisionEncoder,
description: "NomicVision image encoder.",
});
register(ArchSpec {
name: "dinov2",
family: ArchFamily::VisionEncoder,
description: "DINOv2 ViT (Meta) — self-supervised image encoder; optional register tokens.",
});
register(ArchSpec {
name: "vjepa2",
family: ArchFamily::VisionEncoder,
description: "V-JEPA2 (Meta) — video ViT encoder + JEPA predictor + attentive pooler. ViT-G @ 384² / 64 frames.",
});
register(ArchSpec {
name: "sam",
family: ArchFamily::Segmenter,
description: "Segment Anything v1 (Meta) — ViT-B/L/H encoder. Phase 1 ships encoder; decoder follows.",
});
register(ArchSpec {
name: "sam2",
family: ArchFamily::Segmenter,
description: "Segment Anything 2 (Meta) — Hiera image encoder + FPN. Phase 1 ships encoder + neck; prompt/mask decoder + memory follow.",
});
register(ArchSpec {
name: "sam3",
family: ArchFamily::Segmenter,
description: "Segment Anything 3 (Meta) — concept-conditioned image segmentation and video tracking.",
});
register(ArchSpec {
name: "qwen3",
family: ArchFamily::CausalLLM,
description: "Qwen3 (Alibaba) — GQA + QK-norm + SwiGLU dense causal LM. Phase 1 ships prefill graph; KV cache / lm_head / sampling / MTP follow.",
});
register(ArchSpec {
name: "llada2",
family: ArchFamily::Diffusion,
description: "LLaDA2 MoE (inclusionAI) — block diffusion LLM with sigmoid group-limited TopK router and TIDE predictive expert offload.",
});
register(ArchSpec {
name: "llama32",
family: ArchFamily::CausalLLM,
description: "LLaMA-3.2 (Meta) — GQA + Llama 3 RoPE scaling + SwiGLU, no QK-norm. Safetensors + GGUF via rlx-run llama32.",
});
register(ArchSpec {
name: "gemma",
family: ArchFamily::CausalLLM,
description: "Gemma / Gemma 2 (Google) — GQA + RoPE + GeGLU + embed scaling + tied weights. Safetensors + GGUF via rlx-run gemma.",
});
register(ArchSpec {
name: "wav2vec2-bert",
family: ArchFamily::SpeechEncoder,
description: "Wav2Vec2-BERT / W2v-BERT 2.0 (Meta) — Conformer speech encoder on log-mel features.",
});
register(ArchSpec {
name: "flux2",
family: ArchFamily::Diffusion,
description: "FLUX.2 (Black Forest Labs) — rectified-flow image denoiser; CPU native or compiled HIR on metal/mlx/cuda/rocm/gpu/vulkan.",
});
register(ArchSpec {
name: "neutts",
family: ArchFamily::Other,
description: "NeuTTS (Neuphonic) — voice-cloning TTS: GGUF backbone + NeuCodec FSQ/Vocos decoder.",
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_and_lookup() {
register_all();
let bert = lookup("bert").expect("bert should be registered");
assert_eq!(bert.family, ArchFamily::BertEncoder);
assert!(lookup("nonexistent").is_none());
}
#[test]
fn registered_is_sorted() {
register_all();
let names: Vec<&str> = registered().into_iter().map(|s| s.name).collect();
let mut sorted = names.clone();
sorted.sort();
assert_eq!(names, sorted);
}
}