use super::config::ContextConfig;
use super::task_state::TaskState;
use super::token_engine::ContextTokenEngine;
use crate::types::message::Message;
#[derive(Debug, Clone)]
pub struct Partition {
pub messages: Vec<Message>,
pub token_count: u32,
}
impl Partition {
pub fn new() -> Self {
Self { messages: Vec::new(), token_count: 0 }
}
pub fn push(&mut self, mut msg: Message, token_count: u32) {
msg.token_count = Some(token_count);
self.token_count += token_count;
self.messages.push(msg);
}
pub fn clear(&mut self) {
self.messages.clear();
self.token_count = 0;
}
pub fn len(&self) -> usize { self.messages.len() }
pub fn is_empty(&self) -> bool { self.messages.is_empty() }
}
impl Default for Partition {
fn default() -> Self { Self::new() }
}
pub struct ContextPartitions {
pub system: Partition,
pub knowledge: Partition,
pub task_state: TaskState,
pub signals: Vec<String>,
pub history: Partition,
}
impl ContextPartitions {
pub fn new(_config: &ContextConfig) -> Self {
Self {
system: Partition::new(),
knowledge: Partition::new(),
task_state: TaskState::default(),
signals: Vec::new(),
history: Partition::new(),
}
}
pub fn total_tokens(&self, engine: &ContextTokenEngine) -> u32 {
self.system.token_count
+ self.knowledge.token_count
+ engine.count(&self.task_state.format_compact())
+ self.history.token_count
}
}
impl Default for ContextPartitions {
fn default() -> Self {
Self::new(&ContextConfig::default())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::context::config::ContextConfig;
use crate::context::token_engine::ContextTokenEngine;
use crate::types::message::Message;
fn engine() -> ContextTokenEngine { ContextTokenEngine::char_approx() }
#[test]
fn push_updates_token_count() {
let mut ctx = ContextPartitions::new(&ContextConfig::default());
let base = ctx.total_tokens(&engine());
ctx.system.push(Message::system("rules"), 10);
ctx.history.push(Message::user("hello"), 5);
assert_eq!(ctx.total_tokens(&engine()), base + 15);
}
#[test]
fn task_state_tokens_included_in_total() {
use crate::context::task_state::TaskState;
let mut ctx = ContextPartitions::new(&ContextConfig::default());
let before = ctx.total_tokens(&engine());
ctx.task_state = TaskState { goal: "do something important".to_string(), ..Default::default() };
let after = ctx.total_tokens(&engine());
assert!(after > before, "task_state should contribute to total_tokens");
}
#[test]
fn knowledge_tokens_included_in_total() {
let mut ctx = ContextPartitions::new(&ContextConfig::default());
let before = ctx.total_tokens(&engine());
ctx.knowledge.push(Message::system("skill: debug"), 20);
assert_eq!(ctx.total_tokens(&engine()), before + 20);
}
}