use models::ai::{AiMessage, ai_conversation, ai_message, ai_message_fork}; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, Set}; use crate::error::AppError; use uuid::Uuid; use crate::AppService; impl AppService { pub async fn fork_message( &self, conversation_id: Uuid, user_id: Uuid, source_message_id: Uuid, target_message_id: Uuid, ) -> Result { let c = self.find_conversation_owned(conversation_id, user_id).await?; // Mark source as fork origin let mut source: ai_message::ActiveModel = AiMessage::find_by_id(source_message_id) .one(self.db.reader()) .await? .ok_or_else(|| AppError::NotFound("message".into()))? .into(); source.is_fork_origin = Set(true); source.update(self.db.writer()).await?; // Create fork record let fork_record = ai_message_fork::ActiveModel { id: Set(Uuid::new_v4()), conversation_id: Set(Some(conversation_id)), source_message_id: Set(source_message_id), fork_message_id: Set(target_message_id), created_at: Set(chrono::Utc::now()), } .insert(self.db.writer()) .await?; // Update conversation fork_count let fork_count = c.fork_count; let root_msg_id = c.root_message_id; let mut updated: ai_conversation::ActiveModel = c.into(); updated.fork_count = Set(fork_count + 1); if root_msg_id.is_none() { updated.root_message_id = Set(Some(target_message_id)); } updated.update(self.db.writer()).await?; Ok(fork_record) } /// List all fork records for a message within a conversation. pub async fn list_forks( &self, conversation_id: Uuid, user_id: Uuid, source_message_id: Uuid, ) -> Result, AppError> { self.find_conversation_owned(conversation_id, user_id).await?; let forks = ai_message_fork::Entity::find() .filter(ai_message_fork::Column::SourceMessageId.eq(source_message_id)) .filter(ai_message_fork::Column::ConversationId.eq(conversation_id)) .all(self.db.reader()) .await?; Ok(forks) } }