1mod distance;
2mod filter;
3mod flat;
4mod upstash;
5
6pub use distance::{DistanceMetric, cosine_similarity};
7pub use flat::FlatIndex;
8pub use upstash::UpstashVectorIndex;
9
10use std::sync::Arc;
11
12use async_trait::async_trait;
13use mem7_config::VectorConfig;
14use mem7_core::MemoryFilter;
15use mem7_error::{Mem7Error, Result};
16use tracing::info;
17use uuid::Uuid;
18
19#[derive(Debug, Clone)]
21pub struct VectorSearchResult {
22 pub id: Uuid,
23 pub score: f32,
24 pub payload: serde_json::Value,
25}
26
27#[async_trait]
29pub trait VectorIndex: Send + Sync {
30 async fn insert(&self, id: Uuid, vector: &[f32], payload: serde_json::Value) -> Result<()>;
31 async fn search(
32 &self,
33 query: &[f32],
34 limit: usize,
35 filters: Option<&MemoryFilter>,
36 ) -> Result<Vec<VectorSearchResult>>;
37 async fn delete(&self, id: &Uuid) -> Result<()>;
38 async fn update(
39 &self,
40 id: &Uuid,
41 vector: Option<&[f32]>,
42 payload: Option<serde_json::Value>,
43 ) -> Result<()>;
44 async fn get(&self, id: &Uuid) -> Result<Option<(Vec<f32>, serde_json::Value)>>;
45 async fn list(
46 &self,
47 filters: Option<&MemoryFilter>,
48 limit: Option<usize>,
49 ) -> Result<Vec<(Uuid, serde_json::Value)>>;
50 async fn reset(&self) -> Result<()>;
51}
52
53pub fn create_vector_index(config: &VectorConfig) -> Result<Arc<dyn VectorIndex>> {
55 match config.provider.as_str() {
56 "upstash" => {
57 let url = config
58 .upstash_url
59 .as_deref()
60 .ok_or_else(|| Mem7Error::Config("upstash_url is required".into()))?;
61 let token = config
62 .upstash_token
63 .as_deref()
64 .ok_or_else(|| Mem7Error::Config("upstash_token is required".into()))?;
65 info!(namespace = %config.collection_name, "using Upstash Vector");
66 Ok(Arc::new(UpstashVectorIndex::new(
67 url,
68 token,
69 &config.collection_name,
70 )))
71 }
72 "flat" | "" => {
73 info!("using in-memory FlatIndex");
74 Ok(Arc::new(FlatIndex::new(DistanceMetric::Cosine)))
75 }
76 other => Err(Mem7Error::Config(format!(
77 "unknown vector store provider: {other}"
78 ))),
79 }
80}