using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.MLTasks; namespace BotSharp.Core.Routing; /// /// Simulate the dialogue between different agents. /// public class Simulator { private readonly IServiceProvider _services; private readonly ILogger _logger; private List _dialogs; public List Dialogs => _dialogs; public Simulator(IServiceProvider services, ILogger logger) { _services = services; _logger = logger; } public async Task Enter(Agent agent, List whileDialogs) { _dialogs = new List(); foreach (var dialog in whileDialogs.TakeLast(10)) { agent.Instruction += $"\r\n{dialog.Role}: {dialog.Content}"; } var response = await SendMessageToReasoner(agent); var args = JsonSerializer.Deserialize(response.Content); response.FunctionName = args.Function; response.Content = args.Parameters.Reason; if (args.Function == "continue_execute_task") { response.FunctionArgs = JsonSerializer.Serialize(args.Parameters.Arguments); var router = _services.GetRequiredService(); var record = router.GetRecordByName(args.Parameters.AgentName); response.CurrentAgentId = record.AgentId; } return response; } private async Task SendMessageToReasoner(Agent reasoner) { var wholeDialogs = new List { new RoleDialogModel(AgentRole.User, @"What's the next step, your response must be in JSON format with ""function"" and ""parameters"". ") }; var chatCompletion = GetGpt4ChatCompletion(); RoleDialogModel response = null; await chatCompletion.GetChatCompletionsAsync(reasoner, wholeDialogs, async msg => response = msg, fn => Task.CompletedTask); var args = JsonSerializer.Deserialize(response.Content); SaveStateByArgs(args.Parameters.Arguments); // Retrieve information from specific agent var router = _services.GetRequiredService(); var record = router.GetRecordByName(args.Parameters.AgentName); response = await SendMessageToAgent(record.AgentId, new List { new RoleDialogModel(AgentRole.User, args.Parameters.Question) }); _dialogs.Add(new RoleDialogModel(AgentRole.Function, $"{record.Name}: {response.Content}") { FunctionName = args.Function, FunctionArgs = JsonSerializer.Serialize(args.Parameters.Arguments), ExecutionResult = response.Content }); reasoner.Instruction += $"\r\n{record.Name}: {response.Content}"; // Got the response from agent, then send to reasoner again to make the decision await chatCompletion.GetChatCompletionsAsync(reasoner, wholeDialogs, async msg => response = msg, fn => Task.CompletedTask); return response; } private async Task SendMessageToAgent(string agentId, List wholeDialogs) { var agentService = _services.GetRequiredService(); var agent = await agentService.LoadAgent(agentId); var chatCompletion = GetChatCompletion(); RoleDialogModel response = null; await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg => response = msg, fn => Task.CompletedTask); return response; } public IChatCompletion GetChatCompletion() { var completions = _services.GetServices(); var settings = _services.GetRequiredService(); return completions.FirstOrDefault(x => x.GetType().FullName.EndsWith(settings.ChatCompletion)); } public IChatCompletion GetGpt4ChatCompletion() { var completions = _services.GetServices(); return completions.FirstOrDefault(x => x.GetType().FullName.EndsWith("GPT4CompletionProvider")); } private void SaveStateByArgs(JsonDocument args) { var stateService = _services.GetRequiredService(); if (args.RootElement is JsonElement root) { foreach (JsonProperty property in root.EnumerateObject()) { if (!string.IsNullOrEmpty(property.Value.ToString())) { stateService.SetState(property.Name, property.Value.ToString()); } } } } }