//! Compaction middleware — wraps the existing compaction module. use async_trait::async_trait; use zclaw_types::Result; use crate::middleware::{AgentMiddleware, MiddlewareContext, MiddlewareDecision}; use crate::compaction::{self, CompactionConfig}; use crate::growth::GrowthIntegration; use crate::driver::LlmDriver; use std::sync::Arc; /// Middleware that compresses conversation history when it exceeds a token threshold. pub struct CompactionMiddleware { threshold: usize, config: CompactionConfig, /// Optional LLM driver for async compaction (LLM summarisation, memory flush). driver: Option>, /// Optional growth integration for memory flushing during compaction. growth: Option, } impl CompactionMiddleware { pub fn new( threshold: usize, config: CompactionConfig, driver: Option>, growth: Option, ) -> Self { Self { threshold, config, driver, growth } } } #[async_trait] impl AgentMiddleware for CompactionMiddleware { fn name(&self) -> &str { "compaction" } fn priority(&self) -> i32 { 100 } async fn before_completion(&self, ctx: &mut MiddlewareContext) -> Result { if self.threshold == 0 { return Ok(MiddlewareDecision::Continue); } let needs_async = self.config.use_llm || self.config.memory_flush_enabled; if needs_async { let outcome = compaction::maybe_compact_with_config( ctx.messages.clone(), self.threshold, &self.config, &ctx.agent_id, &ctx.session_id, self.driver.as_ref(), self.growth.as_ref(), ) .await; ctx.messages = outcome.messages; } else { ctx.messages = compaction::maybe_compact(ctx.messages.clone(), self.threshold); } Ok(MiddlewareDecision::Continue) } }