Skip to main content

Memory

Trait Memory 

Source
pub trait Memory:
    Send
    + Sync
    + Attributable {
Show 22 methods // Required methods fn name(&self) -> &str; fn store<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait; fn recall<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, query: &'life1 str, limit: usize, session_id: Option<&'life2 str>, since: Option<&'life3 str>, until: Option<&'life4 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, Self: 'async_trait; fn get<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait; fn list<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, category: Option<&'life1 MemoryCategory>, session_id: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait; fn forget<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait; fn forget_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait; fn count<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, Self: 'async_trait; fn health_check<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>> where 'life0: 'async_trait, Self: 'async_trait; fn store_with_agent<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, namespace: Option<&'life4 str>, importance: Option<f64>, agent_id: Option<&'life5 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, Self: 'async_trait; fn recall_for_agents<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>( &'life0 self, allowed_agent_ids: &'life1 [&'life2 str], query: &'life3 str, limit: usize, session_id: Option<&'life4 str>, since: Option<&'life5 str>, until: Option<&'life6 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, Self: 'async_trait; // Provided methods fn get_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait { ... } fn purge_namespace<'life0, 'life1, 'async_trait>( &'life0 self, _namespace: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... } fn purge_session<'life0, 'life1, 'async_trait>( &'life0 self, _session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... } fn purge_session_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _session_id: &'life1 str, _agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait { ... } fn purge_agent<'life0, 'life1, 'async_trait>( &'life0 self, _agent_alias: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... } fn reindex<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, Self: 'async_trait { ... } fn store_procedural<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _messages: &'life1 [ProceduralMessage], _session_id: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait { ... } fn recall_namespaced<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, namespace: &'life1 str, query: &'life2 str, limit: usize, session_id: Option<&'life3 str>, since: Option<&'life4 str>, until: Option<&'life5 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, Self: 'async_trait { ... } fn export<'life0, 'life1, 'async_trait>( &'life0 self, filter: &'life1 ExportFilter, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... } fn store_with_metadata<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, _namespace: Option<&'life4 str>, _importance: Option<f64>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, Self: 'async_trait { ... } fn ensure_agent_uuid<'life0, 'life1, 'async_trait>( &'life0 self, alias: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<String, Error>> + Send + 'async_trait>> where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait { ... }
}
Expand description

Core memory trait — implement for any persistence backend

Required Methods§

Source

fn name(&self) -> &str

Backend name

Source

fn store<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Store a memory entry, optionally scoped to a session

Source

fn recall<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, query: &'life1 str, limit: usize, session_id: Option<&'life2 str>, since: Option<&'life3 str>, until: Option<&'life4 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, Self: 'async_trait,

Recall memories matching a query (keyword search), optionally scoped to a session and time range. Empty, whitespace-only, and bare “” queries return recent/time-only entries. Non-bare wildcard terms such as “wild” remain keyword queries. Time bounds use RFC 3339 / ISO 8601 format (e.g. “2025-03-01T00:00:00Z”); inclusive (created_at >= since, created_at <= until).

Source

fn get<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Get a specific memory by key.

After composite uniqueness landed, multiple rows may share a key (one per agent). This method returns some matching row without an agent filter; callers that need an agent-scoped lookup use get_for_agent.

Source

fn list<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, category: Option<&'life1 MemoryCategory>, session_id: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

List all memory keys, optionally filtered by category and/or session

Source

fn forget<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Remove a memory by key. Deletes every row matching key, regardless of agent attribution. Agent-scoped callers (the AgentScopedMemory wrapper) use forget_for_agent instead.

Source

fn forget_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Remove the row matching (key, agent_id). Siblings of the same key under other agents are untouched. Returns true if a row was removed. Required: no safe default exists for backends or wrappers that can hold more than one row per key — the unscoped forget would destroy sibling rows.

Source

fn count<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Count total memories

Source

fn health_check<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Health check

Source

fn store_with_agent<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, namespace: Option<&'life4 str>, importance: Option<f64>, agent_id: Option<&'life5 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, Self: 'async_trait,

Store a memory entry attributed to an explicit agent UUID. Every backend must implement this explicitly so the agent_id is never silently dropped at storage time. Backends with native agent_id columns (SqliteMemory, PostgresMemory, LucidMemory) persist the attribution in SQL; MarkdownMemory attributes via the per-agent directory path; QdrantMemory persists in the vector payload; NoneMemory is a no-op stub. AgentScopedMemory is the canonical caller.

Source

fn recall_for_agents<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'life6, 'async_trait>( &'life0 self, allowed_agent_ids: &'life1 [&'life2 str], query: &'life3 str, limit: usize, session_id: Option<&'life4 str>, since: Option<&'life5 str>, until: Option<&'life6 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, 'life6: 'async_trait, Self: 'async_trait,

Recall memory entries scoped to a specific set of agent UUIDs. When allowed_agent_ids is non-empty, the backend filters its result set to rows whose agent_id matches one of the listed UUIDs (or is NULL, for legacy rows written before the agent_id column existed). Every backend must implement this explicitly so the allowlist is never silently dropped at read time.

For SQL-backed stores the filter is WHERE agent_id IN (...). For Markdown the implementation walks the allowed agents’ per-agent directories. For Qdrant it’s a payload filter on the agent_id field. For None it returns an empty list. AgentScopedMemory is the canonical caller; direct invocation is also valid for read-only cross-agent queries that bypass the wrapper.

Cross-backend allowlist entries are rejected at config load (agents.<alias>.workspace.read_memory_from cannot point at a sibling on a different memory backend); backends therefore never need to handle a cross-backend recall.

Provided Methods§

Source

fn get_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, key: &'life1 str, agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<Option<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Get the memory row matching (key, agent_id). Siblings of the same key under other agents are invisible.

The default implementation composes get with an agent_id filter and is only correct for backends whose storage layout cannot hold more than one row per key (markdown’s per-agent dir scheme, the none stub). Backends that can hold multiple rows per key (SQL with composite unique, Qdrant) override this with a native composite lookup.

Source

fn purge_namespace<'life0, 'life1, 'async_trait>( &'life0 self, _namespace: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Remove all memories whose namespace field equals the given value. Returns the number of deleted entries. Default: returns unsupported error. Backends that support bulk deletion override this.

Source

fn purge_session<'life0, 'life1, 'async_trait>( &'life0 self, _session_id: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Remove all memories in a session. Returns the number of deleted entries. Default: returns unsupported error. Backends that support bulk deletion override this.

Source

fn purge_session_for_agent<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _session_id: &'life1 str, _agent_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Remove all memories in a session for one agent. Returns the number of deleted entries. Default: returns unsupported error. Backends with per-agent storage override this; agent-scoped wrappers use it instead of composing a session list with key-only deletes.

Source

fn purge_agent<'life0, 'life1, 'async_trait>( &'life0 self, _agent_alias: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Remove every memory row attributed to the given agent alias. Returns the number of deleted entries. Called when an agent alias is removed from [agents.<alias>] so the database doesn’t accumulate rows for retired aliases. Default: returns unsupported error. Backends with per-agent storage (sqlite, postgres) override this; backends without (markdown, none) keep the default and the caller logs a warning.

Source

fn reindex<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<usize, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Rebuild backend indexes: FTS tables and any missing embedding vectors.

Intended as a manual fixup after bulk writes that didn’t go through the normal store() path (e.g. zeroclaw migrate openclaw, which uses NoopEmbedding for speed and leaves embedding = NULL behind). Returns the number of entries that were re-embedded; backends without a vector index or with nothing to fill in return 0.

Default: no-op. Overridden by backends that maintain separate derived indexes (e.g. SqliteMemory).

Source

fn store_procedural<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _messages: &'life1 [ProceduralMessage], _session_id: Option<&'life2 str>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Store a conversation trace as procedural memory.

Backends that support procedural storage override this to extract “how to” patterns from tool-calling turns. The default implementation is a no-op.

Source

fn recall_namespaced<'life0, 'life1, 'life2, 'life3, 'life4, 'life5, 'async_trait>( &'life0 self, namespace: &'life1 str, query: &'life2 str, limit: usize, session_id: Option<&'life3 str>, since: Option<&'life4 str>, until: Option<&'life5 str>, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, 'life5: 'async_trait, Self: 'async_trait,

Recall memories scoped to a specific namespace.

Default implementation delegates to recall() and filters by namespace. Backends with native namespace support should override for efficiency.

Source

fn export<'life0, 'life1, 'async_trait>( &'life0 self, filter: &'life1 ExportFilter, ) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryEntry>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Bulk-export memories matching the given filter criteria.

Intended for GDPR Art. 20 data portability. Returns entries ordered by creation time (ascending). Embeddings are excluded.

Default implementation delegates to list() and post-filters on namespace and time range. Backends with native query support should override for efficiency.

Source

fn store_with_metadata<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>( &'life0 self, key: &'life1 str, content: &'life2 str, category: MemoryCategory, session_id: Option<&'life3 str>, _namespace: Option<&'life4 str>, _importance: Option<f64>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, 'life4: 'async_trait, Self: 'async_trait,

Store a memory entry with namespace and importance.

Default implementation delegates to store(). Backends with native namespace/importance support should override.

Source

fn ensure_agent_uuid<'life0, 'life1, 'async_trait>( &'life0 self, alias: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<String, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Look up (or create) the identifier the backend uses to refer to the agent named by alias.

Backends with an agents table (SqliteMemory, PostgresMemory, LucidMemory) return the row’s UUID, inserting if absent. Backends without (MarkdownMemory, QdrantMemory, NoneMemory) return the alias verbatim — there is no UUID indirection at the storage layer, so the alias serves as the agent_id. Default impl returns the alias unchanged; SQL backends override to do the real lookup.

Implementors§