From a0bf65698f0ecfb6ae12e35e7bc7c0dc17a088b2 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Tue, 27 Feb 2024 21:15:21 -0600 Subject: [PATCH 1/4] Add required flag. --- .../Handlers/RouteToAgentRoutingHandler.cs | 15 ++++++++++++--- .../Routing/RoutingService.InvokeFunction.cs | 1 + .../instruction.liquid | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs index 0e1cce587..2404e896e 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs @@ -14,9 +14,18 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler public List Parameters => new List { - new ParameterPropertyDef("reason", "why route to agent"), - new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response"), - new ParameterPropertyDef("user_goal_agent", "agent who can achieve user original goal"), + new ParameterPropertyDef("reason", "why route to agent") + { + Required = true + }, + new ParameterPropertyDef("next_action_agent", "agent for next action based on user latest response") + { + Required = true + }, + new ParameterPropertyDef("user_goal_agent", "agent who can achieve user original goal") + { + Required = true + }, new ParameterPropertyDef("args", "useful parameters of next action agent, format: { }") { Type = "object" diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs index 4b8bd099f..d1be42549 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs @@ -12,6 +12,7 @@ public async Task InvokeFunction(string name, RoleDialogModel message) var originalFunctionName = message.FunctionName; message.FunctionName = name; message.Role = AgentRole.Function; + message.FunctionArgs = message.FunctionArgs; var result = await function.Execute(message); // restore original function name diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid index 9147979f6..3609e41f1 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/instruction.liquid @@ -13,7 +13,7 @@ You're {{router.name}} ({{router.description}}). Follow these steps to handle us Parameters: - function: {{ handler.name }} {% for p in handler.parameters -%} - - {{ p.name }}: {{ p.description }}{{ "\r\n " }} + - {{ p.name }} {% if p.required -%}(required){%- endif %}: {{ p.description }}{{ "\r\n " }} {%- endfor %} {%- endif %} {% endfor %} From 5ab2e4d97809667e2eee03f22c2cbef6c531582b Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Tue, 27 Feb 2024 22:36:33 -0600 Subject: [PATCH 2/4] Hid function from OpenAPI. --- .../BotSharp.OpenAPI/Controllers/ConversationController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 19bcb5a7d..865613667 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -88,7 +88,7 @@ public async Task> GetDialogs([FromRoute] string Sender = UserViewModel.FromUser(user) }); } - else + else if (message.Role == AgentRole.Assistant) { var agent = await agentService.GetAgent(message.CurrentAgentId); dialogs.Add(new ChatResponseModel From ac40aa645f5b110c0b85834f74783bf1ef1a7334 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Wed, 28 Feb 2024 10:21:14 -0600 Subject: [PATCH 3/4] Stream Routing context log. --- .../BotSharp.Abstraction.csproj | 6 - .../Conversations/ConversationHookBase.cs | 6 - .../Conversations/IConversationHook.cs | 16 --- .../Infrastructures/HookEmittedResult.cs | 5 + .../Routing/IRoutingContext.cs | 13 +++ .../Routing/IRoutingHook.cs | 30 +++++ .../Infrastructures/HookEmitter.cs | 27 +++++ .../Routing/Functions/FallbackToRouterFn.cs | 2 +- .../Routing/Functions/RouteToAgentFn.cs | 12 +- .../RetrieveDataFromAgentRoutingHandler.cs | 2 +- .../Handlers/RouteToAgentRoutingHandler.cs | 2 +- .../Routing/Planning/HFPlanner.cs | 6 +- .../Routing/Planning/NaivePlanner.cs | 2 +- .../Routing/Planning/SequentialPlanner.cs | 2 +- .../TwoStagePlanner/TwoStagePlanner.cs | 2 +- .../Routing}/RoutingContext.cs | 39 ++++++- .../BotSharp.Core/Routing/RoutingPlugin.cs | 2 +- .../Routing/RoutingService.InvokeAgent.cs | 2 +- .../BotSharp.Core/Routing/RoutingService.cs | 10 +- .../Templating/ResponseTemplateService.cs | 4 +- src/Infrastructure/BotSharp.Core/Using.cs | 2 + .../BotSharp.Plugin.ChatHub/ChatHubPlugin.cs | 2 + .../Hooks/StreamingLogHook.cs | 108 ++++++++++++++---- .../RoutingConversationHook.cs | 3 +- .../agent.json | 2 + 25 files changed, 224 insertions(+), 83 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Infrastructures/HookEmittedResult.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs create mode 100644 src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs rename src/Infrastructure/{BotSharp.Abstraction/Routing/Models => BotSharp.Core/Routing}/RoutingContext.cs (63%) diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index 285cb0b8c..bbade11e3 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -10,12 +10,6 @@ $(SolutionDir)packages - - - - - - True diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index 569ac4e10..ea6a03d86 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -69,10 +69,4 @@ public virtual Task OnConversationInitialized(Conversation conversation) public virtual Task OnUserAgentConnectedInitially(Conversation conversation) => Task.CompletedTask; - - public virtual Task OnConversationRedirected(string toAgentId, RoleDialogModel message) - => 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 68360bed2..95afaab40 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs @@ -84,20 +84,4 @@ public interface IConversationHook /// /// Task OnHumanInterventionNeeded(RoleDialogModel message); - - /// - /// Conversation is redirected to another agent - /// - /// - /// - /// - 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.Abstraction/Infrastructures/HookEmittedResult.cs b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/HookEmittedResult.cs new file mode 100644 index 000000000..5084b4123 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Infrastructures/HookEmittedResult.cs @@ -0,0 +1,5 @@ +namespace BotSharp.Abstraction.Infrastructures; + +public class HookEmittedResult +{ +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs new file mode 100644 index 000000000..01da8e317 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs @@ -0,0 +1,13 @@ +namespace BotSharp.Abstraction.Routing; + +public interface IRoutingContext +{ + string GetCurrentAgentId(); + string OriginAgentId { get; } + bool IsEmpty { get; } + string IntentName { get; set; } + void Push(string agentId); + void Pop(); + void Replace(string agentId); + void Empty(); +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs new file mode 100644 index 000000000..34a07162f --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs @@ -0,0 +1,30 @@ +using BotSharp.Abstraction.Functions.Models; + +namespace BotSharp.Abstraction.Routing; + +public interface IRoutingHook +{ + /// + /// Conversation is redirected to another agent + /// + /// + /// + /// + Task OnConversationRedirected(string toAgentId, RoleDialogModel message); + + /// + /// Routing instruction is received from Router + /// + /// routing instruction + /// message + /// + Task OnConversationRouting(FunctionCallFromLlm instruct, RoleDialogModel message); + + Task OnAgentEnqueued(string agentId, string preAgentId); + + Task OnAgentDequeued(string agentId, string currentAgentId); + + Task OnAgentReplaced(string fromAgentId, string toAgentId); + + Task OnAgentQueueEmptied(string agentId); +} diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs new file mode 100644 index 000000000..988863ac2 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs @@ -0,0 +1,27 @@ +using BotSharp.Abstraction.Infrastructures; + +namespace BotSharp.Core.Infrastructures; + +public static class HookEmitter +{ + public static async Task Emit(IServiceProvider services, Action action) + { + var logger = services.GetRequiredService>(); + var result = new HookEmittedResult(); + var hooks = services.GetServices(); + + foreach (var hook in hooks) + { + try + { + action(hook); + } + catch (Exception ex) + { + logger.LogError(ex.ToString()); + } + } + + return result; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs index d6fb3dcb2..4d51113f6 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs @@ -29,7 +29,7 @@ public async Task Execute(RoleDialogModel message) return false; } - var routing = _services.GetRequiredService(); + var routing = _services.GetRequiredService(); routing.Replace(targetAgent.Id); var router = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index ee78fd1b4..c8085cf3f 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -14,9 +14,9 @@ public class RouteToAgentFn : IFunctionCallback { public string Name => "route_to_agent"; private readonly IServiceProvider _services; - private readonly RoutingContext _context; + private readonly IRoutingContext _context; - public RouteToAgentFn(IServiceProvider services, RoutingContext context) + public RouteToAgentFn(IServiceProvider services, IRoutingContext context) { _services = services; _context = context; @@ -153,11 +153,9 @@ private bool HasMissingRequiredField(RoleDialogModel message, out string agentId #else logger.LogInformation($"*** Routing redirect to {record.Name.ToUpper()} ***"); #endif - var hooks = _services.GetServices(); - foreach (var hook in hooks) - { - hook.OnConversationRedirected(routingRule.RedirectTo, message).Wait(); - } + HookEmitter.Emit(_services, async hook => + await hook.OnConversationRedirected(routingRule.RedirectTo, message) + ).Wait(); } else { diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs index 54f3e66c5..24a048ae3 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs @@ -39,7 +39,7 @@ public RetrieveDataFromAgentRoutingHandler(IServiceProvider services, ILogger Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); var agentId = context.GetCurrentAgentId(); var dialogs = new List { diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs index 2404e896e..4aae20db7 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs @@ -39,7 +39,7 @@ public RouteToAgentRoutingHandler(IServiceProvider services, ILogger Handle(IRoutingService routing, FunctionCallFromLlm inst, RoleDialogModel message) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); var function = _services.GetServices().FirstOrDefault(x => x.Name == inst.Function); message.FunctionArgs = JsonSerializer.Serialize(inst); var ret = await function.Execute(message); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs index ccb4f274a..6f49c9332 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/HFPlanner.cs @@ -2,7 +2,7 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Repositories.Filters; -using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Planning; using BotSharp.Abstraction.Templating; @@ -75,7 +75,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R var filter = new AgentFilter { AgentName = inst.AgentName }; var agent = db.GetAgents(filter).FirstOrDefault(); - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); context.Push(agent.Id); } @@ -84,7 +84,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); context.Empty(); return true; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs index 91f35801b..684c947c4 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/NaivePlanner.cs @@ -87,7 +87,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); if (inst.UnmatchedAgent) { var unmatchedAgentId = context.GetCurrentAgentId(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs index 84246d408..24cc2aa7e 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/SequentialPlanner.cs @@ -140,7 +140,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); if (message.StopCompletion) { diff --git a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs index 5688fce43..8dfa2f690 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Planning/TwoStagePlanner/TwoStagePlanner.cs @@ -155,7 +155,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); if (message.StopCompletion || _isTaskCompleted) { diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs similarity index 63% rename from src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs rename to src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index d09658d80..6b39978eb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -1,11 +1,9 @@ -using BotSharp.Abstraction.Agents; using BotSharp.Abstraction.Repositories.Filters; using BotSharp.Abstraction.Routing.Settings; -using Microsoft.Extensions.DependencyInjection; -namespace BotSharp.Abstraction.Routing.Models; +namespace BotSharp.Core.Routing; -public class RoutingContext +public class RoutingContext : IRoutingContext { private readonly IServiceProvider _services; private readonly RoutingSettings _setting; @@ -56,7 +54,12 @@ public void Push(string agentId) { if (_stack.Count == 0 || _stack.Peek() != agentId) { + var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek(); _stack.Push(agentId); + + HookEmitter.Emit(_services, async hook => + await hook.OnAgentEnqueued(agentId, preAgentId) + ).Wait(); } } @@ -65,24 +68,50 @@ public void Push(string agentId) /// public void Pop() { - _stack.Pop(); + if (_stack.Count == 0) + { + return; + } + + var agentId = _stack.Pop(); + + HookEmitter.Emit(_services, async hook => + await hook.OnAgentDequeued(agentId, _stack.Peek()) + ).Wait(); } public void Replace(string agentId) { + var fromAgent = agentId; + var toAgent = agentId; + if (_stack.Count == 0) { _stack.Push(agentId); } else if (_stack.Peek() != agentId) { + fromAgent = _stack.Peek(); _stack.Pop(); _stack.Push(agentId); + + HookEmitter.Emit(_services, async hook => + await hook.OnAgentReplaced(fromAgent, toAgent) + ).Wait(); } } public void Empty() { + if (_stack.Count == 0) + { + return; + } + + var agentId = GetCurrentAgentId(); _stack.Clear(); + HookEmitter.Emit(_services, async hook => + await hook.OnAgentQueueEmptied(agentId) + ).Wait(); } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs index 410070d1d..1ee1d7325 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingPlugin.cs @@ -23,7 +23,7 @@ public object GetNewSettingsInstance() => public void RegisterDI(IServiceCollection services, IConfiguration config) { - services.AddScoped(); + services.AddScoped(); // Register router services.AddScoped(provider => diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs index 9ea133fa8..ede6ee429 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs @@ -64,7 +64,7 @@ private async Task InvokeFunction(RoleDialogModel message, List(); + var routing = _services.GetRequiredService(); // Find response template var templateService = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index d9c4e21b6..8d93b4203 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -80,7 +80,7 @@ public async Task InstructLoop(RoleDialogModel message) var conv = _services.GetRequiredService(); var dialogs = conv.GetDialogHistory(); - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); var executor = _services.GetRequiredService(); var planner = GetPlanner(_router); @@ -98,11 +98,9 @@ public async Task InstructLoop(RoleDialogModel message) // 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); - } + await HookEmitter.Emit(_services, async hook => + await hook.OnConversationRouting(inst, message) + ); // Save states states.SaveStateByArgs(inst.Arguments); diff --git a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs index 6bde9ce6b..5119bc91e 100644 --- a/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs +++ b/src/Infrastructure/BotSharp.Core/Templating/ResponseTemplateService.cs @@ -68,8 +68,8 @@ public async Task RenderIntentResponse(string agentId, RoleDialogModel m // .ToList(); var db = _services.GetRequiredService(); - var context = _services.GetRequiredService(); - var responses = db.GetAgentResponses(agentId, "intent", context.IntentName); + var routing = _services.GetRequiredService(); + var responses = db.GetAgentResponses(agentId, "intent", routing.IntentName); if (responses.Count == 0) { diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs index 4571da54f..c55585e59 100644 --- a/src/Infrastructure/BotSharp.Core/Using.cs +++ b/src/Infrastructure/BotSharp.Core/Using.cs @@ -7,6 +7,7 @@ global using Microsoft.Extensions.DependencyInjection; global using Microsoft.Extensions.Logging; global using EntityFrameworkCore.BootKit; +global using BotSharp.Abstraction.Routing; global using BotSharp.Abstraction.Plugins; global using BotSharp.Abstraction.Agents; global using BotSharp.Abstraction.Conversations; @@ -18,6 +19,7 @@ global using BotSharp.Abstraction.Conversations.Settings; global using BotSharp.Abstraction.Agents.Enums; global using BotSharp.Core.Repository; +global using BotSharp.Core.Routing; global using BotSharp.Core.Agents.Services; global using BotSharp.Core.Conversations.Services; global using BotSharp.Core.Infrastructures; diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs index bec0a01ae..7825f0f10 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Loggers; +using BotSharp.Abstraction.Routing; using BotSharp.Plugin.ChatHub.Hooks; using Microsoft.Extensions.Configuration; @@ -20,5 +21,6 @@ public void RegisterDI(IServiceCollection services, IConfiguration config) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 90fbcefad..5b7f65fc1 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -4,11 +4,12 @@ using BotSharp.Abstraction.Loggers.Enums; using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Routing; using Microsoft.AspNetCore.SignalR; namespace BotSharp.Plugin.ChatHub.Hooks; -public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook +public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IRoutingHook { private readonly ConversationSetting _convSettings; private readonly JsonSerializerOptions _serializerOptions; @@ -17,6 +18,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook private readonly IConversationStateService _state; private readonly IUserIdentity _user; private readonly IAgentService _agentService; + private string _messageId; public StreamingLogHook( ConversationSetting convSettings, @@ -43,32 +45,13 @@ public StreamingLogHook( public override async Task OnMessageReceived(RoleDialogModel message) { + _messageId = message.MessageId; var conversationId = _state.GetConversationId(); - var log = $"{message.Role}: {message.Content}"; + var log = $"{message.Content}"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", 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 conversationId = _state.GetConversationId(); - 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", - BuildContentLog(conversationId, fromAgent.Name, log, ContentLogSource.HardRule, message)); - } - public async Task BeforeGenerating(Agent agent, List conversations) { if (!_convSettings.ShowVerboseLog) return; @@ -147,6 +130,8 @@ private string BuildContentLog(string conversationId, string? name, string logCo CreateTime = DateTime.UtcNow }; + var json = JsonSerializer.Serialize(log, _serializerOptions); + var convSettings = _services.GetRequiredService(); if (convSettings.EnableContentLog) { @@ -154,7 +139,7 @@ private string BuildContentLog(string conversationId, string? name, string logCo db.SaveConversationContentLog(log); } - return JsonSerializer.Serialize(log, _serializerOptions); + return json; } private string BuildStateLog(string conversationId, Dictionary states, RoleDialogModel message) @@ -176,4 +161,81 @@ private string BuildStateLog(string conversationId, Dictionary s return JsonSerializer.Serialize(log, _serializerOptions); } + + #region IRoutingHook + public async Task OnAgentEnqueued(string agentId, string preAgentId) + { + var conversationId = _state.GetConversationId(); + var agent = await _agentService.LoadAgent(agentId); + var preAgent = await _agentService.LoadAgent(preAgentId); + + var log = $"{agent.Name} is enqueued"; + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", + BuildContentLog(conversationId, preAgent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) + { + MessageId = _messageId + })); + } + + public async Task OnAgentDequeued(string agentId, string currentAgentId) + { + var conversationId = _state.GetConversationId(); + var agent = await _agentService.LoadAgent(agentId); + var currentAgent = await _agentService.LoadAgent(currentAgentId); + + var log = $"{agent.Name} is dequeued"; + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", + BuildContentLog(conversationId, currentAgent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) + { + MessageId = _messageId + })); + } + + public async Task OnAgentReplaced(string fromAgentId, string toAgentId) + { + var conversationId = _state.GetConversationId(); + var fromAgent = await _agentService.LoadAgent(fromAgentId); + var toAgent = await _agentService.LoadAgent(toAgentId); + + var log = $"{fromAgent.Name} is replaced to {toAgent.Name}"; + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", + BuildContentLog(conversationId, toAgent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) + { + MessageId = _messageId + })); + } + + public async Task OnAgentQueueEmptied(string agentId) + { + var conversationId = _state.GetConversationId(); + var agent = await _agentService.LoadAgent(agentId); + + var log = $"Agent queue is cleared."; + await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", + BuildContentLog(conversationId, agent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) + { + MessageId = _messageId + })); + } + + public 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 async Task OnConversationRedirected(string toAgentId, RoleDialogModel message) + { + var conversationId = _state.GetConversationId(); + 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", + BuildContentLog(conversationId, fromAgent.Name, log, ContentLogSource.HardRule, message)); + } + #endregion } diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs index 8c6d826e0..b7fab29e4 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs @@ -12,6 +12,7 @@ using System.IO; using BotSharp.Abstraction.Routing.Settings; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing; namespace BotSharp.Plugin.RoutingSpeeder; @@ -31,7 +32,7 @@ public override async Task OnMessageReceived(RoleDialogModel message) // intentClassifier.Train(); // Utilize local discriminative model to predict intent - var context = _services.GetRequiredService(); + var context = _services.GetRequiredService(); context.IntentName = intentClassifier.Predict(vector); if (string.IsNullOrEmpty(context.IntentName)) diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json index 80f66ba91..4f19d5914 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/data/agents/beda4c12-e1ec-4b4b-b328-3df4a6687c4f/agent.json @@ -9,6 +9,8 @@ "isPublic": true, "profiles": [ "tool", "sql" ], "llmConfig": { + "model": "gpt-4-0125", + "model3": "gpt-35-turbo-1106", "max_recursion_depth": 10 } } \ No newline at end of file From 866f412575ea197148d072b815d56a38fd090351 Mon Sep 17 00:00:00 2001 From: Haiping Chen <101423@smsassist.com> Date: Wed, 28 Feb 2024 10:34:08 -0600 Subject: [PATCH 4/4] Fix agent name. --- src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs index 5b7f65fc1..67349f7e3 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs @@ -185,7 +185,7 @@ public async Task OnAgentDequeued(string agentId, string currentAgentId) var log = $"{agent.Name} is dequeued"; await _chatHub.Clients.User(_user.Id).SendAsync("OnConversationContentLogGenerated", - BuildContentLog(conversationId, currentAgent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) + BuildContentLog(conversationId, agent.Name, log, ContentLogSource.HardRule, new RoleDialogModel(AgentRole.System, log) { MessageId = _messageId }));