solo_core/embedder.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! `Embedder` trait. See ADR-0002 for design rationale.
4
5use crate::{
6 error::{Error, Result},
7 types::{Embedding, EmbeddingDtype},
8};
9use async_trait::async_trait;
10
11/// Pluggable embedder. Production impls live in `solo-storage` (or a future
12/// `solo-embed` crate); this trait is the contract.
13#[async_trait]
14pub trait Embedder: Send + Sync {
15 /// Embedder identity. The migration tool `solo reembed` keys on
16 /// `(name, version)` to decide whether stored embeddings need to be
17 /// regenerated.
18 fn name(&self) -> &str;
19
20 /// Embedder version. Bump on any change that produces different vectors
21 /// for the same input.
22 fn version(&self) -> &str;
23
24 /// Output dimension. Must be invariant across calls for a given Embedder
25 /// instance.
26 fn dim(&self) -> usize;
27
28 /// Output dtype. Determines how raw bytes in `Embedding::data` are
29 /// interpreted.
30 fn dtype(&self) -> EmbeddingDtype;
31
32 /// Embed a batch of texts. Output is in input order with the same length
33 /// as the input. Implementations should batch internally for throughput;
34 /// callers may pass any number of texts (including 1).
35 async fn embed_batch(&self, texts: &[&str]) -> Result<Vec<Embedding>>;
36
37 /// Convenience: embed a single text. Default impl calls embed_batch.
38 async fn embed(&self, text: &str) -> Result<Embedding> {
39 let mut results = self.embed_batch(&[text]).await?;
40 results.pop().ok_or(Error::EmbedderProtocol(
41 "embed_batch returned empty for non-empty input",
42 ))
43 }
44}