use crate::context::ResolverContext;
use crate::manifest::{Constraint, MatchExpr, Variant};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Selected<'m> {
pub index: u8,
pub variant: &'m Variant,
}
#[must_use]
pub fn select_variant<'m>(variants: &'m [Variant], ctx: &ResolverContext) -> Option<Selected<'m>> {
let mut best: Option<(u8, Selected<'m>)> = None;
for (i, variant) in variants.iter().enumerate() {
if !matches(&variant.match_expr, ctx) {
continue;
}
let spec = variant.match_expr.specificity();
let candidate_is_better = match &best {
None => true,
Some((best_spec, _)) => spec > *best_spec,
};
if candidate_is_better {
#[allow(clippy::cast_possible_truncation)] let selected = Selected {
index: i as u8,
variant,
};
best = Some((spec, selected));
}
}
best.map(|(_, s)| s)
}
fn matches(expr: &MatchExpr, ctx: &ResolverContext) -> bool {
constraint_accepts(&expr.model_family, ctx.model_family.as_deref())
&& constraint_accepts(&expr.harness, ctx.harness.as_deref())
&& expr
.modalities
.is_none_or(|required| ctx.modalities.contains(required))
&& expr
.posture
.as_ref()
.is_none_or(|allowed| allowed.contains(&ctx.posture))
}
fn constraint_accepts(c: &Constraint, value: Option<&str>) -> bool {
match c {
Constraint::Any => true,
Constraint::OneOf(allowed) => {
value.is_some_and(|v| allowed.iter().any(|a| a.eq_ignore_ascii_case(v)))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::ConsumerKind;
use crate::manifest::{ModalitySet, Posture, VariantBody};
fn inline(tag: &str) -> VariantBody {
VariantBody::Inline {
content_type: "text/plain".into(),
data: tag.into(),
}
}
fn tag(v: &Variant) -> &str {
match &v.body {
VariantBody::Inline { data, .. } => data,
VariantBody::Media(_) => "media",
}
}
fn agent(family: Option<&str>, modalities: ModalitySet, posture: Posture) -> ResolverContext {
ResolverContext {
kind: ConsumerKind::Agent,
model_family: family.map(str::to_owned),
harness: None,
modalities,
posture,
}
}
#[test]
fn empty_variant_list_yields_none_never_panics() {
assert!(select_variant(&[], &ResolverContext::human()).is_none());
}
#[test]
fn undeclared_context_value_fails_a_constrained_dimension() {
let variants = vec![Variant {
match_expr: MatchExpr {
model_family: Constraint::OneOf(vec!["claude".into()]),
..MatchExpr::default()
},
body: inline("claude-only"),
revalidate_after_ms: None,
}];
let anon = agent(None, ModalitySet::TEXT, Posture::Headless);
assert!(
select_variant(&variants, &anon).is_none(),
"a variant asking for claude must not serve an anonymous consumer"
);
}
#[test]
fn family_match_is_case_insensitive() {
let variants = vec![Variant {
match_expr: MatchExpr {
model_family: Constraint::OneOf(vec!["claude".into()]),
..MatchExpr::default()
},
body: inline("c"),
revalidate_after_ms: None,
}];
let ctx = agent(Some("Claude"), ModalitySet::TEXT, Posture::Headless);
assert_eq!(select_variant(&variants, &ctx).unwrap().index, 0);
}
#[test]
fn modalities_are_superset_matched() {
let variants = vec![Variant {
match_expr: MatchExpr {
modalities: Some(ModalitySet::VISION),
..MatchExpr::default()
},
body: inline("needs-eyes"),
revalidate_after_ms: None,
}];
let with_eyes = agent(
None,
ModalitySet::TEXT.with(ModalitySet::VISION),
Posture::Attended,
);
let without = agent(None, ModalitySet::TEXT, Posture::Attended);
assert!(select_variant(&variants, &with_eyes).is_some());
assert!(select_variant(&variants, &without).is_none());
}
#[test]
fn specificity_beats_declaration_order_but_ties_do_not() {
let variants = vec![
Variant {
match_expr: MatchExpr::any(),
body: inline("catch-all"),
revalidate_after_ms: None,
},
Variant {
match_expr: MatchExpr {
model_family: Constraint::OneOf(vec!["gpt".into()]),
harness: Constraint::OneOf(vec!["codex".into()]),
..MatchExpr::default()
},
body: inline("gpt+codex"),
revalidate_after_ms: None,
},
Variant {
match_expr: MatchExpr {
model_family: Constraint::OneOf(vec!["gpt".into()]),
..MatchExpr::default()
},
body: inline("gpt-early"),
revalidate_after_ms: None,
},
Variant {
match_expr: MatchExpr {
harness: Constraint::OneOf(vec!["codex".into()]),
..MatchExpr::default()
},
body: inline("codex-late"),
revalidate_after_ms: None,
},
];
let mut ctx = agent(Some("gpt"), ModalitySet::TEXT, Posture::Headless);
ctx.harness = Some("codex".into());
let sel = select_variant(&variants, &ctx).unwrap();
assert_eq!(tag(sel.variant), "gpt+codex");
let tied: Vec<Variant> = variants
.iter()
.filter(|v| tag(v) != "gpt+codex")
.cloned()
.collect();
let sel = select_variant(&tied, &ctx).unwrap();
assert_eq!(
tag(sel.variant),
"gpt-early",
"ties break by declaration order"
);
}
}