use kernel::{ChatMessage, ContentBlock, Role};
pub use kernel::event::record::Opening;
#[derive(Debug, Clone, Default)]
pub struct Conversation {
messages: Vec<ChatMessage>,
sent: usize,
held: Vec<ContentBlock>,
}
impl Conversation {
pub fn new() -> Conversation {
Conversation::default()
}
pub fn push_task_lines(&mut self, task: &str, goal: &str, opening: Opening) {
self.push_user_text(match opening {
Opening::FromJob => format!("The task is in JOB.md above.\nGoal: {goal}"),
Opening::Inherited => format!("Task: {task}\nGoal: {goal}"),
Opening::WithPerson => task.to_owned(),
});
}
pub fn push_steer(&mut self, source: &str, text: &str) {
self.push_user_text(format!("{source}: {text}"));
}
pub fn push_reminder(&mut self, reminder: &crate::reminder::ContextReminder) {
self.push_user_text(reminder.render());
}
pub fn push_inherited(&mut self, messages: &[ChatMessage]) {
self.messages.extend_from_slice(messages);
}
pub fn push_assistant(&mut self, content: Vec<ContentBlock>) {
if !content.is_empty() {
self.messages.push(ChatMessage {
role: Role::Assistant,
content,
});
}
}
pub fn push_tool_results(&mut self, mut results: Vec<ContentBlock>) {
results.append(&mut self.held);
if results.is_empty() {
return;
}
let reopened = self.messages.len().saturating_sub(1);
match self.messages.last_mut() {
Some(last) if last.role == Role::User => {
last.content.extend(results);
self.sent = self.sent.min(reopened);
}
_ => self.messages.push(ChatMessage {
role: Role::User,
content: results,
}),
}
}
pub fn mark_sent(&mut self) {
self.sent = self.messages.len();
}
pub fn messages(&self) -> &[ChatMessage] {
&self.messages
}
fn push_user_text(&mut self, text: String) {
self.push_user(vec![ContentBlock::Text { text }]);
}
fn push_user(&mut self, blocks: Vec<ContentBlock>) {
if blocks.is_empty() {
return;
}
let open = self.messages.len() > self.sent;
match self.messages.last_mut() {
Some(last) if last.role == Role::User && open => last.content.extend(blocks),
Some(last) if last.role == Role::User => self.held.extend(blocks),
_ => self.messages.push(ChatMessage {
role: Role::User,
content: blocks,
}),
}
}
}