Skip to main content

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:

  1. Extract the general procedure from the specific execution
  2. Give it a name and trigger keywords
  3. 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_k results (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:

  1. Identifies entities (people, places, organizations, crypto assets)
  2. Extracts relationships between entities
  3. Identifies user preferences and preferences
  4. 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 well
  • known_failures: types of tasks that have failed before
  • user_preferences: detected preferences from interactions
  • weekly_stats: message counts, skill usage statistics
  • skill_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.