use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Bench {
LongMemEval,
Locomo,
Convomem,
MembenchSimpleRoles,
MembenchHighlevelMovie,
LongMemEvalHybridV4,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct BenchMeta {
pub id: &'static str,
pub display: &'static str,
pub eta_seconds: u64,
pub dataset_bytes: u64,
pub description: &'static str,
}
impl Bench {
#[must_use]
pub const fn all() -> &'static [Bench] {
&[
Bench::LongMemEval,
Bench::Locomo,
Bench::Convomem,
Bench::MembenchSimpleRoles,
Bench::MembenchHighlevelMovie,
Bench::LongMemEvalHybridV4,
]
}
#[must_use]
pub fn from_id(s: &str) -> Option<Self> {
let lower = s.to_ascii_lowercase();
for b in Self::all() {
if b.metadata().id.eq_ignore_ascii_case(&lower) {
return Some(*b);
}
}
None
}
#[must_use]
pub const fn metadata(self) -> BenchMeta {
match self {
Self::LongMemEval => BenchMeta {
id: "longmemeval",
display: "LongMemEval (per-session, 500q)",
eta_seconds: 600,
dataset_bytes: 264 * 1024 * 1024,
description: "500 questions, MAX-aggregate turn->session, R@5 / R@10.",
},
Self::Locomo => BenchMeta {
id: "locomo",
display: "LoCoMo (session granularity)",
eta_seconds: 300,
dataset_bytes: 3 * 1024 * 1024,
description: "10 conversations x ~200 QA, per-conv label, session R@5 / R@10.",
},
Self::Convomem => BenchMeta {
id: "convomem",
display: "ConvoMem (5 categories, avg recall)",
eta_seconds: 240,
dataset_bytes: 5 * 1024 * 1024,
description: "5 headline evidence categories, substring-match avg_recall.",
},
Self::MembenchSimpleRoles => BenchMeta {
id: "membench-simple-roles",
display: "MemBench simple-roles (R@5)",
eta_seconds: 180,
dataset_bytes: 4 * 1024 * 1024,
description: "MemBench simple/roles slice, target_step_id R@5 over 100 items.",
},
Self::MembenchHighlevelMovie => BenchMeta {
id: "membench-highlevel-movie",
display: "MemBench high-level/movie (R@5)",
eta_seconds: 180,
dataset_bytes: 6 * 1024 * 1024,
description: "MemBench highlevel/movie slice, target_step_id R@5 over 100 items.",
},
Self::LongMemEvalHybridV4 => BenchMeta {
id: "longmemeval-hybrid-v4",
display: "LongMemEval hybrid-v4 (BM25 boost, R@5)",
eta_seconds: 600,
dataset_bytes: 264 * 1024 * 1024,
description: "LongMemEval with BM25-derived post-fusion boost; reuses LME cache.",
},
}
}
}
impl fmt::Display for Bench {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.metadata().display)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum AdapterKind {
Mnem,
}
impl AdapterKind {
#[must_use]
pub const fn id(self) -> &'static str {
match self {
Self::Mnem => "mnem",
}
}
#[must_use]
pub const fn display(self) -> &'static str {
match self {
Self::Mnem => "mnem",
}
}
#[must_use]
pub const fn all() -> &'static [Self] {
&[Self::Mnem]
}
#[must_use]
pub fn from_id(s: &str) -> Option<Self> {
for a in Self::all() {
if a.id().eq_ignore_ascii_case(s) {
return Some(*a);
}
}
None
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum RunMode {
CpuLocal,
}
impl RunMode {
#[must_use]
pub const fn id(self) -> &'static str {
match self {
Self::CpuLocal => "cpu-local",
}
}
#[must_use]
pub const fn display(self) -> &'static str {
match self {
Self::CpuLocal => "CPU local (in-process)",
}
}
#[must_use]
pub const fn all() -> &'static [Self] {
&[Self::CpuLocal]
}
#[must_use]
pub fn from_id(s: &str) -> Option<Self> {
for m in Self::all() {
if m.id().eq_ignore_ascii_case(s) {
return Some(*m);
}
}
None
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum EmbedderChoice {
OnnxMiniLm,
BagOfTokens,
}
impl EmbedderChoice {
#[must_use]
pub const fn id(self) -> &'static str {
match self {
Self::BagOfTokens => "bag-of-tokens",
Self::OnnxMiniLm => "onnx-minilm",
}
}
#[must_use]
pub const fn display(self) -> &'static str {
match self {
Self::BagOfTokens => "bag-of-tokens (built-in, deterministic)",
Self::OnnxMiniLm => "ONNX MiniLM (default, bundled)",
}
}
#[must_use]
pub const fn all() -> &'static [Self] {
&[Self::OnnxMiniLm, Self::BagOfTokens]
}
#[must_use]
pub fn from_id(s: &str) -> Option<Self> {
for e in Self::all() {
if e.id().eq_ignore_ascii_case(s) {
return Some(*e);
}
}
None
}
}