1use std::sync::Arc;
17
18use rig_core::completion::Message;
19use rig_core::conversation::pairing::safe_start;
20use rig_core::wasm_compat::{WasmCompatSend, WasmCompatSync};
21
22use crate::{HeuristicTokenCounter, TokenCounter};
23
24pub trait Recent: WasmCompatSend + WasmCompatSync {
26 fn start(&self, messages: &[Arc<Message>]) -> usize;
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
33pub struct LastMessages(pub usize);
34
35impl Recent for LastMessages {
36 fn start(&self, messages: &[Arc<Message>]) -> usize {
37 messages.len().saturating_sub(self.0)
38 }
39}
40
41#[derive(Clone, Copy, Debug)]
45pub struct TokenBudget<C: TokenCounter = HeuristicTokenCounter> {
46 pub max_tokens: usize,
48 pub counter: C,
50}
51
52impl TokenBudget {
53 pub fn new(max_tokens: usize) -> Self {
56 Self {
57 max_tokens,
58 counter: HeuristicTokenCounter::default(),
59 }
60 }
61}
62
63impl<C: TokenCounter> Recent for TokenBudget<C> {
64 fn start(&self, messages: &[Arc<Message>]) -> usize {
65 let mut budget = self.max_tokens;
66 let mut start = messages.len();
67 for (index, message) in messages.iter().enumerate().rev() {
68 let cost = self.counter.count(message);
69 if cost > budget {
70 break;
71 }
72 budget -= cost;
73 start = index;
74 }
75 start
76 }
77}
78
79pub fn view<'m>(messages: &'m [Arc<Message>], recent: &dyn Recent) -> &'m [Arc<Message>] {
82 let start = safe_start(messages, recent.start(messages));
83 messages.get(start..).unwrap_or_default()
84}
85
86#[cfg(test)]
87mod tests;