-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Code(API::ExecuteNativeAction): Implement feature for execute native …
…action
- Loading branch information
1 parent
8231076
commit 8b9b068
Showing
5 changed files
with
131 additions
and
0 deletions.
There are no files selected for viewing
3 changes: 3 additions & 0 deletions
3
...Server/StellarChat.Server.Api/Features/Actions/ExecuteNativeAction/ExecuteNativeAction.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
namespace StellarChat.Server.Api.Features.Actions.ExecuteNativeAction; | ||
|
||
internal sealed record ExecuteNativeAction([Required] Guid Id, [Required] Guid ChatId, string Message) : ICommand<string>; |
30 changes: 30 additions & 0 deletions
30
...tellarChat.Server.Api/Features/Actions/ExecuteNativeAction/ExecuteNativeActionEndpoint.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
namespace StellarChat.Server.Api.Features.Actions.ExecuteNativeAction; | ||
|
||
public class ExecuteNativeActionEndpoint : IEndpoint | ||
{ | ||
public void Expose(IEndpointRouteBuilder endpoints) | ||
{ | ||
var actions = endpoints.MapGroup("/actions").WithTags("Actions"); | ||
|
||
actions.MapPost("execute", async ([FromBody] ExecuteNativeActionRequest request, IMediator mediator) => | ||
{ | ||
var id = Guid.NewGuid(); | ||
var command = request.Adapt<ExecuteNativeAction>(); | ||
|
||
command = command with { Id = id }; | ||
var result = await mediator.Send(command); | ||
|
||
return Results.Ok(result); | ||
}) | ||
.Produces(StatusCodes.Status200OK) | ||
.Produces(StatusCodes.Status400BadRequest) | ||
.WithOpenApi(operation => new(operation) | ||
{ | ||
Summary = "Executes a new action." | ||
}); | ||
} | ||
|
||
public void Register(IServiceCollection services, IConfiguration configuration) { } | ||
|
||
public void Use(IApplicationBuilder app) { } | ||
} |
89 changes: 89 additions & 0 deletions
89
...StellarChat.Server.Api/Features/Actions/ExecuteNativeAction/ExecuteNativeActionHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
using Microsoft.SemanticKernel; | ||
using StellarChat.Server.Api.Features.Actions.CreateNativeAction; | ||
using StellarChat.Server.Api.Features.Actions.Webhooks.Services; | ||
using StellarChat.Server.Api.Features.Chat.CarryConversation; | ||
|
||
namespace StellarChat.Server.Api.Features.Actions.ExecuteNativeAction; | ||
|
||
internal sealed class ExecuteNativeActionHandler : ICommandHandler<ExecuteNativeAction, string> | ||
{ | ||
private readonly INativeActionRepository _nativeActionRepository; | ||
private readonly IHttpClientService _httpClientService; | ||
private readonly IChatContext _chatContext; | ||
private readonly Kernel _kernel; | ||
private readonly IHubContext<ChatHub, IChatHub> _hubContext; | ||
private readonly TimeProvider _clock; | ||
private readonly ILogger<CreateNativeActionHandler> _logger; | ||
|
||
public ExecuteNativeActionHandler( | ||
INativeActionRepository nativeActionRepository, | ||
IHttpClientService httpClientService, | ||
IChatContext chatContext, | ||
Kernel kernel, | ||
IHubContext<ChatHub, IChatHub> hubContext, | ||
TimeProvider clock, | ||
ILogger<CreateNativeActionHandler> logger) | ||
{ | ||
_nativeActionRepository = nativeActionRepository; | ||
_httpClientService = httpClientService; | ||
_chatContext = chatContext; | ||
_kernel = kernel; | ||
_hubContext = hubContext; | ||
_clock = clock; | ||
_logger = logger; | ||
} | ||
|
||
public async ValueTask<string> Handle(ExecuteNativeAction command, CancellationToken cancellationToken) | ||
{ | ||
var (id, chatId, message) = command; | ||
|
||
var action = await _nativeActionRepository.GetAsync(id) ?? throw new NativeActionNotFoundException(id); | ||
|
||
action.Metaprompt = action.Metaprompt.IsEmpty() | ||
? string.Empty | ||
: _clock.ReplaceDatePlaceholder(action.Metaprompt); | ||
|
||
string semanticResponse = string.Empty; | ||
|
||
await _chatContext.SetChatInstructions(chatId, action.Metaprompt); | ||
await _chatContext.ExtractChatHistoryAsync(chatId); | ||
|
||
var userMessage = CreateUserMessage(chatId, message); | ||
await _chatContext.SaveChatMessageAsync(chatId, userMessage); | ||
|
||
var botMessage = CreateBotMessage(chatId, content: string.Empty); | ||
var botResponseMessage = await _chatContext.StreamResponseToClientAsync(chatId, action.Model, botMessage, _hubContext); | ||
|
||
semanticResponse = botResponseMessage.Content; | ||
|
||
if (action.IsRemoteAction) | ||
{ | ||
var response = await _httpClientService.PostAsync(action.Webhook!.Url, semanticResponse, action.Webhook.Headers, cancellationToken); | ||
botResponseMessage.Content = response; | ||
await _hubContext.Clients.All.ReceiveChatMessageChunk(response); | ||
await _chatContext.SaveChatMessageAsync(chatId, botResponseMessage); | ||
|
||
return response; | ||
} | ||
|
||
await _chatContext.SaveChatMessageAsync(chatId, botResponseMessage); | ||
|
||
return semanticResponse; | ||
} | ||
|
||
private ChatMessage CreateUserMessage(Guid chatId, string message, ChatMessageType messageType = ChatMessageType.Message) | ||
{ | ||
var now = _clock.GetLocalNow(); | ||
|
||
var userMessage = ChatMessage.Create(Guid.NewGuid(), chatId, messageType, Author.User, message, tokenCount: 0, now); | ||
return userMessage; | ||
} | ||
|
||
private ChatMessage CreateBotMessage(Guid chatId, string content, ChatMessageType messageType = ChatMessageType.Message) | ||
{ | ||
var now = _clock.GetLocalNow(); | ||
|
||
var chatMessage = ChatMessage.Create(Guid.NewGuid(), chatId, messageType, Author.Bot, content, tokenCount: 0, now); | ||
return chatMessage; | ||
} | ||
} |
6 changes: 6 additions & 0 deletions
6
src/Shared/StellarChat.Shared.Contracts/Actions/ExecuteNativeActionRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
using System.ComponentModel.DataAnnotations; | ||
using System.Text.Json.Serialization; | ||
|
||
namespace StellarChat.Shared.Contracts.Actions; | ||
|
||
public sealed record ExecuteNativeActionRequest([property: JsonIgnore][Required] Guid Id, [Required] Guid ChatId, string Message); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters