diff --git a/BotSharp.sln b/BotSharp.sln
index a692f403..972dc35f 100644
--- a/BotSharp.sln
+++ b/BotSharp.sln
@@ -131,8 +131,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.Realtime", "s
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.PizzaBot.MCPServer", "tests\BotSharp.PizzaBot.MCPServer\BotSharp.PizzaBot.MCPServer.csproj", "{8D2AD45F-836A-516F-DE6A-71443CEBB18A}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.MCP", "src\Infrastructure\BotSharp.Core.MCP\BotSharp.Core.MCP.csproj", "{534D1DD5-9D62-115C-F230-47080D76CE52}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Test.ComputerUse", "tests\BotSharp.Test.ComputerUse\BotSharp.Test.ComputerUse.csproj", "{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Plugin.OsDriver", "src\Plugins\BotSharp.Plugin.OsDriver\BotSharp.Plugin.OsDriver.csproj", "{B268E2F0-060F-8466-7D81-ABA4D735CA59}"
@@ -553,14 +551,6 @@ Global
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|Any CPU.Build.0 = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x64.ActiveCfg = Release|Any CPU
{8D2AD45F-836A-516F-DE6A-71443CEBB18A}.Release|x64.Build.0 = Release|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Debug|x64.ActiveCfg = Debug|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Debug|x64.Build.0 = Debug|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Release|Any CPU.Build.0 = Release|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Release|x64.ActiveCfg = Release|Any CPU
- {534D1DD5-9D62-115C-F230-47080D76CE52}.Release|x64.Build.0 = Release|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -672,7 +662,6 @@ Global
{AF329442-B48E-4B48-A18A-1C869D1BA6F5} = {D5293208-2BEF-42FC-A64C-5954F61720BA}
{781F1465-365C-0F22-1775-25025DAFA4C7} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{8D2AD45F-836A-516F-DE6A-71443CEBB18A} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
- {534D1DD5-9D62-115C-F230-47080D76CE52} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
{C19D9AC1-97DD-8E65-E8DB-D295A095AA2D} = {32FAFFFE-A4CB-4FEE-BF7C-84518BBC6DCC}
{B268E2F0-060F-8466-7D81-ABA4D735CA59} = {51AFE054-AE99-497D-A593-69BAEFB5106F}
{970BE341-9AC8-99A5-6572-E703C1E02FCB} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749}
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d9fee6f8..01fc6c90 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -60,7 +60,7 @@
-
+
@@ -114,8 +114,8 @@
-
-
+
+
diff --git a/IFunctionExecutor.cs b/IFunctionExecutor.cs
new file mode 100644
index 00000000..a3380e70
--- /dev/null
+++ b/IFunctionExecutor.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BotSharp.Core.Routing
+{
+ public interface IFunctionExecutor
+ {
+ public Task Execute(RoleDialogModel message);
+
+ public Task GetIndication(RoleDialogModel message);
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
index ae6a4eaf..19e29642 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs
@@ -1,13 +1,10 @@
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Hooks;
namespace BotSharp.Abstraction.Agents;
-public interface IAgentHook
+public interface IAgentHook : IHookBase
{
- ///
- /// Agent Id
- ///
- string SelfId { get; }
Agent Agent { get; }
void SetAgent(Agent agent);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
index b722d3fa..6d967391 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
@@ -1,6 +1,8 @@
+using BotSharp.Abstraction.Hooks;
+
namespace BotSharp.Abstraction.Conversations;
-public interface IConversationHook
+public interface IConversationHook : IHookBase
{
int Priority { get; }
Agent Agent { get; }
diff --git a/src/Infrastructure/BotSharp.Abstraction/Crontab/ICrontabHook.cs b/src/Infrastructure/BotSharp.Abstraction/Crontab/ICrontabHook.cs
index 6ad7e06a..b92fd8f5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Crontab/ICrontabHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Crontab/ICrontabHook.cs
@@ -1,6 +1,8 @@
+using BotSharp.Abstraction.Hooks;
+
namespace BotSharp.Abstraction.Crontab;
-public interface ICrontabHook
+public interface ICrontabHook : IHookBase
{
string[]? Triggers
=> null;
diff --git a/src/Infrastructure/BotSharp.Abstraction/Hooks/IHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Hooks/IHookBase.cs
new file mode 100644
index 00000000..a0ad18e6
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Hooks/IHookBase.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BotSharp.Abstraction.Hooks
+{
+ public interface IHookBase
+ {
+ ///
+ /// Agent Id
+ ///
+ string SelfId => string.Empty;
+ bool IsMatch(string id) => string.IsNullOrEmpty(SelfId) || SelfId == id;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs
index c9fa1cd7..23b8bf60 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Instructs/IInstructHook.cs
@@ -1,10 +1,10 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Instructs.Models;
namespace BotSharp.Abstraction.Instructs;
-public interface IInstructHook
+public interface IInstructHook : IHookBase
{
- string SelfId { get; }
Task BeforeCompletion(Agent agent, RoleDialogModel message);
Task AfterCompletion(Agent agent, InstructResult result);
Task OnResponseGenerated(InstructResponseModel response);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Loggers/IContentGeneratingHook.cs b/src/Infrastructure/BotSharp.Abstraction/Loggers/IContentGeneratingHook.cs
index 03b69f5f..79f71d70 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Loggers/IContentGeneratingHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Loggers/IContentGeneratingHook.cs
@@ -1,11 +1,12 @@
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Hooks;
namespace BotSharp.Abstraction.Loggers;
///
/// Model content generating hook, it can be used for logging, metrics and tracing.
///
-public interface IContentGeneratingHook
+public interface IContentGeneratingHook : IHookBase
{
///
/// Before content generating.
diff --git a/src/Infrastructure/BotSharp.Abstraction/Planning/IPlanningHook.cs b/src/Infrastructure/BotSharp.Abstraction/Planning/IPlanningHook.cs
index 4dcff7cb..b65c1a7e 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Planning/IPlanningHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Planning/IPlanningHook.cs
@@ -1,6 +1,8 @@
+using BotSharp.Abstraction.Hooks;
+
namespace BotSharp.Abstraction.Planning;
-public interface IPlanningHook
+public interface IPlanningHook : IHookBase
{
Task GetSummaryAdditionalRequirements(string planner, RoleDialogModel message)
=> Task.FromResult(string.Empty);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Realtime/IRealtimeHook.cs b/src/Infrastructure/BotSharp.Abstraction/Realtime/IRealtimeHook.cs
index 95608ff0..bd131b93 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Realtime/IRealtimeHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Realtime/IRealtimeHook.cs
@@ -1,8 +1,9 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.MLTasks;
namespace BotSharp.Abstraction.Realtime;
-public interface IRealtimeHook
+public interface IRealtimeHook : IHookBase
{
Task OnModelReady(Agent agent, IRealTimeCompletion completer);
string[] OnModelTranscriptPrompt(Agent agent);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs
index c60bf4f1..b893c8c1 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingHook.cs
@@ -1,8 +1,9 @@
using BotSharp.Abstraction.Functions.Models;
+using BotSharp.Abstraction.Hooks;
namespace BotSharp.Abstraction.Routing;
-public interface IRoutingHook
+public interface IRoutingHook : IHookBase
{
///
/// Routing instruction is received from Router
diff --git a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
index 7ff105c9..255faa71 100644
--- a/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
+++ b/src/Infrastructure/BotSharp.Core.Crontab/Services/CrontabService.cs
@@ -125,6 +125,6 @@ public class CrontabService : ICrontabService, ITaskFeeder
await hook.OnCronTriggered(item);
await hook.OnTaskExecuted(item);
}
- });
+ }, item.AgentId);
}
}
diff --git a/src/Infrastructure/BotSharp.Core.MCP/BotSharp.Core.MCP.csproj b/src/Infrastructure/BotSharp.Core.MCP/BotSharp.Core.MCP.csproj
deleted file mode 100644
index 5f513dd9..00000000
--- a/src/Infrastructure/BotSharp.Core.MCP/BotSharp.Core.MCP.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-
-
-
- $(TargetFramework)
- $(LangVersion)
- $(BotSharpVersion)
- $(GeneratePackageOnBuild)
- $(SolutionDir)packages
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs b/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs
deleted file mode 100644
index 898d5a0f..00000000
--- a/src/Infrastructure/BotSharp.Core.MCP/BotSharpMCPExtensions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using BotSharp.Core.MCP.Functions;
-using BotSharp.Core.MCP.Hooks;
-using BotSharp.Core.MCP.Managers;
-using BotSharp.Core.MCP.Services;
-using BotSharp.Core.MCP.Settings;
-using Microsoft.Extensions.Configuration;
-using ModelContextProtocol.Client;
-
-namespace BotSharp.Core.MCP;
-
-public static class BotSharpMcpExtensions
-{
- ///
- /// Add mcp
- ///
- ///
- ///
- ///
- public static IServiceCollection AddBotSharpMCP(this IServiceCollection services, IConfiguration config)
- {
- services.AddScoped();
- var settings = config.GetSection("MCP").Get();
- services.AddScoped(provider => settings);
-
- if (settings != null && settings.Enabled && !settings.McpServerConfigs.IsNullOrEmpty())
- {
- var clientManager = new McpClientManager(settings);
- services.AddSingleton(clientManager);
-
- foreach (var server in settings.McpServerConfigs)
- {
- RegisterFunctionCall(services, server, clientManager)
- .ConfigureAwait(false)
- .GetAwaiter()
- .GetResult();
- }
-
- // Register hooks
- services.AddScoped();
- }
- return services;
- }
-
- private static async Task RegisterFunctionCall(IServiceCollection services, McpServerConfigModel server, McpClientManager clientManager)
- {
- try
- {
- var client = await clientManager.GetMcpClientAsync(server.Id);
- var tools = await client.ListToolsAsync();
-
- foreach (var tool in tools)
- {
- services.AddScoped(provider => tool);
-
- services.AddScoped(provider =>
- {
- var funcTool = new McpToolAdapter(provider, server.Name, tool, clientManager);
- return funcTool;
- });
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Error when registering {server?.Name} MCP tools. {ex.Message}\r\n{ex.InnerException}");
- }
- }
-}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Using.cs b/src/Infrastructure/BotSharp.Core.MCP/Using.cs
deleted file mode 100644
index 0c5dcf37..00000000
--- a/src/Infrastructure/BotSharp.Core.MCP/Using.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-global using System;
-global using System.Collections.Generic;
-global using System.Linq;
-global using System.Threading.Tasks;
-global using Microsoft.Extensions.DependencyInjection;
-
-global using BotSharp.Abstraction.Agents;
-global using BotSharp.Abstraction.Agents.Enums;
-global using BotSharp.Abstraction.Agents.Models;
-global using BotSharp.Abstraction.Agents.Settings;
-global using BotSharp.Abstraction.Conversations;
-global using BotSharp.Abstraction.Conversations.Models;
-global using BotSharp.Abstraction.Functions;
-global using BotSharp.Abstraction.Functions.Models;
-global using BotSharp.Abstraction.Utilities;
-global using BotSharp.Abstraction.MCP.Models;
-global using BotSharp.Abstraction.MCP.Services;
-
diff --git a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
index 104cd22c..9fed0293 100644
--- a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
+++ b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
@@ -49,7 +49,8 @@ public class RealtimeHub : IRealtimeHub
// Not TriggerModelInference, waiting for user utter.
var instruction = await _completer.UpdateSession(_conn, isInit: true);
var data = _conn.OnModelReady();
- await HookEmitter.Emit(_services, async hook => await hook.OnModelReady(agent, _completer));
+ await HookEmitter.Emit(_services, async hook => await hook.OnModelReady(agent, _completer),
+ agent.Id);
await (init?.Invoke(data) ?? Task.CompletedTask);
},
onModelAudioDeltaReceived: async (audioDeltaData, itemId) =>
@@ -92,7 +93,8 @@ public class RealtimeHub : IRealtimeHub
if (message.FunctionName == "route_to_agent")
{
var instruction = JsonSerializer.Deserialize(message.FunctionArgs, BotSharpOptions.defaultJsonOptions);
- await HookEmitter.Emit(_services, async hook => await hook.OnRoutingInstructionReceived(instruction, message));
+ await HookEmitter.Emit(_services, async hook => await hook.OnRoutingInstructionReceived(instruction, message),
+ agent.Id);
}
await routing.InvokeFunction(message.FunctionName, message);
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs
index 636bc811..37e3d445 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,12 @@ 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())
- {
- return null;
- }
+ if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) 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);
- }
+ HookEmitter.Emit(_services, hook => hook.OnAgentLoading(ref id), id);
var agent = await GetAgent(id);
- if (agent == null)
- {
- return null;
- }
+ if (agent == null) return null;
await InheritAgent(agent);
OverrideInstructionByChannel(agent);
@@ -43,13 +27,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 +50,14 @@ public partial class AgentService
hook.OnAgentUtilityLoaded(agent);
}
- if(!agent.McpTools.IsNullOrEmpty())
+ if (!agent.McpTools.IsNullOrEmpty())
{
hook.OnAgentMcpToolLoaded(agent);
}
-
+
hook.OnAgentLoaded(agent);
- }
+
+ }, id);
_logger.LogInformation($"Loaded agent {agent}.");
diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
index ef36f4d7..f862482c 100644
--- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
+++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.Rendering.cs
@@ -132,9 +132,8 @@ public partial class AgentService
agent.TemplateDict[TemplateRenderConstant.RENDER_AGENT] = agent;
var content = render.Render(template, agent.TemplateDict);
- HookEmitter.Emit(_services, async hook =>
- await hook.OnRenderingTemplate(agent, templateName, content)
- ).Wait();
+ HookEmitter.Emit(_services, async hook => await hook.OnRenderingTemplate(agent, templateName, content),
+ agent.Id).Wait();
return content;
}
diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
index b3e29b3f..ddcf68cb 100644
--- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
+++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj
@@ -228,6 +228,7 @@
+
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
index 5ec1ae76..b2b97f4f 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
@@ -158,16 +158,14 @@ public partial class ConversationService
// Emit conversation ending hook
if (response.Instruction.ConversationEnd)
{
- await HookEmitter.Emit(_services, async hook =>
- await hook.OnConversationEnding(response)
- );
+ await HookEmitter.Emit(_services, async hook => await hook.OnConversationEnding(response),
+ response.CurrentAgentId);
response.FunctionName = "conversation_end";
}
}
- await HookEmitter.Emit(_services, async hook =>
- await hook.OnResponseGenerated(response)
- );
+ await HookEmitter.Emit(_services, async hook => await hook.OnResponseGenerated(response),
+ response.CurrentAgentId);
await onResponseReceived(response);
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..dd2e02d4 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,7 @@ public partial class FileInstructService
}
});
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -41,8 +35,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
return message.Content;
}
@@ -59,14 +52,7 @@ public partial class FileInstructService
Instruction = instruction
}, new RoleDialogModel(AgentRole.User, instruction ?? text));
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -76,8 +62,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
return message;
}
@@ -104,14 +89,7 @@ public partial class FileInstructService
stream.Close();
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -119,8 +97,7 @@ public partial class FileInstructService
Model = completion.Model,
UserMessage = string.Empty,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
return message;
}
@@ -149,14 +126,7 @@ public partial class FileInstructService
stream.Close();
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -166,8 +136,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
return message;
}
@@ -205,14 +174,7 @@ public partial class FileInstructService
imageStream.Close();
maskStream.Close();
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -222,8 +184,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
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..cd703cc7 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,7 @@ public partial class FileInstructService
}
});
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != innerAgentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = innerAgentId,
@@ -59,8 +53,7 @@ public partial class FileInstructService
UserMessage = text,
SystemInstruction = instruction,
CompletionText = message.Content
- });
- }
+ }), innerAgentId);
return message.Content;
}
diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs
index a4baf81c..95d55596 100644
--- a/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs
+++ b/src/Infrastructure/BotSharp.Core/Infrastructures/HookEmitter.cs
@@ -1,14 +1,15 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Infrastructures;
namespace BotSharp.Core.Infrastructures;
public static class HookEmitter
{
- public static HookEmittedResult Emit(IServiceProvider services, Action action, HookEmitOption? option = null)
+ public static HookEmittedResult Emit(IServiceProvider services, Action action, string agentId, HookEmitOption? option = null) where T : IHookBase
{
var logger = services.GetRequiredService>();
var result = new HookEmittedResult();
- var hooks = services.GetServices();
+ var hooks = services.GetServices().Where(p => p.IsMatch(agentId));
option = option ?? new();
foreach (var hook in hooks)
@@ -35,11 +36,11 @@ public static class HookEmitter
return result;
}
- public static async Task Emit(IServiceProvider services, Func action, HookEmitOption? option = null)
+ public static async Task Emit(IServiceProvider services, Func action, string agentId, HookEmitOption? option = null) where T : IHookBase
{
var logger = services.GetRequiredService>();
var result = new HookEmittedResult();
- var hooks = services.GetServices();
+ var hooks = services.GetServices().Where(p => p.IsMatch(agentId));
option = option ?? new();
foreach (var hook in hooks)
diff --git a/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs b/src/Infrastructure/BotSharp.Core/Instructs/Functions/ExecuteTemplateFn.cs
index 346218dd..7d8bcb46 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,7 @@ public class ExecuteTemplateFn : IFunctionCallback
new(AgentRole.User, text)
});
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agent.Id)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agent.Id,
@@ -76,8 +70,7 @@ public class ExecuteTemplateFn : IFunctionCallback
Model = completion.Model,
UserMessage = text,
CompletionText = response.Content
- });
- }
+ }), agent.Id);
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.Core/MCP/BotSharpMCPExtensions.cs b/src/Infrastructure/BotSharp.Core/MCP/BotSharpMCPExtensions.cs
new file mode 100644
index 00000000..b3c4e6de
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/MCP/BotSharpMCPExtensions.cs
@@ -0,0 +1,35 @@
+using BotSharp.Core.MCP.Hooks;
+using BotSharp.Core.MCP.Managers;
+using BotSharp.Core.MCP.Services;
+using BotSharp.Core.MCP.Settings;
+using Microsoft.Extensions.Configuration;
+
+namespace BotSharp.Core.MCP;
+
+public static class BotSharpMcpExtensions
+{
+ ///
+ /// Add mcp
+ ///
+ ///
+ ///
+ ///
+ public static IServiceCollection AddBotSharpMCP(this IServiceCollection services, IConfiguration config)
+ {
+ var settings = config.GetSection("MCP").Get();
+ services.AddScoped(provider => settings);
+
+ if (settings != null && settings.Enabled && !settings.McpServerConfigs.IsNullOrEmpty())
+ {
+ services.AddScoped();
+
+ var clientManager = new McpClientManager(settings);
+ services.AddScoped(provider => clientManager);
+
+ // Register hooks
+ services.AddScoped();
+ }
+ return services;
+ }
+
+}
\ No newline at end of file
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Helpers/AiFunctionHelper.cs b/src/Infrastructure/BotSharp.Core/MCP/Helpers/AiFunctionHelper.cs
similarity index 100%
rename from src/Infrastructure/BotSharp.Core.MCP/Helpers/AiFunctionHelper.cs
rename to src/Infrastructure/BotSharp.Core/MCP/Helpers/AiFunctionHelper.cs
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs b/src/Infrastructure/BotSharp.Core/MCP/Hooks/MCPToolAgentHook.cs
similarity index 100%
rename from src/Infrastructure/BotSharp.Core.MCP/Hooks/MCPToolAgentHook.cs
rename to src/Infrastructure/BotSharp.Core/MCP/Hooks/MCPToolAgentHook.cs
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs b/src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs
similarity index 100%
rename from src/Infrastructure/BotSharp.Core.MCP/Managers/McpClientManager.cs
rename to src/Infrastructure/BotSharp.Core/MCP/Managers/McpClientManager.cs
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Services/McpService.cs b/src/Infrastructure/BotSharp.Core/MCP/Services/McpService.cs
similarity index 69%
rename from src/Infrastructure/BotSharp.Core.MCP/Services/McpService.cs
rename to src/Infrastructure/BotSharp.Core/MCP/Services/McpService.cs
index bbc2c3f4..3bff4442 100644
--- a/src/Infrastructure/BotSharp.Core.MCP/Services/McpService.cs
+++ b/src/Infrastructure/BotSharp.Core/MCP/Services/McpService.cs
@@ -1,5 +1,7 @@
+using BotSharp.Core.MCP.Managers;
using BotSharp.Core.MCP.Settings;
using Microsoft.Extensions.Logging;
+using ModelContextProtocol.Client;
namespace BotSharp.Core.MCP.Services;
@@ -7,13 +9,16 @@ public class McpService : IMcpService
{
private readonly IServiceProvider _services;
private readonly ILogger _logger;
+ private readonly McpClientManager _mcpClientManager;
public McpService(
IServiceProvider services,
- ILogger logger)
+ ILogger logger,
+ McpClientManager mcpClient)
{
_services = services;
_logger = logger;
+ _mcpClientManager = mcpClient;
}
public IEnumerable GetServerConfigs()
@@ -24,9 +29,9 @@ public class McpService : IMcpService
foreach (var config in configs)
{
- var tools = _services.GetServices()
- .Where(x => x.Provider == config.Name)
- .Select(x => x.Name);
+ var tools = _mcpClientManager.GetMcpClientAsync(config.Id)
+ .Result.ListToolsAsync()
+ .Result.Select(x=> x.Name);
options.Add(new McpServerOptionModel
{
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs b/src/Infrastructure/BotSharp.Core/MCP/Settings/MCPSettings.cs
similarity index 100%
rename from src/Infrastructure/BotSharp.Core.MCP/Settings/MCPSettings.cs
rename to src/Infrastructure/BotSharp.Core/MCP/Settings/MCPSettings.cs
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Executor/DummyFunctionExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/DummyFunctionExecutor.cs
new file mode 100644
index 00000000..d075e185
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/DummyFunctionExecutor.cs
@@ -0,0 +1,37 @@
+using BotSharp.Abstraction.Templating;
+
+namespace BotSharp.Core.Routing.Executor;
+
+public class DummyFunctionExecutor: IFunctionExecutor
+{
+ private FunctionDef functionDef;
+ private readonly IServiceProvider _services;
+
+ public DummyFunctionExecutor(FunctionDef function, IServiceProvider services)
+ {
+ functionDef = function;
+ _services = services;
+ }
+
+
+ public async Task ExecuteAsync(RoleDialogModel message)
+ {
+ var render = _services.GetRequiredService();
+ var state = _services.GetRequiredService();
+
+ var dict = new Dictionary();
+ foreach (var item in state.GetStates())
+ {
+ dict[item.Key] = item.Value;
+ }
+
+ var text = render.Render(functionDef.Output, dict);
+ message.Content = text;
+ return true;
+ }
+
+ public async Task GetIndicatorAsync(RoleDialogModel message)
+ {
+ return "Running";
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionCallbackExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionCallbackExecutor.cs
new file mode 100644
index 00000000..939f4fb3
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionCallbackExecutor.cs
@@ -0,0 +1,23 @@
+using BotSharp.Abstraction.Functions;
+
+namespace BotSharp.Core.Routing.Executor;
+
+public class FunctionCallbackExecutor : IFunctionExecutor
+{
+ IFunctionCallback functionCallback;
+
+ public FunctionCallbackExecutor(IFunctionCallback functionCallback)
+ {
+ this.functionCallback = functionCallback;
+ }
+
+ public async Task ExecuteAsync(RoleDialogModel message)
+ {
+ return await functionCallback.Execute(message);
+ }
+
+ public async Task GetIndicatorAsync(RoleDialogModel message)
+ {
+ return await functionCallback.GetIndication(message);
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs
new file mode 100644
index 00000000..3fb89509
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/FunctionExecutorFactory.cs
@@ -0,0 +1,41 @@
+using BotSharp.Abstraction.Functions;
+
+namespace BotSharp.Core.Routing.Executor;
+
+internal class FunctionExecutorFactory
+{
+ public static IFunctionExecutor Create(string functionName, Agent agent, IFunctionCallback functioncall, IServiceProvider serviceProvider)
+ {
+ if(functioncall != null)
+ {
+ return new FunctionCallbackExecutor(functioncall);
+ }
+
+ var funDef = agent?.Functions?.FirstOrDefault(x => x.Name == functionName);
+ if (funDef != null)
+ {
+ if (!string.IsNullOrWhiteSpace(funDef?.Output))
+ {
+ return new DummyFunctionExecutor(funDef,serviceProvider);
+ }
+ }
+ else
+ {
+ funDef = agent?.SecondaryFunctions?.FirstOrDefault(x => x.Name == functionName);
+ if (funDef != null)
+ {
+ if (!string.IsNullOrWhiteSpace(funDef?.Output))
+ {
+ return new DummyFunctionExecutor(funDef, serviceProvider);
+ }
+ else
+ {
+ var mcpServerId = agent?.McpTools?.Where(x => x.Functions.Any(y => y.Name == funDef.Name))
+ .FirstOrDefault().ServerId;
+ return new MCPToolExecutor(mcpServerId, functionName, serviceProvider);
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Executor/IFunctionExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/IFunctionExecutor.cs
new file mode 100644
index 00000000..4ba2e69f
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/IFunctionExecutor.cs
@@ -0,0 +1,8 @@
+namespace BotSharp.Core.Routing.Executor;
+
+public interface IFunctionExecutor
+{
+ public Task ExecuteAsync(RoleDialogModel message);
+
+ public Task GetIndicatorAsync(RoleDialogModel message);
+}
diff --git a/src/Infrastructure/BotSharp.Core.MCP/Functions/McpToolAdapter.cs b/src/Infrastructure/BotSharp.Core/Routing/Executor/MCPToolExecutor.cs
similarity index 72%
rename from src/Infrastructure/BotSharp.Core.MCP/Functions/McpToolAdapter.cs
rename to src/Infrastructure/BotSharp.Core/Routing/Executor/MCPToolExecutor.cs
index 0e433597..f7625b48 100644
--- a/src/Infrastructure/BotSharp.Core.MCP/Functions/McpToolAdapter.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Executor/MCPToolExecutor.cs
@@ -1,46 +1,34 @@
-using System.Text.Json;
using BotSharp.Core.MCP.Managers;
using ModelContextProtocol.Client;
-namespace BotSharp.Core.MCP.Functions;
+namespace BotSharp.Core.Routing.Executor;
-public class McpToolAdapter : IFunctionCallback
+public class MCPToolExecutor: IFunctionExecutor
{
- private readonly string _provider;
- private readonly McpClientTool _tool;
private readonly McpClientManager _clientManager;
+ private string mcpServer;
+ private string funcName;
private readonly IServiceProvider _services;
- public McpToolAdapter(
- IServiceProvider services,
- string serverName,
- McpClientTool tool,
- McpClientManager client)
- {
- _services = services ?? throw new ArgumentNullException(nameof(services));
- _tool = tool ?? throw new ArgumentNullException(nameof(tool));
- _clientManager = client ?? throw new ArgumentNullException(nameof(client));
- _provider = serverName;
+ public MCPToolExecutor(string mcpserver, string functionName, IServiceProvider services)
+ {
+ _services = services;
+ this.mcpServer = mcpserver;
+ this.funcName = functionName;
+ _clientManager = services.GetRequiredService();
}
- public string Provider => _provider;
- public string Name => _tool.Name;
-
- public async Task Execute(RoleDialogModel message)
+ public async Task ExecuteAsync(RoleDialogModel message)
{
try
{
// Convert arguments to dictionary format expected by mcpdotnet
- Dictionary argDict = JsonToDictionary(message.FunctionArgs);
- var currentAgentId = message.CurrentAgentId;
- var agentService = _services.GetRequiredService();
- var agent = await agentService.LoadAgent(currentAgentId);
- var serverId = agent.McpTools.Where(t => t.Functions.Any(f => f.Name == Name)).FirstOrDefault().ServerId;
+ Dictionary argDict = JsonToDictionary(message.FunctionArgs);
- var client = await _clientManager.GetMcpClientAsync(serverId);
+ var client = await _clientManager.GetMcpClientAsync(mcpServer);
// Call the tool through mcpdotnet
- var result = await client.CallToolAsync(_tool.Name, !argDict.IsNullOrEmpty() ? argDict : []);
+ var result = await client.CallToolAsync(funcName, !argDict.IsNullOrEmpty() ? argDict : []);
// Extract the text content from the result
var json = string.Join("\n", result.Content.Where(c => c.Type == "text").Select(c => c.Text));
@@ -51,11 +39,17 @@ public class McpToolAdapter : IFunctionCallback
}
catch (Exception ex)
{
- message.Content = $"Error when calling tool {Name} of MCP server {Provider}. {ex.Message}";
+ message.Content = $"Error when calling tool {funcName} of MCP server {mcpServer}. {ex.Message}";
return false;
}
}
+ public async Task GetIndicatorAsync(RoleDialogModel message)
+ {
+ return message.Indication ?? string.Empty;
+ }
+
+
private static Dictionary JsonToDictionary(string? json)
{
if (string.IsNullOrEmpty(json))
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
index e911437d..c93e133c 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
@@ -25,9 +25,8 @@ public class InstructExecutor : IExecutor
{
inst.OriginalAgent = goalAgent;
// Emit hook
- await HookEmitter.Emit(_services, async hook =>
- await hook.OnRoutingInstructionRevised(inst, message)
- );
+ await HookEmitter.Emit(_services, async hook => await hook.OnRoutingInstructionRevised(inst, message),
+ message.CurrentAgentId);
}
message.FunctionArgs = JsonSerializer.Serialize(inst);
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
index 1c4ca518..b422a423 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs
@@ -99,9 +99,8 @@ public class RoutingContext : IRoutingContext
var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek();
_stack.Push(agentId);
- HookEmitter.Emit(_services, async hook =>
- await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason)
- ).Wait();
+ HookEmitter.Emit(_services, async hook => await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason),
+ agentId).Wait();
UpdateLazyRoutingAgent(updateLazyRouting);
}
@@ -120,9 +119,8 @@ public class RoutingContext : IRoutingContext
var agentId = _stack.Pop();
var currentAgentId = GetCurrentAgentId();
- HookEmitter.Emit(_services, async hook =>
- await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason)
- ).Wait();
+ HookEmitter.Emit(_services, async hook => await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason),
+ agentId).Wait();
if (string.IsNullOrEmpty(currentAgentId))
{
@@ -203,9 +201,8 @@ public class RoutingContext : IRoutingContext
_stack.Pop();
_stack.Push(agentId);
- HookEmitter.Emit(_services, async hook =>
- await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason)
- ).Wait();
+ HookEmitter.Emit(_services, async hook => await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason),
+ agentId).Wait();
}
UpdateLazyRoutingAgent(updateLazyRouting);
@@ -220,9 +217,8 @@ public class RoutingContext : IRoutingContext
var agentId = GetCurrentAgentId();
_stack.Clear();
- HookEmitter.Emit(_services, async hook =>
- await hook.OnAgentQueueEmptied(agentId, reason: reason)
- ).Wait();
+ HookEmitter.Emit(_services, async hook => await hook.OnAgentQueueEmptied(agentId, reason: reason),
+ agentId).Wait();
}
public void SetMessageId(string conversationId, string messageId)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
index 364e7198..128debad 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs
@@ -51,9 +51,8 @@ public partial class RoutingService
int loopCount = 1;
while (true)
{
- await HookEmitter.Emit(_services, async hook =>
- await hook.OnRoutingInstructionReceived(inst, message)
- );
+ await HookEmitter.Emit(_services, async hook => await hook.OnRoutingInstructionReceived(inst, message),
+ agent.Id);
// Save states
states.SaveStateByArgs(inst.Arguments);
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
index 8c37536c..126453e8 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs
@@ -1,5 +1,6 @@
using BotSharp.Abstraction.Functions;
using BotSharp.Abstraction.Templating;
+using BotSharp.Core.Routing.Executor;
namespace BotSharp.Core.Routing;
@@ -8,22 +9,22 @@ public partial class RoutingService
public async Task InvokeFunction(string name, RoleDialogModel message)
{
var function = _services.GetServices().FirstOrDefault(x => x.Name == name);
+
+ var currentAgentId = message.CurrentAgentId;
+ var agentService = _services.GetRequiredService();
+ var agent = await agentService.GetAgent(currentAgentId);
- var isFillDummyContent = false;
- var dummyFuncResponse = string.Empty;
- if (function == null)
+ IFunctionExecutor funcExecutor = FunctionExecutorFactory.Create(name, agent, function, _services);
+
+ if (funcExecutor == null)
{
- dummyFuncResponse = await GetDummyFunctionOutput(name, message);
- isFillDummyContent = !string.IsNullOrEmpty(dummyFuncResponse);
- if (!isFillDummyContent)
- {
- message.StopCompletion = true;
- message.Content = $"Can't find function implementation of {name}.";
- _logger.LogError(message.Content);
- return false;
- }
+ message.StopCompletion = true;
+ message.Content = $"Can't find function implementation of {name}.";
+ _logger.LogError(message.Content);
+ return false;
}
+
// Clone message
var clonedMessage = RoleDialogModel.From(message);
clonedMessage.FunctionName = name;
@@ -34,23 +35,13 @@ public partial class RoutingService
var progressService = _services.GetService();
- // Before executing functions
- if (!isFillDummyContent)
- {
- clonedMessage.Indication = await function.GetIndication(message);
- }
- else
- {
- clonedMessage.Indication = "Running";
- }
+ clonedMessage.Indication = await funcExecutor.GetIndicatorAsync(message);
if (progressService?.OnFunctionExecuting != null)
{
await progressService.OnFunctionExecuting(clonedMessage);
}
-
- var agentService = _services.GetRequiredService();
- var agent = await agentService.GetAgent(clonedMessage.CurrentAgentId);
+
foreach (var hook in hooks)
{
hook.SetAgent(agent);
@@ -61,19 +52,7 @@ public partial class RoutingService
try
{
- if (clonedMessage.Handled)
- {
- clonedMessage.Content = clonedMessage.Content;
- }
- else if (!isFillDummyContent)
- {
- result = await function.Execute(clonedMessage);
- }
- else
- {
- clonedMessage.Content = dummyFuncResponse;
- result = true;
- }
+ result = await funcExecutor.ExecuteAsync(clonedMessage);
// After functions have been executed
foreach (var hook in hooks)
@@ -111,41 +90,6 @@ public partial class RoutingService
message.Content = JsonSerializer.Serialize(message.Data);
}
- // Save to Storage as well
- /*if (!message.StopCompletion && message.FunctionName != "route_to_agent")
- {
- var storage = _services.GetRequiredService();
- storage.Append(Context.ConversationId, message);
- }*/
-
return result;
}
-
- private async Task GetDummyFunctionOutput(string functionName, RoleDialogModel message)
- {
- if (string.IsNullOrEmpty(message.CurrentAgentId))
- {
- return null;
- }
-
- var agentService = _services.GetRequiredService();
- var agent = await agentService.GetAgent(message.CurrentAgentId);
- var found = agent?.Functions?.FirstOrDefault(x => x.Name == functionName);
- if (string.IsNullOrWhiteSpace(found?.Output))
- {
- return null;
- }
-
- var render = _services.GetRequiredService();
- var state = _services.GetRequiredService();
-
- var dict = new Dictionary();
- foreach (var item in state.GetStates())
- {
- dict[item.Key] = item.Value;
- }
-
- var text = render.Render(found.Output, dict);
- return text;
- }
}
diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs
index 8b63f96c..aa5a4595 100644
--- a/src/Infrastructure/BotSharp.Core/Using.cs
+++ b/src/Infrastructure/BotSharp.Core/Using.cs
@@ -1,48 +1,44 @@
-global using System;
-global using System.Collections.Generic;
-global using System.Text;
-global using System.Threading.Tasks;
-global using System.Linq;
-global using System.Text.Json;
-global using System.Net.Mime;
-global using System.Net.Http;
-global using System.Threading;
-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;
-global using BotSharp.Abstraction.Crontab.Models;
-global using BotSharp.Abstraction.Users;
-global using BotSharp.Abstraction.Roles;
-global using BotSharp.Abstraction.Roles.Models;
-global using BotSharp.Abstraction.Utilities;
-global using BotSharp.Abstraction.Conversations.Models;
-global using BotSharp.Abstraction.Agents.Settings;
-global using BotSharp.Abstraction.Conversations.Settings;
global using BotSharp.Abstraction.Agents.Enums;
global using BotSharp.Abstraction.Agents.Models;
+global using BotSharp.Abstraction.Agents.Settings;
+global using BotSharp.Abstraction.Conversations;
+global using BotSharp.Abstraction.Conversations.Models;
+global using BotSharp.Abstraction.Conversations.Settings;
+global using BotSharp.Abstraction.Crontab.Models;
+global using BotSharp.Abstraction.Files;
+global using BotSharp.Abstraction.Files.Enums;
+global using BotSharp.Abstraction.Files.Models;
+global using BotSharp.Abstraction.Files.Utilities;
global using BotSharp.Abstraction.Functions.Models;
+global using BotSharp.Abstraction.Infrastructures.Events;
+global using BotSharp.Abstraction.Knowledges.Models;
+global using BotSharp.Abstraction.Loggers.Services;
+global using BotSharp.Abstraction.MCP.Models;
+global using BotSharp.Abstraction.MCP.Services;
+global using BotSharp.Abstraction.Messaging.Enums;
+global using BotSharp.Abstraction.Plugins;
global using BotSharp.Abstraction.Repositories;
global using BotSharp.Abstraction.Repositories.Filters;
-global using BotSharp.Abstraction.Translation;
-global using BotSharp.Abstraction.Files;
-global using BotSharp.Abstraction.Files.Models;
-global using BotSharp.Abstraction.Files.Enums;
-global using BotSharp.Abstraction.Files.Utilities;
-global using BotSharp.Abstraction.Translation.Attributes;
-global using BotSharp.Abstraction.Messaging.Enums;
-global using BotSharp.Abstraction.Knowledges.Models;
+global using BotSharp.Abstraction.Roles;
+global using BotSharp.Abstraction.Roles.Models;
+global using BotSharp.Abstraction.Routing;
global using BotSharp.Abstraction.SideCar.Attributes;
-global using BotSharp.Abstraction.Statistics.Models;
global using BotSharp.Abstraction.Statistics.Enums;
+global using BotSharp.Abstraction.Statistics.Models;
global using BotSharp.Abstraction.Statistics.Services;
+global using BotSharp.Abstraction.Translation;
+global using BotSharp.Abstraction.Translation.Attributes;
+global using BotSharp.Abstraction.Users;
+global using BotSharp.Abstraction.Utilities;
global using BotSharp.Abstraction.Loggers.Services;
global using BotSharp.Abstraction.Infrastructures.Events;
global using BotSharp.Abstraction.Templating.Constants;
global using BotSharp.Abstraction.Realtime.Models.Session;
+global using BotSharp.Core.Agents.Services;
+global using BotSharp.Core.Conversations.Services;
+global using BotSharp.Core.Infrastructures;
+global using BotSharp.Core.Loggers.Services;
global using BotSharp.Core.Repository;
global using BotSharp.Core.Routing;
global using BotSharp.Core.Agents.Services;
@@ -51,4 +47,16 @@ global using BotSharp.Core.Infrastructures;
global using BotSharp.Core.Infrastructures.Websocket;
global using BotSharp.Core.Users.Services;
global using BotSharp.Core.Statistics.Services;
-global using BotSharp.Core.Loggers.Services;
\ No newline at end of file
+global using BotSharp.Core.Users.Services;
+global using EntityFrameworkCore.BootKit;
+global using Microsoft.Extensions.DependencyInjection;
+global using Microsoft.Extensions.Logging;
+global using System;
+global using System.Collections.Generic;
+global using System.Linq;
+global using System.Net.Http;
+global using System.Net.Mime;
+global using System.Text;
+global using System.Text.Json;
+global using System.Threading;
+global using System.Threading.Tasks;
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
index a5a96a12..bcb92f74 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs
@@ -328,7 +328,8 @@ public class ConversationController : ControllerBase
};
await HookEmitter.Emit(_services, async hook =>
- await hook.OnNotificationGenerated(inputMsg)
+ await hook.OnNotificationGenerated(inputMsg),
+ routing.Context.GetCurrentAgentId()
);
return response;
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs
index ca3ec45a..430a4563 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,7 @@ 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)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
@@ -74,8 +68,8 @@ public class InstructModeController : ControllerBase
TemplateName = input.Template,
UserMessage = input.Text,
CompletionText = response
- });
- }
+ }), agentId);
+
return response;
}
@@ -103,14 +97,7 @@ public class InstructModeController : ControllerBase
}
});
- var hooks = _services.GetServices();
- foreach (var hook in hooks)
- {
- if (!string.IsNullOrEmpty(hook.SelfId) && hook.SelfId != agentId)
- {
- continue;
- }
-
+ await HookEmitter.Emit(_services, async hook =>
await hook.OnResponseGenerated(new InstructResponseModel
{
AgentId = agentId,
@@ -120,8 +107,8 @@ public class InstructModeController : ControllerBase
UserMessage = input.Text,
SystemInstruction = message.RenderedInstruction,
CompletionText = message.Content
- });
- }
+ }), agentId);
+
return message.Content;
}
#endregion
diff --git a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Realtime/RealTimeCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Realtime/RealTimeCompletionProvider.cs
index 1cd32215..b3182b9a 100644
--- a/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Realtime/RealTimeCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.GoogleAI/Providers/Realtime/RealTimeCompletionProvider.cs
@@ -300,7 +300,7 @@ public class GoogleRealTimeProvider : IRealTimeCompletion
config.ResponseModalities = [Modality.AUDIO];
var words = new List();
- HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
+ HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)), agent.Id);
config.Temperature = Math.Max(realtimeSetting.Temperature, 0.6f);
config.MaxOutputTokens = realtimeSetting.MaxResponseOutputTokens;
@@ -320,7 +320,7 @@ public class GoogleRealTimeProvider : IRealTimeCompletion
}).ToArray();
await HookEmitter.Emit(_services,
- async hook => { await hook.OnSessionUpdated(agent, prompt, functions, isInit); });
+ async hook => { await hook.OnSessionUpdated(agent, prompt, functions, isInit); }, agent.Id);
if (_settings.Gemini.UseGoogleSearch)
{
diff --git a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs
index 29e495ec..22daf3ff 100644
--- a/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs
+++ b/src/Plugins/BotSharp.Plugin.OpenAI/Providers/Realtime/RealTimeCompletionProvider.cs
@@ -339,7 +339,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
if (realtimeModelSettings.InputAudioTranscribe)
{
var words = new List();
- HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
+ HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)), agent.Id);
sessionUpdate.session.InputAudioTranscription = new InputAudioTranscription
{
@@ -352,7 +352,7 @@ public class RealTimeCompletionProvider : IRealTimeCompletion
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnSessionUpdated(agent, instruction, functions, isInit);
- });
+ }, agent.Id);
await SendEventToModel(sessionUpdate);
await Task.Delay(300);
diff --git a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlGenerationFn.cs b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlGenerationFn.cs
index 4965a67c..11fd2cf7 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlGenerationFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlGenerationFn.cs
@@ -90,7 +90,7 @@ public class SqlGenerationFn : IFunctionCallback
{
var requirement = await x.GetSummaryAdditionalRequirements(nameof(SqlGenerationPlanner), message);
additionalRequirements.Add(requirement);
- });
+ }, message.CurrentAgentId);
var globalKnowledges = new List();
foreach (var hook in knowledgeHooks)
diff --git a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlReviewFn.cs b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlReviewFn.cs
index 6996fb6d..4255dd7f 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlReviewFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/Functions/SqlReviewFn.cs
@@ -30,7 +30,8 @@ public class SqlReviewFn : IFunctionCallback
if (args != null && !args.IsSqlTemplate && args.ContainsSqlStatements)
{
await HookEmitter.Emit(_services, async hook =>
- await hook.OnSourceCodeGenerated(nameof(SqlGenerationPlanner), message, "sql")
+ await hook.OnSourceCodeGenerated(nameof(SqlGenerationPlanner), message, "sql"),
+ message.CurrentAgentId
);
}
return true;
diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Functions/SummaryPlanFn.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Functions/SummaryPlanFn.cs
index 465f1df2..4212d0c2 100644
--- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Functions/SummaryPlanFn.cs
+++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/Functions/SummaryPlanFn.cs
@@ -68,7 +68,8 @@ public class SummaryPlanFn : IFunctionCallback
message.Content = summary.Content;
await HookEmitter.Emit(_services, async hook =>
- await hook.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message)
+ await hook.OnPlanningCompleted(nameof(TwoStageTaskPlanner), message),
+ message.CurrentAgentId
);
return true;
@@ -88,7 +89,7 @@ public class SummaryPlanFn : IFunctionCallback
{
var requirement = await x.GetSummaryAdditionalRequirements(nameof(TwoStageTaskPlanner), message);
additionalRequirements.Add(requirement);
- });
+ }, message.CurrentAgentId);
var globalKnowledges = new List();
foreach (var hook in knowledgeHooks)
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
index 168929ea..99a7744f 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverPlanningHook.cs
@@ -30,7 +30,7 @@ public class SqlDriverPlanningHook : IPlanningHook
await HookEmitter.Emit(_services, async (hook) =>
{
await hook.SqlGenerated(msg);
- });
+ }, msg.CurrentAgentId);
var settings = _services.GetRequiredService();
if (!settings.ExecuteSqlSelectAutonomous)
diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Interfaces/ISqlDriverHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Interfaces/ISqlDriverHook.cs
index b4871e66..63cff60b 100644
--- a/src/Plugins/BotSharp.Plugin.SqlDriver/Interfaces/ISqlDriverHook.cs
+++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Interfaces/ISqlDriverHook.cs
@@ -1,6 +1,8 @@
+using BotSharp.Abstraction.Hooks;
+
namespace BotSharp.Plugin.SqlDriver.Interfaces;
-public interface ISqlDriverHook
+public interface ISqlDriverHook : IHookBase
{
// Get database type
string GetDatabaseType(RoleDialogModel message);
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs
index 9d7df9a0..511abb45 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Agents.Models;
+using BotSharp.Abstraction.Infrastructures;
using BotSharp.Abstraction.Infrastructures.Enums;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Interfaces;
@@ -55,7 +56,7 @@ public class TwilioInboundController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnSessionCreating(request, instruction);
- });
+ }, request.AgentId);
var (agent, conversationId) = await InitConversation(request);
request.ConversationId = conversationId.Id;
@@ -65,9 +66,9 @@ public class TwilioInboundController : TwilioController
if (twilio.MachineDetected(request))
{
response = new VoiceResponse();
-
+
await HookEmitter.Emit(_services,
- async hook => await hook.OnVoicemailStarting(request));
+ async hook => await hook.OnVoicemailStarting(request), request.AgentId);
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
response.Play(new Uri(url));
@@ -118,7 +119,7 @@ public class TwilioInboundController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnSessionCreated(request);
- });
+ }, request.AgentId);
return TwiML(response);
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioOutboundController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioOutboundController.cs
index 4796c02d..5543af38 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioOutboundController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioOutboundController.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Infrastructures;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models;
@@ -32,9 +33,8 @@ public class TwilioOutboundController : TwilioController
if (twilio.MachineDetected(request))
{
response = new VoiceResponse();
-
await HookEmitter.Emit(_services,
- async hook => await hook.OnVoicemailStarting(request));
+ async hook => await hook.OnVoicemailStarting(request), request.AgentId);
var url = twilio.GetSpeechPath(request.ConversationId, "voicemail.mp3");
response.Play(new Uri(url));
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioRecordController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioRecordController.cs
index 4e4b1c75..3d13dc73 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioRecordController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioRecordController.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Infrastructures;
using BotSharp.Core.Infrastructures;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models;
@@ -36,7 +37,7 @@ public class TwilioRecordController : TwilioController
convService.SaveStates();
// recording completed
- await HookEmitter.Emit(_services, x => x.OnRecordingCompleted(request));
+ await HookEmitter.Emit(_services, x => x.OnRecordingCompleted(request), request.AgentId);
}
else
{
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioTranscribeController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioTranscribeController.cs
index 1fa020c0..778aa29d 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioTranscribeController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioTranscribeController.cs
@@ -49,7 +49,8 @@ public class TwilioTranscribeController : TwilioController
// transcription completed
transcript.Language = request.LanguageCode;
- await HookEmitter.Emit(_services, async x => await x.OnTranscribeCompleted(message, transcript));
+ await HookEmitter.Emit(_services, async x => await x.OnTranscribeCompleted(message, transcript),
+ request.AgentId);
}
}
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
index 048d75f3..786f116c 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioVoiceController.cs
@@ -65,7 +65,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnSessionCreating(request, instruction);
- });
+ }, request.AgentId);
var twilio = _services.GetRequiredService();
if (string.IsNullOrWhiteSpace(request.Intent))
@@ -98,7 +98,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnSessionCreated(request);
- });
+ }, request.AgentId);
return TwiML(response);
}
@@ -151,7 +151,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnReceivedUserMessage(request);
- });
+ }, request.AgentId);
}
else
{
@@ -161,7 +161,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnAgentHangUp(request);
- });
+ }, request.AgentId);
response = twilio.HangUp(string.Empty);
}
@@ -185,7 +185,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnWaitingUserResponse(request, instruction);
- });
+ }, request.AgentId);
response = twilio.ReturnInstructions(instruction);
}
@@ -223,7 +223,7 @@ public class TwilioVoiceController : TwilioController
{
request.AIResponseErrorMessage = $"AI response timeout: AIResponseWaitTime greater than {request.AIResponseWaitTime}, please check internal error log!";
await hook.OnAgentHangUp(request);
- });
+ }, request.AgentId);
response = twilio.HangUp($"twilio/error.mp3");
}
@@ -238,7 +238,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnAgentTransferring(request, _settings);
- });
+ }, request.AgentId);
response = twilio.DialCsrAgent($"twilio/voice/speeches/{request.ConversationId}/{reply.SpeechFileName}");
}
@@ -249,7 +249,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnAgentHangUp(request);
- });
+ }, request.AgentId);
}
else
{
@@ -274,7 +274,7 @@ public class TwilioVoiceController : TwilioController
await HookEmitter.Emit(_services, async hook =>
{
await hook.OnAgentResponsing(request, instruction);
- });
+ }, request.AgentId);
response = twilio.ReturnInstructions(instruction);
}
@@ -343,41 +343,35 @@ public class TwilioVoiceController : TwilioController
{
var twilio = _services.GetRequiredService();
- // Define the options with the predicate
- var emitOptions = new HookEmitOption
- {
- ShouldExecute = hook => hook.IsMatch(request)
- };
-
switch (request.CallStatus)
{
case "completed":
if (twilio.MachineDetected(request))
{
// voicemail
- await HookEmitter.Emit(_services, hook => hook.OnVoicemailLeft(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnVoicemailLeft(request), request.AgentId);
}
else
{
// phone call completed
- await HookEmitter.Emit(_services, hook => hook.OnUserDisconnected(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnUserDisconnected(request), request.AgentId);
}
break;
case "busy":
- await HookEmitter.Emit(_services, hook => hook.OnCallBusyStatus(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnCallBusyStatus(request), request.AgentId);
break;
case "no-answer":
- await HookEmitter.Emit(_services, hook => hook.OnCallNoAnswerStatus(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnCallNoAnswerStatus(request), request.AgentId);
break;
case "canceled":
- await HookEmitter.Emit(_services, hook => hook.OnCallCanceledStatus(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnCallCanceledStatus(request), request.AgentId);
break;
case "failed":
- await HookEmitter.Emit(_services, hook => hook.OnCallFailedStatus(request), emitOptions);
+ await HookEmitter.Emit(_services, hook => hook.OnCallFailedStatus(request), request.AgentId);
break;
default:
_logger.LogError($"Unknown call status: {request.CallStatus}, {request.CallSid}");
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioCallStatusHook.cs b/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioCallStatusHook.cs
index ae461595..e7ce0932 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioCallStatusHook.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioCallStatusHook.cs
@@ -1,11 +1,11 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Plugin.Twilio.Models;
using Task = System.Threading.Tasks.Task;
namespace BotSharp.Plugin.Twilio.Interfaces;
-public interface ITwilioCallStatusHook
+public interface ITwilioCallStatusHook : IHookBase
{
- bool IsMatch(ConversationalVoiceRequest request) => true;
Task OnVoicemailLeft(ConversationalVoiceRequest request) => Task.CompletedTask;
Task OnUserDisconnected(ConversationalVoiceRequest request) => Task.CompletedTask;
Task OnRecordingCompleted(ConversationalVoiceRequest request) => Task.CompletedTask;
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioSessionHook.cs b/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioSessionHook.cs
index 40525475..00837b6a 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioSessionHook.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Interfaces/ITwilioSessionHook.cs
@@ -1,10 +1,11 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Realtime.Models;
using BotSharp.Plugin.Twilio.Models;
using Task = System.Threading.Tasks.Task;
namespace BotSharp.Plugin.Twilio.Interfaces;
-public interface ITwilioSessionHook
+public interface ITwilioSessionHook : IHookBase
{
///
/// Before session creating
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
index 0ca10949..84f88b5b 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs
@@ -157,7 +157,8 @@ public class TwilioMessageQueueService : BackgroundService
var agentService = sp.GetRequiredService();
var agent = agentService.GetAgent(agentId).Result;
var extraWords = new List();
- HookEmitter.Emit(sp, hook => extraWords.AddRange(hook.OnModelTranscriptPrompt(agent)));
+ HookEmitter.Emit(sp, hook => extraWords.AddRange(hook.OnModelTranscriptPrompt(agent)),
+ agentId);
var phrases = reply.Content.Split(',', StringSplitOptions.RemoveEmptyEntries);
int capcity = 100;
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
index 7bc95382..e0618aaf 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioService.cs
@@ -235,7 +235,8 @@ public class TwilioService
if (_settings.TranscribeEnabled)
{
var words = new List();
- HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)));
+ HookEmitter.Emit(_services, hook => words.AddRange(hook.OnModelTranscriptPrompt(agent)),
+ agent.Id);
var hints = string.Join(", ", words);
var start = new Start();
start.Transcription(
@@ -323,10 +324,8 @@ public class TwilioService
ActionOnEmptyResult = true
};
- await HookEmitter.Emit(_services, async hook =>
- {
- await hook.OnWaitingAgentResponse(request, instruction);
- });
+ await HookEmitter.Emit(_services, async hook => await hook.OnWaitingAgentResponse(request, instruction),
+ request.AgentId);
response = ReturnInstructions(instruction);
}
diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj
index 85ff73ab..5db5199f 100644
--- a/src/WebStarter/WebStarter.csproj
+++ b/src/WebStarter/WebStarter.csproj
@@ -36,7 +36,6 @@
-