diff --git a/src/Core.Application/Abstractions/IAuthorResponse.cs b/src/Core.Application/Abstractions/IAuthorResponse.cs new file mode 100644 index 0000000..bd353cb --- /dev/null +++ b/src/Core.Application/Abstractions/IAuthorResponse.cs @@ -0,0 +1,9 @@ +namespace Goodtocode.SemanticKernel.Core.Application.Abstractions; + +public interface IAuthorResponse +{ + Guid AuthorId { get; } + string? Name { get; } + string Status { get; } + string? Message { get; } +} \ No newline at end of file diff --git a/src/Core.Application/Abstractions/IAuthorsPlugin.cs b/src/Core.Application/Abstractions/IAuthorsPlugin.cs index 6046c47..6fe7851 100644 --- a/src/Core.Application/Abstractions/IAuthorsPlugin.cs +++ b/src/Core.Application/Abstractions/IAuthorsPlugin.cs @@ -1,6 +1,6 @@ -namespace Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Plugins; +namespace Goodtocode.SemanticKernel.Core.Application.Abstractions; public interface IAuthorsPlugin { - Task GetAuthorInfoAsync(string authorId, CancellationToken cancellationToken); + Task GetAuthorNameAsync(Guid authorId, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/Core.Application/Abstractions/IChatMessagesPlugin.cs b/src/Core.Application/Abstractions/IChatMessagesPlugin.cs index b8ba38e..e243467 100644 --- a/src/Core.Application/Abstractions/IChatMessagesPlugin.cs +++ b/src/Core.Application/Abstractions/IChatMessagesPlugin.cs @@ -1,7 +1,7 @@ -namespace Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Plugins; +namespace Goodtocode.SemanticKernel.Core.Application.Abstractions; public interface IChatMessagesPlugin { Task> ListRecentMessagesAsync(DateTime? startDate, DateTime? endDate, CancellationToken cancellationToken); - Task> GetChatMessagesAsync(string sessionId, CancellationToken cancellationToken); + Task> GetChatMessagesAsync(Guid sessionId, CancellationToken cancellationToken); } diff --git a/src/Core.Application/Abstractions/IChatSessionsPlugin.cs b/src/Core.Application/Abstractions/IChatSessionsPlugin.cs index 9418b31..76a9dd3 100644 --- a/src/Core.Application/Abstractions/IChatSessionsPlugin.cs +++ b/src/Core.Application/Abstractions/IChatSessionsPlugin.cs @@ -1,7 +1,7 @@ -namespace Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Plugins; +namespace Goodtocode.SemanticKernel.Core.Application.Abstractions; public interface IChatSessionsPlugin { Task> ListRecentSessionsAsync(DateTime? startDate, DateTime? endDate, CancellationToken cancellationToken); - Task UpdateChatSessionTitleAsync(string sessionId, string newTitle, CancellationToken cancellationToken); + Task UpdateChatSessionTitleAsync(Guid sessionId, string newTitle, CancellationToken cancellationToken); } \ No newline at end of file diff --git a/src/Infrastructure.SemanticKernel/ConfigureServices.cs b/src/Infrastructure.SemanticKernel/ConfigureServices.cs index 49a71fd..16c770d 100644 --- a/src/Infrastructure.SemanticKernel/ConfigureServices.cs +++ b/src/Infrastructure.SemanticKernel/ConfigureServices.cs @@ -1,4 +1,5 @@ -using Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Options; +using Goodtocode.SemanticKernel.Core.Application.Abstractions; +using Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Options; using Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Plugins; using Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Services; using Microsoft.Extensions.Configuration; diff --git a/src/Infrastructure.SemanticKernel/Plugins/AuthorsPlugin.cs b/src/Infrastructure.SemanticKernel/Plugins/AuthorsPlugin.cs index 1c14370..cd994e6 100644 --- a/src/Infrastructure.SemanticKernel/Plugins/AuthorsPlugin.cs +++ b/src/Infrastructure.SemanticKernel/Plugins/AuthorsPlugin.cs @@ -5,17 +5,45 @@ namespace Goodtocode.SemanticKernel.Infrastructure.SemanticKernel.Plugins; +public class AuthorResponse : IAuthorResponse +{ + public Guid AuthorId { get; set; } + public string? Name { get; set; } + public string? Status { get; set; } + public string? Message { get; set; } +} + public sealed class AuthorsPlugin(IServiceProvider serviceProvider) : IAuthorsPlugin { private readonly IServiceProvider _serviceProvider = serviceProvider; [KernelFunction("get_author")] - [Description("Returns the author's name for the specified author ID, or 'Author not found' if no match exists.")] - public async Task GetAuthorInfoAsync(string authorId, CancellationToken cancellationToken) + [Description("Returns structured author info including name, status, and explanation.")] + async Task IAuthorsPlugin.GetAuthorNameAsync(Guid authorId, CancellationToken cancellationToken) { using var scope = _serviceProvider.CreateScope(); var context = scope.ServiceProvider.GetRequiredService(); var author = await context.Authors.FindAsync([authorId, cancellationToken], cancellationToken: cancellationToken); - return author?.Name ?? "Author not found"; + + if (author == null) + { + return new AuthorResponse + { + AuthorId = authorId, + Name = null, + Status = "NotFound", + Message = "No author found with the specified ID." + }; + } + + return new AuthorResponse + { + AuthorId = authorId, + Name = author.Name, + Status = string.IsNullOrWhiteSpace(author.Name) ? "Partial" : "Found", + Message = string.IsNullOrWhiteSpace(author.Name) + ? "Author exists but name is not yet linked to Entra External ID." + : "Author found." + }; } } diff --git a/src/Infrastructure.SemanticKernel/Plugins/ChatMessagesPlugin.cs b/src/Infrastructure.SemanticKernel/Plugins/ChatMessagesPlugin.cs index 99093be..83a2e02 100644 --- a/src/Infrastructure.SemanticKernel/Plugins/ChatMessagesPlugin.cs +++ b/src/Infrastructure.SemanticKernel/Plugins/ChatMessagesPlugin.cs @@ -35,7 +35,7 @@ public async Task> ListRecentMessagesAsync(DateTime? startDa [KernelFunction("get_messages")] [Description("Retrieves all messages from a specific chat session.")] - public async Task> GetChatMessagesAsync(string sessionId, + public async Task> GetChatMessagesAsync(Guid sessionId, CancellationToken cancellationToken = default) { // Get ISemanticKernelContext directly instead of constructor DI to allow this plugin to be registered via AddSingleton() and not scoped due to EF. @@ -43,7 +43,7 @@ public async Task> GetChatMessagesAsync(string sessionId, var context = scope.ServiceProvider.GetRequiredService(); var messages = await context.ChatMessages - .Where(x => x.ChatSessionId.ToString() == sessionId) + .Where(x => x.ChatSessionId == sessionId) .ToListAsync(cancellationToken); return messages.Select(m => $"{m.ChatSessionId}: {m.Timestamp} - {m.Role}: {m.Content}"); diff --git a/src/Infrastructure.SemanticKernel/Plugins/ChatSessionsPlugin.cs b/src/Infrastructure.SemanticKernel/Plugins/ChatSessionsPlugin.cs index 422abb6..17ea76e 100644 --- a/src/Infrastructure.SemanticKernel/Plugins/ChatSessionsPlugin.cs +++ b/src/Infrastructure.SemanticKernel/Plugins/ChatSessionsPlugin.cs @@ -37,7 +37,7 @@ public async Task> ListRecentSessionsAsync( [KernelFunction("change_title")] [Description("Changes the title on this chat session.")] - public async Task UpdateChatSessionTitleAsync(string sessionId, string newTitle, + public async Task UpdateChatSessionTitleAsync(Guid sessionId, string newTitle, CancellationToken cancellationToken = default) { // Get ISemanticKernelContext directly instead of constructor DI to allow this plugin to be registered via AddSingleton() and not scoped due to EF. @@ -45,7 +45,7 @@ public async Task UpdateChatSessionTitleAsync(string sessionId, string n var context = scope.ServiceProvider.GetRequiredService(); var chatSession = await context.ChatSessions - .FirstOrDefaultAsync(x => x.Id.ToString() == sessionId, cancellationToken: cancellationToken); + .FirstOrDefaultAsync(x => x.Id == sessionId, cancellationToken: cancellationToken); chatSession!.Title = newTitle; context.ChatSessions.Update(chatSession); await context.SaveChangesAsync(cancellationToken);