Memory¶
MemoryProvider ¶
Bases: ABC
Pluggable memory backend for AI context construction.
Implement this ABC to control how conversation history is retrieved
for AI generation. The library ships with :class:SlidingWindowMemory
(simple last-N events) as the default.
Lifecycle methods ingest, clear, and close are concrete
no-ops so that simple implementations only need to override retrieve.
recent_events_window
property
¶
How many recent events this provider may read from RoomContext.
The framework uses the largest window across a room's bound channels to
decide how many events to load into RoomContext.recent_events — so a
provider that windows to last-N should report N (avoids loading and
deserialising the whole ceiling every turn). Defaults to the full pool
for providers that don't trim by event count (e.g. token-aware ones).
retrieve
abstractmethod
async
¶
Retrieve context for AI generation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
room_id
|
str
|
The room being processed. |
required |
current_event
|
RoomEvent
|
The event that triggered AI generation. |
required |
context
|
RoomContext
|
Full room context including recent events, bindings, and participants. |
required |
channel_id
|
str | None
|
The AI channel requesting memory (useful when multiple AI channels share a room). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
MemoryResult
|
class: |
MemoryResult
|
in the AI context. |
ingest
async
¶
Ingest an event into memory (optional).
Stateful providers (e.g. summarization, vector stores) can override this to update their internal state as events arrive. The default implementation is a no-op.
MemoryResult
dataclass
¶
Result returned by a memory provider.
Memory providers can return pre-built AI messages (e.g. summaries, synthetic context) and/or raw room events that AIChannel will convert using its own content extraction logic (preserving vision support).
A provider may populate any of the fields. messages are prepended
first, then events are converted and appended.
notes is what the provider retrieved for the current turn only
(knowledge passages, say). It changes from one turn to the next, so the
channel carries it with the turn's notes, after the input, rather than in
the history a provider caches (RFC §20.2). A provider that wraps another
and rebuilds its result carries the inner notes
(dataclasses.replace keeps them).
speakers is the labels messages name participants by, as the
runtime gives them (a summary's lines, Alice, @sms1): the channel
counts them toward labelling the turns that follow, so a conversation a
summary named several people in labels its turns (RFC §6.4).
SlidingWindowMemory ¶
Bases: MemoryProvider
Return the most recent events from the room context.
This replicates the original AIChannel behavior of slicing
context.recent_events[-max_events:].
BudgetAwareMemory ¶
BudgetAwareMemory(inner, max_context_tokens, safety_margin_ratio=0.15, min_events=3, reserved_tokens=0)
Bases: _MemoryWrapper
Wraps a MemoryProvider and trims results to fit within a token budget.
The history's budget is what is left of the window once everything else in
it is paid for — see :func:roomkit.memory.token_estimator.history_budget,
which owns the arithmetic. Read for an AI channel's turn, the rest of the
turn is what the channel measured (:func:current_turn_footprint, RFC
§20): its input is reserved, and its reply budget when larger than the
safety margin. reserved_tokens is a floor on that input (system prompt,
tool schemas, the channel's notes), for a caller that knows a part the
channel cannot; it is not added to the measure. The injected messages,
the memory's notes and the current turn this wrapper passes through are
measured here. A current turn that alone exceeds a known window raises a
non-retryable ProviderError(context_overflow=True) before retrieval or
generation: trimming history cannot make that message fit.
Events are trimmed from the oldest, preserving the most recent conversation.
The one way the result can still exceed the budget is min_events: the
most recent few events are kept even when they don't fit, because returning
an empty history is worse than returning one that needs compaction.
The turn's footprint¶
TurnFootprint
dataclass
¶
What a turn takes of the context window besides its history (RFC §20).
Measured by the AI channel as round 0 will send it, before it reads its memory. What a hook adds to the context afterwards is not in it.
Attributes:
| Name | Type | Description |
|---|---|---|
input_tokens |
int
|
The system prompt, the tools declared (Tool Search's collapse and the re-read tool included) and the notes the channel adds to the turn's input (the room's plan, the digest of the tools already used, the speaker attribution). |
reply_tokens |
int
|
The reply budget the turn requests; 0 when the channel sets none and the provider applies its own. |
current_turn_footprint ¶
What the turn takes of the context window besides its history (RFC §20).
Measured by the AI channel before it reads its memory: a memory reading
the room for a turn sizes the history to what the window leaves. Readable
from that read on, through the turn's BEFORE_AI_GENERATION hooks.
None outside an AI channel's turn, before the channel measured it, and
in a tool handler, whose loop context is the call's own.
SummarizingMemory ¶
SummarizingMemory(inner, provider, max_context_tokens, *, tier1_ratio=0.5, tier2_ratio=0.85, truncate_chars=2000, summary_max_tokens=1000, min_events=5, summary_cache_ttl_seconds=1800.0)
Bases: _MemoryWrapper
Two-tier memory provider that proactively manages context budget.
Wraps an inner MemoryProvider (typically SlidingWindowMemory)
and applies two tiers of context reduction:
- Tier 1 — truncate large event bodies in older messages when total
estimated tokens exceed
tier1_ratio * max_context_tokens. - Tier 2 — summarize older events via a lightweight AI provider when
total tokens still exceed
tier2_ratio * max_context_tokens.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
inner
|
MemoryProvider
|
The wrapped memory provider. |
required |
provider
|
AIProvider
|
A lightweight AI provider for summarization (e.g. Haiku). |
required |
max_context_tokens
|
int
|
Total token budget for the AI context. |
required |
tier1_ratio
|
float
|
Fraction of budget that triggers tier-1 truncation. |
0.5
|
tier2_ratio
|
float
|
Fraction of budget that triggers tier-2 summarization. |
0.85
|
truncate_chars
|
int
|
Max characters per old event body in tier 1. |
2000
|
summary_max_tokens
|
int
|
Max tokens for the LLM summary response. |
1000
|
min_events
|
int
|
Minimum events to keep before summarizing (tier 2). |
5
|
summary_cache_ttl_seconds
|
float
|
TTL for cached summaries. |
1800.0
|
RetrievalMemory ¶
Bases: _MemoryWrapper
Wraps an inner provider and enriches context with knowledge sources.
On retrieve, queries all configured knowledge sources concurrently,
merges results by score, and returns the passages as the turn's note
(MemoryResult.notes), each in a <knowledge> block: they ride the
turn's input, not the history a provider caches (RFC §20.2).
On ingest, forwards to the inner provider and indexes text content
in all knowledge sources.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sources
|
list[KnowledgeSource]
|
Knowledge sources to query on each retrieval. |
required |
inner
|
MemoryProvider
|
The wrapped memory provider for conversation history. |
required |
max_results
|
int
|
Maximum knowledge results to include in context. |
5
|
min_query_length
|
int
|
Minimum query length to trigger search. |
3
|
MockMemoryProvider ¶
Bases: MemoryProvider
Mock memory provider that records calls and returns configured results.
Example::
mock = MockMemoryProvider(
messages=[AIMessage(role="system", content="Summary of conversation")],
)
result = await mock.retrieve("room1", event, context)
assert len(mock.retrieve_calls) == 1