Skip to main content

vtcode_commons/interjection/
format.rs

1/// Truncation threshold, matching the shell's large-prompt limit.
2pub const LARGE_PROMPT_THRESHOLD: usize = 25_000;
3
4/// Wrap a user message in the canonical `<user_query>` envelope.
5pub fn user_query(user_message: &str) -> String {
6    format!(
7        r#"<user_query>
8{user_message}
9</user_query>"#
10    )
11}
12
13/// Wrap interjection text as a synthetic user message with a mid-turn note.
14/// No deferral instruction: the model decides how to weigh it against
15/// in-flight work. Output is byte-identical to the shell's historical format.
16pub fn format_interjection(text: String) -> String {
17    let truncated = if text.len() > LARGE_PROMPT_THRESHOLD {
18        let end = text
19            .char_indices()
20            .take_while(|(i, _)| *i < LARGE_PROMPT_THRESHOLD)
21            .last()
22            .map(|(i, c)| i + c.len_utf8())
23            .unwrap_or(text.len());
24        format!("{}... [truncated]", &text[..end])
25    } else {
26        text
27    };
28
29    format!("The user sent a message while you were working:\n{}", user_query(&truncated))
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn wraps_in_user_query_with_midturn_note() {
38        let out = format_interjection("stop and fix the test first".into());
39        assert!(out.starts_with("The user sent a message while you were working:\n<user_query>\n"));
40        assert!(out.ends_with("\n</user_query>"));
41        assert!(out.contains("stop and fix the test first"));
42    }
43
44    #[test]
45    fn truncates_at_utf8_boundary() {
46        let s = "é".repeat(LARGE_PROMPT_THRESHOLD);
47        let out = format_interjection(s);
48        assert!(out.contains("... [truncated]"));
49        assert!(out.len() < LARGE_PROMPT_THRESHOLD + 200);
50    }
51
52    #[test]
53    fn short_text_untouched() {
54        let out = format_interjection("hi".into());
55        assert!(!out.contains("[truncated]"));
56    }
57}