Skip to content

A3S-Lab/Memory

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

a3s-memory

Pluggable memory storage for A3S.

Provides the MemoryStore trait and two default implementations. Agents that need to persist and recall knowledge across sessions depend on this crate directly — nothing else required.

Design

The crate follows a minimal core + external extensions pattern:

Core (stable, non-replaceable):

  • MemoryStore — storage backend trait
  • MemoryItem — the unit of memory
  • MemoryType — episodic / semantic / procedural / working
  • RelevanceConfig — scoring parameters

Extensions (replaceable via MemoryStore):

  • InMemoryStore — default, ephemeral (testing and non-persistent use)
  • FileMemoryStore — persistent, atomic writes, in-memory index

Three-tier session memory (AgentMemory) and context injection (MemoryContextProvider) live in a3s-code, not here. This crate only owns the storage layer.

Usage

[dependencies]
a3s-memory = { version = "0.1", path = "../memory" }

Store and retrieve

use a3s_memory::{InMemoryStore, MemoryItem, MemoryStore, MemoryType};
use std::sync::Arc;

let store = Arc::new(InMemoryStore::new());

let item = MemoryItem::new("Prefer write_all over write for file I/O")
    .with_importance(0.8)
    .with_tag("rust")
    .with_type(MemoryType::Semantic);

store.store(item).await?;

let results = store.search("file I/O", 5).await?;

Persistent storage

use a3s_memory::{FileMemoryStore, MemoryStore};

let store = FileMemoryStore::new("/var/lib/agent/memory").await?;
// Directory layout:
//   memory/
//     index.json        ← in-memory index, persisted atomically
//     items/{id}.json   ← one file per memory item

Custom backend

Implement MemoryStore to use any storage system (SQLite, vector DB, etc.):

use a3s_memory::{MemoryItem, MemoryStore};

struct MyStore { /* ... */ }

#[async_trait::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!() }
    // ... remaining methods
}

Relevance scoring

score = importance × importance_weight + decay × recency_weight
decay = exp(−age_days / decay_days)

Default: importance_weight = 0.7, recency_weight = 0.3, decay_days = 30.

use a3s_memory::{MemoryItem, RelevanceConfig};

let config = RelevanceConfig {
    decay_days: 7.0,        // faster decay
    importance_weight: 0.9,
    recency_weight: 0.1,
};

let score = item.relevance_score_at(now, &config);

What this crate does NOT own

Concern Lives in
Three-tier session memory (working / short-term / long-term) a3s-code
MemoryConfig (max_short_term, max_working) a3s-code
MemoryStats a3s-code
Context injection into agent prompts a3s-code

Tests

32 tests covering MemoryItem, RelevanceConfig, InMemoryStore, and FileMemoryStore (including persistence, index rebuild, and path traversal prevention).

cargo test

Community

Join us on Discord for questions, discussions, and updates.

License

MIT

About

Pluggable memory storage for A3S

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages