pub struct CompactingMemory<M, P, C: Compactor> { /* private fields */ }Expand description
A ConversationMemory adapter that wraps a backend with a
MemoryPolicy and a Compactor, replacing truncated turns with
a summary artifact spliced at the front of the loaded history.
CompactingMemory is the next layer above DemotingPolicyMemory: a
demotion hook only observes what the policy evicted, while a compactor
substitutes the evicted prefix with a derived Message. The loaded
history shape is therefore [summary_message, ...kept_window] whenever
any compaction has occurred for the conversation, and just kept_window
otherwise. The summary itself is recomputed (rolled forward) on every
load that produces newly-evicted messages, so older summaries are folded
into newer ones via the compactor’s carry_over parameter.
§Concurrency
Concurrent ConversationMemory::load calls on the same
conversation_id are serialised at the compaction seam: only one call
at a time invokes the compactor for a given conversation. Other
concurrent loads observe the in-flight compaction and immediately
return the previously-stored summary spliced in front of kept,
without re-running the compactor. Newly-evicted messages skipped this
way are folded into the next compaction.
Failure visibility. A compactor error is returned only to the
caller whose load actually drove the compaction. Concurrent callers
that short-circuited on in_flight see Ok([old_summary?, ...kept])
even if the in-flight compaction ultimately failed; the watermark
stays unchanged so the next load retries.
§Persistence
The carry-over summary and delivery watermarks are kept in process memory only. Across process restarts, the first load on each conversation re-evicts and re-compacts the same prefix; compactors that have side effects (LLM calls, persistent writes) should deduplicate.
§Prompt shape and budgets
CompactingMemory is policy-agnostic: the wrapped
MemoryPolicy decides which messages are kept versus demoted, and
only the kept window is bounded by that policy. The summary artifact
produced by the Compactor is spliced outside that budget — so
the loaded prompt has shape [summary, ...kept_window] where
kept_window respects the policy’s bounds and summary adds an
extra message on top of it.
Callers that combine CompactingMemory with a token-budgeted policy
(e.g. TokenWindowMemory) must use a Compactor that bounds
its own artifact, or accept that the loaded prompt may exceed the
policy’s budget by the size of the summary. The reference
TemplateCompactor grows monotonically by default; configure it
with TemplateCompactor::with_max_bytes to cap the rolled-up text.
§Example
use rig_memory::{
CompactingMemory, InMemoryConversationMemory, SlidingWindowMemory,
TemplateCompactor,
};
let memory = CompactingMemory::new(
InMemoryConversationMemory::new(),
SlidingWindowMemory::last_messages(20),
TemplateCompactor::new(),
);Implementations§
Source§impl<M, P, C: Compactor> CompactingMemory<M, P, C>
impl<M, P, C: Compactor> CompactingMemory<M, P, C>
Sourcepub fn new(inner: M, policy: P, compactor: C) -> Self
pub fn new(inner: M, policy: P, compactor: C) -> Self
Wrap inner so every load runs through policy and demoted messages
are summarised by compactor.
Sourcepub fn into_inner(self) -> (M, P, C)
pub fn into_inner(self) -> (M, P, C)
Consume the wrapper and return its three components.
Sourcepub fn forget(&self, conversation_id: &str)
pub fn forget(&self, conversation_id: &str)
Drop the in-process compaction state for conversation_id.
Call this when a conversation has ended to bound memory usage; the state map is otherwise unbounded. If the internal lock has been poisoned by a panic in another thread, this is a no-op.
Sourcepub fn tracked_conversations(&self) -> usize
pub fn tracked_conversations(&self) -> usize
Number of conversations currently tracked in the compaction state
map. Useful for telemetry and leak detection. Returns 0 if the
internal lock is poisoned.
Trait Implementations§
Source§impl<M, P, C> ConversationMemory for CompactingMemory<M, P, C>
impl<M, P, C> ConversationMemory for CompactingMemory<M, P, C>
Source§fn load<'a>(
&'a self,
conversation_id: &'a str,
) -> WasmBoxedFuture<'a, Result<Vec<Message>, MemoryError>>
fn load<'a>( &'a self, conversation_id: &'a str, ) -> WasmBoxedFuture<'a, Result<Vec<Message>, MemoryError>>
conversation_id. Read moreSource§fn append<'a>(
&'a self,
conversation_id: &'a str,
messages: Vec<Message>,
) -> WasmBoxedFuture<'a, Result<(), MemoryError>>
fn append<'a>( &'a self, conversation_id: &'a str, messages: Vec<Message>, ) -> WasmBoxedFuture<'a, Result<(), MemoryError>>
Source§fn clear<'a>(
&'a self,
conversation_id: &'a str,
) -> WasmBoxedFuture<'a, Result<(), MemoryError>>
fn clear<'a>( &'a self, conversation_id: &'a str, ) -> WasmBoxedFuture<'a, Result<(), MemoryError>>
conversation_id.