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);
}
}