use crate::provider::Message;
use crate::session::pages::{PageKind, classify, classify_all};
pub struct History<'a> {
buf: &'a mut Vec<Message>,
pages: Option<&'a mut Vec<PageKind>>,
}
impl<'a> History<'a> {
pub fn new(buf: &'a mut Vec<Message>) -> Self {
Self { buf, pages: None }
}
pub(crate) fn with_pages(buf: &'a mut Vec<Message>, pages: &'a mut Vec<PageKind>) -> Self {
Self {
buf,
pages: Some(pages),
}
}
pub fn append(&mut self, msg: Message) {
if let Some(pages) = self.pages.as_deref_mut() {
if pages.len() != self.buf.len() {
*pages = classify_all(self.buf);
}
pages.push(classify(&msg));
}
self.buf.push(msg);
}
pub fn view(&self) -> &[Message] {
self.buf
}
pub fn len(&self) -> usize {
self.buf.len()
}
pub fn is_empty(&self) -> bool {
self.buf.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::provider::{ContentPart, Role};
fn text(role: Role, s: &str) -> Message {
Message {
role,
content: vec![ContentPart::Text {
text: s.to_string(),
}],
}
}
#[test]
fn append_then_view_is_monotonic() {
let mut buf: Vec<Message> = Vec::new();
let mut history = History::new(&mut buf);
assert!(history.is_empty());
assert_eq!(history.len(), 0);
history.append(text(Role::User, "a"));
history.append(text(Role::Assistant, "b"));
history.append(text(Role::Tool, "c"));
let view = history.view();
assert_eq!(view.len(), 3);
assert!(matches!(view[0].role, Role::User));
assert!(matches!(view[1].role, Role::Assistant));
assert!(matches!(view[2].role, Role::Tool));
}
#[test]
fn len_tracks_underlying_vec() {
let mut buf: Vec<Message> = vec![text(Role::User, "seed")];
let history = History::new(&mut buf);
assert_eq!(history.len(), 1);
assert!(!history.is_empty());
}
}