From 9bbea3bece958d7a8d0c00d6c85fbbc3366c57c5 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Fri, 6 Dec 2024 00:57:46 -0600 Subject: [PATCH 1/2] add common agent hook --- .../Agents/AgentHookBase.cs | 73 ---------------- .../BotSharp.Core/Agents/AgentPlugin.cs | 2 + .../Agents/Hooks/CommonAgentHook.cs | 83 +++++++++++++++++++ 3 files changed, 85 insertions(+), 73 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs index 867d9d78..a3746ca8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs @@ -1,10 +1,5 @@ using BotSharp.Abstraction.Agents.Settings; -using BotSharp.Abstraction.Conversations; using BotSharp.Abstraction.Functions.Models; -using BotSharp.Abstraction.Repositories; -using BotSharp.Abstraction.Routing; -using Microsoft.Extensions.DependencyInjection; -using System.Data; namespace BotSharp.Abstraction.Agents; @@ -60,73 +55,5 @@ public abstract class AgentHookBase : IAgentHook public virtual void OnAgentUtilityLoaded(Agent agent) { - if (agent.Type == AgentType.Routing) return; - - var conv = _services.GetRequiredService(); - var isConvMode = conv.IsConversationMode(); - if (!isConvMode) return; - - agent.Functions ??= []; - agent.Utilities ??= []; - - var (functions, templates) = GetUtilityContent(agent); - - foreach (var fn in functions) - { - if (!agent.Functions.Any(x => x.Name.Equals(fn.Name, StringComparison.OrdinalIgnoreCase))) - { - agent.Functions.Add(fn); - } - } - - foreach (var prompt in templates) - { - agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n"; - } - } - - private (IEnumerable, IEnumerable) GetUtilityContent(Agent agent) - { - var db = _services.GetRequiredService(); - var (functionNames, templateNames) = GetUniqueContent(agent.Utilities); - - if (agent.MergeUtility) - { - var routing = _services.GetRequiredService(); - var entryAgentId = routing.EntryAgentId; - if (!string.IsNullOrEmpty(entryAgentId)) - { - var entryAgent = db.GetAgent(entryAgentId); - var (fns, tps) = GetUniqueContent(entryAgent?.Utilities); - functionNames = functionNames.Concat(fns).Distinct().ToList(); - templateNames = templateNames.Concat(tps).Distinct().ToList(); - } - } - - var ua = db.GetAgent(BuiltInAgentId.UtilityAssistant); - var functions = ua?.Functions?.Where(x => functionNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; - var templates = ua?.Templates?.Where(x => templateNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.Select(x => x.Content)?.ToList() ?? []; - return (functions, templates); - } - - private (IEnumerable, IEnumerable) GetUniqueContent(IEnumerable? utilities) - { - if (utilities.IsNullOrEmpty()) - { - return ([], []); - } - - var prefix = "util-"; - utilities = utilities?.Where(x => !string.IsNullOrEmpty(x.Name) && !x.Disabled)?.ToList() ?? []; - var functionNames = utilities.SelectMany(x => x.Functions) - .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(prefix)) - .Select(x => x.Name) - .Distinct().ToList(); - var templateNames = utilities.SelectMany(x => x.Templates) - .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(prefix)) - .Select(x => x.Name) - .Distinct().ToList(); - - return (functionNames, templateNames); } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs index cfbc541f..51b0da05 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs @@ -3,6 +3,7 @@ using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Settings; using BotSharp.Abstraction.Templating; using BotSharp.Abstraction.Users.Enums; +using BotSharp.Core.Agents.Hooks; using Microsoft.Extensions.Configuration; namespace BotSharp.Core.Agents; @@ -30,6 +31,7 @@ public class AgentPlugin : IBotSharpPlugin { services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(provider => { diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs new file mode 100644 index 00000000..78420fad --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs @@ -0,0 +1,83 @@ +namespace BotSharp.Core.Agents.Hooks; + +public class CommonAgentHook : AgentHookBase +{ + public override string SelfId => string.Empty; + + public CommonAgentHook(IServiceProvider services, AgentSettings settings) + : base(services, settings) + { + } + + public override void OnAgentUtilityLoaded(Agent agent) + { + if (agent.Type == AgentType.Routing) return; + + var conv = _services.GetRequiredService(); + var isConvMode = conv.IsConversationMode(); + if (!isConvMode) return; + + agent.Functions ??= []; + agent.Utilities ??= []; + + var (functions, templates) = GetUtilityContent(agent); + + foreach (var fn in functions) + { + if (!agent.Functions.Any(x => x.Name.Equals(fn.Name, StringComparison.OrdinalIgnoreCase))) + { + agent.Functions.Add(fn); + } + } + + foreach (var prompt in templates) + { + agent.Instruction += $"\r\n\r\n{prompt}\r\n\r\n"; + } + } + + private (IEnumerable, IEnumerable) GetUtilityContent(Agent agent) + { + var db = _services.GetRequiredService(); + var (functionNames, templateNames) = GetUniqueContent(agent.Utilities); + + if (agent.MergeUtility) + { + var routing = _services.GetRequiredService(); + var entryAgentId = routing.EntryAgentId; + if (!string.IsNullOrEmpty(entryAgentId)) + { + var entryAgent = db.GetAgent(entryAgentId); + var (fns, tps) = GetUniqueContent(entryAgent?.Utilities); + functionNames = functionNames.Concat(fns).Distinct().ToList(); + templateNames = templateNames.Concat(tps).Distinct().ToList(); + } + } + + var ua = db.GetAgent(BuiltInAgentId.UtilityAssistant); + var functions = ua?.Functions?.Where(x => functionNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; + var templates = ua?.Templates?.Where(x => templateNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.Select(x => x.Content)?.ToList() ?? []; + return (functions, templates); + } + + private (IEnumerable, IEnumerable) GetUniqueContent(IEnumerable? utilities) + { + if (utilities.IsNullOrEmpty()) + { + return ([], []); + } + + var prefix = "util-"; + utilities = utilities?.Where(x => !string.IsNullOrEmpty(x.Name) && !x.Disabled)?.ToList() ?? []; + var functionNames = utilities.SelectMany(x => x.Functions) + .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(prefix)) + .Select(x => x.Name) + .Distinct().ToList(); + var templateNames = utilities.SelectMany(x => x.Templates) + .Where(x => !string.IsNullOrEmpty(x.Name) && x.Name.StartsWith(prefix)) + .Select(x => x.Name) + .Distinct().ToList(); + + return (functionNames, templateNames); + } +} From e1e56b596af5ebb557ef49cb79bf4c2105f52f5c Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Fri, 6 Dec 2024 01:27:57 -0600 Subject: [PATCH 2/2] rename --- .../Agents/Models/AgentUtility.cs | 5 +++++ .../BotSharp.Core/Agents/AgentPlugin.cs | 2 +- .../{CommonAgentHook.cs => BasicAgentHook.cs} | 4 ++-- .../Routing/RoutingService.InstructLoop.cs | 20 +++++++++---------- 4 files changed, 17 insertions(+), 14 deletions(-) rename src/Infrastructure/BotSharp.Core/Agents/Hooks/{CommonAgentHook.cs => BasicAgentHook.cs} (96%) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs index 40828944..ce39c568 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentUtility.cs @@ -21,6 +21,11 @@ public class AgentUtility Functions = functions ?? []; Templates = templates ?? []; } + + public override string ToString() + { + return Name; + } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs index 51b0da05..b21772a1 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/AgentPlugin.cs @@ -31,7 +31,7 @@ public class AgentPlugin : IBotSharpPlugin { services.AddScoped(); services.AddScoped(); - services.AddScoped(); + services.AddScoped(); services.AddScoped(provider => { diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs similarity index 96% rename from src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs rename to src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs index 78420fad..2a4a7374 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/CommonAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs @@ -1,10 +1,10 @@ namespace BotSharp.Core.Agents.Hooks; -public class CommonAgentHook : AgentHookBase +public class BasicAgentHook : AgentHookBase { public override string SelfId => string.Empty; - public CommonAgentHook(IServiceProvider services, AgentSettings settings) + public BasicAgentHook(IServiceProvider services, AgentSettings settings) : base(services, settings) { } diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs index c3e1a8f4..18f330a3 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs @@ -2,7 +2,6 @@ using BotSharp.Abstraction.Infrastructures.Enums; using BotSharp.Abstraction.Planning; using BotSharp.Abstraction.Routing.Enums; using BotSharp.Abstraction.Routing.Reasoning; -using BotSharp.Core.Routing.Reasoning; namespace BotSharp.Core.Routing; @@ -21,7 +20,7 @@ public partial class RoutingService var states = _services.GetRequiredService(); var executor = _services.GetRequiredService(); - var planner = GetReasoner(_router); + var reasoner = GetReasoner(_router); _context.Push(_router.Id); @@ -46,7 +45,7 @@ public partial class RoutingService // Get first instruction _router.TemplateDict["conversation"] = await GetConversationContent(dialogs); - var inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs); + var inst = await reasoner.GetNextInstruction(_router, message.MessageId, dialogs); int loopCount = 1; while (true) @@ -63,30 +62,30 @@ public partial class RoutingService #else _logger.LogInformation($"*** Next Instruction *** {inst}"); #endif - await planner.AgentExecuting(_router, inst, message, dialogs); + await reasoner.AgentExecuting(_router, inst, message, dialogs); // Handover to Task Agent if (inst.HandleDialogsByPlanner) { - var dialogWithoutContext = planner.BeforeHandleContext(inst, message, dialogs); + var dialogWithoutContext = reasoner.BeforeHandleContext(inst, message, dialogs); response = await executor.Execute(this, inst, message, dialogWithoutContext); - planner.AfterHandleContext(dialogs, dialogWithoutContext); + reasoner.AfterHandleContext(dialogs, dialogWithoutContext); } else { response = await executor.Execute(this, inst, message, dialogs); } - await planner.AgentExecuted(_router, inst, response, dialogs); + await reasoner.AgentExecuted(_router, inst, response, dialogs); - if (loopCount >= planner.MaxLoopCount || _context.IsEmpty) + if (loopCount >= reasoner.MaxLoopCount || _context.IsEmpty) { break; } // Get next instruction from Planner _router.TemplateDict["conversation"] = await GetConversationContent(dialogs); - inst = await planner.GetNextInstruction(_router, message.MessageId, dialogs); + inst = await reasoner.GetNextInstruction(_router, message.MessageId, dialogs); loopCount++; } @@ -103,8 +102,7 @@ public partial class RoutingService return _services.GetServices().First(x => x.Name == "Naive Reasoner"); } - var reasoner = _services.GetServices(). - FirstOrDefault(x => x.GetType().Name.EndsWith(rule.Field)); + var reasoner = _services.GetServices().FirstOrDefault(x => x.GetType().Name.EndsWith(rule.Field)); if (reasoner == null) {