diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationCompletionHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationCompletionHookBase.cs index edbea27f..ce735120 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationCompletionHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationCompletionHookBase.cs @@ -46,9 +46,9 @@ public abstract class ConversationCompletionHookBase : IConversationCompletionHo return Task.CompletedTask; } - public virtual async Task OnFunctionExecution(string name, string args) + public virtual Task OnFunctionExecuting(string name, string args) { - return "{}"; + return Task.CompletedTask; } public virtual Task AfterCompletion(RoleDialogModel message) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationCompletionHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationCompletionHook.cs index 333b40fc..fbd402fc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationCompletionHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationCompletionHook.cs @@ -18,6 +18,6 @@ public interface IConversationCompletionHook IConversationCompletionHook SetChatCompletion(IChatCompletion chatCompletion); Task BeforeCompletion(); - Task OnFunctionExecution(string name, string args); + Task OnFunctionExecuting(string name, string args); Task AfterCompletion(RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/IFunctionCallback.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/IFunctionCallback.cs new file mode 100644 index 00000000..5b9605c8 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/IFunctionCallback.cs @@ -0,0 +1,7 @@ +namespace BotSharp.Abstraction.Functions; + +public interface IFunctionCallback +{ + string Name { get; } + Task Execute(string args); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionDef.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs similarity index 83% rename from src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionDef.cs rename to src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs index 719f581d..75b98fbc 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionDef.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionDef.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace BotSharp.Abstraction.Conversations.Models; +namespace BotSharp.Abstraction.Functions.Models; public class FunctionDef { diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionResult.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionResult.cs similarity index 87% rename from src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionResult.cs rename to src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionResult.cs index dfb73a44..5cf77f75 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionResult.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace BotSharp.Abstraction.Conversations.Models; +namespace BotSharp.Abstraction.Functions.Models; public class FunctionExecutionResult where T : new() { diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionValidationResult.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionValidationResult.cs similarity index 85% rename from src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionValidationResult.cs rename to src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionValidationResult.cs index 34cbb28d..aa1db6f3 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/FunctionExecutionValidationResult.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionExecutionValidationResult.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace BotSharp.Abstraction.Conversations.Models; +namespace BotSharp.Abstraction.Functions.Models; public class FunctionExecutionValidationResult { @@ -9,7 +9,7 @@ public class FunctionExecutionValidationResult } - public FunctionExecutionValidationResult(string validationStatus, string validationMessage = "") + public FunctionExecutionValidationResult(string validationStatus, string? validationMessage = null) { ValidationStatus = validationStatus; ValidationMessage = validationMessage; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index e9cbee53..63b5e6c7 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -1,10 +1,7 @@ using BotSharp.Abstraction.Conversations.Models; -using BotSharp.Abstraction.Conversations.Settings; +using BotSharp.Abstraction.Functions; using BotSharp.Abstraction.Knowledges.Models; using BotSharp.Abstraction.MLTasks; -using MongoDB.Bson.IO; -using Newtonsoft.Json; -using System.Text.Json; namespace BotSharp.Core.Conversations.Services; @@ -80,18 +77,25 @@ public class ConversationService : IConversationService { if (msg.Role == "function") { - var result = msg.ExecutionResult.Replace("\r", " ").Replace("\n", " "); - var content = $"{result}"; - Console.WriteLine($"{msg.Role}: {content}"); - _storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content) + // Invoke functions + var functions = _services.GetServices().Where(x => x.Name == msg.FunctionName); + foreach (var fn in functions) { - FunctionName = msg.FunctionName, - }); + msg.ExecutionResult = await fn.Execute(msg.Content); + + var result = msg.ExecutionResult.Replace("\r", " ").Replace("\n", " "); + var content = $"{result}"; + // Console.WriteLine($"{msg.Role}: {content}"); + _storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content) + { + FunctionName = msg.FunctionName, + }); + } } else { var content = msg.Content.Replace("\r", " ").Replace("\n", " "); - Console.WriteLine($"{msg.Role}: {content}"); + // Console.WriteLine($"{msg.Role}: {content}"); _storage.Append(agentId, conversationId, new RoleDialogModel(msg.Role, content)); await onMessageReceived(msg); @@ -135,10 +139,10 @@ public class ConversationService : IConversationService { if (msg.Role == "function") { - // Execute functions + // Before executing functions foreach (var hook in hooks) { - msg.ExecutionResult = await hook.OnFunctionExecution(msg.FunctionName, msg.Content); + await hook.OnFunctionExecuting(msg.FunctionName, msg.Content); } } else diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index b3759e43..49cae228 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -2,6 +2,7 @@ using Azure; using Azure.AI.OpenAI; using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.MLTasks; using BotSharp.Plugin.AzureOpenAI.Settings; using System; @@ -108,10 +109,13 @@ public class ChatCompletionProvider : IChatCompletion FunctionName = message.FunctionCall.Name }; + // Execute functions await onMessageReceived(funcContextIn); // After function is executed, pass the result to LLM - chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, funcContextIn.ExecutionResult) + var fnResult = JsonSerializer.Deserialize>(funcContextIn.ExecutionResult); + var fnJsonResult = JsonSerializer.Serialize(fnResult.Result); + chatCompletionsOptions.Messages.Add(new ChatMessage(ChatRole.Function, fnJsonResult) { Name = funcContextIn.FunctionName }); diff --git a/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs b/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs index 98ba76f9..1b72e2f9 100644 --- a/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs +++ b/src/Plugins/BotSharp.Plugin.WeChat/WeChatBackgroundService.cs @@ -56,9 +56,10 @@ namespace BotSharp.Plugin.WeChat AgentId = AgentId }))?.Id; - var result = await conversationService.SendMessage(AgentId, latestConversationId, new RoleDialogModel("user", message)); - - await ReplyTextMessageAsync(openid, result); + var result = await conversationService.SendMessage(AgentId, latestConversationId, new RoleDialogModel("user", message), async msg => + { + await ReplyTextMessageAsync(openid, msg.Content); + }); } private async Task GetWeChatAccountUserAsync(string openId, IServiceProvider service)