use kiromi_ai_memory::{Embedder, EmbedderRegistry};
use crate::config::EmbedderConfig;
use crate::error::{CliError, ExitCode};
#[must_use]
pub(crate) fn build_registry() -> EmbedderRegistry {
let mut r = EmbedderRegistry::empty();
#[cfg(feature = "embed-onnx")]
{
kiromi_ai_embed_onnx::register(&mut r);
}
register_mock(&mut r);
r
}
pub(crate) async fn resolve(
cfg: Option<&EmbedderConfig>,
) -> Result<Option<Box<dyn Embedder>>, CliError> {
let Some(cfg) = cfg else {
return Ok(None);
};
if cfg.family == "onnx" && !cfg!(feature = "embed-onnx") {
return Err(CliError {
kind: ExitCode::Config,
source: anyhow::anyhow!(
"the 'onnx' embedder family is not compiled in. Reinstall with \
`cargo install kiromi-ai-cli --features embed-onnx`, or use \
`--no-embedder` to manage embeddings outside the engine."
),
});
}
let registry = build_registry();
let e = registry
.build(&cfg.family, cfg.config.clone())
.await
.map_err(CliError::from)?;
Ok(Some(e))
}
fn register_mock(r: &mut EmbedderRegistry) {
r.register("mock", |_cfg| async {
let e: Box<dyn Embedder> = Box::new(kiromi_ai_test_suite::MockEmbedder::new());
Ok::<_, kiromi_ai_memory::Error>(e)
});
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::ExitCode;
#[tokio::test]
async fn mock_family_resolves() {
let cfg = EmbedderConfig {
family: "mock".into(),
config: serde_json::Value::Null,
};
let e = resolve(Some(&cfg)).await.unwrap().unwrap();
assert!(!e.id().is_empty());
}
#[tokio::test]
async fn no_embedder_returns_none() {
let none = resolve(None).await.unwrap();
assert!(none.is_none());
}
#[tokio::test]
async fn unknown_family_is_config_error() {
let cfg = EmbedderConfig {
family: "no-such".into(),
config: serde_json::Value::Null,
};
let err = resolve(Some(&cfg)).await.unwrap_err();
assert_eq!(err.kind, ExitCode::Config);
}
}