BotSharp/src/Infrastructure/BotSharp.Core/Instructs/InstructService.cs

128 lines
4 KiB
C#
Raw Normal View History

2023-09-01 22:26:25 +00:00
using BotSharp.Abstraction.Agents.Enums;
using BotSharp.Abstraction.Agents.Models;
using BotSharp.Abstraction.Instructs;
2023-09-08 17:03:49 +00:00
using BotSharp.Abstraction.Instructs.Models;
2023-09-01 22:26:25 +00:00
using BotSharp.Abstraction.MLTasks;
using BotSharp.Abstraction.Templating;
2023-09-08 17:03:49 +00:00
using System.IO;
2023-09-01 22:26:25 +00:00
namespace BotSharp.Core.Instructs;
public partial class InstructService : IInstructService
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
public InstructService(IServiceProvider services, ILogger<InstructService> logger)
{
_services = services;
_logger = logger;
}
2023-09-08 17:03:49 +00:00
public async Task<InstructResult> ExecuteInstruction(Agent agent,
RoleDialogModel message,
Func<RoleDialogModel, Task> onMessageReceived,
Func<RoleDialogModel, Task> onFunctionExecuting,
Func<RoleDialogModel, Task> onFunctionExecuted)
{
var response = new InstructResult();
var wholeDialogs = new List<RoleDialogModel>
{
2023-09-09 15:37:38 +00:00
message
2023-09-08 17:03:49 +00:00
};
// Trigger before completion hooks
var hooks = _services.GetServices<IInstructHook>();
foreach (var hook in hooks)
{
await hook.BeforeCompletion(message);
}
await ExecuteInstructionRecursively(agent,
wholeDialogs,
async msg =>
{
response.Text = msg.Content;
await onMessageReceived(msg);
},
async fn =>
{
response.Function = fn.FunctionName;
await onFunctionExecuting(fn);
},
async fn =>
{
2023-10-23 00:31:49 +00:00
response.Data = fn.Data;
2023-09-08 17:03:49 +00:00
await onFunctionExecuted(fn);
});
foreach (var hook in hooks)
{
await hook.AfterCompletion(response);
}
return response;
}
private async Task<bool> ExecuteInstructionRecursively(Agent agent,
2023-09-01 22:26:25 +00:00
List<RoleDialogModel> wholeDialogs,
Func<RoleDialogModel, Task> onMessageReceived,
Func<RoleDialogModel, Task> onFunctionExecuting,
Func<RoleDialogModel, Task> onFunctionExecuted)
{
2023-09-14 01:41:51 +00:00
var chatCompletion = CompletionProvider.GetChatCompletion(_services);
2023-09-01 22:26:25 +00:00
var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg =>
{
await onMessageReceived(msg);
2023-09-08 17:03:49 +00:00
wholeDialogs.Add(msg);
2023-09-01 22:26:25 +00:00
}, async fn =>
{
var preAgentId = agent.Id;
await HandleFunctionMessage(fn, onFunctionExecuting, onFunctionExecuted);
// Function executed has exception
2023-10-23 00:31:49 +00:00
if (fn.Content == null || fn.StopCompletion)
2023-09-01 22:26:25 +00:00
{
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, fn.Content));
return;
}
2023-10-23 00:31:49 +00:00
fn.Content = fn.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim() + " => " + fn.Content;
2023-09-01 22:26:25 +00:00
// Find response template
var templateService = _services.GetRequiredService<IResponseTemplateService>();
var response = await templateService.RenderFunctionResponse(agent.Id, fn);
if (!string.IsNullOrEmpty(response))
{
await onMessageReceived(new RoleDialogModel(AgentRole.Assistant, response));
return;
}
// After function is executed, pass the result to LLM to get a natural response
wholeDialogs.Add(fn);
await ExecuteInstructionRecursively(agent,
wholeDialogs,
onMessageReceived,
onFunctionExecuting,
onFunctionExecuted);
});
return result;
}
private async Task HandleFunctionMessage(RoleDialogModel msg,
Func<RoleDialogModel, Task> onFunctionExecuting,
Func<RoleDialogModel, Task> onFunctionExecuted)
{
// Call functions
await onFunctionExecuting(msg);
await CallFunctions(msg);
await onFunctionExecuted(msg);
}
}