memory / episodes.py — EpisodicMemory
Structured episodes — sequences of actions and outcomes — with optional vector search for trigger similarity.
Storage
SQLite at memory_dir/episodic_memory.db; threading.RLock guards all access.
Tables
episodes
| Column | Type |
|---|---|
| id | INTEGER PK |
| trigger / context / outcome / lesson / cluster_id | TEXT |
| outcome_success | 0/1 |
| timestamp | REAL |
| consolidated | 0/1 |
Indexes on trigger, cluster_id, timestamp.
episode_actions
| Column | Type |
|---|---|
| id | INTEGER PK |
| episode_id | FK → episodes.id |
| action_order | INT |
| tool_name | TEXT |
| tool_args | JSON |
| result | TEXT |
| success | 0/1 |
Retention
MAX_EPISODES = 500. When exceeded the oldest non-lesson, non-consolidated episodes are deleted first. MAX_ACTIONS_PER_EPISODE = 20.
Public API
| Method | Effect |
|---|---|
record_episode(trigger, context, actions, outcome, success, lesson, cluster_id) -> int | Insert episode + action rows; return id. |
search_similar(trigger, limit, vector_memory=None) -> list[dict] | Vector search if vector_memory available; else substring match. |
search_by_outcome(success, limit) | Filter by success/failure. |
search_recoveries(error_context, limit, vector_memory=None) | Find recovery strategies for similar past errors. |
get_episode(id) | Full episode + actions. |
get_recent_episodes(limit) | Most recent episodes (no actions). |
get_episodes_by_cluster(cluster_id, limit) | Cluster-grouped. |
mark_consolidated(ids) / get_unconsolidated(limit) | Dream-cycle markers. |
format_for_context(episodes, max_chars) | LLM-injection format. |
count() | Total episodes. |