Add agent system with Core and Librarian agent implementations
Define IAgent interface and implement CoreAgent (main conversational agent) and LibrarianAgent (knowledge retrieval agent). Includes DI service collection extensions for agent registration.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
using Luna.Configuration;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Luna.Agents.Abstractions;
|
||||
|
||||
public interface IAgent
|
||||
{
|
||||
public static virtual string Name { get; } = null!;
|
||||
|
||||
public string DisplayName { get; }
|
||||
public string Description { get; }
|
||||
public AgentOptions Options { get; init; }
|
||||
|
||||
Task<IEnumerable<ChatMessage>> ProcessAsync(IReadOnlyList<ChatMessage> messages,
|
||||
CancellationToken ct = default);
|
||||
|
||||
IAsyncEnumerable<ChatResponseUpdate> ProcessStreamingAsync(IReadOnlyList<ChatMessage> messages,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="10.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Luna.Configuration\Luna.Configuration.csproj" />
|
||||
<ProjectReference Include="..\Luna.Shared\Luna.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Text.Json;
|
||||
using Luna.Agents.Abstractions;
|
||||
using Luna.Configuration;
|
||||
using Luna.Providers.Abstractions;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Luna.Agents.Core;
|
||||
|
||||
public class CoreAgent(
|
||||
[FromKeyedServices("Mistral")] IProvider provider,
|
||||
IOptionsMonitor<AgentOptions> options,
|
||||
ILogger<CoreAgent> logger)
|
||||
: IAgent
|
||||
{
|
||||
private readonly IChatClient chatClient = provider.GetChatClient(options.Get(Name).ModelId);
|
||||
|
||||
public static string Name => "Core";
|
||||
|
||||
public string DisplayName => Options.DisplayName ?? Name;
|
||||
public string Description => Options.Description ?? string.Empty;
|
||||
public AgentOptions Options { get; init; } = options.Get(Name);
|
||||
|
||||
public async Task<IEnumerable<ChatMessage>> ProcessAsync(
|
||||
IReadOnlyList<ChatMessage> messages,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var messagesJson = JsonSerializer.Serialize(messages);
|
||||
logger.LogInformation("Processing messages: {MessagesJson}", messagesJson);
|
||||
|
||||
var chatOptions = new ChatOptions
|
||||
{
|
||||
Instructions = Options.Instructions
|
||||
};
|
||||
|
||||
var response = await chatClient.GetResponseAsync(messages, chatOptions, ct);
|
||||
|
||||
logger.LogInformation("Response: {ResponseJson}", JsonSerializer.Serialize(response));
|
||||
return response.Messages;
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<ChatResponseUpdate> ProcessStreamingAsync(
|
||||
IReadOnlyList<ChatMessage> messages,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
var chatOptions = new ChatOptions
|
||||
{
|
||||
Instructions = Options.Instructions
|
||||
};
|
||||
|
||||
return chatClient.GetStreamingResponseAsync(messages, chatOptions, ct);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Luna.Agents.Abstractions;
|
||||
using Luna.Agents.Core;
|
||||
using Luna.Agents.Librarian;
|
||||
using Luna.Configuration.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Luna.Agents.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
{
|
||||
extension(IServiceCollection services)
|
||||
{
|
||||
public IServiceCollection AddAgents()
|
||||
{
|
||||
services.AddAgent<CoreAgent>();
|
||||
services.AddAgent<LibrarianAgent>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public IServiceCollection AddAgent<TAgent>(string? name = null)
|
||||
where TAgent : class, IAgent
|
||||
{
|
||||
name ??= TAgent.Name;
|
||||
|
||||
services.AddAgentOptions(name);
|
||||
services.AddKeyedTransient<IAgent, TAgent>(name);
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Luna.Agents.Abstractions;
|
||||
using Luna.Configuration;
|
||||
using Luna.Providers.Abstractions;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Luna.Agents.Librarian;
|
||||
|
||||
public class LibrarianAgent(
|
||||
[FromKeyedServices("Mistral")] IProvider provider,
|
||||
IOptionsMonitor<AgentOptions> options)
|
||||
: IAgent
|
||||
{
|
||||
private readonly IChatClient chatClient = provider.GetChatClient(options.Get(Name).ModelId);
|
||||
|
||||
public static string Name => "Librarian";
|
||||
|
||||
public string DisplayName => Options.DisplayName ?? Name;
|
||||
public string Description => Options.Description ?? string.Empty;
|
||||
public AgentOptions Options { get; init; } = options.Get(Name);
|
||||
|
||||
public async Task<IEnumerable<ChatMessage>> ProcessAsync(
|
||||
IReadOnlyList<ChatMessage> messages,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var chatOptions = new ChatOptions
|
||||
{
|
||||
Instructions = Options.Instructions
|
||||
};
|
||||
|
||||
var messagesWithoutSystemPrompt = messages
|
||||
.Where(m => m.Role != ChatRole.System)
|
||||
.ToList();
|
||||
|
||||
var response = await chatClient.GetResponseAsync(messagesWithoutSystemPrompt, chatOptions, ct);
|
||||
return response.Messages
|
||||
.Where(m => m.Role != ChatRole.System);
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<ChatResponseUpdate> ProcessStreamingAsync(IReadOnlyList<ChatMessage> messages, CancellationToken ct = default)
|
||||
{
|
||||
var chatOptions = new ChatOptions
|
||||
{
|
||||
Instructions = Options.Instructions
|
||||
};
|
||||
|
||||
var messagesWithoutSystemPrompt = messages
|
||||
.Where(m => m.Role != ChatRole.System)
|
||||
.ToList();
|
||||
|
||||
await foreach (var update in chatClient.GetStreamingResponseAsync(messagesWithoutSystemPrompt, chatOptions, ct))
|
||||
{
|
||||
if (update.Role != ChatRole.System)
|
||||
{
|
||||
yield return update;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.AI.Abstractions" Version="10.4.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Luna.Agents.Abstractions\Luna.Agents.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Luna.Providers.Abstractions\Luna.Providers.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\Luna.Configuration\Luna.Configuration.csproj" />
|
||||
<ProjectReference Include="..\Luna.Shared\Luna.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user