use std::num::NonZeroUsize;
use super::{CUSTOM_MODEL_FILE, get_preset};
use crate::XbergError;
use crate::core::config::EmbeddingModelType;
#[cfg(feature = "embeddings")]
use super::ENGINE_CACHE;
#[cfg(feature = "static-embeddings")]
use super::STATIC_ENGINE_CACHE;
fn resolve_model_identity(model: &EmbeddingModelType) -> crate::Result<(String, String)> {
match model {
EmbeddingModelType::Preset { name } => {
let preset =
get_preset(name).ok_or_else(|| XbergError::embedding(format!("Unknown embedding preset: {name}")))?;
Ok((preset.model_repo, preset.model_file))
}
EmbeddingModelType::Custom { model_id, .. } => Ok((model_id.clone(), CUSTOM_MODEL_FILE.to_string())),
EmbeddingModelType::Llm { .. } => Err(XbergError::embedding(
"LLM embeddings keep no local model to evict; the provider serves them over HTTP.",
)),
EmbeddingModelType::Plugin { .. } => Err(XbergError::embedding(
"Plugin embeddings keep no local model to evict; the registered backend owns the model lifecycle.",
)),
}
}
#[cfg_attr(alef, alef(skip))]
pub fn evict_model(model: &EmbeddingModelType) -> crate::Result<usize> {
let (repo_name, model_file) = resolve_model_identity(model)?;
let matches = |repo: &str, file: &str| repo == repo_name && file == model_file;
let mut removed = 0;
#[cfg(feature = "embeddings")]
{
removed += ENGINE_CACHE.evict_where(|key| matches(&key.repo_name, &key.model_file));
}
#[cfg(feature = "static-embeddings")]
{
removed += STATIC_ENGINE_CACHE.evict_where(|key| matches(&key.repo_name, &key.model_file));
}
Ok(removed)
}
#[cfg_attr(alef, alef(skip))]
pub fn clear_engine_cache() -> usize {
let mut removed = 0;
#[cfg(feature = "embeddings")]
{
removed += ENGINE_CACHE.clear();
}
#[cfg(feature = "static-embeddings")]
{
removed += STATIC_ENGINE_CACHE.clear();
}
removed
}
#[cfg_attr(alef, alef(skip))]
pub fn set_engine_cache_limit(max_resident: Option<NonZeroUsize>) {
#[cfg(feature = "embeddings")]
ENGINE_CACHE.set_limit(max_resident);
#[cfg(feature = "static-embeddings")]
STATIC_ENGINE_CACHE.set_limit(max_resident);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn evict_model_reports_zero_when_the_model_is_not_resident() {
let removed = evict_model(&EmbeddingModelType::Preset {
name: "fast".to_string(),
})
.expect("a known preset resolves");
assert_eq!(removed, 0);
}
#[test]
fn evict_model_rejects_an_unknown_preset() {
let err = evict_model(&EmbeddingModelType::Preset {
name: "no-such-preset".to_string(),
})
.unwrap_err();
assert!(err.to_string().contains("Unknown embedding preset"), "{err}");
}
#[test]
fn evict_model_rejects_a_plugin_model_which_keeps_no_local_engine() {
let err = evict_model(&EmbeddingModelType::Plugin {
name: "custom".to_string(),
})
.unwrap_err();
assert!(err.to_string().contains("no local model to evict"), "{err}");
}
}