Merge pull request #1103 from iceljc/refine/add-invoke-source

add invoke source
This commit is contained in:
Haiping 2025-07-24 16:38:25 -05:00 committed by GitHub
commit a3f0f57890
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 61 additions and 33 deletions

View file

@ -49,10 +49,10 @@ public abstract class ConversationHookBase : IConversationHook
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)

View file

@ -59,15 +59,17 @@ public interface IConversationHook : IHookBase
/// Triggered before LLM calls function.
/// </summary>
/// <param name="message"></param>
/// <param name="from"></param>
/// <returns></returns>
Task OnFunctionExecuting(RoleDialogModel message);
Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual);
/// <summary>
/// Triggered when the function calling completed.
/// </summary>
/// <param name="message"></param>
/// <param name="from"></param>
/// <returns></returns>
Task OnFunctionExecuted(RoleDialogModel message);
Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual);
Task OnResponseGenerated(RoleDialogModel message);

View file

@ -0,0 +1,19 @@
namespace BotSharp.Abstraction.Routing.Enums;
public static class InvokeSource
{
/// <summary>
/// Invoke manually
/// </summary>
public const string Manual = "manual";
/// <summary>
/// Invoke by LLM directly
/// </summary>
public const string Llm = "llm";
/// <summary>
/// Invoke by agent routing
/// </summary>
public const string Routing = "routing";
}

View file

@ -30,8 +30,8 @@ public interface IRoutingService
//int GetRecursiveCounter();
//void SetRecursiveCounter(int counter);
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
Task<bool> InvokeFunction(string name, RoleDialogModel messages);
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, string from = InvokeSource.Manual);
Task<bool> InvokeFunction(string name, RoleDialogModel messages, string from = InvokeSource.Manual);
Task<RoleDialogModel> InstructLoop(Agent agent, RoleDialogModel message, List<RoleDialogModel> dialogs);
/// <summary>

View file

@ -12,6 +12,7 @@ global using BotSharp.Abstraction.Agents.Enums;
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;

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Utilities;
namespace BotSharp.Core.Realtime.Hooks;
@ -10,7 +11,7 @@ public class RealtimeConversationHook : ConversationHookBase, IConversationHook
_services = services;
}
public async Task OnFunctionExecuting(RoleDialogModel message)
public async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hub = _services.GetRequiredService<IRealtimeHub>();
if (hub.HubConn == null)
@ -31,10 +32,10 @@ public class RealtimeConversationHook : ConversationHookBase, IConversationHook
}
}
public async Task OnFunctionExecuted(RoleDialogModel message)
public async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hub = _services.GetRequiredService<IRealtimeHub>();
if (hub.HubConn == null)
if (from != InvokeSource.Llm || hub.HubConn == null)
{
return;
}

View file

@ -2,6 +2,7 @@ using BotSharp.Abstraction.Functions.Models;
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 @@ public class RealtimeHub : IRealtimeHub
agent.Id);
}
await routing.InvokeFunction(message.FunctionName, message);
await routing.InvokeFunction(message.FunctionName, message, from: InvokeSource.Llm);
}
else
{

View file

@ -2,7 +2,6 @@ using BotSharp.Abstraction.Hooks;
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;

View file

@ -22,13 +22,13 @@ public class EvaluationConversationHook : ConversationHookBase
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)

View file

@ -33,7 +33,7 @@ public class InstructExecutor : IExecutor
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 @@ public class InstructExecutor : IExecutor
}
else
{
var ret = await routing.InvokeAgent(agentId, dialogs);
var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing);
}
var response = dialogs.Last();

View file

@ -4,7 +4,7 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
public async Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs)
public async Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, string from = InvokeSource.Manual)
{
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(agentId);
@ -46,7 +46,7 @@ public partial class RoutingService
message.Indication = response.Indication;
message.CurrentAgentId = agent.Id;
await InvokeFunction(message, dialogs);
await InvokeFunction(message, dialogs, from: from);
}
else
{
@ -66,7 +66,7 @@ public partial class RoutingService
return true;
}
private async Task<bool> InvokeFunction(RoleDialogModel message, List<RoleDialogModel> dialogs)
private async Task<bool> InvokeFunction(RoleDialogModel message, List<RoleDialogModel> dialogs, string from)
{
// execute function
// Save states
@ -75,7 +75,7 @@ public partial class RoutingService
var routing = _services.GetRequiredService<IRoutingService>();
// 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 @@ public partial class RoutingService
// Send to Next LLM
var curAgentId = routing.Context.GetCurrentAgentId();
await InvokeAgent(curAgentId, dialogs);
await InvokeAgent(curAgentId, dialogs, from);
}
}
else

View file

@ -5,7 +5,7 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
public async Task<bool> InvokeFunction(string name, RoleDialogModel message)
public async Task<bool> InvokeFunction(string name, RoleDialogModel message, string from = InvokeSource.Manual)
{
var currentAgentId = message.CurrentAgentId;
var agentService = _services.GetRequiredService<IAgentService>();
@ -36,7 +36,7 @@ public partial class RoutingService
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 partial class RoutingService
// 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

View file

@ -51,7 +51,7 @@ public partial class RoutingService : IRoutingService
}
else
{
var ret = await routing.InvokeAgent(agentId, dialogs);
var ret = await routing.InvokeAgent(agentId, dialogs, from: InvokeSource.Routing);
}
var response = dialogs.Last();

View file

@ -22,6 +22,7 @@ global using BotSharp.Abstraction.Repositories;
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;

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Enums;
namespace BotSharp.OpenAPI.Controllers;
@ -25,7 +26,7 @@ public class RealtimeController : ControllerBase
FunctionName = functionName,
FunctionArgs = JsonSerializer.Serialize(args)
};
await routing.InvokeFunction(functionName, message);
await routing.InvokeFunction(functionName, message, from: InvokeSource.Llm);
return message.Content;
}
}

View file

@ -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 class ChatHubConversationHook : ConversationHookBase
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<IConversationService>();
var action = new ConversationSenderActionModel
@ -95,7 +96,7 @@ public class ChatHubConversationHook : ConversationHookBase
};
await GenerateSenderAction(conv.ConversationId, action);
await base.OnFunctionExecuting(message);
await base.OnFunctionExecuting(message, from: from);
}
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)

View file

@ -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 class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
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 class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
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;

View file

@ -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 class TwilioConversationHook : ConversationHookBase, IConversationHook
_logger = logger;
}
public override async Task OnFunctionExecuted(RoleDialogModel message)
public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
{
var hooks = _services.GetHooks<ITwilioSessionHook>(message.CurrentAgentId);