Agent Substrate

Memory & Context

The problem

An agent needs to remember the conversation — but a model's context window is finite and every token costs money and latency. So there are really two problems hiding under "memory":

  1. Persistence — where do past turns live, so the agent can recall them across runs and restarts?
  2. Context assembly — how do you fit a long history into a small window before each model call, without losing what matters?

Agent Substrate splits these cleanly: a HistoryProvider owns persistence; a CompactionPipeline owns context assembly. They meet in the ContextConfig you pass to an agent.

diagram
Rendering diagram…

The full transcript always lives in the history provider. Compaction produces a view for the model — it never deletes the source.


Persistence: the HistoryProvider

A HistoryProvider is a small Protocol for reading and writing turns, always scoped by session_id so conversations never bleed into each other:

python
class HistoryProvider(Protocol):
    async def append(self, agent_id, message, *, session_id, run_id): ...
    async def append_many(self, agent_id, messages, *, session_id, run_id): ...
    async def get_messages(self, agent_id, *, session_id) -> list[ChatMessage]: ...
    async def clear(self, agent_id, *, session_id): ...
    async def clear_run(self, agent_id, *, session_id, run_id): ...

Three backends ship, all interchangeable:

BackendUse
InMemoryHistoryProviderDev, tests, throwaway sessions
RedisHistoryProviderFast, TTL'd session memory
DurableHistoryProviderDurable, queryable transcripts

Retention: how long history lives

Different agents want different lifetimes. ContextConfig carries a HistoryRetention policy:

PolicyBehaviourFor
PERMANENTKept foreverUser-facing assistants
RUNDeleted when the run endsTransient sub-agents
NONENever writtenStateless workers

When a run completes, the Worker honours this: a RUN-retention sub-agent's history is cleared automatically, so a fleet of short-lived helpers doesn't accumulate junk.


Context assembly: the CompactionPipeline

Before every model call, the agent runs the history through a CompactionPipeline — an ordered chain of strategies, each taking the previous one's output:

diagram
Rendering diagram…

Strategies that ship in agents/context/compaction/:

StrategyWhat it does
SlidingWindowCompactionKeep the most recent N messages (the default)
ToolResultCompactionStrategyShrink large/old tool results, which bloat context fastest
SelectiveToolCallCompactionStrategyDrop tool-call noise that's no longer relevant
SummarizationCompactionReplace old turns with an LLM-generated summary
TruncationStrategyHard cap on message count
TokenBudgetComposedStrategyCompose strategies to hit a token budget

Compose them to taste:

python
from substrate.agents.context import (
    ContextConfig, InMemoryHistoryProvider,
    CompactionPipeline, ToolResultCompactionStrategy, SlidingWindowCompaction,
)
from substrate.kernel.agent.supervision import HistoryRetention

ctx = ContextConfig(
    InMemoryHistoryProvider(),
    CompactionPipeline([
        ToolResultCompactionStrategy(),
        SlidingWindowCompaction(max_messages=40),
    ]),
    retention=HistoryRetention.PERMANENT,
)
agent = ReActAgent("bot", model=model, context=ctx)

An empty pipeline is a valid no-op (returns history unchanged). Pass a single strategy directly without wrapping it.


When trimming isn't enough

Sliding windows and summaries are lossy by recency — they assume old means irrelevant. That assumption breaks for long-running agents that must recall a specific fact or decision from far back. For those, Agent Substrate has three orthogonal advanced strategies that recall by relevance or structure instead of recency. They are not mutually exclusive — you can layer them with the basic pipeline above.

diagram
Rendering diagram…
StrategyRecalls byBest forFailure mode
Vector MemoryEmbedding similarityFuzzy recall over big historiesMisses causally-important but dissimilar turns
Graph MemoryEntity / relationship traversalStructured facts, constraints, decisionsLoses unstructured narrative
Paged MemoryExplicit pages + agent-driven retrievalFull-fidelity recall, agent decides what to loadIndex summary may miss detail

All three plug in as compaction strategies (or alongside them), backed by the in-memory stores in agents/storage/ for dev and the Postgres-backed PgVectorStore / AGEGraphStore in capabilities/ for production.


Where this lives

PieceLocation
HistoryProvider Protocolkernel/storage/history.py
ContextConfig, AgentContextagents/context/context.py
CompactionPipeline + strategiesagents/context/compaction/
History backendsagents/context/history.py, capabilities/history/
HistoryRetentionkernel/agent/supervision.py

Next: Supervision & Budgets — bounding multi-agent systems.