use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AccountingMode {
ExactTokenizer,
ConservativeUpperBound,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TokenAccountantRef {
pub id: String,
pub mode: AccountingMode,
}
const MESSAGE_FRAMING_TOKENS: u64 = 8;
impl TokenAccountantRef {
pub fn approx_bytes_v1() -> Self {
Self {
id: "approx_bytes_v1".into(),
mode: AccountingMode::ConservativeUpperBound,
}
}
pub fn count_text(&self, text: &str) -> u64 {
(text.len() as u64).div_ceil(3)
}
pub fn count_message(&self, content: &str) -> u64 {
self.count_text(content) + MESSAGE_FRAMING_TOKENS
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn counting_is_a_conservative_upper_bound() {
let accountant = TokenAccountantRef::approx_bytes_v1();
assert_eq!(accountant.count_text(""), 0);
assert_eq!(accountant.count_text("abc"), 1);
assert_eq!(accountant.count_text("abcd"), 2);
let text = "let value = compute(input); // typical code density";
assert!(accountant.count_text(text) * 4 > text.len() as u64);
assert_eq!(accountant.count_message("abc"), 1 + MESSAGE_FRAMING_TOKENS);
}
}