use directories::ProjectDirs;
use tokio::{
sync::mpsc::{Receiver, Sender},
time::{Duration, interval},
};
use crate::{
core::conversation::{Conversation, ConversationItemKind},
session::SessionMessage,
};
#[derive(Clone, Debug, PartialEq)]
enum DummyConversationItem {
UserPrompt(String),
AssistantMessage(Vec<String>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum LlmMessage {
SubmitPrompt(String),
Quit,
}
#[derive(Debug)]
pub struct Llm {
session_tx: Sender<SessionMessage>,
rx: Receiver<LlmMessage>,
data: Vec<DummyConversationItem>,
}
impl Llm {
pub fn new(session_tx: Sender<SessionMessage>, rx: Receiver<LlmMessage>) -> Self {
Self {
session_tx,
rx,
data: Vec::new(),
}
}
pub async fn run(&mut self) {
let conversation: Conversation =
if let Some(proj_dirs) = ProjectDirs::from("org", "codemonk", "monothink") {
let mut state_dir = proj_dirs
.state_dir()
.expect("Running on other OS than Linux is not supported.")
.to_path_buf();
state_dir.push("sessions");
state_dir.push("test_long.json");
let test_path = state_dir.as_path();
Conversation::from_file(test_path).expect("Test file must be present")
} else {
panic!("Could not read test data from test.json.");
};
for item in conversation.messages() {
match &item.content {
ConversationItemKind::UserMessage(message_content) => {
self.data.push(DummyConversationItem::UserPrompt(
message_content.raw().to_owned(),
));
}
ConversationItemKind::AssistantMessage(message_content) => {
let raw: Vec<char> = message_content.raw().chars().collect();
let mut msg: Vec<String> = raw.chunks(20).map(|c| c.iter().collect()).collect();
msg.reverse();
self.data.push(DummyConversationItem::AssistantMessage(msg));
}
ConversationItemKind::AssistantThinking(_message_content) => {}
ConversationItemKind::ToolInvocation(_tool_invocation_content) => {}
ConversationItemKind::ToolOutput(_tool_output_content) => {}
ConversationItemKind::System(_) => {}
}
}
self.data.reverse();
self.data.pop();
let mut redraw_tick = interval(Duration::from_millis(25));
let mut hold = true;
loop {
redraw_tick.tick().await;
if hold {
let event = self.rx.recv().await;
if let Some(msg) = event {
match msg {
LlmMessage::SubmitPrompt(_) => {
hold = false;
redraw_tick = interval(Duration::from_millis(25));
}
LlmMessage::Quit => break,
}
}
}
let mut pop = false;
if let Some(msg) = self.data.last_mut() {
match msg {
DummyConversationItem::UserPrompt(_) => {
hold = true;
pop = true;
}
DummyConversationItem::AssistantMessage(items) => {
if let Some(item) = items.pop() {
self.session_tx
.send(SessionMessage::AgentResponse(item.to_string()))
.await
.unwrap();
}
if items.is_empty() {
pop = true;
}
}
}
if pop {
self.data.pop();
}
} else {
break;
};
}
}
}