Event compaction

Summarize older session events into a compact replacement so long-running conversations stop growing LLM context without bound.

Sessions are append-only, so a long-lived conversation eventually drags its entire history into every LLM call. Event compaction fixes the read side: after enough invocations accumulate, the runner asks a summarizer to compress the older window into one summary event, and history assembly replaces the covered events with that summary — the model sees summary + recent events instead of everything.

EventsCompactionConfig

EventsCompactionConfig::new(model: Arc<dyn Model>) -> Self
Construct with the default LlmEventSummarizer over model, compaction_interval: 5 and overlap_size: 2.
compaction_interval(self, n: usize) -> Self — default 5
Run compaction after this many invocations have accumulated since the previous compaction. Clamped to a minimum of 1.
overlap_size(self, n: usize) -> Self — default 2
Number of already-compacted events to re-include at the start of the next window, for continuity across summaries.
summarizer(self, s: Arc<dyn EventSummarizer>) -> Self
Swap in a custom summarizer.

The summarizer

The EventSummarizer trait has one method: summarize(&self, events: &[Event]) -> Result<Option<Content>>. Returning Ok(None) skips compaction for that window (e.g. nothing summarizable). The default LlmEventSummarizer uses the model you pass to EventsCompactionConfig::new — any Arc<dyn Model>, independent of the agents' models, so you can point it at a cheap, fast model. It renders the window as a transcript (text lines, [calls f(args)], [f returned ...]), sends it with a fixed compaction system instruction, and wraps the reply as "[Summary of earlier conversation] …".

trait EventSummarizer { async fn summarize(&self, events: &[Event]) -> Result<Option<Content>> }
Produces the replacement Content for a window of events.
LlmEventSummarizer::new(model: Arc<dyn Model>) -> Self
Default LLM-backed summarizer.

When and what gets compacted

After each invocation completes, the runner counts the distinct invocation ids in the tail — the events after the most recent compaction marker. Once the tail spans at least compaction_interval invocations, the window is formed: overlap_size events from just before the tail (skipping prior compaction markers) plus the whole tail. The summarizer runs, and a marker event is appended whose actions.compaction carries:

struct EventCompaction { start_timestamp: f64, end_timestamp: f64, compacted_content: Content }
Timestamps (seconds) of the earliest and latest compacted events, plus the replacement content — typically the summary.

How history is rebuilt

When an LlmAgent assembles conversation history it calls history_with_compaction(&session.events) instead of mapping events to contents directly. Events whose timestamps fall inside a compaction's [start_timestamp, end_timestamp] range (and that precede the marker) are replaced by the compacted_content, emitted once in place of the first covered event. Marker events themselves never appear in history, and when overlapping compactions cover the same event, the newest one wins.

pub fn history_with_compaction(events: &[Event]) -> Vec<Content>
Assemble LLM history from session events, honouring compaction ranges. Exported from adk_rs::core.

Example

Compaction every 8 invocations, cheap summarizer modelrust
use adk_rs::core::Model;
use adk_rs::providers::gemini::Gemini;
use adk_rs::runner::{EventsCompactionConfig, Runner};
use std::sync::Arc;

let summarizer_model = Arc::new(Gemini::from_env("gemini-2.5-flash")?);

let runner = Runner::builder()
    .app_name("longchat")
    .agent(agent)
    .session_service(svc.clone())
    .compaction(
        EventsCompactionConfig::new(summarizer_model as Arc<dyn Model>)
            .compaction_interval(8)
            .overlap_size(2),
    )
    .build()?;

// ... after >= 8 invocations on one session, the session log gains a
// marker event (event.actions.compaction is Some) and subsequent turns
// send "[Summary of earlier conversation] ..." instead of the old events.