Memory Management Guide¶
Echo Agent's memory system uses a tiered architecture that mimics how human memory works — from short-term working memory to long-term archival storage. Each tier has different capacity, persistence, and retrieval characteristics.
Architecture Overview¶
┌─────────────────────────────────────────────────────────┐
│ Memory System │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ ┌───────────────────────────┐ │
│ │Working Memory │───▶│ Eligibility Check │ │
│ │ (max 20) │ │ (eligibility.py) │ │
│ └───────────────┘ └───────────┬───────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ ┌───────────────────────────┐ │
│ │Episodic Memory│◀───│ Review & Quality │ │
│ │ (temporal idx) │ │ (reviewer.py) │ │
│ └───────┬───────┘ └───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ ┌───────────────────────────┐ │
│ │Semantic Memory│◀──▶│ Contradiction Detection │ │
│ │ (vector idx) │ │ (contradiction.py) │ │
│ └───────┬───────┘ └───────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ ┌───────────────────────────┐ │
│ │Archival Memory│◀───│ Consolidation │ │
│ │ (long-term) │ │ (consolidator.py) │ │
│ └───────────────┘ └───────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Retrieval Layer │ │
│ │ Vector │ BM25 │ Hybrid (retrieval.py) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Local Embeddings & Reranking │ │
│ │ (local_embed.py / local_rerank.py) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
The Four Memory Tiers¶
Tier 1: Working Memory¶
Working memory is an in-process buffer that holds immediate context for the current conversation. Like human short-term memory, it has limited capacity and is not persisted.
| Property | Value |
|---|---|
| Max entries | 20 |
| Persisted | No |
| Context rendering | Markdown, max 2000 characters |
| Scope | Current conversation |
Example:
# Working memory automatically collects key information from the conversation
working_memory.add(MemoryEntry(
key="user_preference_lang",
content="User prefers communicating in English",
tier=MemoryTier.WORKING,
type=MemoryType.USER
))
# Render context for model consumption
context = working_memory.get_context(max_chars=2000)
Working memory does not persist across conversations
Working memory is lost when the conversation ends. If important information needs to be retained, the system uses Eligibility Check to determine whether to promote it to a higher tier.
Tier 2: Episodic Memory¶
Episodic memory stores conversation episodes with temporal indexing. It records "what happened" — timestamped interaction records.
| Property | Value |
|---|---|
| Indexing | Temporal |
| Persisted | Yes |
| Content type | Conversation episodes, event records |
| Decay | Subject to time-based decay |
Example:
# Episodic memory records user interaction history
episodic_entry = MemoryEntry(
key="episode_2024_0315_debug_session",
content="User requested help debugging a database connection issue; root cause was connection pool exhaustion",
tier=MemoryTier.EPISODIC,
type=MemoryType.USER,
provenance=Provenance(source="conversation", timestamp="2024-03-15T10:30:00Z")
)
Tier 3: Semantic Memory¶
Semantic memory stores structured knowledge with vector indexing for semantic retrieval. It records "what is known" — facts, preferences, rules.
| Property | Value |
|---|---|
| Indexing | Vector (local_embed.py) |
| Persisted | Yes |
| Content type | Structured knowledge, user preferences, environment info |
| Retrieval | Supports semantic similarity search |
Example:
# Semantic memory stores structured knowledge
semantic_entry = MemoryEntry(
key="user_tech_stack",
content="User primarily uses Python + FastAPI for backend, Vue 3 for frontend",
tier=MemoryTier.SEMANTIC,
type=MemoryType.USER
)
Tier 4: Archival Memory¶
Archival memory is the long-term storage tier, holding consolidated and verified important information. Analogous to human long-term memory.
| Property | Value |
|---|---|
| Storage | Persistent long-term |
| Source | Consolidated from upper tiers |
| Content type | Verified core knowledge |
| Decay | Minimal |
Example:
# Archival memory holds consolidated core knowledge
archival_entry = MemoryEntry(
key="project_architecture_v2",
content="Project uses microservices architecture with 5 core services communicating via gRPC",
tier=MemoryTier.ARCHIVAL,
type=MemoryType.ENVIRONMENT
)
Memory Lifecycle¶
A memory goes through a complete lifecycle from creation to eventual archival (or forgetting):
Creation ──▶ Eligibility ──▶ Review ──▶ Storage ──▶ Consolidation ──▶ Archival
│ │ │
│ ▼ ▼
│ Decay ──▶ Forgetting
│
└──▶ Ineligible ──▶ Discarded
Creation¶
Memories can be created in two ways:
- Implicit: The system automatically extracts noteworthy information from conversations
- Explicit: Manual storage via the
memorytool
Eligibility Check¶
eligibility.py determines what information is worth remembering:
- Explicit user preference statements
- Recurring patterns
- Environment configuration information
- Key project decisions
Quality Review¶
reviewer.py performs quality control on memories that pass eligibility:
- Is the content clear and unambiguous?
- Does it duplicate existing memories?
- Does it include sufficient context?
Consolidation¶
consolidator.py periodically merges and summarizes related memories:
# Consolidation merges multiple related memories into a single refined entry
# Example: multiple mentions of "user prefers concise code style" get merged
# into one high-confidence memory
Consolidation triggers once the entry count reaches memory.consolidationThreshold (20 by default). memory.sleepConsolidation is on by default and runs an additional pass while the agent is idle.
Decay and Forgetting¶
forgetting.py implements time-based memory decay:
- Memories that haven't been accessed for extended periods gradually lose priority
- Memories that decay below a threshold are marked as "forgotten"
- Forgetting does not mean deletion — the archival tier may still retain the information
Decay reduces the importance score over the period set by memory.importanceDecayDays (30 days by default). Memories scoring below memory.archivalThreshold (0.05) move to the archival tier; those below memory.forgetThreshold (0.01) are forgotten.
Retrieval Modes¶
retrieval.py provides three retrieval modes suited to different scenarios:
Vector Retrieval¶
Semantic similarity-based retrieval using embeddings generated by local_embed.py.
# Semantic search — understands intent rather than matching keywords
results = memory.retrieve(
query="user's programming language preferences",
mode="vector"
)
Best for: Fuzzy queries, conceptually related information, cross-language matching.
BM25 Retrieval¶
Traditional term frequency-inverse document frequency retrieval algorithm.
# Exact keyword matching
results = memory.retrieve(
query="FastAPI database connection",
mode="bm25"
)
Best for: Exact term searches, code snippet matching, proper noun lookups.
Hybrid Retrieval¶
Combines the strengths of Vector and BM25, with reranking via local_rerank.py.
# Hybrid mode — balances semantic understanding with exact matching
results = memory.retrieve(
query="database connection pool configuration",
mode="hybrid"
)
Best for: Most general query scenarios (recommended as the default).
Choosing a retrieval mode
Use Hybrid mode for everyday use. Switch to Vector or BM25 only when you specifically need pure semantic matching or pure keyword matching.
Prefetch Mechanism¶
prefetch.py implements proactive memory loading:
- At conversation start, predicts which memories will likely be needed based on context
- Pre-loads them into working memory to reduce retrieval latency
- Predictions are based on user historical behavior patterns
Using the memory Tool¶
The memory tool provides explicit operations on the memory system:
Store a Memory¶
Search Memories¶
Delete a Memory¶
View Memory Status¶
Memory scope
The memory system is isolated per user (memory_scope provided by ToolExecutionContext). Memories are not visible across different users.
Provenance Tracking¶
Every MemoryEntry includes provenance information, recording the origin and change history of the memory:
class MemoryEntry:
key: str # Unique identifier
content: str # Memory content
tier: MemoryTier # Current tier
type: MemoryType # USER or ENVIRONMENT
provenance: Provenance # Provenance information
Provenance information includes:
- Source: Where the memory came from (conversation, tool call, consolidation)
- Timestamp: Creation and last modification time
- Change chain: History of consolidations and updates
This enables the system to: - Trace any memory back to its original source - Determine which memory is more trustworthy during contradiction detection - Audit the complete lifecycle of a memory
Contradiction Detection and Resolution¶
contradiction.py is responsible for discovering and handling conflicting memories:
Detection Mechanism¶
When a new memory is written, the system automatically checks for contradictions with existing memories:
# System detects a contradiction
# Existing memory: "Project uses MySQL database"
# New memory: "Project has migrated to PostgreSQL"
# → Contradiction detection triggered
Resolution Strategies¶
- Recency priority: More recent memories take precedence
- Provenance trust: Explicit user statements > system inferences
- Confirmation mechanism: When automatic resolution is not possible, flagged for confirmation
Contradictions are never silently lost
When a contradiction is detected, the old memory is not deleted outright. Instead, it is marked as "superseded" and the full change history is preserved.
Configuration Options¶
Working Memory Configuration¶
| Parameter | Default | Description |
|---|---|---|
max_entries |
20 | Maximum number of working memory entries |
max_context_chars |
2000 | Maximum characters rendered by get_context() |
Retrieval Configuration¶
| Parameter | Default | Description |
|---|---|---|
memory.retrievalOnMiss |
degrade |
Behaviour on a retrieval-cache miss: degrade runs a time-bounded synchronous search and falls back to keyword search on timeout; sync always runs the full synchronous search |
memory.retrievalMissTimeoutSeconds |
0.8 |
Time budget for that bounded search; 0 skips it entirely |
memory.rerankEnabled |
true |
Apply cross-encoder reranking to the fused top-K |
memory.rerankTopK |
10 |
How many fused candidates get reranked |
memory.rerankMinScore |
0.0 |
Absolute relevance floor; 0 reranks without dropping candidates |
Decay configuration¶
| Option | Default | Description |
|---|---|---|
memory.importanceDecayDays |
30.0 |
Importance decay period, in days |
memory.archivalThreshold |
0.05 |
Memories scoring below this move to the archival tier |
memory.forgetThreshold |
0.01 |
Memories scoring below this are forgotten |
Consolidation configuration¶
| Option | Default | Description |
|---|---|---|
memory.consolidationThreshold |
20 |
Entry count that triggers consolidation |
memory.sleepConsolidation |
true |
Run an extra consolidation pass while idle |
memory.contradictionDetection |
true |
Enable contradiction detection |
Memory Types¶
The system supports two memory types:
- USER: User-related memories (preferences, habits, interaction history)
- ENVIRONMENT: Environment-related memories (project configuration, tech stack, system information)
Best Practices¶
1. Let the System Work Automatically¶
In most cases, the memory system handles storage and retrieval automatically. Only use the explicit memory tool when you need to ensure specific critical information is remembered.
2. Use Meaningful Keys¶
3. Keep Content Concise and Clear¶
Each memory should be self-contained and independently understandable. Avoid overly long or ambiguous content.
4. Use Types to Differentiate Scope¶
- Personal user preferences →
USERtype - Project/environment information →
ENVIRONMENTtype
5. Trust Contradiction Detection¶
When the system flags a memory contradiction, confirm which one is correct promptly. Do not ignore contradiction alerts.
6. Monitor Memory Status Regularly¶
Use memory status to understand the current distribution and health of your memories, ensuring important information hasn't been lost to decay.
About prefetch
The prefetch mechanism automatically loads relevant memories based on conversation context. If you find certain memories are consistently missing when needed, consider promoting them to the semantic memory tier to improve retrieval hit rates.