diff --git a/docs/index.rst b/docs/index.rst index ca220b75b..c3730fe6b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,6 +80,7 @@ The main documentation for the site is organized into the following sections: :caption: Prompt Engineering prompt/intro + prompt/template .. _architecture-docs: diff --git a/docs/prompt/intro.md b/docs/prompt/intro.md index 2d10f0367..da1ae5f24 100644 --- a/docs/prompt/intro.md +++ b/docs/prompt/intro.md @@ -1 +1,3 @@ -# Prompt Engineering \ No newline at end of file +# Prompt Engineering + +LLM uses prompt as input, and the model produces different outputs according to the input. \ No newline at end of file diff --git a/docs/prompt/template.md b/docs/prompt/template.md new file mode 100644 index 000000000..35260c446 --- /dev/null +++ b/docs/prompt/template.md @@ -0,0 +1,3 @@ +# Template + +We can define the prompt as a template, and the template can be changed according to variables, so that a instruction file can be used to generate a dynamic prompt. \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs deleted file mode 100644 index 6953dee9a..000000000 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs +++ /dev/null @@ -1,46 +0,0 @@ -using BotSharp.Abstraction.Conversations.Models; - -namespace BotSharp.Abstraction.Agents; - -public abstract class AgentHookBase : IAgentHook -{ - protected Agent _agent; - public Agent Agent => _agent; - - public void SetAget(Agent agent) - { - _agent = agent; - } - - public virtual bool OnAgentLoading(ref string id) - { - return true; - } - - public virtual bool OnInstructionLoaded(ref string instruction) - { - _agent.Instruction = instruction; - return true; - } - - public virtual bool OnFunctionsLoaded(ref string functions) - { - _agent.Functions = functions; - return true; - } - - public virtual bool OnSamplesLoaded(ref string samples) - { - _agent.Samples = samples; - return true; - } - - public virtual void OnAgentLoaded(Agent agent) - { - } - - public virtual bool OnAgentRouting(RoleDialogModel message, ref string id) - { - return true; - } -} diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs index 7b0b73dd7..f071caafb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs @@ -13,7 +13,7 @@ public interface IAgentHook bool OnAgentLoading(ref string id); - bool OnInstructionLoaded(ref string instruction); + bool OnInstructionLoaded(string template, Dictionary dict); bool OnFunctionsLoaded(ref string functions); diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs index 6b0928057..dfc108226 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Settings/AgentSettings.cs @@ -7,4 +7,5 @@ public class AgentSettings /// public string RouterId { get; set; } public string DataDir { get; set; } + public string TemplateFormat { get; set; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs index 65e523abc..8c01cbbc3 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs @@ -5,6 +5,6 @@ namespace BotSharp.Abstraction.Conversations; public interface IConversationStorage { void InitStorage(string conversationId); - void Append(string conversationId, RoleDialogModel dialog); + void Append(string conversationId, Agent agent, RoleDialogModel dialog); List GetDialogs(string conversationId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs index 3886445ae..3335617ef 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/RoleDialogModel.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Agents.Enums; + namespace BotSharp.Abstraction.Conversations.Models; public class RoleDialogModel @@ -40,6 +42,13 @@ public RoleDialogModel(string role, string text) public override string ToString() { - return $"{Role}: {Content}"; + if (Role == AgentRole.Function) + { + return $"{Role}: {FunctionName}"; + } + else + { + return $"{Role}: {Content}"; + } } } diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs index 26fecf8a8..be3a170b8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs +++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs @@ -4,7 +4,10 @@ namespace BotSharp.Abstraction.MLTasks; public interface IChatCompletion { - // string GetChatCompletions(Agent agent, List conversations, Func onMessageReceived); - Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived); + Task GetChatCompletionsAsync(Agent agent, + List conversations, + Func onMessageReceived, + Func onFunctionExecuting); + Task GetChatCompletionsStreamingAsync(Agent agent, List conversations, Func onMessageReceived); } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentHookBase.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentHookBase.cs new file mode 100644 index 000000000..88e3ec1fb --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentHookBase.cs @@ -0,0 +1,76 @@ +using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Conversations.Models; +using Fluid; +using Microsoft.AspNetCore.Mvc; + +namespace BotSharp.Core.Agents.Services; + +public abstract class AgentHookBase : IAgentHook +{ + protected Agent _agent; + public Agent Agent => _agent; + private static readonly FluidParser _parser = new FluidParser(); + + private readonly IServiceProvider _services; + + public AgentHookBase(IServiceProvider services) + { + _services = services; + } + + public void SetAget(Agent agent) + { + _agent = agent; + } + + public virtual bool OnAgentLoading(ref string id) + { + return true; + } + + public virtual bool OnInstructionLoaded(string template, Dictionary dict) + { + if (_parser.TryParse(template, out var t, out var error)) + { + PopulateStateTokens(dict); + var context = new TemplateContext(dict); + _agent.Instruction = t.Render(context); + return true; + } + else + { + return false; + } + } + + private void PopulateStateTokens(Dictionary dict) + { + var stateService = _services.GetRequiredService(); + var state = stateService.Load(); + foreach (var t in state) + { + dict[t.Key] = t.Value; + } + } + + public virtual bool OnFunctionsLoaded(ref string functions) + { + _agent.Functions = functions; + return true; + } + + public virtual bool OnSamplesLoaded(ref string samples) + { + _agent.Samples = samples; + return true; + } + + public virtual void OnAgentLoaded(Agent agent) + { + } + + public virtual bool OnAgentRouting(RoleDialogModel message, ref string id) + { + return true; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs index 8f1123928..1c28bad3e 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentRouter.cs @@ -20,8 +20,8 @@ public AgentRouter(IServiceProvider services, public async Task LoadCurrentAgent() { // Load current agent from state - var stateService = _services.GetRequiredService(); - var currentAgentId = stateService.GetState("agentId"); + var state = _services.GetRequiredService(); + var currentAgentId = state.GetState("agentId"); if (string.IsNullOrEmpty(currentAgentId)) { currentAgentId = _settings.RouterId; @@ -30,7 +30,7 @@ public async Task LoadCurrentAgent() var agent = await agentService.LoadAgent(currentAgentId); // Set agent and trigger state changed - stateService.SetState("agentId", currentAgentId); + state.SetState("agentId", currentAgentId); return agent; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index dc9d417a9..7bf27a44b 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -1,5 +1,4 @@ using BotSharp.Abstraction.Agents.Models; -using Microsoft.Extensions.Logging; using System.IO; namespace BotSharp.Core.Agents.Services; @@ -26,7 +25,7 @@ public async Task GetAgent(string id) var profile = query.FirstOrDefault(); var dir = GetAgentDataDir(id); - var instructionFile = Path.Combine(dir, "instruction.txt"); + var instructionFile = Path.Combine(dir, $"instruction.{_settings.TemplateFormat}"); if (File.Exists(instructionFile)) { profile.Instruction = File.ReadAllText(instructionFile); @@ -36,7 +35,7 @@ public async Task GetAgent(string id) _logger.LogError($"Can't find instruction file from {instructionFile}"); } - var samplesFile = Path.Combine(dir, "samples.txt"); + var samplesFile = Path.Combine(dir, $"samples.{_settings.TemplateFormat}"); if (File.Exists(samplesFile)) { profile.Samples = File.ReadAllText(samplesFile); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 09c463eed..f3b91e3ed 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -23,8 +23,7 @@ public async Task LoadAgent(string id) if (!string.IsNullOrEmpty(agent.Instruction)) { - var instruction = agent.Instruction; - hook.OnInstructionLoaded(ref instruction); + hook.OnInstructionLoaded(agent.Instruction, new Dictionary()); } if (!string.IsNullOrEmpty(agent.Functions)) diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index 4f21e5b78..c3a188fd1 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -75,6 +75,7 @@ + diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs index e9dec02b9..8a26a569b 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationController.cs @@ -47,14 +47,16 @@ public async Task SendMessage([FromRoute] string agentId, var conv = _services.GetRequiredService(); var response = new MessageResponseModel(); + var stackMsg = new List(); await conv.SendMessage(agentId, conversationId, new RoleDialogModel("user", input.Text), async msg => - response.Text = msg.Content, + stackMsg.Add(msg), async fn => await Task.CompletedTask); + response.Text = string.Join("\r\n", stackMsg.Select(x => x.Content)); return response; } } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 12b6fed79..78516b222 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -73,15 +73,10 @@ public async Task NewConversation(Conversation sess) } public async Task SendMessage(string agentId, string conversationId, - RoleDialogModel lastDalog, + RoleDialogModel lastDialog, Func onMessageReceived, Func onFunctionExecuting) { - lastDalog.CurrentAgentId = agentId; - _storage.Append(conversationId, lastDalog); - - var wholeDialogs = GetDialogHistory(conversationId); - var converation = await GetConversation(conversationId); // Create conversation if this conversation not exists @@ -103,6 +98,11 @@ public async Task SendMessage(string agentId, string conversationId, var router = _services.GetRequiredService(); var agent = await router.LoadCurrentAgent(); + lastDialog.CurrentAgentId = agent.Id; + _storage.Append(conversationId, agent, lastDialog); + + var wholeDialogs = GetDialogHistory(conversationId); + // Get relevant domain knowledge /*if (_settings.EnableKnowledgeBase) { @@ -127,100 +127,81 @@ public async Task SendMessage(string agentId, string conversationId, } var chatCompletion = GetChatCompletion(); - var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg => - { - await HandleMessage(conversationId, agent, msg, onMessageReceived, onFunctionExecuting); - - if (msg.NeedReloadAgent) - { - await HandleMessageIfAgentReloaded(conversationId, agent, msg, wholeDialogs, onMessageReceived, onFunctionExecuting); - } - }); + var result = await GetChatCompletionsAsyncRecursively(chatCompletion, + conversationId, + agent, + wholeDialogs, + onMessageReceived, + onFunctionExecuting); return result; } - private async Task HandleMessage(string conversationId, Agent agent, RoleDialogModel msg, + private async Task GetChatCompletionsAsyncRecursively(IChatCompletion chatCompletion, + string conversationId, + Agent agent, + List wholeDialogs, Func onMessageReceived, Func onFunctionExecuting) { - if (msg.Role == "function") + var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg => { - // Save states - SaveStateByArgs(msg.FunctionArgs); - - // Call functions - await onFunctionExecuting(msg); - await CallFunctions(msg); + await HandleAssistantMessage(msg, onMessageReceived); // Add to dialog history - if (msg.ExecutionResult != null) - { - if (msg.NeedReloadAgent) - { - _logger.LogInformation($"Skipped append dialog log: {msg.FunctionName}\n{msg.FunctionArgs}\n{msg.ExecutionResult}"); - return; - } - - _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.Content) - { - CurrentAgentId = agent.Id, - FunctionName = msg.FunctionName, - FunctionArgs = msg.FunctionArgs, - ExecutionResult = msg.ExecutionResult - }); - } - } - else + _storage.Append(conversationId, agent, msg); + }, async fn => { - // Add to dialog history - _storage.Append(conversationId, new RoleDialogModel(msg.Role, msg.Content) - { - CurrentAgentId = agent.Id - }); + var preAgentId = agent.Id; - var hooks = _services.GetServices().ToList(); - // After chat completion hook - foreach (var hook in hooks) + await HandleFunctionMessage(fn, onFunctionExecuting); + + // Agent has been transferred + if (fn.CurrentAgentId != preAgentId) { - await hook.AfterCompletion(msg); + var agentService = _services.GetRequiredService(); + agent = await agentService.LoadAgent(fn.CurrentAgentId); + + // Set state to make next conversation will go to this agent directly + var state = _services.GetRequiredService(); + state.SetState("agentId", fn.CurrentAgentId); } - await onMessageReceived(msg); - } + fn.Content = fn.ExecutionResult; + + // Add to dialog history + _storage.Append(conversationId, agent, fn); + + // After function is executed, pass the result to LLM to get a natural response + wholeDialogs.Add(fn); + + await GetChatCompletionsAsyncRecursively(chatCompletion, conversationId, agent, wholeDialogs, onMessageReceived, onFunctionExecuting); + }); + + return result; } - private async Task HandleMessageIfAgentReloaded(string conversationId, Agent agent, - RoleDialogModel msg, - List wholeDialogs, - Func onMessageReceived, - Func onFunctionExecuting) + private async Task HandleAssistantMessage(RoleDialogModel msg, Func onMessageReceived) { - var state = _services.GetRequiredService(); - var currentAgentId = state.GetState("agentId"); - - // Send to LLM to get final response when agent is switched. - var conv = _services.GetRequiredService(); - var chatCompletion = conv.GetChatCompletion(); - var agentService = _services.GetRequiredService(); - var newAgent = await agentService.LoadAgent(currentAgentId); - await chatCompletion.GetChatCompletionsAsync(newAgent, wholeDialogs, async newMsg => + var hooks = _services.GetServices().ToList(); + + // After chat completion hook + foreach (var hook in hooks) { - if (newMsg.Role == AgentRole.Function) - { - await HandleMessage(conversationId, agent, newMsg, onMessageReceived, onFunctionExecuting); - } - else - { - msg.StopPropagate = true; - await onMessageReceived(newMsg); + await hook.AfterCompletion(msg); + } - _storage.Append(conversationId, new RoleDialogModel(newMsg.Role, newMsg.Content) - { - CurrentAgentId = agent.Id - }); - } - }); + await onMessageReceived(msg); + } + + private async Task HandleFunctionMessage(RoleDialogModel msg, Func onFunctionExecuting) + { + // Save states + SaveStateByArgs(msg.FunctionArgs); + + // Call functions + await onFunctionExecuting(msg); + await CallFunctions(msg); } private void SaveStateByArgs(string args) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 0d2d249e9..380971060 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Enums; +using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; using System.IO; @@ -12,7 +13,7 @@ public ConversationStorage(MyDatabaseSettings dbSettings) _dbSettings = dbSettings; } - public void Append(string conversationId, RoleDialogModel dialog) + public void Append(string conversationId, Agent agent, RoleDialogModel dialog) { var conversationFile = GetStorageFile(conversationId); var sb = new StringBuilder(); @@ -21,7 +22,7 @@ public void Append(string conversationId, RoleDialogModel dialog) { var args = dialog.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim(); - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{dialog.CurrentAgentId}|{dialog.FunctionName}|{args}"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agent.Name}|{dialog.FunctionName}|{args}"); var content = dialog.ExecutionResult.Replace("\r", " ").Replace("\n", " ").Trim(); if (string.IsNullOrEmpty(content)) @@ -32,7 +33,7 @@ public void Append(string conversationId, RoleDialogModel dialog) } else if (dialog.Role == AgentRole.Assistant) { - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|||"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agent.Name}||"); var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); if (string.IsNullOrEmpty(content)) { @@ -42,7 +43,7 @@ public void Append(string conversationId, RoleDialogModel dialog) } else { - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{dialog.CurrentAgentId}||"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agent.Name}||"); var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); if (string.IsNullOrEmpty(content)) { diff --git a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs index 20d678202..75e845ac5 100644 --- a/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs +++ b/src/Infrastructure/BotSharp.Core/Plugins/LLamaSharp/ChatCompletionProvider.cs @@ -19,7 +19,10 @@ public string GetChatCompletions(Agent agent, List conversation throw new NotImplementedException(); } - public async Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived) + public async Task GetChatCompletionsAsync(Agent agent, + List conversations, + Func onMessageReceived, + Func onFunctionExecuting) { var content = string.Join("\n", conversations.Select(x => $"{x.Role}: {x.Content.Replace("user:", "User:")}")).Trim(); content += "\nBob: "; diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index f71475e34..111a54120 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -1,5 +1,6 @@ using Azure; using Azure.AI.OpenAI; +using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Functions.Models; @@ -31,36 +32,6 @@ private OpenAIClient GetClient() return client; } - /*public string GetChatCompletions(Agent agent, List conversations, Func onMessageReceived) - { - var client = GetClient(); - var chatCompletionsOptions = PrepareOptions(agent, conversations); - - var response = client.GetChatCompletions(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions); - var choice = response.Value.Choices[0]; - var message = choice.Message; - - if (choice.FinishReason == CompletionsFinishReason.FunctionCall) - { - response = HandleFunctionCall(message, - onMessageReceived, - chatCompletionsOptions).Result; - } - - choice = response.Value.Choices[0]; - message = choice.Message; - - _logger.LogInformation(message.Content); - - if (!string.IsNullOrEmpty(message.Content)) - { - onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content)) - .Wait(); - } - - return message.Content.Trim(); - }*/ - public List GetChatSamples(string sampleText) { var samples = new List(); @@ -107,7 +78,10 @@ public List GetFunctions(string functionsJson) return functions; } - public async Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived) + public async Task GetChatCompletionsAsync(Agent agent, + List conversations, + Func onMessageReceived, + Func onFunctionExecuting) { var client = GetClient(); var chatCompletionsOptions = PrepareOptions(agent, conversations); @@ -118,24 +92,29 @@ public async Task GetChatCompletionsAsync(Agent agent, List {message.FunctionCall.Arguments}"); - if (response != null) - { - choice = response.Value.Choices[0]; - message = choice.Message; + var funcContextIn = new RoleDialogModel(AgentRole.Function, message.Content) + { + CurrentAgentId = agent.Id, + FunctionName = message.FunctionCall.Name, + FunctionArgs = message.FunctionCall.Arguments + }; - _logger.LogInformation(message.Content); + // Execute functions + await onFunctionExecuting(funcContextIn); + } + else + { + _logger.LogInformation($"[{agent.Name}] {message.Role}: {message.Content}"); - if (!string.IsNullOrEmpty(message.Content)) + var msg = new RoleDialogModel(AgentRole.Assistant, message.Content) { - var msgByLlm = new RoleDialogModel(ChatRole.Assistant.ToString(), message.Content); - await onMessageReceived(msgByLlm); - } + CurrentAgentId= agent.Id + }; + + // Text response received + await onMessageReceived(msg); } return true; @@ -185,56 +164,6 @@ public async Task GetChatCompletionsStreamingAsync(Agent agent, List> HandleFunctionCall(Agent agent, - ChatMessage message, - Func onMessageReceived, - ChatCompletionsOptions chatCompletionsOptions) - { - Response response = default; - - if (message.FunctionCall == null || message.FunctionCall.Arguments == null) - { - return response; - } - - _logger.LogInformation($"{message.FunctionCall.Name}: {message.FunctionCall.Arguments}"); - var funcContextIn = new RoleDialogModel(ChatRole.Function.ToString(), message.Content) - { - CurrentAgentId = agent.Id, - FunctionName = message.FunctionCall.Name, - FunctionArgs = message.FunctionCall.Arguments - }; - - // Execute functions - await onMessageReceived(funcContextIn); - - if (funcContextIn.StopPropagate) - { - return response; - } - - if (funcContextIn.IsConversationEnd) - { - await onMessageReceived(new RoleDialogModel(ChatRole.Assistant.ToString(), funcContextIn.Content) - { - IsConversationEnd = true - }); - return response; - } - - // After function is executed, pass the result to LLM - if (funcContextIn.ExecutionResult != null) - { - chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, funcContextIn.ExecutionResult) - { - Name = funcContextIn.FunctionName - }); - var client = GetClient(); - response = client.GetChatCompletions(_settings.DeploymentModel.ChatCompletionModel, chatCompletionsOptions); - } - - return response; - } private ChatCompletionsOptions PrepareOptions(Agent agent, List conversations) { diff --git a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/fastTextEmbeddingProvider.cs b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/fastTextEmbeddingProvider.cs index f1141a560..d6e1824df 100644 --- a/src/Plugins/BotSharp.Plugin.MetaAI/Providers/fastTextEmbeddingProvider.cs +++ b/src/Plugins/BotSharp.Plugin.MetaAI/Providers/fastTextEmbeddingProvider.cs @@ -26,26 +26,18 @@ public int Dimension public fastTextEmbeddingProvider(fastTextSetting settings) { _settings = settings; - _fastText = new FastTextWrapper(); - if (!File.Exists(settings.ModelPath)) - { - throw new FileNotFoundException($"Can't load pre-trained word vectors from {settings.ModelPath}.\n Try to download from https://fasttext.cc/docs/en/english-vectors.html."); - } } public float[] GetVector(string text) { - if (!_fastText.IsModelReady()) - { - _fastText.LoadModel(_settings.ModelPath); - } - + LoadModel(); return _fastText.GetSentenceVector(text); } public List GetVectors(List texts) { + LoadModel(); var vectors = new List(); for (int i = 0; i < texts.Count; i++) { @@ -53,4 +45,22 @@ public List GetVectors(List texts) } return vectors; } + + private void LoadModel() + { + if (_fastText == null) + { + if (!File.Exists(_settings.ModelPath)) + { + throw new FileNotFoundException($"Can't load pre-trained word vectors from {_settings.ModelPath}.\n Try to download from https://fasttext.cc/docs/en/english-vectors.html."); + } + + _fastText = new FastTextWrapper(); + + if (!_fastText.IsModelReady()) + { + _fastText.LoadModel(_settings.ModelPath); + } + } + } } diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 61b34f0b5..606ec0b26 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -14,7 +14,9 @@ }, "Agent": { - "DataDir": "agents" + "RouterId": "", + "DataDir": "agents", + "TemplateFormat": "liquid" }, "Conversation": {