Multi-agent AI laboratory with ASP.NET Core 8.0 backend and Flutter frontend. Implements CQRS architecture, OpenAPI contract-first API design. BACKEND: Agent management, conversations, executions with PostgreSQL + Ollama FRONTEND: Cross-platform UI with strict typing and Result-based error handling Co-Authored-By: Jean-Philippe Brule <jp@svrnty.io>
65 lines
1.9 KiB
C#
65 lines
1.9 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Codex.Dal;
|
|
using Codex.Dal.Entities;
|
|
using FluentValidation;
|
|
using OpenHarbor.CQRS.Abstractions;
|
|
|
|
namespace Codex.CQRS.Commands;
|
|
|
|
/// <summary>
|
|
/// Creates a new conversation for grouping related messages
|
|
/// </summary>
|
|
public record CreateConversationCommand
|
|
{
|
|
/// <summary>Conversation title</summary>
|
|
public string Title { get; init; } = string.Empty;
|
|
|
|
/// <summary>Optional summary or description</summary>
|
|
public string? Summary { get; init; }
|
|
}
|
|
|
|
public class CreateConversationCommandHandler : ICommandHandler<CreateConversationCommand, Guid>
|
|
{
|
|
private readonly CodexDbContext _dbContext;
|
|
|
|
public CreateConversationCommandHandler(CodexDbContext dbContext)
|
|
{
|
|
_dbContext = dbContext;
|
|
}
|
|
|
|
public async Task<Guid> HandleAsync(CreateConversationCommand command, CancellationToken cancellationToken = default)
|
|
{
|
|
var conversation = new Conversation
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
Title = command.Title,
|
|
Summary = command.Summary,
|
|
StartedAt = DateTime.UtcNow,
|
|
LastMessageAt = DateTime.UtcNow,
|
|
IsActive = true,
|
|
MessageCount = 0
|
|
};
|
|
|
|
_dbContext.Conversations.Add(conversation);
|
|
await _dbContext.SaveChangesAsync(cancellationToken);
|
|
|
|
return conversation.Id;
|
|
}
|
|
}
|
|
|
|
public class CreateConversationCommandValidator : AbstractValidator<CreateConversationCommand>
|
|
{
|
|
public CreateConversationCommandValidator()
|
|
{
|
|
RuleFor(x => x.Title)
|
|
.NotEmpty().WithMessage("Title is required")
|
|
.MaximumLength(500).WithMessage("Title cannot exceed 500 characters");
|
|
|
|
RuleFor(x => x.Summary)
|
|
.MaximumLength(2000).WithMessage("Summary cannot exceed 2000 characters")
|
|
.When(x => !string.IsNullOrEmpty(x.Summary));
|
|
}
|
|
}
|