Memory Systems
WASP has 8 persistent memory systems. Unlike most AI assistants, WASP's memory is not context-window-limited — it persists across sessions, across days, and across container restarts.
Memory Architecture Overview
┌─────────────────────────────────────────────────────┐
│ MemoryManager │
├──────────────┬──────────────┬──────────────────────┤
│ Episodic │ Semantic │ Working Memory │
│ (PostgreSQL) │ (PostgreSQL) │ (Redis) │
├──────────────┼──────────────┼──────────────────────┤
│ Procedural │ Visual │ Vector Memory │
│ (PostgreSQL) │ (PostgreSQL) │ (PostgreSQL, optional)│
├──────────────┼──────────────┼──────────────────────┤
│ Knowledge │ Self-Model │ Temporal Model │
│ Graph │ (Redis+File)│ (PostgreSQL) │
│ (PostgreSQL) │ │ │
└──────────────┴──────────────┴──────────────────────┘
1. Episodic Memory
Storage: PostgreSQL memory_entries table
Purpose: Conversation history, events, facts from interactions
Episodic memories store:
- Conversation exchanges with timestamps
- Explicit memory saves (
memory(action="store", ...)) - Important facts extracted from conversations
Retrieved via semantic similarity search for relevant context injection.
2. Semantic Memory
Storage: PostgreSQL memory_entries table (type=semantic)
Purpose: Durable facts, user preferences, learned knowledge
Semantic memories are long-lived facts:
- User preferences ("I prefer concise responses")
- Domain knowledge ("The user's server is at IP 76.13.232.149")
- Learned associations
3. Working Memory
Storage: Redis (session-scoped) Purpose: Current conversation context, temporary data
Working memory holds the current session state and is cleared between conversations. It provides fast access to recent context without database queries.
4. Procedural Memory (src/memory/procedural.py)
Storage: PostgreSQL procedural_memory table
Purpose: Learned multi-step procedures
When the agent successfully completes a complex task using 3+ skill calls, the abstract_procedure() function uses the LLM to:
- Extract the general procedure from the specific execution
- Give it a name and trigger keywords
- Store it for future retrieval
Example: After browsing a crypto exchange and extracting prices 5 times, a procedure "check_crypto_price_from_exchange" is created with steps.
Procedures are retrieved by find_procedures(task) and injected into the system prompt as few-shot hints.
5. Visual Memory (src/memory/visual.py)
Storage: PostgreSQL visual_memory table
Purpose: Index of screenshots and images
When the browser skill takes a screenshot, metadata (URL, timestamp, description) is stored in visual memory. This allows the agent to recall "I already have a screenshot of that site from yesterday."
6. Vector Memory (optional)
Storage: PostgreSQL memory_embeddings table
Purpose: Semantic similarity search
When enabled (VECTOR_MEMORY_ENABLED=true), memories are embedded using an Ollama model (default: nomic-embed-text) and stored as vectors. This enables:
- Semantic similarity search across all memories
- Retrieval of related memories even without keyword overlap
vector_top_kresults (default: 8)
Requires Ollama with an embedding model pulled:
docker exec agent-ollama ollama pull nomic-embed-text
7. Knowledge Graph (src/memory/knowledge_graph.py)
Storage: PostgreSQL knowledge_nodes + knowledge_relations tables, Redis cache
Purpose: Entity and relationship tracking
After every conversation, the KG extractor:
- Identifies entities (people, places, organizations, crypto assets)
- Extracts relationships between entities
- Identifies user preferences and preferences
- Updates or creates nodes/edges in the graph
The KG is injected into every system prompt as a [KNOWLEDGE GRAPH] block, providing persistent relational context.
Redis cache: kg:node:{id} keys with short TTL for fast reads.
8. Self-Model (src/agent/self_model.py)
Storage: Redis key agent:self_model + file backup /data/memory/self_model.json
Purpose: Agent self-knowledge and metacognition
The self-model tracks:
strengths: domains where the agent performs wellknown_failures: types of tasks that have failed beforeuser_preferences: detected preferences from interactionsweekly_stats: message counts, skill usage statisticsskill_success_rates: per-skill success/failure ratios
Updated after every message. Falls back to file if Redis miss (survives restarts).
The self-model is injected into the system prompt as [SELF-MODEL], enabling the agent to reason about its own capabilities.
Memory Lifecycle
Message received
→ MemoryManager.retrieve() — find relevant episodic/semantic memories
→ build_context() — inject relevant memories into prompt
→ LLM generates response
→ [async] MemoryManager.store() — save conversation
→ [async] KG extraction
→ [async] Temporal extraction
→ [async] Procedure abstraction
Memory Promotion
The PromotionEngine (runs every 12 hours) promotes frequently-accessed episodic memories to semantic memories, increasing their weight in future retrieval.
Memory Cleanup
The MemoryCleanupJob (runs daily) removes:
- Episodic memories older than the retention threshold
- Orphaned vector embeddings
- Temporary working memory entries
Accessing Memory via Skill
# Store a fact
memory(action="store", content="User's birthday is March 15", type="semantic")
# Search memories
memory(action="search", query="user preferences coding style")
# List recent memories
memory(action="list", limit=10)
Memory Snapshots
The SnapshotJob (runs daily) creates full memory snapshots to /data/memory/snapshot_*.json, enabling recovery from database issues.