use rig::{agent::MultiTurnStreamItem, message::Message};
use serde::Serialize;
use unicode_width::UnicodeWidthStr;
pub trait Estimator {
fn estimate(&self, msg: &Message) -> u64;
fn estimate_chunk(&self, chunk: &MultiTurnStreamItem) -> u64;
fn context_pressure(
&self,
prompt: &rig::message::Message,
history: &[rig::message::Message],
) -> u64 {
self.estimate(prompt) + history.iter().map(|msg| self.estimate(msg)).sum::<u64>()
}
}
#[derive(Clone)]
pub struct SimpleEstimator {
characters_per_token: f64,
}
impl SimpleEstimator {
pub fn new(characters_per_token: f64) -> Self {
SimpleEstimator {
characters_per_token,
}
}
}
impl Estimator for SimpleEstimator {
fn estimate(&self, msg: &Message) -> u64 {
f64::ceil(message_width(msg) as f64 / self.characters_per_token) as u64
}
fn estimate_chunk(&self, chunk: &MultiTurnStreamItem) -> u64 {
f64::ceil(message_width(chunk) as f64 / self.characters_per_token) as u64
}
}
fn message_width<T: ?Sized + Serialize>(msg: &T) -> u64 {
serde_json::to_string(msg).unwrap_or_default().width() as u64
}