A3S Memory
Custom Backend
Implement MemoryStore to use any storage system — SQLite, Redis, vector DB
Custom Backend
Implement the MemoryStore trait to use any storage system. The search() method is the only one where backends meaningfully differ — FileMemoryStore uses substring matching, a vector store would use semantic similarity.
MemoryStore trait
use a3s_memory::{MemoryItem, MemoryStore};
use async_trait::async_trait;
struct MyStore { /* ... */ }
#[async_trait]
impl MemoryStore for MyStore {
async fn store(&self, item: MemoryItem) -> anyhow::Result<()> { todo!() }
async fn retrieve(&self, id: &str) -> anyhow::Result<Option<MemoryItem>> { todo!() }
async fn search(&self, query: &str, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
async fn search_by_tags(&self, tags: &[String], limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
async fn get_recent(&self, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
async fn get_important(&self, threshold: f32, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
async fn delete(&self, id: &str) -> anyhow::Result<()> { todo!() }
async fn clear(&self) -> anyhow::Result<()> { todo!() }
async fn count(&self) -> anyhow::Result<usize> { todo!() }
}Method reference
Prop
Type
Vector store example
use a3s_memory::{MemoryItem, MemoryStore};
use async_trait::async_trait;
struct VectorStore {
client: MyVectorDbClient,
}
#[async_trait]
impl MemoryStore for VectorStore {
async fn store(&self, item: MemoryItem) -> anyhow::Result<()> {
let embedding = self.client.embed(&item.content).await?;
self.client.upsert(&item.id, embedding, &item).await?;
Ok(())
}
async fn search(&self, query: &str, limit: usize) -> anyhow::Result<Vec<MemoryItem>> {
let embedding = self.client.embed(query).await?;
let results = self.client.ann_search(embedding, limit).await?;
Ok(results)
}
// remaining methods: standard CRUD against your DB
# async fn retrieve(&self, id: &str) -> anyhow::Result<Option<MemoryItem>> { todo!() }
# async fn search_by_tags(&self, tags: &[String], limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
# async fn get_recent(&self, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
# async fn get_important(&self, threshold: f32, limit: usize) -> anyhow::Result<Vec<MemoryItem>> { todo!() }
# async fn delete(&self, id: &str) -> anyhow::Result<()> { todo!() }
# async fn clear(&self) -> anyhow::Result<()> { todo!() }
# async fn count(&self) -> anyhow::Result<usize> { todo!() }
}Use with A3S Code
use std::sync::Arc;
SessionOptions::new().with_memory(Arc::new(VectorStore::new()))Use standalone
use std::sync::Arc;
use a3s_memory::MemoryStore;
let store: Arc<dyn MemoryStore> = Arc::new(VectorStore::new());
store.store(MemoryItem::new("some fact")).await?;
let results = store.search("fact", 5).await?;MemoryStore is object-safe — Arc<dyn MemoryStore> works without any additional bounds.