pub fn flatten_conversation<'a, I>(messages: I) -> String
where
I: IntoIterator<Item = (&'a str, &'a str)>,
{
let non_empty: Vec<(&str, &str)> = messages
.into_iter()
.filter(|(_, content)| !content.trim().is_empty())
.collect();
if non_empty.len() == 1 && non_empty[0].0 == "user" {
return non_empty[0].1.to_string();
}
non_empty
.iter()
.map(|(role, content)| format!("[{role}] {content}"))
.collect::<Vec<_>>()
.join("\n\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lone_user_is_bare() {
assert_eq!(
flatten_conversation([("user", "what is rust?")]),
"what is rust?"
);
}
#[test]
fn lone_non_user_is_prefixed() {
assert_eq!(
flatten_conversation([("assistant", "hi")]),
"[assistant] hi"
);
}
#[test]
fn multi_turn_prefixes_each_role() {
let out = flatten_conversation([
("user", "what is rust?"),
("assistant", "a systems language"),
("user", "vs go?"),
]);
assert_eq!(
out,
"[user] what is rust?\n\n[assistant] a systems language\n\n[user] vs go?"
);
}
#[test]
fn empty_messages_are_dropped() {
let out = flatten_conversation([("assistant", " "), ("user", "real"), ("user", "next")]);
assert_eq!(out, "[user] real\n\n[user] next");
}
#[test]
fn all_empty_yields_empty_string() {
assert_eq!(
flatten_conversation([("user", ""), ("assistant", " ")]),
""
);
}
}