using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Codex.Dal; using Codex.Dal.Enums; using Microsoft.EntityFrameworkCore; using OpenHarbor.CQRS.Abstractions; namespace Codex.CQRS.Queries; /// /// Get conversation with all messages by ID /// public record GetConversationQuery { /// Conversation ID public Guid Id { get; init; } } /// /// Detailed conversation information with messages /// public record ConversationDetails { /// Unique conversation identifier public Guid Id { get; init; } /// Conversation title public string Title { get; init; } = string.Empty; /// Conversation summary public string? Summary { get; init; } /// Whether conversation is active public bool IsActive { get; init; } /// Conversation start timestamp public DateTime StartedAt { get; init; } /// Last message timestamp public DateTime LastMessageAt { get; init; } /// Total message count public int MessageCount { get; init; } /// All messages in conversation public List Messages { get; init; } = new(); } /// /// Individual message within a conversation /// public record ConversationMessageItem { /// Message identifier public Guid Id { get; init; } /// Conversation identifier public Guid ConversationId { get; init; } /// Execution identifier if from agent execution public Guid? ExecutionId { get; init; } /// Message role (user, assistant, system, tool) public MessageRole Role { get; init; } /// Message content public string Content { get; init; } = string.Empty; /// Message index/order in conversation public int MessageIndex { get; init; } /// Whether message is in active context window public bool IsInActiveWindow { get; init; } /// Message creation timestamp public DateTime CreatedAt { get; init; } } public class GetConversationQueryHandler : IQueryHandler { private readonly CodexDbContext _dbContext; public GetConversationQueryHandler(CodexDbContext dbContext) { _dbContext = dbContext; } public async Task HandleAsync( GetConversationQuery query, CancellationToken cancellationToken = default) { return await _dbContext.Conversations .AsNoTracking() .Where(c => c.Id == query.Id) .Select(c => new ConversationDetails { Id = c.Id, Title = c.Title, Summary = c.Summary, IsActive = c.IsActive, StartedAt = c.StartedAt, LastMessageAt = c.LastMessageAt, MessageCount = c.MessageCount, Messages = c.Messages .OrderBy(m => m.MessageIndex) .Select(m => new ConversationMessageItem { Id = m.Id, ConversationId = m.ConversationId, ExecutionId = m.ExecutionId, Role = m.Role, Content = m.Content, MessageIndex = m.MessageIndex, IsInActiveWindow = m.IsInActiveWindow, CreatedAt = m.CreatedAt }) .ToList() }) .FirstOrDefaultAsync(cancellationToken); } }