change to options

This commit is contained in:
Jicheng Lu 2025-08-04 14:21:11 -05:00
parent 2edee6beff
commit 6308bdea5f
15 changed files with 81 additions and 40 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, string from = InvokeSource.Manual)
public virtual Task OnFunctionExecuting(RoleDialogModel message, InvokeFunctionOptions? options = null)
=> Task.CompletedTask;
public virtual Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
public virtual Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null)
=> Task.CompletedTask;
public virtual Task OnMessageReceived(RoleDialogModel message)

View file

@ -61,7 +61,7 @@ public interface IConversationHook : IHookBase
/// <param name="message"></param>
/// <param name="from"></param>
/// <returns></returns>
Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual);
Task OnFunctionExecuting(RoleDialogModel message, InvokeFunctionOptions? options = null);
/// <summary>
/// Triggered when the function calling completed.
@ -69,7 +69,7 @@ public interface IConversationHook : IHookBase
/// <param name="message"></param>
/// <param name="from"></param>
/// <returns></returns>
Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual);
Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null);
Task OnResponseGenerated(RoleDialogModel message);

View file

@ -26,8 +26,8 @@ public interface IRoutingService
/// <returns></returns>
RoutingRule[] GetRulesByAgentId(string id);
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, string from = InvokeSource.Manual, bool useStream = false);
Task<bool> InvokeFunction(string name, RoleDialogModel messages, string from = InvokeSource.Manual);
Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs, InvokeAgentOptions? options = null);
Task<bool> InvokeFunction(string name, RoleDialogModel messages, InvokeFunctionOptions? options = null);
Task<RoleDialogModel> InstructLoop(Agent agent, RoleDialogModel message, List<RoleDialogModel> dialogs);
/// <summary>

View file

@ -0,0 +1,31 @@
namespace BotSharp.Abstraction.Routing.Models;
public abstract class InvokeOptions
{
public string From { get; set; }
}
public class InvokeAgentOptions : InvokeOptions
{
public bool UseStream { get; set; }
public static InvokeAgentOptions Default()
{
return new()
{
From = InvokeSource.Manual,
UseStream = false
};
}
}
public class InvokeFunctionOptions : InvokeOptions
{
public static InvokeFunctionOptions Default()
{
return new()
{
From = InvokeSource.Manual
};
}
}

View file

@ -11,7 +11,7 @@ public class RealtimeConversationHook : ConversationHookBase, IConversationHook
_services = services;
}
public async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
public async Task OnFunctionExecuting(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
var hub = _services.GetRequiredService<IRealtimeHub>();
if (hub.HubConn == null)
@ -32,10 +32,10 @@ public class RealtimeConversationHook : ConversationHookBase, IConversationHook
}
}
public async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
public async Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
var hub = _services.GetRequiredService<IRealtimeHub>();
if (from != InvokeSource.Llm || hub.HubConn == null)
if (options?.From != InvokeSource.Llm || hub.HubConn == null)
{
return;
}

View file

@ -99,7 +99,7 @@ public class RealtimeHub : IRealtimeHub
agent.Id);
}
await routing.InvokeFunction(message.FunctionName, message, from: InvokeSource.Llm);
await routing.InvokeFunction(message.FunctionName, message, options: new() { From = InvokeSource.Llm });
}
else
{

View file

@ -1,4 +1,5 @@
using BotSharp.Abstraction.Evaluations;
using BotSharp.Abstraction.Routing.Models;
namespace BotSharp.Core.Evaluations;
@ -22,13 +23,13 @@ public class EvaluationConversationHook : ConversationHookBase
return base.OnMessageReceived(message);
}
public override Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
public override Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
if (Conversation != null && _convSettings.EnableExecutionLog)
{
_logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.FunctionName}({message.FunctionArgs}) => {message.Content}");
}
return base.OnFunctionExecuted(message, from: from);
return base.OnFunctionExecuted(message, options);
}
public override Task OnResponseGenerated(RoleDialogModel message)

View file

@ -1,5 +1,6 @@
using BotSharp.Abstraction.Infrastructures.Enums;
using BotSharp.Abstraction.Planning;
using BotSharp.Abstraction.Routing.Models;
namespace BotSharp.Core.Routing.Reasoning;
@ -33,7 +34,7 @@ public class InstructExecutor : IExecutor
if (message.FunctionName != null)
{
var msg = RoleDialogModel.From(message, role: AgentRole.Function);
await routing.InvokeFunction(message.FunctionName, msg, from: InvokeSource.Llm);
await routing.InvokeFunction(message.FunctionName, msg, options: new() { From = InvokeSource.Routing });
}
var agentId = routing.Context.GetCurrentAgentId();
@ -59,11 +60,12 @@ public class InstructExecutor : IExecutor
{
var state = _services.GetRequiredService<IConversationStateService>();
var useStreamMsg = state.GetState("use_stream_message");
var ret = await routing.InvokeAgent(
agentId,
dialogs,
from: InvokeSource.Routing,
useStream: bool.TryParse(useStreamMsg, out var useStream) && useStream);
var options = new InvokeAgentOptions()
{
From = InvokeSource.Routing,
UseStream = bool.TryParse(useStreamMsg, out var useStream) && useStream
};
var ret = await routing.InvokeAgent(agentId, dialogs, options);
}
var response = dialogs.Last();

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.Templating;
namespace BotSharp.Core.Routing;
@ -7,9 +8,9 @@ public partial class RoutingService
public async Task<bool> InvokeAgent(
string agentId,
List<RoleDialogModel> dialogs,
string from = InvokeSource.Manual,
bool useStream = false)
InvokeAgentOptions? options = null)
{
options ??= InvokeAgentOptions.Default();
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.LoadAgent(agentId);
@ -36,7 +37,7 @@ public partial class RoutingService
RoleDialogModel response;
var message = dialogs.Last();
if (useStream)
if (options?.UseStream == true)
{
response = await chatCompletion.GetChatCompletionsStreamingAsync(agent, dialogs);
}
@ -59,7 +60,7 @@ public partial class RoutingService
message.CurrentAgentId = agent.Id;
message.IsStreaming = response.IsStreaming;
await InvokeFunction(message, dialogs, from: from, useStream: useStream);
await InvokeFunction(message, dialogs, options);
}
else
{
@ -83,8 +84,7 @@ public partial class RoutingService
private async Task<bool> InvokeFunction(
RoleDialogModel message,
List<RoleDialogModel> dialogs,
string from,
bool useStream)
InvokeAgentOptions? options = null)
{
// execute function
// Save states
@ -93,7 +93,8 @@ public partial class RoutingService
var routing = _services.GetRequiredService<IRoutingService>();
// Call functions
await routing.InvokeFunction(message.FunctionName, message, from: from);
var funcOptions = options != null ? new InvokeFunctionOptions() { From = options.From } : null;
await routing.InvokeFunction(message.FunctionName, message, options: funcOptions);
// Pass execution result to LLM to get response
if (!message.StopCompletion)
@ -120,7 +121,7 @@ public partial class RoutingService
// Send to Next LLM
var curAgentId = routing.Context.GetCurrentAgentId();
await InvokeAgent(curAgentId, dialogs, from, useStream);
await InvokeAgent(curAgentId, dialogs, options);
}
}
else

View file

@ -1,3 +1,4 @@
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Core.MessageHub;
using BotSharp.Core.Routing.Executor;
@ -5,8 +6,9 @@ namespace BotSharp.Core.Routing;
public partial class RoutingService
{
public async Task<bool> InvokeFunction(string name, RoleDialogModel message, string from = InvokeSource.Manual)
public async Task<bool> InvokeFunction(string name, RoleDialogModel message, InvokeFunctionOptions? options = null)
{
options ??= InvokeFunctionOptions.Default();
var currentAgentId = message.CurrentAgentId;
var agentService = _services.GetRequiredService<IAgentService>();
var agent = await agentService.GetAgent(currentAgentId);
@ -38,7 +40,7 @@ public partial class RoutingService
foreach (var hook in hooks)
{
hook.SetAgent(agent);
await hook.OnFunctionExecuting(clonedMessage, from: from);
await hook.OnFunctionExecuting(clonedMessage, options);
}
bool result = false;
@ -50,7 +52,7 @@ public partial class RoutingService
// After functions have been executed
foreach (var hook in hooks)
{
await hook.OnFunctionExecuted(clonedMessage, from: from);
await hook.OnFunctionExecuted(clonedMessage, options);
}
// Set result to original message

View file

@ -53,11 +53,12 @@ public partial class RoutingService : IRoutingService
{
var state = _services.GetRequiredService<IConversationStateService>();
var useStreamMsg = state.GetState("use_stream_message");
var ret = await routing.InvokeAgent(
agentId,
dialogs,
from: InvokeSource.Routing,
useStream: bool.TryParse(useStreamMsg, out var useStream) && useStream);
var options = new InvokeAgentOptions()
{
From = InvokeSource.Routing,
UseStream = bool.TryParse(useStreamMsg, out var useStream) && useStream
};
var ret = await routing.InvokeAgent(agentId, dialogs, options);
}
var response = dialogs.Last();

View file

@ -26,7 +26,7 @@ public class RealtimeController : ControllerBase
FunctionName = functionName,
FunctionArgs = JsonSerializer.Serialize(args)
};
await routing.InvokeFunction(functionName, message, from: InvokeSource.Llm);
await routing.InvokeFunction(functionName, message, options: new() { From = InvokeSource.Llm });
return message.Content;
}
}

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.Conversations.Dtos;
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Abstraction.SideCar;
using BotSharp.Abstraction.Users.Dtos;
using Microsoft.AspNetCore.SignalR;
@ -78,9 +79,9 @@ public class ChatHubConversationHook : ConversationHookBase
await base.OnMessageReceived(message);
}
public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
public override async Task OnFunctionExecuting(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
await base.OnFunctionExecuting(message, from: from);
await base.OnFunctionExecuting(message, options);
}
public override async Task OnPostbackMessageReceived(RoleDialogModel message, PostbackMessageModel replyMsg)

View file

@ -1,5 +1,6 @@
using BotSharp.Abstraction.Conversations.Enums;
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Models;
using Microsoft.AspNetCore.SignalR;
using System.Runtime.CompilerServices;
using System.Text.Encodings.Web;
@ -141,7 +142,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
if (!_convSettings.ShowVerboseLog) return;
}
public override async Task OnFunctionExecuting(RoleDialogModel message, string from = InvokeSource.Manual)
public override async Task OnFunctionExecuting(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
var conversationId = _state.GetConversationId();
if (string.IsNullOrEmpty(conversationId)) return;
@ -165,7 +166,7 @@ public class StreamingLogHook : ConversationHookBase, IContentGeneratingHook, IR
await SendEvent(ChatEvent.OnConversationContentLogGenerated, conversationId, BuildContentLog(input));
}
public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
public override async Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
var conversationId = _state.GetConversationId();
if (string.IsNullOrEmpty(conversationId)) return;

View file

@ -1,6 +1,7 @@
using BotSharp.Abstraction.Hooks;
using BotSharp.Abstraction.Routing;
using BotSharp.Abstraction.Routing.Enums;
using BotSharp.Abstraction.Routing.Models;
using BotSharp.Plugin.Twilio.Interfaces;
using BotSharp.Plugin.Twilio.Models;
using Twilio.Rest.Api.V2010.Account;
@ -23,7 +24,7 @@ public class TwilioConversationHook : ConversationHookBase, IConversationHook
_logger = logger;
}
public override async Task OnFunctionExecuted(RoleDialogModel message, string from = InvokeSource.Manual)
public override async Task OnFunctionExecuted(RoleDialogModel message, InvokeFunctionOptions? options = null)
{
var hooks = _services.GetHooks<ITwilioSessionHook>(message.CurrentAgentId);