use adk_core::intra_compaction::{IntraCompactionConfig, estimate_tokens};
use adk_core::{BaseEventsSummarizer, Event, Result};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct IntraInvocationCompactor {
config: IntraCompactionConfig,
summarizer: Arc<dyn BaseEventsSummarizer>,
compacted_this_cycle: AtomicBool,
}
impl IntraInvocationCompactor {
pub fn new(config: IntraCompactionConfig, summarizer: Arc<dyn BaseEventsSummarizer>) -> Self {
Self { config, summarizer, compacted_this_cycle: AtomicBool::new(false) }
}
pub async fn maybe_compact(&self, events: &[Event]) -> Result<Option<Vec<Event>>> {
if self
.compacted_this_cycle
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
.is_err()
{
return Ok(None);
}
let estimated = estimate_tokens(events, self.config.chars_per_token);
if estimated <= self.config.token_threshold {
self.compacted_this_cycle.store(false, Ordering::SeqCst);
return Ok(None);
}
let overlap = self.config.overlap_event_count.min(events.len());
let summarize_end = events.len().saturating_sub(overlap);
if summarize_end == 0 {
self.compacted_this_cycle.store(false, Ordering::SeqCst);
return Ok(None);
}
let events_to_summarize = &events[..summarize_end];
let overlap_events = &events[summarize_end..];
match self.summarizer.summarize_events(events_to_summarize).await {
Ok(Some(summary_event)) => {
let mut compacted = Vec::with_capacity(1 + overlap);
compacted.push(summary_event);
compacted.extend_from_slice(overlap_events);
Ok(Some(compacted))
}
Ok(None) => {
Ok(None)
}
Err(e) => {
tracing::warn!(
error = %e,
"intra-invocation compaction failed, continuing with uncompacted history"
);
Ok(None)
}
}
}
pub fn reset_cycle(&self) {
self.compacted_this_cycle.store(false, Ordering::SeqCst);
}
}