/// Truncation threshold, matching the shell's large-prompt limit. pub const LARGE_PROMPT_THRESHOLD: usize = 25_000; /// Wrap a user message in the canonical `` envelope. pub fn user_query(user_message: &str) -> String { format!( r#" {user_message} "# ) } /// Wrap interjection text as a synthetic user message with a mid-turn note. /// No deferral instruction: the model decides how to weigh it against /// in-flight work. Output is byte-identical to the shell's historical format. pub fn format_interjection(text: String) -> String { let truncated = if text.len() > LARGE_PROMPT_THRESHOLD { let end = text .char_indices() .take_while(|(i, _)| *i < LARGE_PROMPT_THRESHOLD) .last() .map(|(i, c)| i + c.len_utf8()) .unwrap_or(text.len()); format!("{}... [truncated]", &text[..end]) } else { text }; format!( "The user sent a message while you were working:\n{}", user_query(&truncated) ) } #[cfg(test)] mod tests { use super::*; #[test] fn wraps_in_user_query_with_midturn_note() { let out = format_interjection("stop and fix the test first".into()); assert!(out.starts_with("The user sent a message while you were working:\n\n")); assert!(out.ends_with("\n")); assert!(out.contains("stop and fix the test first")); } #[test] fn truncates_at_utf8_boundary() { let s = "é".repeat(LARGE_PROMPT_THRESHOLD); let out = format_interjection(s); assert!(out.contains("... [truncated]")); assert!(out.len() < LARGE_PROMPT_THRESHOLD + 200); } #[test] fn short_text_untouched() { let out = format_interjection("hi".into()); assert!(!out.contains("[truncated]")); } }