pub mod qdrant;
use crate::{
error::Result,
types::{ContextLayer, Filters, Memory, ScoredMemory},
};
use async_trait::async_trait;
pub use qdrant::QdrantVectorStore;
pub fn uri_to_vector_id(uri: &str, layer: ContextLayer) -> String {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let id_string = match layer {
ContextLayer::L0Abstract => format!("{}#/L0", uri),
ContextLayer::L1Overview => format!("{}#/L1", uri),
ContextLayer::L2Detail => uri.to_string(),
};
let mut hasher1 = DefaultHasher::new();
id_string.hash(&mut hasher1);
let hash1 = hasher1.finish();
let mut hasher2 = DefaultHasher::new();
hash1.hash(&mut hasher2);
let hash2 = hasher2.finish();
format!("{:08x}-{:04x}-{:04x}-{:04x}-{:012x}",
((hash1 >> 32) & 0xFFFFFFFF) as u32, ((hash1 >> 16) & 0xFFFF) as u16, (hash1 & 0xFFFF) as u16, ((hash2 >> 48) & 0xFFFF) as u16, hash2 & 0xFFFFFFFFFFFF )
}
pub fn parse_vector_id(vector_id: &str) -> (String, ContextLayer) {
if vector_id.ends_with("#/L0") {
let uri = vector_id.trim_end_matches("#/L0").to_string();
return (uri, ContextLayer::L0Abstract);
}
if vector_id.ends_with("#/L1") {
let uri = vector_id.trim_end_matches("#/L1").to_string();
return (uri, ContextLayer::L1Overview);
}
let parts: Vec<&str> = vector_id.split('-').collect();
if parts.len() == 5 &&
parts[0].len() == 8 && parts[1].len() == 4 &&
parts[2].len() == 4 && parts[3].len() == 4 && parts[4].len() == 12 {
return (vector_id.to_string(), ContextLayer::L2Detail);
}
(vector_id.to_string(), ContextLayer::L2Detail)
}
#[async_trait]
pub trait VectorStore: Send + Sync + dyn_clone::DynClone {
async fn insert(&self, memory: &Memory) -> Result<()>;
async fn search(
&self,
query_vector: &[f32],
filters: &Filters,
limit: usize,
) -> Result<Vec<ScoredMemory>>;
async fn search_with_threshold(
&self,
query_vector: &[f32],
filters: &Filters,
limit: usize,
score_threshold: Option<f32>,
) -> Result<Vec<ScoredMemory>>;
async fn update(&self, memory: &Memory) -> Result<()>;
async fn delete(&self, id: &str) -> Result<()>;
async fn get(&self, id: &str) -> Result<Option<Memory>>;
async fn list(&self, filters: &Filters, limit: Option<usize>) -> Result<Vec<Memory>>;
async fn health_check(&self) -> Result<bool>;
async fn scroll_ids(&self, filters: &Filters, limit: usize) -> Result<Vec<String>>;
}
dyn_clone::clone_trait_object!(VectorStore);