use crate::types::Message;
pub const MAX_CONVERSATION_MESSAGES_PAGE_LIMIT: u32 = 200;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ClientMessageWindowMeta {
pub total_count: u32,
pub window_start_index: u32,
pub has_older: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ClientMessageWindowSlice {
pub meta: ClientMessageWindowMeta,
pub messages: Vec<Message>,
}
#[must_use]
pub fn slice_messages_for_client_window(
all: &[Message],
limit: Option<u32>,
before_index: Option<u32>,
) -> ClientMessageWindowSlice {
let total = u32::try_from(all.len()).unwrap_or(u32::MAX);
let full = |items: Vec<Message>| ClientMessageWindowSlice {
meta: ClientMessageWindowMeta {
total_count: total,
window_start_index: 0,
has_older: false,
},
messages: items,
};
let Some(lim_raw) = limit.filter(|&n| n > 0) else {
return full(all.to_vec());
};
let lim = lim_raw.clamp(1, MAX_CONVERSATION_MESSAGES_PAGE_LIMIT) as usize;
let end = before_index
.map(|i| i.min(total) as usize)
.unwrap_or(all.len());
let end = end.min(all.len());
let start = end.saturating_sub(lim);
ClientMessageWindowSlice {
meta: ClientMessageWindowMeta {
total_count: total,
window_start_index: u32::try_from(start).unwrap_or(u32::MAX),
has_older: start > 0,
},
messages: all[start..end].to_vec(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::types::{Message, MessageContent};
fn user_msg(text: &str) -> Message {
Message {
role: "user".to_string(),
content: Some(MessageContent::from(text)),
reasoning_content: None,
reasoning_details: None,
tool_calls: None,
name: None,
tool_call_id: None,
}
}
#[test]
fn no_limit_returns_full() {
let all = vec![user_msg("a"), user_msg("b"), user_msg("c")];
let w = slice_messages_for_client_window(&all, None, None);
assert_eq!(w.messages.len(), 3);
assert!(!w.meta.has_older);
assert_eq!(w.meta.window_start_index, 0);
}
#[test]
fn tail_page_takes_last_n() {
let all: Vec<_> = (0..10).map(|i| user_msg(&format!("m{i}"))).collect();
let w = slice_messages_for_client_window(&all, Some(3), None);
assert_eq!(w.messages.len(), 3);
assert!(w.meta.has_older);
assert_eq!(w.meta.window_start_index, 7);
assert_eq!(w.meta.total_count, 10);
}
#[test]
fn before_index_loads_older_page() {
let all: Vec<_> = (0..10).map(|i| user_msg(&format!("m{i}"))).collect();
let w = slice_messages_for_client_window(&all, Some(3), Some(7));
assert_eq!(w.messages.len(), 3);
assert!(w.meta.has_older);
assert_eq!(w.meta.window_start_index, 4);
}
}