Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/jp_llm/src/model.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) mod catalog;

use chrono::NaiveDate;
use jp_config::model::{
id::ModelIdConfig,
Expand Down
85 changes: 85 additions & 0 deletions crates/jp_llm/src/model/catalog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Hand-maintained model tables, for providers whose API reports too little.
//!
//! A [`Catalog`] holds one [`Entry`] per model.
//! An entry is found under the model's canonical id or any of its aliases, such
//! as a dated snapshot or a `-latest` pointer.
//! What an entry carries is up to the provider: the full [`ModelDetails`] when
//! the API reports nothing, or only the facts the API leaves out.

use std::iter;

use crate::model::ModelDetails;

/// A value a [`Catalog`] can hold: something that names its canonical model id.
pub(crate) trait Cataloged {
/// The id the model is cataloged under, without its provider prefix.
fn catalog_id(&self) -> &str;
}

impl Cataloged for ModelDetails {
fn catalog_id(&self) -> &str {
self.id.name.as_ref()
}
}

/// One model in a [`Catalog`].
pub(crate) struct Entry<T> {
/// Other ids the provider serves the model under.
pub aliases: &'static [&'static str],

/// What the provider knows about the model.
pub value: T,
}

/// A provider's table of models, looked up by canonical id or alias.
pub(crate) struct Catalog<T>(Vec<Entry<T>>);

impl<T: Cataloged> Catalog<T> {
/// Build a catalog from its entries, in the order they are listed.
///
/// # Panics
///
/// In debug builds, if two entries claim the same id: a lookup would
/// silently return whichever comes first.
pub(crate) fn new(entries: Vec<Entry<T>>) -> Self {
let catalog = Self(entries);
if let Some(id) = catalog.duplicate_id() {
debug_assert!(false, "{id} is cataloged twice");
}

catalog
}

/// The value cataloged under `id`, as its canonical id or an alias.
pub(crate) fn get(&self, id: &str) -> Option<&T> {
self.0
.iter()
.find(|entry| entry.value.catalog_id() == id || entry.aliases.contains(&id))
.map(|entry| &entry.value)
}

/// Every value, in the order the entries were listed.
pub(crate) fn values(&self) -> impl Iterator<Item = &T> {
self.0.iter().map(|entry| &entry.value)
}

/// The first id, canonical or alias, that more than one entry claims.
pub(crate) fn duplicate_id(&self) -> Option<&str> {
let mut seen = vec![];
self.0
.iter()
.flat_map(|entry| {
let aliases = entry.aliases.iter().copied();
iter::once(entry.value.catalog_id()).chain(aliases)
})
.find(|id| {
let duplicate = seen.contains(id);
seen.push(*id);
duplicate
})
}
}

#[cfg(test)]
#[path = "catalog_tests.rs"]
mod tests;
84 changes: 84 additions & 0 deletions crates/jp_llm/src/model/catalog_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use super::*;

struct Model(&'static str);

impl Cataloged for Model {
fn catalog_id(&self) -> &str {
self.0
}
}

fn catalog() -> Catalog<Model> {
Catalog::new(vec![
Entry {
aliases: &["alpha-latest", "alpha-2026-01-01"],
value: Model("alpha"),
},
Entry {
aliases: &[],
value: Model("beta"),
},
])
}

#[test]
fn finds_an_entry_under_its_canonical_id() {
assert_eq!(catalog().get("beta").map(|m| m.0), Some("beta"));
}

#[test]
fn finds_an_entry_under_any_alias() {
let catalog = catalog();

assert_eq!(catalog.get("alpha-latest").map(|m| m.0), Some("alpha"));
assert_eq!(catalog.get("alpha-2026-01-01").map(|m| m.0), Some("alpha"));
}

#[test]
fn an_unlisted_id_finds_nothing() {
assert!(catalog().get("gamma").is_none());
}

#[test]
fn values_come_back_in_listed_order() {
let ids: Vec<_> = catalog().values().map(|m| m.0).collect();

assert_eq!(ids, vec!["alpha", "beta"]);
}

#[test]
fn an_alias_that_repeats_another_canonical_id_is_a_duplicate() {
let catalog = Catalog(vec![
Entry {
aliases: &[],
value: Model("alpha"),
},
Entry {
aliases: &["alpha"],
value: Model("beta"),
},
]);

assert_eq!(catalog.duplicate_id(), Some("alpha"));
}

#[test]
fn distinct_ids_have_no_duplicate() {
assert_eq!(catalog().duplicate_id(), None);
}

#[test]
#[cfg(debug_assertions)]
#[should_panic(expected = "alpha is cataloged twice")]
fn building_a_catalog_with_a_duplicate_panics_in_debug() {
Catalog::new(vec![
Entry {
aliases: &[],
value: Model("alpha"),
},
Entry {
aliases: &[],
value: Model("alpha"),
},
]);
}
Loading
Loading