diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs deleted file mode 100644 index 4046cda44..000000000 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/AgentRoutingArgs.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System.Text.Json.Serialization; - -namespace BotSharp.Abstraction.Agents.Models; - -public class AgentRoutingArgs -{ - [JsonPropertyName("agent_id")] - public string AgentId { get; set; } -} diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingArgs.cs new file mode 100644 index 000000000..e02b1c7b9 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingArgs.cs @@ -0,0 +1,14 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Abstraction.Agents.Models; + +public class RoutingArgs +{ + [JsonPropertyName("agent_name")] + public string AgentName { get; set; } + + public override string ToString() + { + return AgentName; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingResult.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingResult.cs new file mode 100644 index 000000000..b8ecdf6b6 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingResult.cs @@ -0,0 +1,11 @@ +namespace BotSharp.Abstraction.Agents.Models; + +public class RoutingResult +{ + public string Result { get; set; } + + public RoutingResult(string result) + { + Result = result; + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingTable.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingTable.cs new file mode 100644 index 000000000..2feedcf83 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/RoutingTable.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace BotSharp.Abstraction.Agents.Models; + +public class RoutingTable +{ + [JsonPropertyName("agent_id")] + public string AgentId { get; set; } + + [JsonPropertyName("name")] + public string AgentName { get; set; } + + [JsonPropertyName("required")] + public List RequiredFields { get; set; } + + public override string ToString() + { + return AgentName; + } +} diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs index 71698ebdc..c1fd2e307 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.GetChatCompletionsAsyncRecursively.cs @@ -53,18 +53,19 @@ await HandleAssistantMessage(new RoleDialogModel(AgentRole.Assistant, fn.Content return; } - fn.Content = fn.ExecutionResult; + fn.Content = fn.FunctionArgs.Replace("\r", " ").Replace("\n", " ").Trim() + " => " + fn.ExecutionResult; // Agent has been transferred + var agentSettings = _services.GetRequiredService(); if (fn.CurrentAgentId != preAgentId) { - var agentSettings = _services.GetRequiredService(); var agentService = _services.GetRequiredService(); agent = await agentService.LoadAgent(fn.CurrentAgentId); } // Add to dialog history - _storage.Append(conversationId, preAgentId, fn); + // The server had an error processing your request. Sorry about that! + // _storage.Append(conversationId, preAgentId, fn); // After function is executed, pass the result to LLM to get a natural response wholeDialogs.Add(fn); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 521f30546..45ede9dc0 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -85,7 +85,10 @@ private void SaveStateByArgs(string args) { foreach (JsonProperty property in root.EnumerateObject()) { - stateService.SetState(property.Name, property.Value.ToString()); + if (!string.IsNullOrEmpty(property.Value.ToString())) + { + stateService.SetState(property.Name, property.Value.ToString()); + } } } } diff --git a/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs index c8cd625d8..bae33c7e8 100644 --- a/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Functions/RouteToAgentFn.cs @@ -2,6 +2,8 @@ using BotSharp.Abstraction.Conversations.Models; using BotSharp.Abstraction.Functions; using BotSharp.Abstraction.Functions.Models; +using Microsoft.Extensions.Logging; +using System.IO; namespace BotSharp.Core.Functions; @@ -17,20 +19,51 @@ public RouteToAgentFn(IServiceProvider services) public async Task Execute(RoleDialogModel message) { - var args = JsonSerializer.Deserialize(message.FunctionArgs); + var args = JsonSerializer.Deserialize(message.FunctionArgs); + var result = new RoutingResult($"Routed to {args.AgentName}"); - if (string.IsNullOrEmpty(args.AgentId)) + if (string.IsNullOrEmpty(args.AgentName)) { - var result = new FunctionExecutionValidationResult("false", "agent_id can't be parsed."); - message.ExecutionResult = JsonSerializer.Serialize(result); + result = new RoutingResult($"Can't find {args.AgentName}"); } else { - var result = new FunctionExecutionValidationResult("true"); - message.ExecutionResult = JsonSerializer.Serialize(result); - message.CurrentAgentId = args.AgentId; + var agentSettings = _services.GetRequiredService(); + var dbSettings = _services.GetRequiredService(); + var filePath = Path.Combine(dbSettings.FileRepository, agentSettings.DataDir, agentSettings.RouterId, "route.json"); + var routes = JsonSerializer.Deserialize(File.ReadAllText(filePath)); + + var agent = routes.FirstOrDefault(x => x.AgentName.ToLower() == args.AgentName.ToLower()); + if (agent == null) + { + result = new RoutingResult($"Can't find agent {args.AgentName}."); + } + else + { + // Check required fields + var jo = JsonSerializer.Deserialize(message.FunctionArgs); + bool hasMissingField = false; + foreach (var field in agent.RequiredFields) + { + if (jo is JsonElement root) + { + if (!root.EnumerateObject().Any(x => x.Name == field)) + { + result = new RoutingResult($"Please provide {field}."); + hasMissingField = true; + break; + } + } + } + + if (!hasMissingField) + { + message.CurrentAgentId = agent.AgentId; + } + } } + message.ExecutionResult = JsonSerializer.Serialize(result); return true; } } diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs index 47e87dc33..a83e424a4 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/Controllers/WebhookController.cs @@ -124,7 +124,10 @@ public async Task> Messages([FromRoute] string age try { var parsed = JsonSerializer.Deserialize(json, jsonOpt); - reply.QuickReplies = parsed; + if (parsed.Length > 0) + { + reply.QuickReplies = parsed; + } } catch(Exception ex) { diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs index e0db69250..9d577143f 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/MessagingModels/QuickReplyMessage.cs @@ -13,5 +13,6 @@ public class QuickReplyMessage : IResponseMessage public string Text { get; set; } [JsonPropertyName("quick_replies")] - public QuickReplyMessageItem[] QuickReplies { get; set; } + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public QuickReplyMessageItem[]? QuickReplies { get; set; } }