vtcode_commons/interjection/
buffer.rs1use super::events::EventQueue;
2use super::format::format_interjection;
3
4#[derive(Debug, Clone, PartialEq)]
7pub struct PendingInterjection<Attachment> {
8 pub text: String,
9 pub attachments: Vec<Attachment>,
10}
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct FormattedInterjection<Attachment> {
15 pub text: String,
16 pub attachments: Vec<Attachment>,
17}
18
19pub type InterjectionBuffer<Attachment> = EventQueue<PendingInterjection<Attachment>>;
23
24pub fn drain_formatted<Attachment>(
29 buffer: &InterjectionBuffer<Attachment>,
30 sanitize_text: impl Fn(String) -> String,
31) -> Vec<FormattedInterjection<Attachment>> {
32 buffer
33 .drain_all()
34 .into_iter()
35 .map(|entry| FormattedInterjection {
36 text: format_interjection(sanitize_text(entry.text)),
37 attachments: entry.attachments,
38 })
39 .collect()
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45
46 #[test]
47 fn drain_formatted_sanitizes_wraps_and_preserves_order() {
48 let buf: InterjectionBuffer<()> = InterjectionBuffer::new();
49 buf.push(PendingInterjection {
50 text: "look at [SECRET] one".into(),
51 attachments: vec![],
52 });
53 buf.push(PendingInterjection { text: "two".into(), attachments: vec![] });
54
55 let out = drain_formatted(&buf, |t| t.replace("[SECRET] ", ""));
56 assert!(buf.is_empty());
57 assert_eq!(out.len(), 2, "one message per entry, never merged");
58 assert!(out[0].text.contains("<user_query>\nlook at one\n</user_query>"));
59 assert!(out[1].text.contains("<user_query>\ntwo\n</user_query>"));
60 assert!(out[0].text.starts_with("The user sent a message while you were working:"));
61 }
62}