use crate::compression::{CompressionInput, CompressionOutput, ContextCompressor};
use echo_core::error::Result;
use echo_core::llm::types::Message;
use futures::future::BoxFuture;
pub struct HybridCompressor {
stages: Vec<Box<dyn ContextCompressor>>,
}
impl ContextCompressor for HybridCompressor {
fn compress(&self, input: CompressionInput) -> BoxFuture<'_, Result<CompressionOutput>> {
Box::pin(async move {
let token_limit = input.token_limit;
let current_query = input.current_query.clone();
let mut messages = input.messages;
let mut all_evicted: Vec<Message> = Vec::new();
for stage in &self.stages {
let output = stage
.compress(CompressionInput {
messages,
token_limit,
current_query: current_query.clone(),
})
.await?;
all_evicted.extend(output.evicted);
messages = output.messages;
}
Ok(CompressionOutput {
messages,
evicted: all_evicted,
})
})
}
}
impl HybridCompressor {
pub fn builder() -> HybridCompressorBuilder {
HybridCompressorBuilder::default()
}
}
#[derive(Default)]
pub struct HybridCompressorBuilder {
stages: Vec<Box<dyn ContextCompressor>>,
}
impl HybridCompressorBuilder {
pub fn stage(mut self, compressor: impl ContextCompressor + 'static) -> Self {
self.stages.push(Box::new(compressor));
self
}
pub fn build(self) -> HybridCompressor {
HybridCompressor {
stages: self.stages,
}
}
}