Skip to main content

Overview

OpenFang’s memory substrate provides a unified API over three specialized storage backends, all backed by a single SQLite database. Agents interact with a single Memory trait that abstracts over structured KV storage, semantic search, and knowledge graphs.
The entire memory system is synchronous at the storage layer (SQLite) but exposed via async APIs to the runtime. This allows non-blocking I/O while maintaining ACID guarantees.

The Three Layers

Structured Store

Key-value pairs, agent state, session persistence. Fast lookups by exact key.

Semantic Store

Text-based memory fragments with vector embeddings. Recalls relevant memories by similarity.

Knowledge Graph

Entities and relations extracted from conversations. Enables graph queries and reasoning.

Memory Substrate Architecture

All stores share a single SQLite connection with:
  • WAL mode (Write-Ahead Logging) for concurrent reads
  • 5-second busy timeout to handle contention
  • Foreign key constraints for referential integrity
  • Automatic migrations on first open
1

Opening the Substrate

This creates the database if it doesn’t exist and runs all pending migrations.
2

Schema Initialization

Tables are created for:
  • agents: Agent manifests
  • sessions: Message history per agent
  • kv_store: Key-value pairs
  • memory_fragments: Semantic memory with optional embeddings
  • entities: Knowledge graph nodes
  • relations: Knowledge graph edges
  • usage_log: Token usage and cost tracking
3

Ready for Use

The substrate is wrapped in Arc<MemorySubstrate> and passed to the kernel and runtime.

Layer 1: Structured Store

The structured store is a simple key-value store scoped by agent ID:
  • Agent state: Counters, flags, timestamps
  • Hand metrics: Dashboard metrics (e.g., reports_count)
  • Configuration overrides: Per-agent settings
  • Cached results: Expensive computations that don’t need semantic recall

Layer 2: Semantic Store

The semantic store holds memory fragments — snippets of text with optional vector embeddings for similarity search.

Storing Memories

Memory sources tag where the information came from:

Recalling Memories

Uses SQLite full-text search (FTS5):
This returns fragments ranked by:
  1. Keyword match score (BM25)
  2. Recency (newer memories rank higher)
  3. Access frequency (decay-based score)
If an embedding driver is available, OpenFang uses cosine similarity for more accurate recall:
This computes cosine similarity between the query vector and all stored fragment vectors, returning the top K matches.

Vector Embeddings

OpenFang supports pluggable embedding drivers:
Built-in drivers:
  • OpenAI (text-embedding-3-small, 1536 dims)
  • Voyage AI (voyage-2, 1024 dims)
  • Cohere (embed-english-v3.0, 1024 dims)
  • Local Transformers (via rust-bert crate, offline)
Configure in openfang.toml:
Embedding generation is not required — OpenFang falls back to full-text search (SQLite FTS5) if no driver is configured. Embeddings improve recall quality but add latency and cost.

Layer 3: Knowledge Graph

The knowledge store represents entities (nodes) and relations (edges) extracted from agent conversations.

Entities

Example:

Relations

Example:

Graph Queries

This performs a breadth-first search in the knowledge graph.
Returns all (Person) -[works_for]-> (OpenAI) matches.

Memory Consolidation

Over time, memory fragments accumulate. The consolidation engine runs periodically to:
  1. Decay importance scores using exponential decay
  2. Merge similar fragments to reduce redundancy
  3. Delete low-importance memories below a threshold
  4. Compact embeddings by re-clustering and averaging
Importance decays exponentially based on time since last access:
Default decay rate: 0.95 (95% retention per day, 50% after ~14 days)
Two fragments are merged if:
  • Cosine similarity > 0.9 (for vector embeddings)
  • Edit distance < 10% (for text-only)
  • Same agent and source
The merged fragment retains the higher importance score and combines access counts.

Session Management

Every agent has sessions — isolated conversation threads:
Sessions are automatically saved after every agent loop iteration. On the next message, the session is loaded and the conversation continues.
1

Create or Load Session

If no session exists, a new one is created with an empty message list.
2

Append Messages

During the agent loop, messages are appended:
3

Save Session

This updates the database with the new message history.
Sessions are channel-scoped — an agent can have different sessions for Telegram vs Discord. This prevents context leakage across channels.

Usage Tracking

The UsageStore records every LLM call:
Query total spend:
Rank agents by cost:
Output:

Memory Limits & Auto-Trimming

To prevent unbounded growth:
  • Session trimming: When a session exceeds 20 messages, the oldest are removed (keeping the most recent context)
  • Fragment pruning: During consolidation, fragments with importance < 0.1 are deleted
  • Embedding cache: Only the most recent 10,000 embeddings are cached in memory
SQLite databases can grow large over time. Run periodic consolidation or export/archive old sessions.

Import/Export

Next Steps

Memory API Reference

Full API documentation for memory operations

Agent Lifecycle

See how agents use memory during execution

Knowledge Graphs

Advanced guide to graph queries and entity extraction

Embeddings

Configure and optimize vector-based memory recall