Fifth pipeline stage — episodic archive with BM25 recall.
Before Summary compresses the middle of history into a paragraph,
this stage slices that middle into discrete episodes and stores their
text in state.meta[:episodic_archive]. On every pipeline run it
also checks whether any archived episode is relevant to the current
turn and injects matching episodes into the compact_view.
Why this over RAG
Agent conversations have strong temporal structure — turn N depends on N-1 (tool call + result pairs). Embedding-based retrieval doesn't model that dependency. BM25 on code/tool output works better because the model asks about specific function names, file paths, and error strings — exact-token matches, not semantic proximity.
What this solves
Summary's biggest weakness: "found bug at line 47 of auth.ex" compresses to "the agent investigated auth". The finding — file, line, what the bug was — is gone. When the model needs that detail later it re-reads the file. EpisodicArchive keeps the text of each episode in a sidecar and injects it back when it scores above threshold.
Configuration
config :ex_athena, :compactor,
episodic_episode_size: 8, # messages per episode
episodic_top_k: 2, # episodes recalled per turn
episodic_score_threshold: 1.5, # minimum BM25 score to recall
episodic_recall_chars: 800 # max chars per recalled episode