From eeb0f9a65e422928d9b7ffebf0a364c7fa025a2d Mon Sep 17 00:00:00 2001 From: "nick.yi" Date: Fri, 23 Jan 2026 11:43:08 +0800 Subject: [PATCH 1/5] optimize IRoutingContext use async method --- .../Routing/IRoutingContext.cs | 10 ++--- .../Routing/IRoutingService.cs | 2 +- .../Agents/Hooks/BasicAgentHook.cs | 16 ++++--- .../ConversationService.SendMessage.cs | 6 +-- .../Routing/Functions/FallbackToRouterFn.cs | 2 +- .../Routing/Functions/RouteToAgentFn.cs | 8 ++-- .../Routing/Reasoning/HFReasoner.cs | 8 ++-- .../Routing/Reasoning/NaiveReasoner.cs | 8 ++-- .../Reasoning/OneStepForwardReasoner.cs | 8 ++-- .../BotSharp.Core/Routing/RoutingContext.cs | 42 +++++++++---------- .../RoutingService.HasMissingRequiredField.cs | 29 ++++++++----- .../Routing/RoutingService.InstructLoop.cs | 2 +- .../BotSharp.Core/Routing/RoutingService.cs | 2 +- .../Sequential/SequentialPlanner.cs | 10 ++--- .../SqlGeneration/SqlGenerationPlanner.cs | 4 +- .../TwoStaging/TwoStageTaskPlanner.cs | 4 +- .../Hooks/SqlDriverCrontabHook.cs | 2 +- .../TwilioStreamMiddleware.cs | 2 +- 18 files changed, 86 insertions(+), 79 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs index d50bced0e..4bf0e0c6a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs @@ -13,11 +13,11 @@ public interface IRoutingContext bool IsEmpty { get; } string IntentName { get; set; } int AgentCount { get; } - void Push(string agentId, string? reason = null, bool updateLazyRouting = true); - void Pop(string? reason = null, bool updateLazyRouting = true); - void PopTo(string agentId, string reason, bool updateLazyRouting = true); - void Replace(string agentId, string? reason = null, bool updateLazyRouting = true); - void Empty(string? reason = null); + Task Push(string agentId, string? reason = null, bool updateLazyRouting = true); + Task Pop(string? reason = null, bool updateLazyRouting = true); + Task PopTo(string agentId, string reason, bool updateLazyRouting = true); + Task Replace(string agentId, string? reason = null, bool updateLazyRouting = true); + Task Empty(string? reason = null); int CurrentRecursionDepth { get; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index d387fab16..456262b6e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -40,5 +40,5 @@ public interface IRoutingService Task GetConversationContent(List dialogs, int maxDialogCount = 100); - (bool, string) HasMissingRequiredField(RoleDialogModel message, out string agentId); + Task<(bool hasMissing, string reason, string agentId)> HasMissingRequiredField(RoleDialogModel message); } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs index 332337492..a2265a911 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs @@ -11,27 +11,25 @@ public BasicAgentHook(IServiceProvider services, AgentSettings settings) { } - public override Task OnAgentUtilityLoaded(Agent agent) + public override async Task OnAgentUtilityLoaded(Agent agent) { var conv = _services.GetRequiredService(); var isConvMode = conv.IsConversationMode(); - if (!isConvMode) return Task.CompletedTask; + if (!isConvMode) return; agent.Utilities ??= []; agent.SecondaryFunctions ??= []; agent.SecondaryInstructions ??= []; - var (functions, templates) = GetUtilityContent(agent); + var (functions, templates) = await GetUtilityContent(agent); agent.SecondaryFunctions = agent.SecondaryFunctions.Concat(functions).DistinctBy(x => x.Name, StringComparer.OrdinalIgnoreCase).ToList(); var contents = templates.Select(x => x.Content); agent.SecondaryInstructions = agent.SecondaryInstructions.Concat(contents).Distinct(StringComparer.OrdinalIgnoreCase).ToList(); - - return Task.CompletedTask; } - + - private (IEnumerable, IEnumerable) GetUtilityContent(Agent agent) + private async Task<(IEnumerable, IEnumerable)> GetUtilityContent(Agent agent) { var db = _services.GetRequiredService(); var (functionNames, templateNames) = FilterUtilityContent(agent.Utilities, agent); @@ -42,14 +40,14 @@ public override Task OnAgentUtilityLoaded(Agent agent) var entryAgentId = routing.EntryAgentId; if (!string.IsNullOrEmpty(entryAgentId)) { - var entryAgent = db.GetAgent(entryAgentId, basicsOnly: true); + var entryAgent = await db.GetAgentAsync(entryAgentId, basicsOnly: true); var (fns, tps) = FilterUtilityContent(entryAgent?.Utilities, agent); functionNames = functionNames.Concat(fns).Distinct().ToList(); templateNames = templateNames.Concat(tps).Distinct().ToList(); } } - var ua = db.GetAgent(BuiltInAgentId.UtilityAssistant); + var ua = await db.GetAgentAsync(BuiltInAgentId.UtilityAssistant); var functions = ua?.Functions?.Where(x => functionNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; var templates = ua?.Templates?.Where(x => templateNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; return (functions, templates); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index eb4d2d74f..1fe78b7ea 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -62,7 +62,7 @@ public async Task SendMessage(string agentId, if (message.StopCompletion) { stopCompletion = true; - routing.Context.Pop(); + await routing.Context.Pop(); break; } } @@ -83,12 +83,12 @@ public async Task SendMessage(string agentId, // Check the routing mode var states = _services.GetRequiredService(); var routingMode = states.GetState(StateConst.ROUTING_MODE, agent.Mode ?? RoutingMode.Eager); - routing.Context.Push(agent.Id, reason: "request started", updateLazyRouting: false); + await routing.Context.Push(agent.Id, reason: "request started", updateLazyRouting: false); if (routingMode == RoutingMode.Lazy) { message.CurrentAgentId = states.GetState(StateConst.LAZY_ROUTING_AGENT_ID, message.CurrentAgentId); - routing.Context.Push(message.CurrentAgentId, reason: "lazy routing", updateLazyRouting: false); + await routing.Context.Push(message.CurrentAgentId, reason: "lazy routing", updateLazyRouting: false); } response = await routing.InstructLoop(agent, message, dialogs); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs index 3438a2215..88e3fe955 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/FallbackToRouterFn.cs @@ -17,7 +17,7 @@ public async Task Execute(RoleDialogModel message) { var args = JsonSerializer.Deserialize(message.FunctionArgs); var routing = _services.GetRequiredService(); - routing.Context.PopTo(routing.Context.EntryAgentId, "pop to entry agent"); + await routing.Context.PopTo(routing.Context.EntryAgentId, "pop to entry agent"); message.Content = args.Reason; return true; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index 2b14a9efa..1fa3f13ee 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -51,14 +51,14 @@ public async Task Execute(RoleDialogModel message) var originalAgent = (await db.GetAgents(filter)).FirstOrDefault(); if (originalAgent != null) { - _context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " " + originalAgent.Name + " & is corrected" : "")}"); + await _context.Push(originalAgent.Id, $"user goal agent{(correctToOriginalAgent ? " " + originalAgent.Name + " & is corrected" : "")}"); } } // Push next action agent if (!string.IsNullOrEmpty(args.AgentName) && args.AgentName.Length < 32) { - _context.Push(args.AgentName, args.NextActionReason); + await _context.Push(args.AgentName, args.NextActionReason); states.SetState(StateConst.NEXT_ACTION_AGENT, args.AgentName, isNeedVersion: true); } @@ -83,11 +83,11 @@ public async Task Execute(RoleDialogModel message) } var routing = _services.GetRequiredService(); - var (missingfield, reason) = routing.HasMissingRequiredField(message, out var agentId); + var (missingfield, reason, agentId) = await routing.HasMissingRequiredField(message); if (missingfield && message.CurrentAgentId != agentId) { // Stack redirection agent - _context.Push(agentId, reason: $"REDIRECTION {reason}"); + await _context.Push(agentId, reason: $"REDIRECTION {reason}"); message.Content = reason; states.SetState(StateConst.AGENT_REDIRECTION_REASON, reason, isNeedVersion: false); } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs index b63ca4947..e10cef51a 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs @@ -69,7 +69,7 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R var agent = (await db.GetAgents(filter)).FirstOrDefault(); var context = _services.GetRequiredService(); - context.Push(agent.Id, reason: inst.NextActionReason); + await context.Push(agent.Id, reason: inst.NextActionReason); // Set user content as Planner's question message.FunctionName = inst.Function; @@ -79,11 +79,11 @@ public async Task AgentExecuting(Agent router, FunctionCallFromLlm inst, R return true; } - public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { var context = _services.GetRequiredService(); - context.Empty(reason: $"Agent queue is cleared by {nameof(HFReasoner)}"); - return Task.FromResult(true); + await context.Empty(reason: $"Agent queue is cleared by {nameof(HFReasoner)}"); + return true; } private string GetNextStepPrompt(Agent router) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs index 48c8423d2..062452ad7 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs @@ -73,7 +73,7 @@ public Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDia return Task.FromResult(true); } - public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { var context = _services.GetRequiredService(); if (inst.UnmatchedAgent) @@ -85,14 +85,14 @@ public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDial router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray(); // Handover to Router; - context.Pop(); + await context.Pop(); } else { - context.Empty(reason: $"Agent queue is cleared by {nameof(NaiveReasoner)}"); + await context.Empty(reason: $"Agent queue is cleared by {nameof(NaiveReasoner)}"); // context.Push(inst.OriginalAgent, "Push user goal agent"); } - return Task.FromResult(true); + return true; } private string GetNextStepPrompt(Agent router) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs index f2d7ed868..065d280d6 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs @@ -80,7 +80,7 @@ public Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDia return Task.FromResult(true); } - public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { var context = _services.GetRequiredService(); if (inst.UnmatchedAgent) @@ -92,14 +92,14 @@ public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDial router.TemplateDict["routing_agents"] = agents.Where(x => x.AgentId != unmatchedAgentId).ToArray(); // Handover to Router; - context.Pop(); + await context.Pop(); } else { - context.Empty(reason: $"Agent queue is cleared by {nameof(OneStepForwardReasoner)}"); + await context.Empty(reason: $"Agent queue is cleared by {nameof(OneStepForwardReasoner)}"); // context.Push(inst.OriginalAgent, "Push user goal agent"); } - return Task.FromResult(true); + return true; } private string GetNextStepPrompt(Agent router) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index 167866ddb..a24517441 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -81,13 +81,13 @@ public string GetCurrentAgentId() /// /// Id or Name /// - public void Push(string agentId, string? reason = null, bool updateLazyRouting = true) + public async Task Push(string agentId, string? reason = null, bool updateLazyRouting = true) { // Convert id to name if (!Guid.TryParse(agentId, out _)) { var agentService = _services.GetRequiredService(); - var agents = agentService.GetAgentOptions([agentId], byName: true).ConfigureAwait(false).GetAwaiter().GetResult(); + var agents = await agentService.GetAgentOptions([agentId], byName: true); if (agents.Count > 0) { @@ -100,8 +100,8 @@ public void Push(string agentId, string? reason = null, bool updateLazyRouting = var preAgentId = _stack.Count == 0 ? agentId : _stack.Peek(); _stack.Push(agentId); - HookEmitter.Emit(_services, async hook => await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason), - agentId).Wait(); + await HookEmitter.Emit(_services, async hook => await hook.OnAgentEnqueued(agentId, preAgentId, reason: reason), + agentId); UpdateLazyRoutingAgent(updateLazyRouting); } @@ -110,7 +110,7 @@ public void Push(string agentId, string? reason = null, bool updateLazyRouting = /// /// Pop current agent /// - public void Pop(string? reason = null, bool updateLazyRouting = true) + public async Task Pop(string? reason = null, bool updateLazyRouting = true) { if (_stack.Count == 0) { @@ -120,8 +120,8 @@ public void Pop(string? reason = null, bool updateLazyRouting = true) var agentId = _stack.Pop(); var currentAgentId = GetCurrentAgentId(); - HookEmitter.Emit(_services, async hook => await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason), - agentId).Wait(); + await HookEmitter.Emit(_services, async hook => await hook.OnAgentDequeued(agentId, currentAgentId, reason: reason), + agentId); if (string.IsNullOrEmpty(currentAgentId)) { @@ -130,7 +130,7 @@ public void Pop(string? reason = null, bool updateLazyRouting = true) // Run the routing rule var agentService = _services.GetRequiredService(); - var agent = agentService.GetAgent(currentAgentId).ConfigureAwait(false).GetAwaiter().GetResult(); + var agent = await agentService.GetAgent(currentAgentId); var message = new RoleDialogModel(AgentRole.User, $"Try to route to agent {agent.Name}") { @@ -145,25 +145,25 @@ public void Pop(string? reason = null, bool updateLazyRouting = true) }; var routing = _services.GetRequiredService(); - var (missingfield, _) = routing.HasMissingRequiredField(message, out agentId); + var (missingfield, _, redirectedAgentId) = await routing.HasMissingRequiredField(message); if (missingfield) { - if (currentAgentId != agentId) + if (currentAgentId != redirectedAgentId) { - _stack.Push(agentId); + await Push(redirectedAgentId); } } UpdateLazyRoutingAgent(updateLazyRouting); } - public void PopTo(string agentId, string reason, bool updateLazyRouting = true) + public async Task PopTo(string agentId, string reason, bool updateLazyRouting = true) { var currentAgentId = GetCurrentAgentId(); while (!string.IsNullOrEmpty(currentAgentId) && currentAgentId != agentId) { - Pop(reason, updateLazyRouting: updateLazyRouting); + await Pop(reason, updateLazyRouting: updateLazyRouting); currentAgentId = GetCurrentAgentId(); } } @@ -187,29 +187,29 @@ public bool ContainsAgentId(string agentId) return _stack.ToArray().Contains(agentId); } - public void Replace(string agentId, string? reason = null, bool updateLazyRouting = true) + public async Task Replace(string agentId, string? reason = null, bool updateLazyRouting = true) { var fromAgent = agentId; var toAgent = agentId; if (_stack.Count == 0) { - _stack.Push(agentId); + await Push(agentId); } else if (_stack.Peek() != agentId) { fromAgent = _stack.Peek(); _stack.Pop(); - _stack.Push(agentId); + await Push(agentId); - HookEmitter.Emit(_services, async hook => await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason), - agentId).Wait(); + await HookEmitter.Emit(_services, async hook => await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason), + agentId); } UpdateLazyRoutingAgent(updateLazyRouting); } - public void Empty(string? reason = null) + public async Task Empty(string? reason = null) { if (_stack.Count == 0) { @@ -218,8 +218,8 @@ public void Empty(string? reason = null) var agentId = GetCurrentAgentId(); _stack.Clear(); - HookEmitter.Emit(_services, async hook => await hook.OnAgentQueueEmptied(agentId, reason: reason), - agentId).Wait(); + await HookEmitter.Emit(_services, async hook => await hook.OnAgentQueueEmptied(agentId, reason: reason), + agentId); } public void SetMessageId(string conversationId, string messageId) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs index d88b65ba1..aadef612d 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs @@ -9,9 +9,10 @@ public partial class RoutingService /// If the target agent needs some required fields but the /// /// - public (bool, string) HasMissingRequiredField(RoleDialogModel message, out string agentId) + public async Task<(bool hasMissing, string reason, string agentId)> HasMissingRequiredField(RoleDialogModel message) { var reason = string.Empty; + var agentId = string.Empty; var args = JsonSerializer.Deserialize(message.FunctionArgs); var routing = _services.GetRequiredService(); @@ -20,7 +21,7 @@ public partial class RoutingService if (routingRules == null || !routingRules.Any()) { agentId = message.CurrentAgentId; - return (false, reason); + return (false, reason, agentId); } agentId = routingRules.First().AgentId; @@ -78,19 +79,27 @@ public partial class RoutingService // Handle redirect var routingRule = routingRules.FirstOrDefault(x => missingFields.Contains(x.Field)); - if (!string.IsNullOrEmpty(routingRule.RedirectTo)) + if (!string.IsNullOrEmpty(routingRule?.RedirectTo)) { var db = _services.GetRequiredService(); - var record = db.GetAgent(routingRule.RedirectTo); + var record = await db.GetAgentAsync(routingRule.RedirectTo); - // Add redirected agent - message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "redirect_to", record.Name); - agentId = routingRule.RedirectTo; + if (record != null) + { + // Add redirected agent + message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "redirect_to", record.Name); + agentId = routingRule.RedirectTo; #if DEBUG - Console.WriteLine($"*** Routing redirect to {record.Name.ToUpper()} ***"); + Console.WriteLine($"*** Routing redirect to {record.Name.ToUpper()} ***"); #else - logger.LogInformation($"*** Routing redirect to {record.Name.ToUpper()} ***"); + logger.LogInformation($"*** Routing redirect to {record.Name.ToUpper()} ***"); #endif + } + else + { + // back to router + agentId = message.CurrentAgentId; + } } else { @@ -99,7 +108,7 @@ public partial class RoutingService } } - return (missingFields.Any(), reason); + return (missingFields.Any(), reason, agentId); } private string AppendPropertyToArgs(string args, string key, string value) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs index e49410616..9fff55c92 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InstructLoop.cs @@ -21,7 +21,7 @@ public async Task InstructLoop(Agent agent, RoleDialogModel mes var reasoner = GetReasoner(_router); - _context.Push(_router.Id); + await _context.Push(_router.Id); // Handle multi-language for input var agentSettings = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index 4ac3f7314..cf078c852 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -36,7 +36,7 @@ public async Task InstructDirect(Agent agent, RoleDialogModel m Context.SetDialogs(dialogs); var routing = _services.GetRequiredService(); - routing.Context.Push(agent.Id, "instruct directly"); + await routing.Context.Push(agent.Id, "instruct directly"); var agentId = routing.Context.GetCurrentAgentId(); // Update next action agent's name diff --git a/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs index 975a60e9b..59743cb7c 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/Sequential/SequentialPlanner.cs @@ -130,23 +130,23 @@ public Task AgentExecuting(Agent router, FunctionCallFromLlm inst, RoleDia return Task.FromResult(true); } - public Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) + public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, RoleDialogModel message, List dialogs) { var context = _services.GetRequiredService(); if (message.StopCompletion) { - context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialPlanner)}"); - return Task.FromResult(false); + await context.Empty(reason: $"Agent queue is cleared by {nameof(SequentialPlanner)}"); + return false; } // Handover to Router; - context.Pop(); + await context.Pop(); var routing = _services.GetRequiredService(); routing.Context.ResetRecursiveCounter(); - return Task.FromResult(true); + return true; } private string GetNextStepPrompt(Agent router) diff --git a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs index a295ad2f9..d9027edfd 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs @@ -76,13 +76,13 @@ public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, Ro if (message.StopCompletion) { - context.Empty(reason: $"Agent queue is cleared by {nameof(SqlGenerationPlanner)}"); + await context.Empty(reason: $"Agent queue is cleared by {nameof(SqlGenerationPlanner)}"); return false; } if (dialogs.Last().Role == AgentRole.Assistant) { - context.Empty(); + await context.Empty(); return false; } diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs index 42303e9e3..2b7428602 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs @@ -104,13 +104,13 @@ public async Task AgentExecuted(Agent router, FunctionCallFromLlm inst, Ro if (message.StopCompletion) { - context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStageTaskPlanner)}"); + await context.Empty(reason: $"Agent queue is cleared by {nameof(TwoStageTaskPlanner)}"); return false; } if (dialogs.Last().Role == AgentRole.Assistant) { - context.Empty(); + await context.Empty(); return false; } diff --git a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs index 21ad01636..2688379f8 100644 --- a/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs +++ b/src/Plugins/BotSharp.Plugin.SqlDriver/Hooks/SqlDriverCrontabHook.cs @@ -42,7 +42,7 @@ public async Task OnCronTriggered(CrontabItem item) }) }; var routing = _services.GetRequiredService(); - routing.Context.Push(BuiltInAgentId.SqlDriver); + await routing.Context.Push(BuiltInAgentId.SqlDriver); await routing.InvokeFunction("sql_select", message); item.AgentId = BuiltInAgentId.SqlDriver; diff --git a/src/Plugins/BotSharp.Plugin.Twilio/TwilioStreamMiddleware.cs b/src/Plugins/BotSharp.Plugin.Twilio/TwilioStreamMiddleware.cs index a3a532684..d653a3417 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/TwilioStreamMiddleware.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/TwilioStreamMiddleware.cs @@ -88,7 +88,7 @@ private async Task HandleWebSocket(IServiceProvider services, string agentId, st await convService.States.Save(); var routing = services.GetRequiredService(); - routing.Context.Push(agentId); + await routing.Context.Push(agentId); await foreach (ChatSessionUpdate update in session.ReceiveUpdatesAsync(CancellationToken.None)) { From 766477d2554e3f39240280a4332a68d83c6b722f Mon Sep 17 00:00:00 2001 From: "nick.yi" Date: Fri, 23 Jan 2026 13:56:22 +0800 Subject: [PATCH 2/5] remove GetAgent sync method --- .../Repositories/IBotSharpRepository.cs | 4 +--- .../BotSharp.Core/Agents/Hooks/BasicAgentHook.cs | 4 ++-- .../Agents/Services/AgentService.GetAgents.cs | 2 +- .../Agents/Services/AgentService.UpdateAgent.cs | 4 ++-- .../Conversations/Services/ConversationService.cs | 2 +- .../FileRepository/FileRepository.Agent.cs | 13 ++++--------- .../RoutingService.HasMissingRequiredField.cs | 2 +- .../Conversation/TranslationController.cs | 4 ++-- .../BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs | 2 +- .../Repository/MongoRepository.Agent.cs | 14 +------------- 10 files changed, 16 insertions(+), 35 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 99cb1c9f4..af96dc226 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -70,9 +70,7 @@ Task UpdateRole(Role role, bool updateRoleAgents = false) #region Agent Task UpdateAgent(Agent agent, AgentField field) => throw new NotImplementedException(); - Agent? GetAgent(string agentId, bool basicsOnly = false) - => throw new NotImplementedException(); - Task GetAgentAsync(string agentId, bool basicsOnly = false) + Task GetAgent(string agentId, bool basicsOnly = false) => throw new NotImplementedException(); Task> GetAgents(AgentFilter filter) => throw new NotImplementedException(); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs index a2265a911..0cfadba67 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs @@ -40,14 +40,14 @@ public override async Task OnAgentUtilityLoaded(Agent agent) var entryAgentId = routing.EntryAgentId; if (!string.IsNullOrEmpty(entryAgentId)) { - var entryAgent = await db.GetAgentAsync(entryAgentId, basicsOnly: true); + var entryAgent = await db.GetAgent(entryAgentId, basicsOnly: true); var (fns, tps) = FilterUtilityContent(entryAgent?.Utilities, agent); functionNames = functionNames.Concat(fns).Distinct().ToList(); templateNames = templateNames.Concat(tps).Distinct().ToList(); } } - var ua = await db.GetAgentAsync(BuiltInAgentId.UtilityAssistant); + var ua = await db.GetAgent(BuiltInAgentId.UtilityAssistant); var functions = ua?.Functions?.Where(x => functionNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; var templates = ua?.Templates?.Where(x => templateNames.Contains(x.Name, StringComparer.OrdinalIgnoreCase))?.ToList() ?? []; return (functions, templates); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index 875785738..800a393c3 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -50,7 +50,7 @@ public async Task GetAgent(string id) return null; } - var profile = await _db.GetAgentAsync(id); + var profile = await _db.GetAgent(id); if (profile == null) { _logger.LogError($"Can't find agent {id}"); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs index b89b5d787..53bbcb8f4 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs @@ -18,7 +18,7 @@ public async Task UpdateAgent(Agent agent, AgentField updateField) return; } - var record = await _db.GetAgentAsync(agent.Id); + var record = await _db.GetAgent(agent.Id); if (record == null) return; record.Name = agent.Name ?? string.Empty; @@ -65,7 +65,7 @@ public async Task PatchAgentTemplate(Agent agent) return patchResult; } - var record = await _db.GetAgentAsync(agent.Id); + var record = await _db.GetAgent(agent.Id); if (record == null) { patchResult = $"Cannot find agent {agent.Id}"; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index fa1b8ec7a..cab3e3dab 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -230,7 +230,7 @@ public bool IsConversationMode() if (string.IsNullOrEmpty(routingCtx.EntryAgentId)) return null; - var agent = await db.GetAgentAsync(routingCtx.EntryAgentId, basicsOnly: true); + var agent = await db.GetAgent(routingCtx.EntryAgentId, basicsOnly: true); return agent?.MaxMessageCount; } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs index c71805458..43a5bf659 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs @@ -564,14 +564,14 @@ public async Task> GetAgentResponses(string agentId, string prefix, return responses; } - public Agent? GetAgent(string agentId, bool basicsOnly = false) + public async Task GetAgent(string agentId, bool basicsOnly = false) { var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir); var dir = Directory.EnumerateDirectories(agentDir).FirstOrDefault(x => x.Split(Path.DirectorySeparatorChar).Last() == agentId); if (!string.IsNullOrEmpty(dir)) { - var json = File.ReadAllText(Path.Combine(dir, AGENT_FILE)); + var json = await File.ReadAllTextAsync(Path.Combine(dir, AGENT_FILE)); if (string.IsNullOrEmpty(json)) { return null; @@ -593,23 +593,18 @@ public async Task> GetAgentResponses(string agentId, string prefix, var samples = FetchSamples(dir); var templates = FetchTemplates(dir); var responses = FetchResponses(dir); - return record.SetInstruction(defaultInstruction) + var result = record.SetInstruction(defaultInstruction) .SetChannelInstructions(channelInstructions) .SetFunctions(functions) .SetTemplates(templates) .SetSamples(samples) .SetResponses(responses); + return result; } return null; } - public Task GetAgentAsync(string agentId, bool basicsOnly = false) - { - var agent = GetAgent(agentId, basicsOnly); - return Task.FromResult(agent); - } - public Task> GetAgents(AgentFilter filter) { if (filter == null) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs index aadef612d..24635e445 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs @@ -82,7 +82,7 @@ public partial class RoutingService if (!string.IsNullOrEmpty(routingRule?.RedirectTo)) { var db = _services.GetRequiredService(); - var record = await db.GetAgentAsync(routingRule.RedirectTo); + var record = await db.GetAgent(routingRule.RedirectTo); if (record != null) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/Conversation/TranslationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Conversation/TranslationController.cs index 6d047dd8f..e2ea1903a 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/Conversation/TranslationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/Conversation/TranslationController.cs @@ -23,7 +23,7 @@ public TranslationController(IServiceProvider services, public async Task Translate([FromBody] TranslationRequestModel model) { var db = _services.GetRequiredService(); - var agent = await db.GetAgentAsync(BuiltInAgentId.AIAssistant); + var agent = await db.GetAgent(BuiltInAgentId.AIAssistant); var translator = _services.GetRequiredService(); var states = _services.GetRequiredService(); states.SetState("max_tokens", "8192"); @@ -38,7 +38,7 @@ public async Task Translate([FromBody] TranslationRequ public async Task SendMessageSse([FromBody] TranslationLongTextRequestModel model) { var db = _services.GetRequiredService(); - var agent = await db.GetAgentAsync(BuiltInAgentId.AIAssistant); + var agent = await db.GetAgent(BuiltInAgentId.AIAssistant); var translator = _services.GetRequiredService(); Response.StatusCode = 200; diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs index 3bf22d779..92e94f364 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/WelcomeHook.cs @@ -36,7 +36,7 @@ public WelcomeHook( public override async Task OnUserAgentConnectedInitially(Conversation conversation) { var db = _services.GetRequiredService(); - var agent = await db.GetAgentAsync(conversation.AgentId); + var agent = await db.GetAgent(conversation.AgentId); // Check if the Welcome template exists. var welcomeTemplate = agent?.Templates?.FirstOrDefault(x => x.Name == ".welcome"); diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs index a62971baa..c1e20f5d6 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs @@ -429,19 +429,7 @@ private async Task UpdateAgentAllFields(Agent agent) } #endregion - - public Agent? GetAgent(string agentId, bool basicsOnly = false) - { - var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId); - if (agent == null) - { - return null; - } - - return TransformAgentDocument(agent); - } - - public async Task GetAgentAsync(string agentId, bool basicsOnly = false) + public async Task GetAgent(string agentId, bool basicsOnly = false) { var agent = await _dc.Agents.AsQueryable().FirstOrDefaultAsync(x => x.Id == agentId); if (agent == null) From 58d30af0502fbc9af6bbf344610f376c5b5ac8a1 Mon Sep 17 00:00:00 2001 From: "nick.yi" Date: Fri, 23 Jan 2026 14:39:46 +0800 Subject: [PATCH 3/5] optimize IRoutingService,IHttpRequestHook use async method --- .../Http/IHttpRequestHook.cs | 2 +- .../Routing/IRoutingService.cs | 6 ++--- .../Routing/Hooks/RoutingAgentHook.cs | 8 +++---- .../Routing/Reasoning/HFReasoner.cs | 2 +- .../Routing/Reasoning/NaiveReasoner.cs | 2 +- .../Reasoning/OneStepForwardReasoner.cs | 2 +- .../Routing/Reasoning/ReasonerHelper.cs | 7 +++--- .../RoutingService.HasMissingRequiredField.cs | 2 +- .../BotSharp.Core/Routing/RoutingService.cs | 18 +++++++------- .../Users/Services/UserService.Token.cs | 24 +++++++++---------- .../Functions/HandleHttpRequestFn.cs | 6 ++--- .../Hooks/BasicHttpRequestHook.cs | 3 ++- .../SqlGeneration/SqlGenerationPlanner.cs | 2 +- .../TwoStaging/TwoStageTaskPlanner.cs | 2 +- .../Services/TwilioMessageQueueService.cs | 6 ++--- 15 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs b/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs index 61a7e116e..49073e0d0 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Http/IHttpRequestHook.cs @@ -4,5 +4,5 @@ namespace BotSharp.Abstraction.Http; public interface IHttpRequestHook { - void OnAddHttpHeaders(HttpHeaders headers, Uri uri); + Task OnAddHttpHeaders(HttpHeaders headers, Uri uri); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index 456262b6e..6c33cc410 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -10,21 +10,21 @@ public interface IRoutingService /// /// router's profile /// - RoutableAgent[] GetRoutableAgents(List profiles); + Task GetRoutableAgents(List profiles); /// /// Get rules by agent name /// /// agent name /// - RoutingRule[] GetRulesByAgentName(string name); + Task GetRulesByAgentName(string name); /// /// Get rules by agent id /// /// agent id /// - RoutingRule[] GetRulesByAgentId(string id); + Task GetRulesByAgentId(string id); Task InvokeAgent(string agentId, List dialogs, InvokeAgentOptions? options = null); Task InvokeFunction(string name, RoleDialogModel messages, InvokeFunctionOptions? options = null); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs index 7522a869e..24ad26093 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Hooks/RoutingAgentHook.cs @@ -22,9 +22,9 @@ public override async Task OnInstructionLoaded(string template, IDictionar dict["router"] = _agent; var routing = _services.GetRequiredService(); - var agents = routing.GetRoutableAgents(_agent.Profiles); + var agents = await routing.GetRoutableAgents(_agent.Profiles); - // 过滤 Planner + // filter Planner var planningRule = _agent.RoutingRules.FirstOrDefault(x => x.Type == "planner"); if (planningRule != null) { @@ -68,8 +68,8 @@ public override async Task OnFunctionsLoaded(List functions) { // check if enabled the routing rule var routing = _services.GetRequiredService(); - var rule = routing.GetRulesByAgentId(_agent.Id) - .FirstOrDefault(x => x.Type == RuleType.Fallback); + var rules = await routing.GetRulesByAgentId(_agent.Id); + var rule = rules.FirstOrDefault(x => x.Type == RuleType.Fallback); if (rule != null) { var agentService = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs index e10cef51a..7af5e63e9 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/HFReasoner.cs @@ -55,7 +55,7 @@ public async Task GetNextInstruction(Agent router, string m var inst = response.Content.JsonContent(); // Fix LLM malformed response - ReasonerHelper.FixMalformedResponse(_services, inst); + await ReasonerHelper.FixMalformedResponse(_services, inst); return inst; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs index 062452ad7..39e8be430 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/NaiveReasoner.cs @@ -59,7 +59,7 @@ public async Task GetNextInstruction(Agent router, string m var inst = (response.FunctionArgs ?? response.Content).JsonContent(); // Fix LLM malformed response - ReasonerHelper.FixMalformedResponse(_services, inst); + await ReasonerHelper.FixMalformedResponse(_services, inst); return inst; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs index 065d280d6..7d396fbb2 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/OneStepForwardReasoner.cs @@ -66,7 +66,7 @@ public async Task GetNextInstruction(Agent router, string m var inst = response.Content.JsonContent(); // Fix LLM malformed response - ReasonerHelper.FixMalformedResponse(_services, inst); + await ReasonerHelper.FixMalformedResponse(_services, inst); return inst; } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/ReasonerHelper.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/ReasonerHelper.cs index 278fd155b..4c138268b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoning/ReasonerHelper.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Reasoning/ReasonerHelper.cs @@ -6,13 +6,14 @@ public static class ReasonerHelper /// Sometimes LLM hallucinates and fails to set function names correctly. /// /// - public static void FixMalformedResponse(IServiceProvider services, FunctionCallFromLlm args) + public static async Task FixMalformedResponse(IServiceProvider services, FunctionCallFromLlm args) { var agentService = services.GetRequiredService(); - var agents = agentService.GetAgents(new AgentFilter + var agentsResult = await agentService.GetAgents(new AgentFilter { Types = [AgentType.Task] - }).ConfigureAwait(false).GetAwaiter().GetResult().Items.ToList(); + }); + var agents = agentsResult.Items.ToList(); var malformed = false; // Sometimes it populate malformed Function in Agent name diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs index 24635e445..f95031a56 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs @@ -16,7 +16,7 @@ public partial class RoutingService var args = JsonSerializer.Deserialize(message.FunctionArgs); var routing = _services.GetRequiredService(); - var routingRules = routing.GetRulesByAgentName(args.AgentName); + var routingRules = await routing.GetRulesByAgentName(args.AgentName); if (routingRules == null || !routingRules.Any()) { diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index cf078c852..a17d94d93 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -70,7 +70,7 @@ public async Task InstructDirect(Agent agent, RoleDialogModel m #if !DEBUG [SharpCache(10)] #endif - protected RoutingRule[] GetRoutingRecords() + protected async Task GetRoutingRecords() { var db = _services.GetRequiredService(); @@ -78,7 +78,7 @@ protected RoutingRule[] GetRoutingRecords() { Disabled = false }; - var agents = db.GetAgents(filter).ConfigureAwait(false).GetAwaiter().GetResult(); + var agents = await db.GetAgents(filter); var records = agents.Where(x => x.Type == AgentType.Task || x.Type == AgentType.Planning).SelectMany(x => { x.RoutingRules.ForEach(r => @@ -95,7 +95,7 @@ protected RoutingRule[] GetRoutingRecords() #if !DEBUG [SharpCache(10)] #endif - public RoutableAgent[] GetRoutableAgents(List profiles) + public async Task GetRoutableAgents(List profiles) { var db = _services.GetRequiredService(); @@ -104,7 +104,7 @@ public RoutableAgent[] GetRoutableAgents(List profiles) Disabled = false }; - var agents = db.GetAgents(filter).ConfigureAwait(false).GetAwaiter().GetResult(); + var agents = await db.GetAgents(filter); var routableAgents = agents.Where(x => x.Type == AgentType.Task || x.Type == AgentType.Planning || x.Type == AgentType.A2ARemote).Select(x => new RoutableAgent { AgentId = x.Id, @@ -144,16 +144,18 @@ public RoutableAgent[] GetRoutableAgents(List profiles) return routableAgents; } - public RoutingRule[] GetRulesByAgentName(string name) + public async Task GetRulesByAgentName(string name) { - return GetRoutingRecords() + var records = await GetRoutingRecords(); + return records .Where(x => x.AgentName.ToLower() == name.ToLower()) .ToArray(); } - public RoutingRule[] GetRulesByAgentId(string id) + public async Task GetRulesByAgentId(string id) { - return GetRoutingRecords() + var records = await GetRoutingRecords(); + return records .Where(x => x.AgentId == id) .ToArray(); } diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.Token.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.Token.cs index 7aa485775..7c4f1da7b 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.Token.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.Token.cs @@ -97,7 +97,7 @@ record = await db.GetUserByPhone(id, regionCode: regionCode); return default; } - var (token, jwt) = BuildToken(record); + var (token, jwt) = await BuildToken(record); foreach (var hook in hooks) { hook.UserAuthenticated(record, token); @@ -165,7 +165,7 @@ record = await db.GetUserByPhone(id, regionCode: regionCode); } // Issue a new access token - var (newToken, _) = BuildToken(user); + var (newToken, _) = await BuildToken(user); // Notify hooks for token issuance foreach (var hook in hooks) @@ -220,7 +220,7 @@ record = await db.GetUserByPhone(id, regionCode: (string.IsNullOrWhiteSpace(mode await db.UpdateUserVerified(record.Id); - var accessToken = GenerateJwtToken(record); + var accessToken = await GenerateJwtToken(record); var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken); var token = new Token { @@ -232,9 +232,9 @@ record = await db.GetUserByPhone(id, regionCode: (string.IsNullOrWhiteSpace(mode return token; } - public Task CreateTokenByUser(User user) + public async Task CreateTokenByUser(User user) { - var accessToken = GenerateJwtToken(user); + var accessToken = await GenerateJwtToken(user); var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken); var token = new Token { @@ -243,7 +243,7 @@ public Task CreateTokenByUser(User user) TokenType = "Bearer", Scope = "api" }; - return Task.FromResult(token); + return token; } public async Task GetAffiliateToken(string authorization) @@ -263,7 +263,7 @@ public Task CreateTokenByUser(User user) return default; } - var (token, jwt) = BuildToken(record); + var (token, jwt) = await BuildToken(record); return token; } @@ -289,7 +289,7 @@ public Task CreateTokenByUser(User user) return default; } - var (token, jwt) = BuildToken(record); + var (token, jwt) = await BuildToken(record); return token; } @@ -301,9 +301,9 @@ public async Task GetUserTokenExpires() } #region Private methods - private (Token, JwtSecurityToken) BuildToken(User record) + private async Task<(Token, JwtSecurityToken)> BuildToken(User record) { - var accessToken = GenerateJwtToken(record); + var accessToken = await GenerateJwtToken(record); var jwt = new JwtSecurityTokenHandler().ReadJwtToken(accessToken); var token = new Token { @@ -315,7 +315,7 @@ public async Task GetUserTokenExpires() return (token, jwt); } - private string GenerateJwtToken(User user) + private async Task GenerateJwtToken(User user) { var claims = new List { @@ -358,7 +358,7 @@ private string GenerateJwtToken(User user) }; var tokenHandler = new JwtSecurityTokenHandler(); var token = tokenHandler.CreateToken(tokenDescriptor); - SaveUserTokenExpiresCache(user.Id, expires, expireInMinutes).GetAwaiter().GetResult(); + await SaveUserTokenExpiresCache(user.Id, expires, expireInMinutes); return tokenHandler.WriteToken(token); } diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs b/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs index e0f73dd33..0984d298f 100644 --- a/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs +++ b/src/Plugins/BotSharp.Plugin.HttpHandler/Functions/HandleHttpRequestFn.cs @@ -58,7 +58,7 @@ public async Task Execute(RoleDialogModel message) using var client = _httpClientFactory.CreateClient(); var (uri, request) = BuildHttpRequest(url, method, content); - PrepareRequestHeaders(client, uri); + await PrepareRequestHeaders(client, uri); var response = await client.SendAsync(request); if (response == null || !response.IsSuccessStatusCode) @@ -69,12 +69,12 @@ public async Task Execute(RoleDialogModel message) return response; } - private void PrepareRequestHeaders(HttpClient client, Uri uri) + private async Task PrepareRequestHeaders(HttpClient client, Uri uri) { var hooks = _services.GetServices(); foreach (var hook in hooks) { - hook.OnAddHttpHeaders(client.DefaultRequestHeaders, uri); + await hook.OnAddHttpHeaders(client.DefaultRequestHeaders, uri); } } diff --git a/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs b/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs index f5c2f831c..053790f74 100644 --- a/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs +++ b/src/Plugins/BotSharp.Plugin.HttpHandler/Hooks/BasicHttpRequestHook.cs @@ -20,7 +20,7 @@ public BasicHttpRequestHook( _context = context; } - public void OnAddHttpHeaders(HttpHeaders headers, Uri uri) + public Task OnAddHttpHeaders(HttpHeaders headers, Uri uri) { var settings = _services.GetRequiredService(); @@ -36,5 +36,6 @@ public void OnAddHttpHeaders(HttpHeaders headers, Uri uri) { headers.Add(ORIGIN, origin); } + return Task.CompletedTask; } } diff --git a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs index d9027edfd..bb4ce21e5 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/SqlGeneration/SqlGenerationPlanner.cs @@ -36,7 +36,7 @@ public async Task GetNextInstruction(Agent router, string m inst = response.Content.JsonContent(); // Fix LLM malformed response - ReasonerHelper.FixMalformedResponse(_services, inst); + await ReasonerHelper.FixMalformedResponse(_services, inst); return inst; } diff --git a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs index 2b7428602..420fb8d7c 100644 --- a/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs +++ b/src/Plugins/BotSharp.Plugin.Planner/TwoStaging/TwoStageTaskPlanner.cs @@ -64,7 +64,7 @@ public async Task GetNextInstruction(Agent router, string m inst = response.Content.JsonContent(); // Fix LLM malformed response - ReasonerHelper.FixMalformedResponse(_services, inst); + await ReasonerHelper.FixMalformedResponse(_services, inst); return inst; } diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs index 35cf78aed..fbf6160dd 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Services/TwilioMessageQueueService.cs @@ -117,7 +117,7 @@ private async Task ProcessUserMessageAsync(CallerMessage message) reply.SpeechFileName = await GetReplySpeechFileName(message.ConversationId, reply, sp); } - reply.Hints = GetHints(agentId, reply, sp); + reply.Hints = await GetHints(agentId, reply, sp); await sessionManager.SetAssistantReplyAsync(message.ConversationId, message.SeqNumber, reply); } @@ -158,10 +158,10 @@ private static async Task GetReplySpeechFileName(string conversationId, return fileName; } - private static string GetHints(string agentId, AssistantMessage reply, IServiceProvider sp) + private static async Task GetHints(string agentId, AssistantMessage reply, IServiceProvider sp) { var agentService = sp.GetRequiredService(); - var agent = agentService.GetAgent(agentId).ConfigureAwait(false).GetAwaiter().GetResult(); + var agent = await agentService.GetAgent(agentId); var extraWords = new List(); HookEmitter.Emit(sp, hook => extraWords.AddRange(hook.OnModelTranscriptPrompt(agent)), agentId); From 0949ed418918c5d9a72ef800644626508beeefc8 Mon Sep 17 00:00:00 2001 From: "nick.yi" Date: Fri, 23 Jan 2026 15:01:28 +0800 Subject: [PATCH 4/5] revert origin logic --- src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index a24517441..716d49c04 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -150,7 +150,7 @@ await HookEmitter.Emit(_services, async hook => await hook.OnAgent { if (currentAgentId != redirectedAgentId) { - await Push(redirectedAgentId); + _stack.Push(redirectedAgentId); } } From a3f27ab9ec199910bc89664345b4757984930a77 Mon Sep 17 00:00:00 2001 From: "nick.yi" Date: Fri, 23 Jan 2026 15:09:11 +0800 Subject: [PATCH 5/5] revert RoutingContext Replace origin logic --- src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index 716d49c04..985af20ee 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -194,13 +194,13 @@ public async Task Replace(string agentId, string? reason = null, bool updateLazy if (_stack.Count == 0) { - await Push(agentId); + _stack.Push(agentId); } else if (_stack.Peek() != agentId) { fromAgent = _stack.Peek(); _stack.Pop(); - await Push(agentId); + _stack.Push(agentId); await HookEmitter.Emit(_services, async hook => await hook.OnAgentReplaced(fromAgent, toAgent, reason: reason), agentId);