From c67d0cc68ff27020e8208d9c8dd44033caa35669 Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Thu, 22 Feb 2024 19:53:00 -0600 Subject: [PATCH] Add hook of OnConversationRouting. --- .../Conversations/ConversationHookBase.cs | 57 ++++++------------- .../Conversations/IConversationHook.cs | 10 ++++ .../Routing/Functions/RouteToAgentFn.cs | 2 +- .../BotSharp.Core/Routing/RoutingService.cs | 6 ++ .../Hooks/StreamingLogHook.cs | 53 +++++++---------- 5 files changed, 57 insertions(+), 71 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index cd45a39e..569ac4e1 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Functions.Models; + namespace BotSharp.Abstraction.Conversations; public abstract class ConversationHookBase : IConversationHook @@ -27,19 +29,13 @@ public abstract class ConversationHookBase : IConversationHook } public virtual Task OnStateLoaded(ConversationState state) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnStateChanged(string name, string preValue, string currentValue) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnDialogRecordLoaded(RoleDialogModel dialog) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnDialogsLoaded(List dialogs) { @@ -48,52 +44,35 @@ public abstract class ConversationHookBase : IConversationHook } public virtual Task OnConversationEnding(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnCurrentTaskEnding(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnHumanInterventionNeeded(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnFunctionExecuting(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnFunctionExecuted(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnMessageReceived(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnResponseGenerated(RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnConversationInitialized(Conversation conversation) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnUserAgentConnectedInitially(Conversation conversation) - { - return Task.CompletedTask; - } + => Task.CompletedTask; public virtual Task OnConversationRedirected(string toAgentId, RoleDialogModel message) - { - return Task.CompletedTask; - } + => Task.CompletedTask; + + public virtual Task OnConversationRouting(FunctionCallFromLlm instruct, RoleDialogModel message) + => Task.CompletedTask; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs index 6056718d..68360bed 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs @@ -1,3 +1,5 @@ +using BotSharp.Abstraction.Functions.Models; + namespace BotSharp.Abstraction.Conversations; public interface IConversationHook @@ -90,4 +92,12 @@ public interface IConversationHook /// /// Task OnConversationRedirected(string toAgentId, RoleDialogModel message); + + /// + /// Routing instruction is received from Router + /// + /// routing instruction + /// message + /// + Task OnConversationRouting(FunctionCallFromLlm instruct, RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index c367d631..ee78fd1b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -156,7 +156,7 @@ public class RouteToAgentFn : IFunctionCallback var hooks = _services.GetServices(); foreach (var hook in hooks) { - hook.OnConversationRedirected(routingRule.RedirectTo, message); + hook.OnConversationRedirected(routingRule.RedirectTo, message).Wait(); } } else diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index 793793b4..d9c4e21b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -98,6 +98,12 @@ public partial class RoutingService : IRoutingService // Get instruction from Planner var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs); + var hooks = _services.GetServices(); + foreach (var hook in hooks) + { + await hook.OnConversationRouting(inst, message); + } + // Save states states.SaveStateByArgs(inst.Arguments); diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 0f802b07..27cff56d 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -5,7 +5,6 @@ using BotSharp.Abstraction.Loggers.Enums; using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Repositories; using Microsoft.AspNetCore.SignalR; -using Serilog; namespace BotSharp.Plugin.ChatHub.Hooks; @@ -17,24 +16,28 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook private readonly IHubContext _chatHub; private readonly IConversationStateService _state; private readonly IUserIdentity _user; + private readonly IAgentService _agentService; public StreamingLogHook( ConversationSetting convSettings, IServiceProvider serivces, IHubContext chatHub, IConversationStateService state, - IUserIdentity user) + IUserIdentity user, + IAgentService agentService) { _convSettings = convSettings; _services = serivces; _chatHub = chatHub; _state = state; _user = user; + _agentService = agentService; _serializerOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - AllowTrailingCommas = true + AllowTrailingCommas = true, + WriteIndented = true }; } @@ -46,12 +49,20 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook BuildContentLog(conversationId, _user.UserName, log, ContentLogSource.UserInput, message)); } + public override async Task OnConversationRouting(FunctionCallFromLlm instruct, RoleDialogModel message) + { + var conversationId = _state.GetConversationId(); + var agent = await _agentService.LoadAgent(message.CurrentAgentId); + var log = JsonSerializer.Serialize(instruct, _serializerOptions); + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", + BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.AgentResponse, message)); + } + public override async Task OnConversationRedirected(string toAgentId, RoleDialogModel message) { - var agentService = _services.GetRequiredService(); var conversationId = _state.GetConversationId(); - var fromAgent = await agentService.LoadAgent(message.CurrentAgentId); - var toAgent = await agentService.LoadAgent(toAgentId); + var fromAgent = await _agentService.LoadAgent(message.CurrentAgentId); + var toAgent = await _agentService.LoadAgent(toAgentId); var log = $"{message.Content}\r\n=====\r\nREDIRECTED TO {toAgent.Name}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", @@ -71,10 +82,9 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook public override async Task OnFunctionExecuted(RoleDialogModel message) { - var agentService = _services.GetRequiredService(); var conversationId = _state.GetConversationId(); - var agent = await agentService.LoadAgent(message.CurrentAgentId); - var log = $"[{agent?.Name}]: {message.FunctionName}({message.FunctionArgs}) => {message.Content}"; + var agent = await _agentService.LoadAgent(message.CurrentAgentId); + var log = $"{message.FunctionName}({message.FunctionArgs})\r\n => {message.Content}"; log += $"\r\n<== MessageId: {message.MessageId}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, ContentLogSource.FunctionCall, message)); @@ -90,31 +100,14 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook { if (!_convSettings.ShowVerboseLog) return; - var agentService = _services.GetRequiredService(); var conversationId = _state.GetConversationId(); - var agent = await agentService.LoadAgent(message.CurrentAgentId); + var agent = await _agentService.LoadAgent(message.CurrentAgentId); var logSource = string.Empty; var log = tokenStats.Prompt; logSource = ContentLogSource.Prompt; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", BuildContentLog(conversationId, agent?.Name, log, logSource, message)); - - // Log routing output - try - { - var inst = message.Content.JsonContent(); - if (!string.IsNullOrEmpty(inst.Function)) - { - logSource = ContentLogSource.AgentResponse; - await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", - BuildContentLog(conversationId, agent?.Name, message.Content, logSource, message)); - } - } - catch - { - // ignore - } } /// @@ -125,14 +118,12 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook public override async Task OnResponseGenerated(RoleDialogModel message) { var conv = _services.GetRequiredService(); - var state = _services.GetRequiredService(); - await _chatHub.Clients.User(_user.Id).SendAsync("OnConversateStateLogGenerated", BuildStateLog(conv.ConversationId, state.GetStates(), message)); + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversateStateLogGenerated", BuildStateLog(conv.ConversationId, _state.GetStates(), message)); if (message.Role == AgentRole.Assistant) { - var agentService = _services.GetRequiredService(); - var agent = await agentService.LoadAgent(message.CurrentAgentId); + var agent = await _agentService.LoadAgent(message.CurrentAgentId); var log = $"{message.Content}"; if (message.RichContent != null && message.RichContent.Message.RichType != "text") {