A3S Docs
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

The A3S Code v2.1.0 Node SDK supports FileMemoryStore and MemorySessionStore. Passing an arbitrary Rust MemoryStore implementation into an A3S Code session is outside this page's scope.

Use this page for standalone a3s-memory backend design. Add an A3S Code custom-memory adapter only after testing that adapter in your application.

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.

On this page