use std::sync::Arc;
use rig_core::completion::Message;
use rig_core::conversation::{Author, Conversation, MessageId};
use crate::{
MemoryStore, Session, SummaryState, Writer, apply_summary, as_of, history, load, undo_summary,
};
fn writer() -> (Arc<MemoryStore>, Writer) {
let store = Arc::new(MemoryStore::default());
let (writer, _) = Writer::open(store.clone()).expect("opened");
writer.start();
(store, writer)
}
fn say(writer: &Writer, log: &str, conversation: &mut Conversation, messages: &[Message]) {
for message in messages {
conversation.push(message.clone());
writer.save(log, conversation);
}
}
fn said(texts: &[&str]) -> Vec<Arc<Message>> {
let message = |text: &&str| match text.ends_with('?') {
true => Message::user(*text),
false => Message::assistant(*text),
};
texts.iter().map(message).map(Arc::new).collect()
}
#[test]
fn a_fork_copies_the_log_up_to_a_turn_boundary_and_goes_on_by_itself() {
let (store, writer) = writer();
let mut main = Conversation::new();
let turns = [
Message::user("one?"),
Message::assistant("one."),
Message::user("two?"),
Message::assistant("two."),
];
say(&writer, "main", &mut main, &turns);
let id = |at: usize| main.id(at).expect("an id");
let fork = |to: &str, through: Option<MessageId>| writer.fork_log("main", to, through);
let whole = fork("whole", None).expect("forked");
assert_eq!(whole.conversation.messages(), main.messages());
let answered = fork("answered", Some(id(1))).expect("forked");
assert_eq!(answered.conversation.messages(), said(&["one?", "one."]));
let asked = fork("asked", Some(id(2))).expect("forked");
assert_eq!(asked.conversation.messages(), said(&["one?", "one."]));
let first = fork("first", Some(id(0))).expect("forked");
assert!(first.conversation.messages().is_empty());
let nowhere: MessageId = "m99".parse().expect("an id");
assert!(fork("nowhere", Some(nowhere)).is_err());
assert!(fork("whole", None).is_err(), "a log that exists is refused");
assert_eq!(answered.conversation.id(1), Some(id(1)));
let mut copy = answered.conversation;
let saved = {
copy.push(Message::user("three?"));
writer.save("answered", &mut copy)
};
assert_eq!(saved.len(), 1, "one push, not a reset");
writer.flush().expect("flushed");
assert_eq!(load(&*store, "answered").expect("read"), copy);
assert_eq!(load(&*store, "main").expect("read"), main);
let read = Session::read(&*store).expect("read");
assert_eq!(read.agents.len(), 5);
}
#[test]
fn a_fork_made_after_a_compaction_can_undo_it() {
let (store, writer) = writer();
let mut main = Conversation::new();
let turns = [
Message::user("one?"),
Message::assistant("one."),
Message::user("two?"),
Message::assistant("two."),
];
say(&writer, "main", &mut main, &turns);
let kept = main.id(2);
let state = SummaryState {
summary: "Asked one.".to_owned(),
..SummaryState::default()
};
assert!(apply_summary(&mut main, kept, &state).is_some());
writer.save("main", &mut main);
say(&writer, "main", &mut main, &[Message::user("three?")]);
say(&writer, "main", &mut main, &[Message::assistant("three.")]);
let mut copy = writer.fork_log("main", "fork", None).expect("forked");
assert_eq!(copy.conversation.messages(), main.messages());
let by = Author::plugin("test");
let undone = undo_summary(&mut copy.conversation, &*store, "fork", by);
assert!(undone.is_ok(), "{undone:?}");
let all = ["one?", "one.", "two?", "two.", "three?", "three."];
assert_eq!(copy.conversation.messages(), said(&all));
let copied = history(&*store, "fork").expect("history");
let source = history(&*store, "main").expect("history");
assert_eq!(copied, source);
let (stamp, _) = copied.get(2).expect("a third record");
let then = as_of(&*store, "fork", stamp.n).expect("as of");
assert_eq!(then.messages(), said(&["one?", "one."]));
}