diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index da87646e8..0a5244f89 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -49,10 +49,10 @@ public virtual Task OnTaskCompleted(RoleDialogModel message) public virtual Task OnHumanInterventionNeeded(RoleDialogModel message) => Task.CompletedTask; - public virtual Task OnFunctionExecuting(RoleDialogModel message) + public virtual Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual) => Task.CompletedTask; - public virtual Task OnFunctionExecuted(RoleDialogModel message) + public virtual Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual) => Task.CompletedTask; public virtual Task OnMessageReceived(RoleDialogModel message) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs index 6d967391c..d1b6f83c8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs @@ -59,15 +59,17 @@ public interface IConversationHook : IHookBase /// Triggered before LLM calls function. /// /// + /// /// - Task OnFunctionExecuting(RoleDialogModel message); + Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual); /// /// Triggered when the function calling completed. /// /// + /// /// - Task OnFunctionExecuted(RoleDialogModel message); + Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual); Task OnResponseGenerated(RoleDialogModel message); diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs new file mode 100644 index 000000000..b3460bb67 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs @@ -0,0 +1,19 @@ +namespace BotSharp.Abstraction.Routing.Enums; + +public static class InvokeSource +{ + /// + /// Invoke manually + /// + public const string Manual = "manual"; + + /// + /// Invoke by LLM directly + /// + public const string Llm = "llm"; + + /// + /// Invoke by agent routing + /// + public const string Routing = "routing"; +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index 97be88741..384a606f5 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -30,8 +30,8 @@ public interface IRoutingService //int GetRecursiveCounter(); //void SetRecursiveCounter(int counter); - Task InvokeAgent(string agentId, List dialogs); - Task InvokeFunction(string name, RoleDialogModel messages); + Task InvokeAgent(string agentId, List dialogs, string from = InvokeSource.Manual); + Task InvokeFunction(string name, RoleDialogModel messages, string from = InvokeSource.Manual); Task InstructLoop(Agent agent, RoleDialogModel message, List dialogs); /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Using.cs b/src/Infrastructure/BotSharp.Abstraction/Using.cs index 8a9d30cb6..38a6dca00 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Using.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Using.cs @@ -12,6 +12,7 @@ global using BotSharp.Abstraction.Infrastructures.Enums; global using BotSharp.Abstraction.Models; global using BotSharp.Abstraction.Routing.Models; +global using BotSharp.Abstraction.Routing.Enums; global using BotSharp.Abstraction.Templating; global using BotSharp.Abstraction.Translation.Attributes; global using BotSharp.Abstraction.Messaging.Enums; diff --git a/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs b/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs index 4eb4c64e9..095ff2b8f 100644 --- a/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs +++ b/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Routing.Enums; using BotSharp.Abstraction.Utilities; namespace BotSharp.Core.Realtime.Hooks; @@ -10,7 +11,7 @@ public RealtimeConversationHook(IServiceProvider services) _services = services; } - public async Task OnFunctionExecuting(RoleDialogModel message) + public async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual) { var hub = _services.GetRequiredService(); if (hub.HubConn == null) @@ -31,10 +32,10 @@ public async Task OnFunctionExecuting(RoleDialogModel message) } } - public async Task OnFunctionExecuted(RoleDialogModel message) + public async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual) { var hub = _services.GetRequiredService(); - if (hub.HubConn == null) + if (from != InvokeSource.Llm || hub.HubConn == null) { return; } diff --git a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs index 32b0a1127..fe544b4d2 100644 --- a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs +++ b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs @@ -2,6 +2,7 @@ using BotSharp.Abstraction.Hooks; using BotSharp.Abstraction.Models; using BotSharp.Abstraction.Options; +using BotSharp.Abstraction.Routing.Enums; using BotSharp.Core.Infrastructures; namespace BotSharp.Core.Realtime.Services; @@ -98,7 +99,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti agent.Id); } - await routing.InvokeFunction(message.FunctionName, message); + await routing.InvokeFunction(message.FunctionName, message, from: InvokeSource.Llm); } else { diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index a28ccbc78..1155dc38e 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -2,7 +2,6 @@ using BotSharp.Abstraction.Infrastructures.Enums; using BotSharp.Abstraction.Messaging; using BotSharp.Abstraction.Messaging.Models.RichContent; -using BotSharp.Abstraction.Routing.Enums; using BotSharp.Abstraction.Routing.Settings; namespace BotSharp.Core.Conversations.Services; diff --git a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs index b315b6830..b1b4541e6 100644 --- a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs +++ b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs @@ -22,13 +22,13 @@ public override Task OnMessageReceived(RoleDialogModel message) return base.OnMessageReceived(message); } - public override Task OnFunctionExecuted(RoleDialogModel message) + public override Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual) { if (Conversation != null && _convSettings.EnableExecutionLog) { _logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.FunctionName}({message.FunctionArgs}) => {message.Content}"); } - return base.OnFunctionExecuted(message); + return base.OnFunctionExecuted(message, from: from); } public override Task OnResponseGenerated(RoleDialogModel message) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs index c93e133ce..308064518 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs @@ -33,7 +33,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti if (message.FunctionName != null) { var msg = RoleDialogModel.From(message, role: AgentRole.Function); - await routing.InvokeFunction(message.FunctionName, msg); + await routing.InvokeFunction(message.FunctionName, msg, from: InvokeSource.Llm); } var agentId = routing.Context.GetCurrentAgentId(); @@ -57,7 +57,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti } else { - var ret = await routing.InvokeAgent(agentId, dialogs); + var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing); } var response = dialogs.Last(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs index 7bfd93523..8e625a364 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs @@ -4,7 +4,7 @@ namespace BotSharp.Core.Routing; public partial class RoutingService { - public async Task InvokeAgent(string agentId, List dialogs) + public async Task InvokeAgent(string agentId, List dialogs, string from = InvokeSource.Manual) { var agentService = _services.GetRequiredService(); var agent = await agentService.LoadAgent(agentId); @@ -46,7 +46,7 @@ public async Task InvokeAgent(string agentId, List dialog message.Indication = response.Indication; message.CurrentAgentId = agent.Id; - await InvokeFunction(message, dialogs); + await InvokeFunction(message, dialogs, from: from); } else { @@ -66,7 +66,7 @@ public async Task InvokeAgent(string agentId, List dialog return true; } - private async Task InvokeFunction(RoleDialogModel message, List dialogs) + private async Task InvokeFunction(RoleDialogModel message, List dialogs, string from) { // execute function // Save states @@ -75,7 +75,7 @@ private async Task InvokeFunction(RoleDialogModel message, List(); // Call functions - await routing.InvokeFunction(message.FunctionName, message); + await routing.InvokeFunction(message.FunctionName, message, from: from); // Pass execution result to LLM to get response if (!message.StopCompletion) @@ -102,7 +102,7 @@ private async Task InvokeFunction(RoleDialogModel message, List InvokeFunction(string name, RoleDialogModel message) + public async Task InvokeFunction(string name, RoleDialogModel message, string from = InvokeSource.Manual) { var currentAgentId = message.CurrentAgentId; var agentService = _services.GetRequiredService(); @@ -36,7 +36,7 @@ public async Task InvokeFunction(string name, RoleDialogModel message) foreach (var hook in hooks) { hook.SetAgent(agent); - await hook.OnFunctionExecuting(clonedMessage); + await hook.OnFunctionExecuting(clonedMessage, from: from); } bool result = false; @@ -48,7 +48,7 @@ public async Task InvokeFunction(string name, RoleDialogModel message) // After functions have been executed foreach (var hook in hooks) { - await hook.OnFunctionExecuted(clonedMessage); + await hook.OnFunctionExecuted(clonedMessage, from: from); } // Set result to original message diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index 3e45fd63f..262c30016 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -51,7 +51,7 @@ public async Task InstructDirect(Agent agent, RoleDialogModel m } else { - var ret = await routing.InvokeAgent(agentId, dialogs); + var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing); } var response = dialogs.Last(); diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs index aa5a45953..0e8e27622 100644 --- a/src/Infrastructure/BotSharp.Core/Using.cs +++ b/src/Infrastructure/BotSharp.Core/Using.cs @@ -22,6 +22,7 @@ global using BotSharp.Abstraction.Repositories.Filters; global using BotSharp.Abstraction.Roles; global using BotSharp.Abstraction.Roles.Models; +global using BotSharp.Abstraction.Routing.Enums; global using BotSharp.Abstraction.Routing; global using BotSharp.Abstraction.SideCar.Attributes; global using BotSharp.Abstraction.Statistics.Enums; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs index f8851cb3d..61ae77a7f 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Enums; namespace BotSharp.OpenAPI.Controllers; @@ -25,7 +26,7 @@ public async Task ExecuteFunction(string agentId, string functionName, [ FunctionName = functionName, FunctionArgs = JsonSerializer.Serialize(args) }; - await routing.InvokeFunction(functionName, message); + await routing.InvokeFunction(functionName, message, from: InvokeSource.Llm); return message.Content; } } diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index 3c7a675d4..74735bd86 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Conversations.Dtos; +using BotSharp.Abstraction.Routing.Enums; using BotSharp.Abstraction.SideCar; using BotSharp.Abstraction.Users.Dtos; using Microsoft.AspNetCore.SignalR; @@ -84,7 +85,7 @@ public override async Task OnMessageReceived(RoleDialogModel message) await base.OnMessageReceived(message); } - public override async Task OnFunctionExecuting(RoleDialogModel message) + public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual) { var conv = _services.GetRequiredService(); var action = new ConversationSenderActionModel @@ -95,7 +96,7 @@ public override async Task OnFunctionExecuting(RoleDialogModel message) }; await GenerateSenderAction(conv.ConversationId, action); - await base.OnFunctionExecuting(message); + await base.OnFunctionExecuting(message, from: from); } public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg) diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 720f3fd0a..991a64e50 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Routing.Enums; using Microsoft.AspNetCore.SignalR; using System.Text.Encodings.Web; using System.Text.Unicode; @@ -141,7 +142,7 @@ public async Task BeforeGenerating(Agent agent, List conversati if (!_convSettings.ShowVerboseLog) return; } - public override async Task OnFunctionExecuting(RoleDialogModel message) + public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual) { var conversationId = _state.GetConversationId(); if (string.IsNullOrEmpty(conversationId)) return; @@ -164,7 +165,7 @@ public override async Task OnFunctionExecuting(RoleDialogModel message) await SendContentLog(conversationId, input); } - public override async Task OnFunctionExecuted(RoleDialogModel message) + public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual) { var conversationId = _state.GetConversationId(); if (string.IsNullOrEmpty(conversationId)) return; diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs b/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs index bc6471407..11bd8d36c 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs @@ -1,9 +1,10 @@ +using BotSharp.Abstraction.Hooks; using BotSharp.Abstraction.Routing; -using Task = System.Threading.Tasks.Task; -using Twilio.Rest.Api.V2010.Account; +using BotSharp.Abstraction.Routing.Enums; using BotSharp.Plugin.Twilio.Interfaces; using BotSharp.Plugin.Twilio.Models; -using BotSharp.Abstraction.Hooks; +using Twilio.Rest.Api.V2010.Account; +using Task = System.Threading.Tasks.Task; namespace BotSharp.Plugin.Twilio.Hooks; @@ -22,7 +23,7 @@ public TwilioConversationHook(IServiceProvider services, _logger = logger; } - public override async Task OnFunctionExecuted(RoleDialogModel message) + public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual) { var hooks = _services.GetHooks(message.CurrentAgentId);