Import:
from gaia.agents.base.memory import MemoryMixin
Import: from gaia.agents.base.memory_store import MemoryStore
Import: from gaia.agents.base.discovery import SystemDiscoveryArchitecture
The memory system has three layers:MemoryMixin
The primary integration point. Add this mixin to any Agent subclass to give it persistent memory.Inheritance Order
MemoryMixin must come before Agent in the class declaration. This is required because MemoryMixin overrides process_query and _execute_tool, both of which call super() to reach the Agent base class. If Agent is listed first, both overrides are silently shadowed.
init_memory()
Initialize the memory subsystem. Call this beforesuper().__init__().
v2 startup sequence:
- Open/create DB, apply schema migrations (v1 → v2: adds
embedding BLOB,superseded_by TEXT,consolidated_at TEXT) - Validate Lemonade embedding service connectivity — raises
RuntimeErrorif unreachable - Backfill embeddings for items missing them (up to 100 per startup)
- Rebuild FAISS index from stored embeddings
apply_confidence_decay()— 30-day decayreconcile_memory()— Hindsight-inspired, max 20 pairsconsolidate_old_sessions()— max 5 sessionsprune()— 90-day hard delete- Generate session UUID
get_memory_system_prompt()
Returns the stable frozen prefix for the system prompt. Always includes proactive usage instructions for the LLM, plus any stored preferences, facts, skills, and error patterns. Nothing time-sensitive. This method is called automatically byAgent._get_mixin_prompts().
- Includes items from
globalcontext + active context - Excludes items where
sensitive=1 - Excludes items where
superseded_by IS NOT NULL(only current/active items) - Sorted by confidence descending
- Hard limits: max 10 preferences, 5 facts, 3 skills, 5 errors
- Hard cap on total output: 4000 chars (truncated with
... (memory truncated)if exceeded)
get_memory_dynamic_context()
Returns the per-turn dynamic context that is prepended to the user message each turn. Contains the current time and upcoming/overdue items.init_memory() has not been called.
register_memory_tools()
Registers the 5 LLM-facing memory tools with the agent’s tool registry. Call this from your agent’s_register_tools() method.
remember, recall, update_memory, forget, search_past_conversations.
set_memory_context()
Switch the active context mid-session. Affects system prompt filtering and the default context for newremember calls.
reset_memory_session()
Start a fresh memory session. Generates a new session ID and applies confidence decay to unused knowledge.Properties
Embedding Pipeline
These methods handle the vector embedding pipeline for hybrid search. All are internal (_-prefixed) — you do not call them directly.
LemonadeProvider for embedding. Cached for the process lifetime. Raises RuntimeError if Lemonade is unreachable.
user.embeddinggemma-300m-GGUF. Returns a normalized numpy array suitable for cosine similarity via FAISS IndexFlatIP.
The embedder switched from
nomic-embed-text-v2-moe-GGUF to user.embeddinggemma-300m-GGUF because the current llama.cpp server cannot load the nomic MOE embedder. Both are 768-dim, so the schema is unchanged — but old nomic vectors are not comparable to EmbeddingGemma vectors, so the changed model name invalidates the stored embeddings and existing memory stores are re-embedded automatically on the next run.init_memory() startup. Returns the number of items backfilled.
Hybrid Search
- Embed query via Lemonade (
user.embeddinggemma-300m-GGUF, 768-dim) - FAISS cosine search: top-K × 4 candidates (oversample)
- FTS5 BM25 search: top-K × 4 candidates (oversample)
- Deduplicate by ID, apply RRF weights:
0.6 / (60 + rank_vector) + 0.4 / (60 + rank_bm25) - Cross-encoder reranking (
cross-encoder/ms-marco-MiniLM-L-6-v2, ~22MB, CPU) on fused candidates - Return final top-K results
- Bump confidence +0.02 and increment
use_counton recalled items
Complexity-Aware Recall Depth
top_k value — no LLM call needed, purely heuristic:
Mem0-Style LLM Extraction
The extraction fetches top-10 relevant existing items first via
_hybrid_search(), so the LLM can see what already exists and decide whether to add, update, delete, or do nothing. This replaces v1’s regex-based heuristic extraction.
Error handling: Invalid JSON → logged error, skip this turn. Timeout (3s) → logged warning, skip. Individual operation failure → logged, continue with remaining operations. No fallback to regex heuristics.
Consolidation
init_memory() startup.
Returns: {"consolidated": int, "extracted_items": int}
Criteria for consolidation:
- All turns in the session are > 14 days old
- Session has ≥ 5 turns
- At least one turn has
consolidated_at IS NULL
- Fetch up to 20 turns per session (oldest first)
- Call LLM with consolidation prompt → returns summary + extracted knowledge
- Store summary as
knowledge(category="note", source="consolidation", domain="session:{id[:8]}") - Store each extracted item via
store()(normal dedup applies) - Mark all fetched turns with
consolidated_at = now
Reconciliation
{"pairs_checked": int, "reinforced": int, "contradicted": int, "weakened": int, "neutral": int}
Process:
- For each context, compute pairwise embedding similarity among active items
- Flag pairs with cosine similarity > 0.85
- For each flagged pair, a single LLM call classifies the relationship:
Rate-limited to
max_pairs classifications per startup (~20s on local LLM). Highest-similarity pairs processed first.
Lifecycle Hooks
MemoryMixin hooks into the Agent lifecycle at 3 points. These are automatic — you do not call them directly. Hook 1:process_query() override
Prepends per-turn dynamic context (time + upcoming items) to the user message. Saves the original user input so _after_process_query can store the clean version without the context prefix.
Hook 2: _execute_tool() override
Wraps every non-memory tool call to auto-log it to tool_history. If a tool fails, the error is automatically stored as knowledge (category="error") for future avoidance. Memory tools (remember, recall, etc.) are excluded from logging to avoid noise and recursion.
Hook 3: _after_process_query() callback
Called after process_query() completes. Stores both conversation turns (user + assistant) in the conversations table and runs Mem0-style LLM extraction (ADD/UPDATE/DELETE/NOOP operations against existing memory). For turns ≥ 20 words, the extraction pipeline fetches top-10 relevant existing items via _hybrid_search(), then asks the LLM to decide what operations to perform — no regex heuristic fallback.
KV-Cache Frozen Prefix Design
The system prompt is deliberately split into two parts:
This design allows LLM inference engines (like Lemonade Server) to cache the attention computations for the system prompt and reuse them across conversation turns. Only the small dynamic section (typically 2-5 lines) changes per turn.
MemoryStore
The pure data layer. Agent-agnostic — no imports fromgaia.agents. Thread-safe via threading.Lock. Uses WAL mode for concurrent reads.
Constructor
Database Schema (v2)
Three tables in a single SQLite file. Schema version 2 adds vector embedding support and fact lineage tracking.conversations— every conversation turn, persistent across sessions, with FTS5 index. v2 addsconsolidated_at TEXTcolumn for tracking which turns have been distilled to knowledge.knowledge— persistent facts, preferences, errors, skills with FTS5 index, confidence scoring, context scoping, entity linking, temporal fields (due_at,reminded_at). v2 addsembedding BLOB(768-dim float32 vector) andsuperseded_by TEXT(fact lineage — ID of newer item that replaced this one).tool_history— every tool call the agent makes, auto-logged with success/failure, duration, error messages
MemoryStore.__init__(). v1 → v2 adds:
Knowledge Methods
store()
category + context + entity scope, the existing entry is updated with the newer content. The newer fact is assumed to be more current.
Validation: content must be non-empty (raises ValueError otherwise). Content longer than 2000 characters is silently truncated. due_at, if provided, is normalized to timezone-aware ISO 8601.
Embedding: After storage, MemoryMixin immediately embeds the new item via _embed_text() and writes the embedding BLOB back via store_embedding(). The FAISS index is incrementally updated.
search()
superseded_by IS NULL to return only current/active items.
The time_from and time_to parameters add temporal filtering on created_at, narrowing results before BM25 ranking.
This is the keyword component of search. For full hybrid search (vector + BM25 + RRF + cross-encoder reranking), use
MemoryMixin._hybrid_search(), which calls this method internally as one of its two retrieval signals.get_by_category()
superseded_by IS NULL to return only current/active items.
get_by_entity()
superseded_by IS NULL to return only current/active items.
get_upcoming()
superseded_by IS NULL to return only current/active items.
update()
updated_at to the current time. When content is updated, the stored embedding is cleared (embedding = NULL) to force re-embedding. The superseded_by parameter is used by the LLM extraction pipeline to mark old items as replaced by newer versions while preserving fact lineage.
delete()
apply_confidence_decay()
decay_factor for items not accessed in days_threshold days. Called once per session start via reset_memory_session().
update_confidence()
delta, clamped to [0.0, 1.0]. Used internally by reconciliation (+0.05 reinforce, +0.1 contradict newer, -0.1 weaken) and hybrid search (+0.02 per recall for vector-only results).
delete_by_source()
"discovery"). Returns the number of entries deleted. Used by gaia memory bootstrap --reset to clear discovery items.
Conversation Methods
Tool History Methods
Dashboard Methods
Aggregate queries for the Memory Dashboard UI:Embedding & Vector Methods (v2)
Consolidation Methods (v2)
Reconciliation Methods (v2)
SystemDiscovery
Local system scanner for day-zero bootstrap. Returns lists of discovered facts for user review — nothing is stored directly.Methods
Each method returns dicts like:
Discovery never reads file contents, email content, or browser page content. It reads names, extensions, URLs, and metadata only. All browser history and email items are auto-flagged as sensitive.
Code Examples
Minimal Agent with Memory
Switching Contexts
Accessing the Store Directly
Custom DB Path
Memory Tools Reference
These 5 tools are registered byregister_memory_tools() and exposed to the LLM:
remember
Store a fact, preference, error, skill, note, or reminder. Supports
category, domain, due_at, context, sensitive, entity.recall
Search memory by query (hybrid: vector + BM25 + cross-encoder), category, context, entity, or time range. Returns results with IDs for use with update/forget.
update_memory
Modify an existing entry by ID. Only non-empty fields change. Use
reminded_at="now" after mentioning time-sensitive items.forget
Delete a specific memory entry by ID.
search_past_conversations
Search conversation history by keywords, time range, or both. Returns matching turns with timestamps and session IDs.
remember = create, recall = read, update_memory = update, forget = delete, plus search_past_conversations for history.
Knowledge Sources
v2 replaces the v1
heuristic source (regex-based) with llm_extract (Mem0-style LLM extraction). The LLM sees both the conversation and existing memory, then decides what operations to perform (ADD/UPDATE/DELETE/NOOP). This produces higher-quality extractions with proper deduplication and contradiction resolution.API Reference
MemoryMixin Methods
MemoryStore Methods
Related
- User Guide — What agent memory does, CLI commands, dashboard walkthrough
- Agent System — Base Agent class that MemoryMixin extends
- Tool Decorator — How the 5 memory tools are registered
- Agent UI — Desktop interface with Memory Dashboard
- Agent SDK — Chat SDK for building conversational agents