diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs index ae6a4eaf..7ad9858e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs @@ -9,6 +9,8 @@ public interface IAgentHook /// string SelfId { get; } Agent Agent { get; } + + bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id; void SetAgent(Agent agent); /// diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs index c9fa1cd7..c2b9a5fe 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs @@ -5,6 +5,7 @@ namespace BotSharp.Abstraction.Instructs; public interface IInstructHook { string SelfId { get; } + bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id; Task BeforeCompletion(Agent agent, RoleDialogModel message); Task AfterCompletion(Agent agent, InstructResult result); Task OnResponseGenerated(InstructResponseModel response); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 636bc811..3aa2e422 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Infrastructures; using BotSharp.Abstraction.Routing.Models; using System.Collections.Concurrent; @@ -10,29 +11,16 @@ public partial class AgentService // [SharpCache(10, perInstanceCache: true)] public async Task LoadAgent(string id, bool loadUtility = true) { - if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) + if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) return null; + + var emitOptions = new HookEmitOption { - return null; - } - - var hooks = _services.GetServices(); - - // Before agent is loaded. - foreach (var hook in hooks) - { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id) - { - continue; - } - - hook.OnAgentLoading(ref id); - } + ShouldExecute = hook => hook.IsMatch(id) + }; + HookEmitter.Emit(_services, hook => hook.OnAgentLoading(ref id), emitOptions); var agent = await GetAgent(id); - if (agent == null) - { - return null; - } + if (agent == null) return null; await InheritAgent(agent); OverrideInstructionByChannel(agent); @@ -43,13 +31,7 @@ public partial class AgentService PopulateState(agent.TemplateDict); // After agent is loaded - foreach (var hook in hooks) - { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != id) - { - continue; - } - + HookEmitter.Emit(_services, hook => { hook.SetAgent(agent); if (!string.IsNullOrEmpty(agent.Instruction)) @@ -72,13 +54,14 @@ public partial class AgentService hook.OnAgentUtilityLoaded(agent); } - if(!agent.McpTools.IsNullOrEmpty()) + if (!agent.McpTools.IsNullOrEmpty()) { hook.OnAgentMcpToolLoaded(agent); } - + hook.OnAgentLoaded(agent); - } + + }, emitOptions); _logger.LogInformation($"Loaded agent {agent}."); diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs index defd1459..4f5e928e 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Image.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.Instructs.Models; using BotSharp.Abstraction.Instructs; using System.IO; +using BotSharp.Abstraction.Infrastructures; namespace BotSharp.Core.Files.Services; @@ -24,14 +25,11 @@ public partial class FileInstructService } }); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -41,8 +39,7 @@ public partial class FileInstructService UserMessage = text, SystemInstruction = instruction, CompletionText = message.Content - }); - } + }), emitOptions); return message.Content; } @@ -59,14 +56,11 @@ public partial class FileInstructService Instruction = instruction }, new RoleDialogModel(AgentRole.User, instruction ?? text)); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -76,8 +70,7 @@ public partial class FileInstructService UserMessage = text, SystemInstruction = instruction, CompletionText = message.Content - }); - } + }), emitOptions); return message; } @@ -104,14 +97,11 @@ public partial class FileInstructService stream.Close(); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -119,8 +109,7 @@ public partial class FileInstructService Model = completion.Model, UserMessage = string.Empty, CompletionText = message.Content - }); - } + }), emitOptions); return message; } @@ -150,13 +139,11 @@ public partial class FileInstructService stream.Close(); var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -166,8 +153,7 @@ public partial class FileInstructService UserMessage = text, SystemInstruction = instruction, CompletionText = message.Content - }); - } + }), emitOptions); return message; } @@ -205,14 +191,11 @@ public partial class FileInstructService imageStream.Close(); maskStream.Close(); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -222,8 +205,7 @@ public partial class FileInstructService UserMessage = text, SystemInstruction = instruction, CompletionText = message.Content - }); - } + }), emitOptions); return message; } diff --git a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs index 2336363a..12b950b6 100644 --- a/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs +++ b/src/Infrastructure/BotSharp.Core/Files/Services/Instruct/FileInstructService.Pdf.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.Files.Converters; using BotSharp.Abstraction.Instructs.Models; using BotSharp.Abstraction.Instructs; +using BotSharp.Abstraction.Infrastructures; namespace BotSharp.Core.Files.Services; @@ -42,14 +43,11 @@ public partial class FileInstructService } }); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(innerAgentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = innerAgentId, @@ -59,8 +57,7 @@ public partial class FileInstructService UserMessage = text, SystemInstruction = instruction, CompletionText = message.Content - }); - } + }), emitOptions); return message.Content; } diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs b/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs index 346218dd..e225b6d3 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Functions; +using BotSharp.Abstraction.Infrastructures; using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Instructs.Models; @@ -60,14 +61,11 @@ public class ExecuteTemplateFn : IFunctionCallback new(AgentRole.User, text) }); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(agent.Id) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = agent.Id, @@ -76,8 +74,7 @@ public class ExecuteTemplateFn : IFunctionCallback Model = completion.Model, UserMessage = text, CompletionText = response.Content - }); - } + }), emitOptions); return response.Content; } diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs index 71a7488b..3bc069d5 100644 --- a/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs +++ b/src/Infrastructure/BotSharp.Core/Instructs/Services/InstructService.Execute.cs @@ -23,14 +23,9 @@ public partial class InstructService } // Trigger before completion hooks - var hooks = _services.GetServices(); + var hooks = _services.GetServices().Where(p => p.IsMatch(agentId)); foreach (var hook in hooks) { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId) - { - continue; - } - await hook.BeforeCompletion(agent, message); // Interrupted by hook @@ -99,11 +94,6 @@ public partial class InstructService foreach (var hook in hooks) { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId) - { - continue; - } - await hook.AfterCompletion(agent, response); await hook.OnResponseGenerated(new InstructResponseModel { diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index ca3ec45a..b5669a5f 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Files.Utilities; +using BotSharp.Abstraction.Infrastructures; using BotSharp.Abstraction.Instructs; using BotSharp.Abstraction.Instructs.Models; using BotSharp.Core.Infrastructures; @@ -58,14 +59,11 @@ public class InstructModeController : ControllerBase var textCompletion = CompletionProvider.GetTextCompletion(_services); var response = await textCompletion.GetCompletion(input.Text, agentId, Guid.NewGuid().ToString()); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(agentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = agentId, @@ -74,8 +72,8 @@ public class InstructModeController : ControllerBase TemplateName = input.Template, UserMessage = input.Text, CompletionText = response - }); - } + }), emitOptions); + return response; } @@ -103,14 +101,11 @@ public class InstructModeController : ControllerBase } }); - var hooks = _services.GetServices(); - foreach (var hook in hooks) + var emitOptions = new HookEmitOption { - if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId) - { - continue; - } - + ShouldExecute = hook => hook.IsMatch(agentId) + }; + await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(new InstructResponseModel { AgentId = agentId, @@ -120,8 +115,8 @@ public class InstructModeController : ControllerBase UserMessage = input.Text, SystemInstruction = message.RenderedInstruction, CompletionText = message.Content - }); - } + }), emitOptions); + return message.Content; } #endregion