diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs
index da87646e8..0a5244f89 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs
@@ -49,10 +49,10 @@ public virtual Task OnTaskCompleted(RoleDialogModel message)
public virtual Task OnHumanInterventionNeeded(RoleDialogModel message)
=> Task.CompletedTask;
- public virtual Task OnFunctionExecuting(RoleDialogModel message)
+ public virtual Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
=> Task.CompletedTask;
- public virtual Task OnFunctionExecuted(RoleDialogModel message)
+ public virtual Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
=> Task.CompletedTask;
public virtual Task OnMessageReceived(RoleDialogModel message)
diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
index 6d967391c..d1b6f83c8 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationHook.cs
@@ -59,15 +59,17 @@ public interface IConversationHook : IHookBase
/// Triggered before LLM calls function.
///
///
+ ///
///
- Task OnFunctionExecuting(RoleDialogModel message);
+ Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual);
///
/// Triggered when the function calling completed.
///
///
+ ///
///
- Task OnFunctionExecuted(RoleDialogModel message);
+ Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual);
Task OnResponseGenerated(RoleDialogModel message);
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs
new file mode 100644
index 000000000..b3460bb67
--- /dev/null
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Enums/InvokeSource.cs
@@ -0,0 +1,19 @@
+namespace BotSharp.Abstraction.Routing.Enums;
+
+public static class InvokeSource
+{
+ ///
+ /// Invoke manually
+ ///
+ public const string Manual = "manual";
+
+ ///
+ /// Invoke by LLM directly
+ ///
+ public const string Llm = "llm";
+
+ ///
+ /// Invoke by agent routing
+ ///
+ public const string Routing = "routing";
+}
diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
index 97be88741..384a606f5 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs
@@ -30,8 +30,8 @@ public interface IRoutingService
//int GetRecursiveCounter();
//void SetRecursiveCounter(int counter);
- Task InvokeAgent(string agentId, List dialogs);
- Task InvokeFunction(string name, RoleDialogModel messages);
+ Task InvokeAgent(string agentId, List dialogs, string from = InvokeSource.Manual);
+ Task InvokeFunction(string name, RoleDialogModel messages, string from = InvokeSource.Manual);
Task InstructLoop(Agent agent, RoleDialogModel message, List dialogs);
///
diff --git a/src/Infrastructure/BotSharp.Abstraction/Using.cs b/src/Infrastructure/BotSharp.Abstraction/Using.cs
index 8a9d30cb6..38a6dca00 100644
--- a/src/Infrastructure/BotSharp.Abstraction/Using.cs
+++ b/src/Infrastructure/BotSharp.Abstraction/Using.cs
@@ -12,6 +12,7 @@
global using BotSharp.Abstraction.Infrastructures.Enums;
global using BotSharp.Abstraction.Models;
global using BotSharp.Abstraction.Routing.Models;
+global using BotSharp.Abstraction.Routing.Enums;
global using BotSharp.Abstraction.Templating;
global using BotSharp.Abstraction.Translation.Attributes;
global using BotSharp.Abstraction.Messaging.Enums;
diff --git a/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs b/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs
index 4eb4c64e9..095ff2b8f 100644
--- a/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs
+++ b/src/Infrastructure/BotSharp.Core.Realtime/Hooks/RealtimeConversationHook.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Utilities;
namespace BotSharp.Core.Realtime.Hooks;
@@ -10,7 +11,7 @@ public RealtimeConversationHook(IServiceProvider services)
_services = services;
}
- public async Task OnFunctionExecuting(RoleDialogModel message)
+ public async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hub = _services.GetRequiredService();
if (hub.HubConn == null)
@@ -31,10 +32,10 @@ public async Task OnFunctionExecuting(RoleDialogModel message)
}
}
- public async Task OnFunctionExecuted(RoleDialogModel message)
+ public async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hub = _services.GetRequiredService();
- if (hub.HubConn == null)
+ if (from != InvokeSource.Llm || hub.HubConn == null)
{
return;
}
diff --git a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
index 32b0a1127..fe544b4d2 100644
--- a/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
+++ b/src/Infrastructure/BotSharp.Core.Realtime/Services/RealtimeHub.cs
@@ -2,6 +2,7 @@
using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Models;
using BotSharp.Abstraction.Options;
+using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Core.Infrastructures;
namespace BotSharp.Core.Realtime.Services;
@@ -98,7 +99,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti
agent.Id);
}
- await routing.InvokeFunction(message.FunctionName, message);
+ await routing.InvokeFunction(message.FunctionName, message, from: InvokeSource.Llm);
}
else
{
diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
index a28ccbc78..1155dc38e 100644
--- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
+++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs
@@ -2,7 +2,6 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using BotSharp.Abstraction.Messaging;
using BotSharp.Abstraction.Messaging.Models.RichContent;
-using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Settings;
namespace BotSharp.Core.Conversations.Services;
diff --git a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs
index b315b6830..b1b4541e6 100644
--- a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs
+++ b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs
@@ -22,13 +22,13 @@ public override Task OnMessageReceived(RoleDialogModel message)
return base.OnMessageReceived(message);
}
- public override Task OnFunctionExecuted(RoleDialogModel message)
+ public override Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
if (Conversation != null && _convSettings.EnableExecutionLog)
{
_logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.FunctionName}({message.FunctionArgs}) => {message.Content}");
}
- return base.OnFunctionExecuted(message);
+ return base.OnFunctionExecuted(message, from: from);
}
public override Task OnResponseGenerated(RoleDialogModel message)
diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
index c93e133ce..308064518 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/InstructExecutor.cs
@@ -33,7 +33,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti
if (message.FunctionName != null)
{
var msg = RoleDialogModel.From(message, role: AgentRole.Function);
- await routing.InvokeFunction(message.FunctionName, msg);
+ await routing.InvokeFunction(message.FunctionName, msg, from: InvokeSource.Llm);
}
var agentId = routing.Context.GetCurrentAgentId();
@@ -57,7 +57,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnRouti
}
else
{
- var ret = await routing.InvokeAgent(agentId, dialogs);
+ var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing);
}
var response = dialogs.Last();
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
index 7bfd93523..8e625a364 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeAgent.cs
@@ -4,7 +4,7 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
- public async Task InvokeAgent(string agentId, List dialogs)
+ public async Task InvokeAgent(string agentId, List dialogs, string from = InvokeSource.Manual)
{
var agentService = _services.GetRequiredService();
var agent = await agentService.LoadAgent(agentId);
@@ -46,7 +46,7 @@ public async Task InvokeAgent(string agentId, List dialog
message.Indication = response.Indication;
message.CurrentAgentId = agent.Id;
- await InvokeFunction(message, dialogs);
+ await InvokeFunction(message, dialogs, from: from);
}
else
{
@@ -66,7 +66,7 @@ public async Task InvokeAgent(string agentId, List dialog
return true;
}
- private async Task InvokeFunction(RoleDialogModel message, List dialogs)
+ private async Task InvokeFunction(RoleDialogModel message, List dialogs, string from)
{
// execute function
// Save states
@@ -75,7 +75,7 @@ private async Task InvokeFunction(RoleDialogModel message, List();
// Call functions
- await routing.InvokeFunction(message.FunctionName, message);
+ await routing.InvokeFunction(message.FunctionName, message, from: from);
// Pass execution result to LLM to get response
if (!message.StopCompletion)
@@ -102,7 +102,7 @@ private async Task InvokeFunction(RoleDialogModel message, List InvokeFunction(string name, RoleDialogModel message)
+ public async Task InvokeFunction(string name, RoleDialogModel message, string from = InvokeSource.Manual)
{
var currentAgentId = message.CurrentAgentId;
var agentService = _services.GetRequiredService();
@@ -36,7 +36,7 @@ public async Task InvokeFunction(string name, RoleDialogModel message)
foreach (var hook in hooks)
{
hook.SetAgent(agent);
- await hook.OnFunctionExecuting(clonedMessage);
+ await hook.OnFunctionExecuting(clonedMessage, from: from);
}
bool result = false;
@@ -48,7 +48,7 @@ public async Task InvokeFunction(string name, RoleDialogModel message)
// After functions have been executed
foreach (var hook in hooks)
{
- await hook.OnFunctionExecuted(clonedMessage);
+ await hook.OnFunctionExecuted(clonedMessage, from: from);
}
// Set result to original message
diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
index 3e45fd63f..262c30016 100644
--- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
+++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs
@@ -51,7 +51,7 @@ public async Task InstructDirect(Agent agent, RoleDialogModel m
}
else
{
- var ret = await routing.InvokeAgent(agentId, dialogs);
+ var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing);
}
var response = dialogs.Last();
diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs
index aa5a45953..0e8e27622 100644
--- a/src/Infrastructure/BotSharp.Core/Using.cs
+++ b/src/Infrastructure/BotSharp.Core/Using.cs
@@ -22,6 +22,7 @@
global using BotSharp.Abstraction.Repositories.Filters;
global using BotSharp.Abstraction.Roles;
global using BotSharp.Abstraction.Roles.Models;
+global using BotSharp.Abstraction.Routing.Enums;
global using BotSharp.Abstraction.Routing;
global using BotSharp.Abstraction.SideCar.Attributes;
global using BotSharp.Abstraction.Statistics.Enums;
diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs
index f8851cb3d..61ae77a7f 100644
--- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs
+++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/RealtimeController.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Routing;
+using BotSharp.Abstraction.Routing.Enums;
namespace BotSharp.OpenAPI.Controllers;
@@ -25,7 +26,7 @@ public async Task ExecuteFunction(string agentId, string functionName, [
FunctionName = functionName,
FunctionArgs = JsonSerializer.Serialize(args)
};
- await routing.InvokeFunction(functionName, message);
+ await routing.InvokeFunction(functionName, message, from: InvokeSource.Llm);
return message.Content;
}
}
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
index 3c7a675d4..74735bd86 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs
@@ -1,4 +1,5 @@
using BotSharp.Abstraction.Conversations.Dtos;
+using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.SideCar;
using BotSharp.Abstraction.Users.Dtos;
using Microsoft.AspNetCore.SignalR;
@@ -84,7 +85,7 @@ public override async Task OnMessageReceived(RoleDialogModel message)
await base.OnMessageReceived(message);
}
- public override async Task OnFunctionExecuting(RoleDialogModel message)
+ public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
{
var conv = _services.GetRequiredService();
var action = new ConversationSenderActionModel
@@ -95,7 +96,7 @@ public override async Task OnFunctionExecuting(RoleDialogModel message)
};
await GenerateSenderAction(conv.ConversationId, action);
- await base.OnFunctionExecuting(message);
+ await base.OnFunctionExecuting(message, from: from);
}
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)
diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
index 720f3fd0a..991a64e50 100644
--- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
+++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/StreamingLogHook.cs
@@ -1,3 +1,4 @@
+using BotSharp.Abstraction.Routing.Enums;
using Microsoft.AspNetCore.SignalR;
using System.Text.Encodings.Web;
using System.Text.Unicode;
@@ -141,7 +142,7 @@ public async Task BeforeGenerating(Agent agent, List conversati
if (!_convSettings.ShowVerboseLog) return;
}
- public override async Task OnFunctionExecuting(RoleDialogModel message)
+ public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
{
var conversationId = _state.GetConversationId();
if (string.IsNullOrEmpty(conversationId)) return;
@@ -164,7 +165,7 @@ public override async Task OnFunctionExecuting(RoleDialogModel message)
await SendContentLog(conversationId, input);
}
- public override async Task OnFunctionExecuted(RoleDialogModel message)
+ public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
var conversationId = _state.GetConversationId();
if (string.IsNullOrEmpty(conversationId)) return;
diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs b/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs
index bc6471407..11bd8d36c 100644
--- a/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs
+++ b/src/Plugins/BotSharp.Plugin.Twilio/Hooks/TwilioConversationHook.cs
@@ -1,9 +1,10 @@
+using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Routing;
-using Task = System.Threading.Tasks.Task;
-using Twilio.Rest.Api.V2010.Account;
+using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models;
-using BotSharp.Abstraction.Hooks;
+using Twilio.Rest.Api.V2010.Account;
+using Task = System.Threading.Tasks.Task;
namespace BotSharp.Plugin.Twilio.Hooks;
@@ -22,7 +23,7 @@ public TwilioConversationHook(IServiceProvider services,
_logger = logger;
}
- public override async Task OnFunctionExecuted(RoleDialogModel message)
+ public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hooks = _services.GetHooks(message.CurrentAgentId);