diff --git a/BotSharp.sln b/BotSharp.sln index c5ce697a..bf96d2a9 100644 --- a/BotSharp.sln +++ b/BotSharp.sln @@ -55,7 +55,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.RoutingSpee EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RAGs", "RAGs", "{4F346DCE-087F-4368-AF88-EE9C720D0E69}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.KnowledgeBase", "src\Plugins\BotSharp.Plugin.KnowledgeBase\BotSharp.Plugin.KnowledgeBase.csproj", "{298AC787-A104-414C-B114-82BE764FBD9C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.KnowledgeBase", "src\Plugins\BotSharp.Plugin.KnowledgeBase\BotSharp.Plugin.KnowledgeBase.csproj", "{298AC787-A104-414C-B114-82BE764FBD9C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DataStorages", "DataStorages", "{5CD330E1-9E5A-4112-8346-6E31CA98EF78}" EndProject @@ -205,6 +205,14 @@ Global {298AC787-A104-414C-B114-82BE764FBD9C}.Release|Any CPU.Build.0 = Release|Any CPU {298AC787-A104-414C-B114-82BE764FBD9C}.Release|x64.ActiveCfg = Release|Any CPU {298AC787-A104-414C-B114-82BE764FBD9C}.Release|x64.Build.0 = Release|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x64.ActiveCfg = Debug|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Debug|x64.Build.0 = Debug|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|Any CPU.Build.0 = Release|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x64.ActiveCfg = Release|Any CPU + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -233,6 +241,7 @@ Global {631D9C12-86C4-44F0-99C3-D32C0754BF37} = {51AFE054-AE99-497D-A593-69BAEFB5106F} {4F346DCE-087F-4368-AF88-EE9C720D0E69} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C} {298AC787-A104-414C-B114-82BE764FBD9C} = {4F346DCE-087F-4368-AF88-EE9C720D0E69} + {DB3DE37B-1208-4ED3-9615-A52AD0AAD69C} = {5CD330E1-9E5A-4112-8346-6E31CA98EF78} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19} diff --git a/Directory.Build.props b/Directory.Build.props index f25af14c..de3640e4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ 10.0 ..\..\..\packages - 0.11.0 + 0.12.0 true \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs index 1805bbe0..5f7066d2 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationStorage.cs @@ -3,6 +3,6 @@ namespace BotSharp.Abstraction.Conversations; public interface IConversationStorage { void InitStorage(string conversationId); - void Append(string conversationId, string agentId, RoleDialogModel dialog); + void Append(string conversationId, RoleDialogModel dialog); List GetDialogs(string conversationId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 8daa7b48..8ce4f486 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -26,7 +26,7 @@ public interface IBotSharpRepository void DeleteRoutingProfiles(); Agent GetAgent(string agentId); - List GetAgentResponses(string agentId); + List GetAgentResponses(string agentId, string prefix, string intent); void CreateNewConversation(Conversation conversation); string GetConversationDialog(string conversationId); diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs index 5786b73f..e0b3f9a1 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs @@ -11,8 +11,8 @@ public class RetrievalArgs : RoutingArgs [JsonPropertyName("answer")] public string Answer { get; set; } - [JsonPropertyName("response")] - public string Response { get; set; } + [JsonPropertyName("reason")] + public string Reason { get; set; } [JsonPropertyName("args")] public JsonDocument Arguments { get; set; } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs index d1f10e03..ee305239 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs @@ -29,26 +29,18 @@ public partial class ConversationService text = latestResponse.Content.Split("=>").Last(); } - var msg = new RoleDialogModel(AgentRole.Assistant, text) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, text) { CurrentAgentId = agent.Id, Channel = wholeDialogs.Last().Channel - }; - - await HandleAssistantMessage(msg, onMessageReceived); - - // Add to dialog history - _storage.Append(_conversationId, agent.Id, msg); + }, onMessageReceived); return false; } var result = await chatCompletion.GetChatCompletionsAsync(agent, wholeDialogs, async msg => { - await HandleAssistantMessage(msg, onMessageReceived); - - // Add to dialog history - _storage.Append(_conversationId, agent.Id, msg); + await HandleAssistantMessage(agent, msg, onMessageReceived); }, async fn => { var preAgentId = agent.Id; @@ -58,26 +50,24 @@ public partial class ConversationService // Function executed has exception if (fn.ExecutionResult == null) { - await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, fn.Content) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, fn.Content) { CurrentAgentId = fn.CurrentAgentId, Channel = fn.Channel }, onMessageReceived); + return; } else if (fn.StopCompletion) { - var message = new RoleDialogModel(AgentRole.Assistant, fn.Content) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, fn.Content) { CurrentAgentId = fn.CurrentAgentId, Channel = fn.Channel, ExecutionData = fn.ExecutionData, ExecutionResult = fn.ExecutionResult - }; + }, onMessageReceived); - await HandleAssistantMessage(message, onMessageReceived); - - _storage.Append(_conversationId, agent.Id, message); return; } @@ -104,7 +94,7 @@ public partial class ConversationService var response = await templateService.RenderFunctionResponse(agent.Id, fn); if (!string.IsNullOrEmpty(response)) { - await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, response) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, response) { CurrentAgentId = agent.Id, Channel = wholeDialogs.Last().Channel @@ -131,17 +121,22 @@ public partial class ConversationService return result; } - private async Task HandleAssistantMessage(RoleDialogModel msg, Func onMessageReceived) + private async Task HandleAssistantMessage(Agent agent, RoleDialogModel message, Func onMessageReceived) { var hooks = _services.GetServices().ToList(); // After chat completion hook foreach (var hook in hooks) { - await hook.AfterCompletion(msg); + await hook.AfterCompletion(message); } - await onMessageReceived(msg); + _logger.LogInformation($"[{agent.Name}] {message.Role}: {message.Content}"); + + await onMessageReceived(message); + + // Add to dialog history + _storage.Append(_conversationId, message); } private async Task HandleFunctionMessage(RoleDialogModel msg, diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index b8fd9b10..7ba6234c 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -25,7 +25,7 @@ public partial class ConversationService var wholeDialogs = GetDialogHistory(); wholeDialogs.Add(lastDialog); - _storage.Append(_conversationId, agent.Id, lastDialog); + _storage.Append(_conversationId, lastDialog); var hooks = _services.GetServices().ToList(); @@ -43,7 +43,7 @@ public partial class ConversationService { var response = new RoleDialogModel(AgentRole.Assistant, lastDialog.Content); await onMessageReceived(response); - _storage.Append(_conversationId, agent.Id, response); + _storage.Append(_conversationId, response); return true; } } @@ -57,20 +57,22 @@ public partial class ConversationService if (reasonedContext.FunctionName == "interrupt_task_execution") { - await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, reasonedContext.Content) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, reasonedContext.Content) { CurrentAgentId = agent.Id, Channel = lastDialog.Channel }, onMessageReceived); + return true; } else if (reasonedContext.FunctionName == "response_to_user") { - await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, reasonedContext.Content) + await HandleAssistantMessage(agent, new RoleDialogModel(AgentRole.Assistant, reasonedContext.Content) { CurrentAgentId = agent.Id, Channel = lastDialog.Channel }, onMessageReceived); + return true; } else if (reasonedContext.FunctionName == "continue_execute_task") @@ -86,7 +88,7 @@ public partial class ConversationService wholeDialogs.Add(x); if (x.Content != null) { - _storage.Append(_conversationId, agent.Id, x); + _storage.Append(_conversationId, x); } }); } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 32be3594..ee7d09ec 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -22,8 +22,9 @@ public class ConversationStorage : IConversationStorage _user = user; } - public void Append(string conversationId, string agentId, RoleDialogModel dialog) + public void Append(string conversationId, RoleDialogModel dialog) { + var agentId = dialog.CurrentAgentId; var db = _services.GetRequiredService(); var dialogText = db.GetConversationDialog(conversationId); var sb = new StringBuilder(dialogText); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 66b75ad5..1804a787 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -108,7 +108,7 @@ public class BotSharpDbContext : Database, IBotSharpRepository throw new NotImplementedException(); } - public List GetAgentResponses(string agentId) + public List GetAgentResponses(string agentId, string prefix, string intent) { throw new NotImplementedException(); } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index b52f7f52..53ed4780 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -338,7 +338,10 @@ public class FileRepository : IBotSharpRepository throw new NotImplementedException(); } - public List GetAgentResponses(string agentId) +#if !DEBUG + [MemoryCache(10 * 60)] +#endif + public List GetAgentResponses(string agentId, string prefix, string intent) { var responses = new List(); var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, "responses"); @@ -346,7 +349,12 @@ public class FileRepository : IBotSharpRepository foreach (var file in Directory.GetFiles(dir)) { - responses.Add(File.ReadAllText(file)); + if (file.Split(Path.DirectorySeparatorChar) + .Last() + .StartsWith(prefix + "." + intent)) + { + responses.Add(File.ReadAllText(file)); + } } return responses; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Simulator.cs b/src/Infrastructure/BotSharp.Core/Routing/Simulator.cs index 579a1a9a..60e52172 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Simulator.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Simulator.cs @@ -45,8 +45,8 @@ public class Simulator } else if (args.Function == "interrupt_task_execution") { - response.Content = args.Parameters.Response; - response.ExecutionResult = args.Parameters.Response; + response.Content = args.Parameters.Reason; + response.ExecutionResult = args.Parameters.Reason; } else if (args.Function == "response_to_user") { diff --git a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs index 4bdcb30a..583ccb2f 100644 --- a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs +++ b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs @@ -26,7 +26,7 @@ public class ResponseTemplateService : IResponseTemplateService // .ToList(); var db = _services.GetRequiredService(); - var responses = db.GetAgentResponses(agentId); + var responses = db.GetAgentResponses(agentId, "func", message.FunctionName); if (responses.Count == 0) { @@ -71,7 +71,7 @@ public class ResponseTemplateService : IResponseTemplateService // .ToList(); var db = _services.GetRequiredService(); - var responses = db.GetAgentResponses(agentId); + var responses = db.GetAgentResponses(agentId, "intent", message.IntentName); if (responses.Count == 0) { diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 8343690f..d00414cf 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -451,13 +451,14 @@ public class MongoRepository : IBotSharpRepository }).ToList(); } - public List GetAgentResponses(string agentId) + public List GetAgentResponses(string agentId, string prefix, string intent) { var responses = new List(); var agent = Agents.FirstOrDefault(x => x.Id == agentId); if (agent == null) return responses; - return agent.Responses; + // Should use name to filter by prefix + return agent.Responses.Where(x => x.StartsWith(prefix + "." + intent)).ToList(); } public Agent GetAgent(string agentId) diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs index 4b8c3bc5..b6c1c6f9 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs @@ -32,6 +32,11 @@ public class RoutingConversationHook: ConversationHookBase // Utilize local discriminative model to predict intent var predText = intentClassifier.Predict(vector); + if (string.IsNullOrEmpty(predText)) + { + return; + } + message.IntentName = predText; // Render by template diff --git a/src/WebStarter/Program.cs b/src/WebStarter/Program.cs index 71b1d637..1b8a0dc7 100644 --- a/src/WebStarter/Program.cs +++ b/src/WebStarter/Program.cs @@ -42,11 +42,6 @@ builder.Services.AddScoped(); // Add BotSharp builder.Services.AddBotSharp(builder.Configuration); -// Change below if you want to use other data storage. -// builder.Services.UsingSqlServer(builder.Configuration); -// Default is using File Storage -//builder.Services.UsingFileRepository(builder.Configuration); - builder.Services.AddCors(options => { options.AddPolicy("MyCorsPolicy", diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index a52e92a7..a3117468 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -86,15 +86,15 @@ "WeixinAppSecret": "#{WeixinAppSecret}#" }, - "KnowledgeBase": { - "VectorDb": "MemVectorDatabase", - // "VectorDb": "QdrantDb", - "TextEmbedding": "fastTextEmbeddingProvider", - // "TextEmbedding": "LLamaSharp.TextEmbeddingProvider", - "TextCompletion": "AzureOpenAI.Providers.TextCompletionProvider", - // "TextCompletion": "LLamaSharp.TextCompletionProvider", - "Pdf2TextConverter": "PaddleSharp.Providers.Pdf2TextConverter" - }, + "KnowledgeBase": { + "VectorDb": "MemVectorDatabase", + // "VectorDb": "QdrantDb", + "TextEmbedding": "fastTextEmbeddingProvider", + // "TextEmbedding": "LLamaSharp.TextEmbeddingProvider", + "TextCompletion": "AzureOpenAI.Providers.TextCompletionProvider", + // "TextCompletion": "LLamaSharp.TextCompletionProvider", + "Pdf2TextConverter": "PaddleSharp.Providers.Pdf2TextConverter" + }, "PluginLoader": { "Assemblies": [ diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs index 4852d4dd..86de63c8 100644 --- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs +++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaPricesFn.cs @@ -10,7 +10,7 @@ public class GetPizzaPricesFn : IFunctionCallback { message.ExecutionData = new { - cheese = "3.5" + cheese_unit_price = "$3.5" }; message.ExecutionResult = "Pepperoni Pizza: $3.5/slice, Cheese Pizza: $2.5/slice, Margherita Pizza: $3.0/slice"; return true;