Episodic Memory
Episodic memory stores past conversation sessions in SQL Server — the agent's "autobiographical" memory. It records what happened in which conversation, with which user, so the agent can recall relevant past interactions when the same user returns.
What Is Episodic Memory?
When a conversation session ends, Octopus persists a summary of that session as an episode in SQL Server. On subsequent turns, episodic memory is searched by user ID and the current message to inject relevant past context into working memory:
// Episode stored after a conversation ends
{
"episodeId": "ep_9a3f...",
"agentId": "agent_hr_01",
"userId": "user_mary_k",
"startedAt": "2025-03-14T09:22:00Z",
"endedAt": "2025-03-14T09:38:00Z",
"summary": "Mary asked about her annual leave balance and remaining days.",
"keyFacts": ["User prefers formal language", "12 days remaining as of March"],
"embedding": [0.012, -0.034, ...] // Vector for semantic recall
}
Key Characteristics
| Property | Value | Notes |
|---|---|---|
| Storage | SQL Server (Octopus_Episodes table) | Managed by SqlServerPlugin |
| Lifetime | Configurable TTL (default 90 days) | Soft-deleted then purged by retention job |
| Scope | Per agent + per user | Agent A cannot read User X's episodes from Agent B |
| Retrieval | Recency or semantic search | Top-K most relevant past episodes |
| Privacy | PII detection + erasure endpoint | GDPR / CCPA compliant |
How Episodes Are Stored
Episodes are written when a session ends via IEpisodicMemoryStore.CloseEpisodeAsync. The closing process generates a summary using an LLM call (optional), computes an embedding for semantic search, and stores the episode row:
public interface IEpisodicMemoryStore
{
Task<Episode> OpenEpisodeAsync(Guid agentId, string userId, Guid tenantId, CancellationToken ct);
Task AddMessageAsync(Guid episodeId, EpisodeMessage message, CancellationToken ct);
Task<Episode> CloseEpisodeAsync(Guid episodeId, CancellationToken ct);
Task<IReadOnlyList<EpisodeSnippet>> SearchAsync(
Guid agentId, string userId, string query, int topK, CancellationToken ct);
}
How Episodes Are Recalled
Before each LLM call, MemoryOrchestrator calls SearchAsync with the current user message. Two recall modes are supported:
| Mode | How It Works | Best For |
|---|---|---|
| Recency | Returns the N most recent episodes by EndedAt DESC | Continuity agents — "what did we discuss last time?" |
| Semantic | Computes query embedding, cosine similarity against stored episode embeddings, returns top-K | Specific topic recall — "when did we last discuss parental leave?" |
What Gets Injected into Working Memory
Recalled episode snippets are formatted and injected into the context as a "Past Conversations" section between the system prompt and message history:
[Past Conversations]
The following are relevant conversations this user has had with you previously:
Date: 2025-03-14
Summary: Mary asked about her annual leave balance. 12 days remaining.
Key facts: Prefers formal English. Has a holiday planned for June.
---
Date: 2025-02-01
Summary: Mary requested clarification on the parental leave policy.
Key facts: She is expecting in August 2025.
---
Use this context to personalise your response.
Retention and Privacy
Episodic memory has a configurable TTL and supports full user data erasure to comply with privacy regulations:
- Retention TTL: Episodes older than the configured TTL (default 90 days) are soft-deleted and then purged by a background job
- User erasure:
EraseUserDataAsync(userId, agentId)hard-deletes all episodes for that user across all sessions - PII detection: Optional pipeline stage that detects and redacts PII before storage
This is a summary page. The Episodic Memory full guide covers episode structure, SQL schema, recall modes with code, episode boundary detection, long-term retention lifecycle, privacy and PII, and the REST API.