use actix_web::{web, HttpResponse, Result}; use session::Session; use service::error::AppError; use uuid::Uuid; use crate::error::ApiError; use crate::ApiResponse; #[derive(Debug, serde::Serialize, utoipa::ToSchema)] pub struct ForkResponse { pub id: Uuid, pub conversation_id: Option, pub source_message_id: Uuid, pub fork_message_id: Uuid, #[schema(value_type = chrono::DateTime)] pub created_at: chrono::DateTime, } #[utoipa::path( post, path = "/api/ai/conversations/{conversation_id}/messages/{message_id}/fork/{target_message_id}", operation_id = "ai_message_fork", params( ("conversation_id" = Uuid, Path, description = "Conversation ID"), ("message_id" = Uuid, Path, description = "Source message ID"), ("target_message_id" = Uuid, Path, description = "Target/fork message ID to create"), ), responses( (status = 200, description = "Fork created", body = ApiResponse), ), tag = "AI Chat" )] pub async fn message_fork( service: web::Data, session: Session, path: web::Path<(Uuid, Uuid, Uuid)>, ) -> Result { let user_id = session .user() .ok_or_else(|| ApiError::from(AppError::Unauthorized))?; let (conversation_id, source_message_id, target_message_id) = path.into_inner(); let fork_record = service .fork_message( conversation_id, user_id, source_message_id, target_message_id, ) .await?; let resp = ForkResponse { id: fork_record.id, conversation_id: fork_record.conversation_id, source_message_id: fork_record.source_message_id, fork_message_id: fork_record.fork_message_id, created_at: fork_record.created_at, }; Ok(ApiResponse::ok(resp).to_response()) } #[utoipa::path( get, path = "/api/ai/conversations/{conversation_id}/messages/{message_id}/forks", operation_id = "ai_message_forks", params( ("conversation_id" = Uuid, Path, description = "Conversation ID"), ("message_id" = Uuid, Path, description = "Source message ID"), ), responses( (status = 200, description = "List forks from message", body = ApiResponse>), ), tag = "AI Chat" )] pub async fn message_forks( service: web::Data, session: Session, path: web::Path<(Uuid, Uuid)>, ) -> Result { let user_id = session .user() .ok_or_else(|| ApiError::from(AppError::Unauthorized))?; let (conversation_id, source_message_id) = path.into_inner(); let forks = service .list_forks(conversation_id, user_id, source_message_id) .await?; let resp: Vec = forks .into_iter() .map(|f| ForkResponse { id: f.id, conversation_id: f.conversation_id, source_message_id: f.source_message_id, fork_message_id: f.fork_message_id, created_at: f.created_at, }) .collect(); Ok(ApiResponse::ok(resp).to_response()) }