use tokenx_rs::estimate_token_count;
use crate::query::{LinkedNote, NoteExcerpt};
pub(super) fn estimate_payload_tokens(
active_notes: &[NoteExcerpt],
linked_context: &[LinkedNote],
) -> usize {
let mut total = 0usize;
for n in active_notes {
total += estimate_token_count(n.vault_path.as_str())
+ estimate_token_count(&n.title)
+ estimate_token_count(&n.snippet)
+ 10; }
for l in linked_context {
total += estimate_token_count(l.vault_path.as_str()) + 6;
}
total
}
pub(super) fn trim_to_budget(
budget: usize,
active_notes: &mut Vec<NoteExcerpt>,
linked_context: &mut Vec<LinkedNote>,
excluded_by_budget: &mut Vec<String>,
) {
loop {
let used = estimate_payload_tokens(active_notes, linked_context);
let budget_with_slack = budget.saturating_add(budget / 50);
if used <= budget_with_slack {
break;
}
let trim_active = active_notes.len() >= linked_context.len();
let popped = if trim_active {
active_notes
.pop()
.map(|item| item.vault_path.as_str().to_string())
.or_else(|| {
linked_context
.pop()
.map(|item| item.vault_path.as_str().to_string())
})
} else {
linked_context
.pop()
.map(|item| item.vault_path.as_str().to_string())
.or_else(|| {
active_notes
.pop()
.map(|item| item.vault_path.as_str().to_string())
})
};
match popped {
Some(path) => excluded_by_budget.push(path),
None => break,
}
}
}