use std::sync::Arc;
use dyn_clone::DynClone;
#[cfg(test)]
use mockall::mock;
use swiftide::chat_completion;
use uuid::Uuid;
#[derive(Debug, Clone)]
pub enum CommandResponse {
Chat(Uuid, chat_completion::ChatMessage),
Activity(Uuid, String),
RenameChat(Uuid, String),
RenameBranch(Uuid, String),
BackendMessage(Uuid, String),
Completed(Uuid),
}
impl CommandResponse {
#[must_use]
pub fn with_uuid(self, uuid: Uuid) -> Self {
match self {
CommandResponse::Chat(uuid, msg) => CommandResponse::Chat(uuid, msg),
CommandResponse::Activity(_, state) => CommandResponse::Activity(uuid, state),
CommandResponse::RenameChat(_, name) => CommandResponse::RenameChat(uuid, name),
CommandResponse::RenameBranch(_, name) => CommandResponse::RenameBranch(uuid, name),
CommandResponse::BackendMessage(_, msg) => CommandResponse::BackendMessage(uuid, msg),
CommandResponse::Completed(_) => CommandResponse::Completed(uuid),
}
}
}
pub trait Responder: std::fmt::Debug + Send + Sync + DynClone {
fn send(&self, response: CommandResponse);
fn agent_message(&self, message: chat_completion::ChatMessage);
fn system_message(&self, message: &str);
fn update(&self, state: &str);
fn rename_chat(&self, name: &str);
fn rename_branch(&self, name: &str);
}
dyn_clone::clone_trait_object!(Responder);
#[cfg(test)]
mock! {
#[derive(Debug)]
pub Responder {}
impl Responder for Responder {
fn send(&self, response: CommandResponse);
fn agent_message(&self, message: chat_completion::ChatMessage);
fn system_message(&self, message: &str);
fn update(&self, state: &str);
fn rename_chat(&self, name: &str);
fn rename_branch(&self, name: &str);
}
impl Clone for Responder {
fn clone(&self) -> Self;
}
}
impl Responder for tokio::sync::mpsc::UnboundedSender<CommandResponse> {
fn send(&self, response: CommandResponse) {
let _ = self.send(response);
}
fn agent_message(&self, message: chat_completion::ChatMessage) {
let _ = self.send(CommandResponse::Chat(Uuid::default(), message));
}
fn system_message(&self, message: &str) {
let _ = self.send(CommandResponse::BackendMessage(
Uuid::default(),
message.to_string(),
));
}
fn update(&self, state: &str) {
let _ = self.send(CommandResponse::Activity(
Uuid::default(),
state.to_string(),
));
}
fn rename_chat(&self, name: &str) {
let _ = self.send(CommandResponse::RenameChat(
Uuid::default(),
name.to_string(),
));
}
fn rename_branch(&self, branch_name: &str) {
let _ = self.send(CommandResponse::RenameBranch(
Uuid::default(),
branch_name.to_string(),
));
}
}
impl Responder for Arc<dyn Responder> {
fn send(&self, response: CommandResponse) {
self.as_ref().send(response);
}
fn agent_message(&self, message: chat_completion::ChatMessage) {
self.as_ref().agent_message(message);
}
fn system_message(&self, message: &str) {
self.as_ref().system_message(message);
}
fn update(&self, state: &str) {
self.as_ref().update(state);
}
fn rename_chat(&self, name: &str) {
self.as_ref().rename_chat(name);
}
fn rename_branch(&self, name: &str) {
self.as_ref().rename_branch(name);
}
}
#[derive(Debug, Clone)]
pub struct DebugResponder;
impl Responder for DebugResponder {
fn send(&self, response: CommandResponse) {
eprintln!("DEBUG: Response: {response:?}");
}
fn agent_message(&self, message: chat_completion::ChatMessage) {
eprintln!("DEBUG: Agent message: {message:?}");
}
fn system_message(&self, message: &str) {
eprintln!("DEBUG: System message: {message}");
}
fn update(&self, state: &str) {
eprintln!("DEBUG: State update: {state}");
}
fn rename_chat(&self, name: &str) {
eprintln!("DEBUG: Chat renamed to: {name}");
}
fn rename_branch(&self, name: &str) {
eprintln!("DEBUG: Branch renamed to: {name}");
}
}
impl Responder for () {
fn send(&self, _response: CommandResponse) {}
fn agent_message(&self, _message: chat_completion::ChatMessage) {}
fn system_message(&self, _message: &str) {}
fn update(&self, _state: &str) {}
fn rename_chat(&self, _name: &str) {}
fn rename_branch(&self, _name: &str) {}
}