From ce7b4954754c564922e65cd400a0c3dd0a9a074e Mon Sep 17 00:00:00 2001 From: Haiping Chen Date: Wed, 24 Apr 2024 16:45:18 -0500 Subject: [PATCH] Return reason from HasMissingRequiredField. --- .../Routing/IRoutingService.cs | 2 +- .../Routing/Models/RoutingArgs.cs | 6 +++--- .../Routing/Functions/RouteToAgentFn.cs | 4 ++-- .../Handlers/ResponseToUserRoutingHandler.cs | 10 +++++----- .../Handlers/RouteToAgentRoutingHandler.cs | 16 ++++++++-------- .../BotSharp.Core/Routing/RoutingContext.cs | 2 +- .../RoutingService.HasMissingRequiredField.cs | 14 +++++++++----- .../Routing/RoutingService.InvokeFunction.cs | 11 ----------- .../Providers/ChatCompletionProvider.cs | 3 ++- 9 files changed, 31 insertions(+), 37 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index da84ffa3..1577d103 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -44,5 +44,5 @@ public interface IRoutingService Task GetConversationContent(List dialogs, int maxDialogCount = 50); - bool HasMissingRequiredField(RoleDialogModel message, out string agentId); + (bool, string) HasMissingRequiredField(RoleDialogModel message, out string agentId); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs index 159b5555..105c0c57 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingArgs.cs @@ -50,12 +50,12 @@ public class RoutingArgs [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string UserGoal { get; set; } - [JsonPropertyName("user_message_in_english")] - public string UserMessageInEnglish { get; set; } - [JsonPropertyName("language")] public string Language { get; set; } = LanguageType.ENGLISH; + [JsonPropertyName("lastest_message_translated_to_english")] + public string UserMessageInEnglish { get; set; } + public override string ToString() { var route = string.IsNullOrEmpty(AgentName) ? "" : $""; diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index 2450a6fc..639c907b 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -83,11 +83,11 @@ public partial class RouteToAgentFn : IFunctionCallback } var routing = _services.GetRequiredService(); - var missingfield = routing.HasMissingRequiredField(message, out var agentId); + var (missingfield, reason) = routing.HasMissingRequiredField(message, out var agentId); if (missingfield && message.CurrentAgentId != agentId) { // Stack redirection agent - _context.Push(agentId, reason: $"REDIRECTION {message.Content}"); + _context.Push(agentId, reason: $"REDIRECTION {reason}"); } } diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs index cca6615e..92a3b137 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ResponseToUserRoutingHandler.cs @@ -11,20 +11,20 @@ public class ResponseToUserRoutingHandler : RoutingHandlerBase, IRoutingHandler public List Parameters => new List { new ParameterPropertyDef("reason", - "why response to user directly without go to other agents"), + "why response to user directly without go to other agents."), new ParameterPropertyDef("response", "response content to user in courteous words with language English. If the user wants to end the conversation, you must set conversation_end to true and response politely."), new ParameterPropertyDef("conversation_end", - "whether to end this conversation", + "whether to end this conversation.", type: "boolean"), new ParameterPropertyDef("task_completed ", "whether the user's task request has been completed.", type: "boolean"), - new ParameterPropertyDef("user_message_in_english", - "Translate user message from non-English to English"), new ParameterPropertyDef("language", - "User prefered language, considering the whole conversation. Language could be English, Spanish or Chinese.", + "User preferred language, considering the whole conversation. Language could be English, Spanish or Chinese.", required: true), + new ParameterPropertyDef("lastest_message_translated_to_english", + "Translate user lastest message in [CONVERSATION] to English"), }; public ResponseToUserRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs index 6aa12998..5c08d679 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RouteToAgentRoutingHandler.cs @@ -12,28 +12,28 @@ public class RouteToAgentRoutingHandler : RoutingHandlerBase, IRoutingHandler public List Parameters => new List { new ParameterPropertyDef("next_action_reason", - "the reason why route to this virtual agent", + "the reason why route to this virtual agent.", required: true), new ParameterPropertyDef("next_action_agent", - "agent for next action based on user latest response, if user is replying last agent's question, you must route to this agent", + "agent for next action based on user latest response, if user is replying last agent's question, you must route to this agent.", required: true), + new ParameterPropertyDef("args", + "useful parameters of next action agent, format: { }", + type: "object"), new ParameterPropertyDef("user_goal_description", "user goal based on user initial task.", required: true), new ParameterPropertyDef("user_goal_agent", "agent who can acheive user initial task, must align with user_goal_description.", required: true), - new ParameterPropertyDef("args", - "useful parameters of next action agent, format: { }", - type: "object"), new ParameterPropertyDef("is_new_task", "whether the user is requesting a new task that is different from the previous topic.", type: "boolean"), - new ParameterPropertyDef("user_message_in_english", - "Translate user message from non-English to English"), new ParameterPropertyDef("language", - "User prefered language, considering the whole conversation. Language could be English, Spanish or Chinese.", + "User preferred language, considering the whole conversation. Language could be English, Spanish or Chinese.", required: true), + new ParameterPropertyDef("lastest_message_translated_to_english", + "Translate lastest user message in [CONVERSATION] to English"), }; public RouteToAgentRoutingHandler(IServiceProvider services, ILogger logger, RoutingSettings settings) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs index 4d8eba43..6b126a37 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingContext.cs @@ -128,7 +128,7 @@ public class RoutingContext : IRoutingContext }; var routing = _services.GetRequiredService(); - var missingfield = routing.HasMissingRequiredField(message, out agentId); + var (missingfield, _) = routing.HasMissingRequiredField(message, out agentId); if (missingfield) { if (currentAgentId != agentId) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs index 2a6b676c..60f3f331 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.HasMissingRequiredField.cs @@ -10,8 +10,9 @@ public partial class RoutingService /// If the target agent needs some required fields but the /// /// - public bool HasMissingRequiredField(RoleDialogModel message, out string agentId) + public (bool, string) HasMissingRequiredField(RoleDialogModel message, out string agentId) { + var reason = 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; + return (false, reason); } agentId = routingRules.First().AgentId; @@ -68,9 +69,13 @@ public partial class RoutingService if (missingFields.Any()) { + var logger = _services.GetRequiredService>(); + // Add field to args message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "missing_fields", missingFields); - message.Content = $"missing some information: {string.Join(", ", missingFields)}"; + reason = $"missing some information: {string.Join(", ", missingFields)}"; + // message.Content = reason; + logger.LogWarning(reason); // Handle redirect var routingRule = routingRules.FirstOrDefault(x => missingFields.Contains(x.Field)); @@ -82,7 +87,6 @@ public partial class RoutingService // Add redirected agent message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "redirect_to", record.Name); agentId = routingRule.RedirectTo; - var logger = _services.GetRequiredService>(); #if DEBUG Console.WriteLine($"*** Routing redirect to {record.Name.ToUpper()} ***", Color.Yellow); #else @@ -96,7 +100,7 @@ public partial class RoutingService } } - return missingFields.Any(); + return (missingFields.Any(), reason); } private string AppendPropertyToArgs(string args, string key, string value) diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs index 86839b67..42465533 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs @@ -4,9 +4,6 @@ namespace BotSharp.Core.Routing; public partial class RoutingService { - private List _functionCallStack = new List(); - public List FunctionCallStack => _functionCallStack; - public async Task InvokeFunction(string name, RoleDialogModel message) { var function = _services.GetServices().FirstOrDefault(x => x.Name == name); @@ -38,14 +35,6 @@ public partial class RoutingService { result = await function.Execute(clonedMessage); - _functionCallStack.Add(new FunctionCallingResponse - { - Role = AgentRole.Function, - FunctionName = clonedMessage.FunctionName, - Args = JsonDocument.Parse(clonedMessage.FunctionArgs ?? "{}"), - Content = clonedMessage.Content - }); - // After functions have been executed foreach (var hook in hooks) { diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index 0e5cc0ab..820dcb84 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -300,6 +300,7 @@ public class ChatCompletionProvider : IChatCompletion })); prompt += $"{verbose}\r\n"; + prompt += "\r\n[CONVERSATION]\r\n"; verbose = string.Join("\r\n", chatCompletionsOptions.Messages .Where(x => x.Role != AgentRole.System).Select(x => { @@ -311,7 +312,7 @@ public class ChatCompletionProvider : IChatCompletion else if (x.Role == ChatRole.User) { var m = x as ChatRequestUserMessage; - return !string.IsNullOrEmpty(m.Name) ? + return !string.IsNullOrEmpty(m.Name) && m.Name != "route_to_agent" ? $"{m.Name}: {m.Content}" : $"{m.Role}: {m.Content}"; }