A pinned model version such as jev-1.13.0: a name, then a
major.minor.patch version (docs.typesafe.ai/models, 2026-09-22).
Aliases (jev-latest, jev-preview, any future one) are refused: the
vendor says an alias "moves when a new release ships, so the answers
behind it can change without a change on your side".
13impl ModelId { 14 pub fn pinned(id: &str) -> Result<Self, ProtocolError> { 15 let id = id.trim(); 16 if id.is_empty() { 17 return Err(ProtocolError::Invalid("the model id is empty".into())); 18 } 19 if !is_versioned(id) { 20 return Err(ProtocolError::Invalid(format!( 21 "{id} is an alias; pin a versioned model such as jev-1.13.0" 22 ))); 23 } 24 Ok(ModelId(id.to_owned())) 25 } 26 27 pub fn as_str(&self) -> &str { 28 &self.0 29 } 30} 31 32impl fmt::Display for ModelId { 33 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 34 f.write_str(&self.0) 35 } 36}
<name>-<major>.<minor>.<patch>, with an optional -<suffix>.
39fn is_versioned(id: &str) -> bool { 40 let Some((name, rest)) = id.split_once('-') else { return false }; 41 let version = rest.split_once('-').map_or(rest, |(v, _)| v); 42 let parts: Vec<&str> = version.split('.').collect(); 43 !name.is_empty() 44 && parts.len() == 3 45 && parts.iter().all(|p| !p.is_empty() && p.bytes().all(|b| b.is_ascii_digit())) 46}
48#[cfg(test)] 49mod tests { 50 use super::*; 51 52 #[test] 53 fn refuses_aliases() { 54 for id in ["jev-1.13.0", "jev-2.0.0-rc1"] { 55 assert!(ModelId::pinned(id).is_ok(), "{id}"); 56 } 57 for alias in ["jev-latest", "jev-preview", "jev-stable", "jev", "jev-1.13", "jev-1.x.0", ""] { 58 assert!(ModelId::pinned(alias).is_err(), "{alias}"); 59 } 60 } 61}