diff --git a/Directory.Build.props b/Directory.Build.props index a0e7305b..6940e0bc 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ 10.0 ..\..\..\packages - 0.13.0 + 0.13.0 true \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs index 5f56004a..d82e8602 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs @@ -6,6 +6,10 @@ public enum AgentField Name, Description, IsPublic, + Disabled, + AllowRouting, + Profiles, + RoutingRules, Instruction, Function, Template, diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs index 8b968035..d3551296 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs @@ -6,7 +6,7 @@ public class Agent { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; - public string Description { get; set; } + public string Description { get; set; } = string.Empty; public DateTime CreatedDateTime { get; set; } public DateTime UpdatedDateTime { get; set; } @@ -81,6 +81,10 @@ public class Agent Samples = agent.Samples, Knowledges = agent.Knowledges, IsPublic = agent.IsPublic, + Disabled = agent.Disabled, + AllowRouting = agent.AllowRouting, + Profiles = agent.Profiles, + RoutingRules = agent.RoutingRules, CreatedDateTime = agent.CreatedDateTime, UpdatedDateTime = agent.UpdatedDateTime, }; @@ -94,7 +98,7 @@ public class Agent public Agent SetTemplates(List templates) { - Templates = templates; + Templates = templates ?? new List(); return this; } @@ -133,4 +137,28 @@ public class Agent IsPublic = isPublic; return this; } + + public Agent SetDisabled(bool disabled) + { + Disabled = disabled; + return this; + } + + public Agent SetAllowRouting(bool allowRouting) + { + AllowRouting = allowRouting; + return this; + } + + public Agent SetProfiles(List profiles) + { + Profiles = profiles ?? new List(); + return this; + } + + public Agent SetRoutingRules(List rules) + { + RoutingRules = rules ?? new List(); + return this; + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index dcb9534f..ba1ea69d 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) Icon.png $(GeneratePackageOnBuild) diff --git a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs index 968ae667..77eb1ff7 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Functions/Models/FunctionCallFromLlm.cs @@ -14,6 +14,6 @@ public class FunctionCallFromLlm public override string ToString() { - return $"{Function}: {Parameters}"; + return $"{Function} {Parameters}"; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs index 15ad54aa..3854e1b0 100644 --- a/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs +++ b/src/Infrastructure/BotSharp.Abstraction/MLTasks/IChatCompletion.cs @@ -2,11 +2,23 @@ namespace BotSharp.Abstraction.MLTasks; public interface IChatCompletion { + /// + /// The LLM provider like Microsoft Azure, OpenAI, ClaudAI + /// string Provider { get; } + + /// + /// Set model name, one provider can consume different model or version(s) + /// + /// + void SetModelName(string model); + Task GetChatCompletionsAsync(Agent agent, List conversations, Func onMessageReceived, Func onFunctionExecuting); - Task GetChatCompletionsStreamingAsync(Agent agent, List conversations, Func onMessageReceived); + Task GetChatCompletionsStreamingAsync(Agent agent, + List conversations, + Func onMessageReceived); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs index 08234983..13115557 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingService.cs @@ -2,6 +2,7 @@ namespace BotSharp.Abstraction.Routing; public interface IRoutingService { + Agent LoadRouter(); List Dialogs { get; } Task Enter(Agent agent, List whileDialogs); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs index bc173c33..37d0fe50 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RetrievalArgs.cs @@ -19,6 +19,6 @@ public class RetrievalArgs : RoutingArgs public override string ToString() { - return $"{AgentName} {Question} ({JsonSerializer.Serialize(Arguments)}) => {Answer} ({Reason})"; + return $" [{AgentName}]: {Question} ({JsonSerializer.Serialize(Arguments)}) => {Answer} ({Reason})"; } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs index 40102d4a..ca24ad6b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Models/RoutingRule.cs @@ -18,4 +18,9 @@ public class RoutingRule { return $"{AgentName} {Field}"; } + + public RoutingRule() + { + + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs index 26377274..e3adbdee 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/RoutingSettings.cs @@ -7,8 +7,5 @@ public class RoutingSettings /// public string RouterId { get; set; } = string.Empty; - /// - /// Reasoner Agent Id - /// - public string ReasonerId { get; set; } = string.Empty; + public bool EnableReasoning { get; set; } = false; } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index 567a3dac..d42e1da0 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -35,6 +35,10 @@ public partial class AgentService .SetName(foundAgent.Name) .SetDescription(foundAgent.Description) .SetIsPublic(foundAgent.IsPublic) + .SetDisabled(foundAgent.Disabled) + .SetAllowRouting(foundAgent.AllowRouting) + .SetProfiles(foundAgent.Profiles) + .SetRoutingRules(foundAgent.RoutingRules) .SetInstruction(foundAgent.Instruction) .SetTemplates(foundAgent.Templates) .SetFunctions(foundAgent.Functions) diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 122b52b0..87e05734 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -1,4 +1,6 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Routing; +using BotSharp.Abstraction.Routing.Settings; using BotSharp.Abstraction.Templating; namespace BotSharp.Core.Agents.Services; @@ -18,7 +20,9 @@ public partial class AgentService hook.OnAgentLoading(ref id); } - var agent = await GetAgent(id); + var settings = _services.GetRequiredService(); + var routingService = _services.GetRequiredService(); + var agent = settings.RouterId == id ? routingService.LoadRouter() : await GetAgent(id); var templateDict = new Dictionary(); PopulateState(templateDict); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs index 7f6b619b..f91fdef0 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Routing.Models; using System.IO; namespace BotSharp.Core.Agents.Services; @@ -15,6 +16,11 @@ public partial class AgentService record.Name = agent.Name ?? string.Empty; record.Description = agent.Description ?? string.Empty; + record.IsPublic = agent.IsPublic; + record.Disabled = agent.Disabled; + record.AllowRouting = agent.AllowRouting; + record.Profiles = agent.Profiles ?? new List(); + record.RoutingRules = agent.RoutingRules ?? new List(); record.Instruction = agent.Instruction ?? string.Empty; record.Functions = agent.Functions ?? new List(); record.Templates = agent.Templates ?? new List(); @@ -53,6 +59,10 @@ public partial class AgentService .SetName(foundAgent.Name) .SetDescription(foundAgent.Description) .SetIsPublic(foundAgent.IsPublic) + .SetDisabled(foundAgent.Disabled) + .SetAllowRouting(foundAgent.AllowRouting) + .SetProfiles(foundAgent.Profiles) + .SetRoutingRules(foundAgent.RoutingRules) .SetInstruction(foundAgent.Instruction) .SetTemplates(foundAgent.Templates) .SetFunctions(foundAgent.Functions) diff --git a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj index cc807aee..52e0a5c9 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj +++ b/src/Infrastructure/BotSharp.Core/BotSharp.Core.csproj @@ -3,7 +3,7 @@ netstandard2.1 $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) @@ -74,6 +74,20 @@ + + + + + + + + PreserveNewest + + + PreserveNewest + + + True diff --git a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs index a0133eac..02c5a515 100644 --- a/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs +++ b/src/Infrastructure/BotSharp.Core/BotSharpServiceCollectionExtensions.cs @@ -51,16 +51,11 @@ public static class BotSharpServiceCollectionExtensions config.Bind("Router", routingSettings); services.AddSingleton((IServiceProvider x) => routingSettings); - services.AddScoped(); - services.AddScoped(); services.AddScoped(); // Register function callback services.AddScoped(); - // Register Hooks - services.AddScoped(); - services.AddScoped(); services.AddScoped(); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 366d13d2..6d3293c4 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -50,7 +50,7 @@ public partial class ConversationService } } - // reasoning + // Routing with reasoning var settings = _services.GetRequiredService(); if (settings.RouterId == agent.Id) { @@ -82,6 +82,13 @@ public partial class ConversationService agent = await agentService.LoadAgent(reasonedContext.CurrentAgentId); } } + else if (reasonedContext.FunctionName == "route_to_agent") + { + if (reasonedContext.CurrentAgentId != agent.Id) + { + agent = await agentService.LoadAgent(reasonedContext.CurrentAgentId); + } + } routing.Dialogs.ForEach(x => { diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index ee7d09ec..3357549a 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -1,5 +1,6 @@ using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Repositories; +using BotSharp.Abstraction.Routing.Settings; using System.IO; namespace BotSharp.Core.Conversations.Services; @@ -44,9 +45,10 @@ public class ConversationStorage : IConversationStorage } else { - var agent = db.Agents.First(x => x.Id == agentId); + var routingSetting = _services.GetRequiredService(); + var agentName = routingSetting.RouterId == agentId ? "Router" : db.Agents.First(x => x.Id == agentId).Name; - sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agent.Name}|"); + sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|"); var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); if (string.IsNullOrEmpty(content)) { diff --git a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs index 9534581e..d7b716f9 100644 --- a/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs +++ b/src/Infrastructure/BotSharp.Core/Infrastructures/CompletionProvider.cs @@ -4,16 +4,31 @@ namespace BotSharp.Core.Infrastructures; public class CompletionProvider { - public static IChatCompletion GetChatCompletion(IServiceProvider services, string? provider = null) + public static IChatCompletion GetChatCompletion(IServiceProvider services, string? provider = null, string? model = null) { var completions = services.GetServices(); var state = services.GetRequiredService(); + if (provider == null) { - provider = state.GetState("provider", "azure-gpt-3.5"); + provider = state.GetState("provider", "azure-openai"); } - - return completions.FirstOrDefault(x => x.Provider == provider); + + if (model == null) + { + model = state.GetState("model", "gpt-3.5-turbo"); + } + + var completer = completions.FirstOrDefault(x => x.Provider == provider); + if (completer == null) + { + var logger = services.GetRequiredService>(); + logger.LogError($"Can't resolve completion provider by {provider}"); + } + + completer.SetModelName(model); + + return completer; } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index 1a6445e7..ecda379f 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -4,6 +4,7 @@ using FunctionDef = BotSharp.Abstraction.Functions.Models.FunctionDef; using BotSharp.Abstraction.Users.Models; using BotSharp.Abstraction.Agents.Models; using MongoDB.Driver; +using BotSharp.Abstraction.Routing.Models; namespace BotSharp.Core.Repository; @@ -240,6 +241,18 @@ public class FileRepository : IBotSharpRepository case AgentField.IsPublic: UpdateAgentIsPublic(agent.Id, agent.IsPublic); break; + case AgentField.Disabled: + UpdateAgentDisabled(agent.Id, agent.Disabled); + break; + case AgentField.AllowRouting: + UpdateAgentAllowRouting(agent.Id, agent.AllowRouting); + break; + case AgentField.Profiles: + UpdateAgentProfiles(agent.Id, agent.Profiles); + break; + case AgentField.RoutingRules: + UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); + break; case AgentField.Instruction: UpdateAgentInstruction(agent.Id, agent.Instruction); break; @@ -298,6 +311,54 @@ public class FileRepository : IBotSharpRepository File.WriteAllText(agentFile, json); } + private void UpdateAgentDisabled(string agentId, bool disabled) + { + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.Disabled = disabled; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + + private void UpdateAgentAllowRouting(string agentId, bool allowRouting) + { + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.AllowRouting = allowRouting; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + + private void UpdateAgentProfiles(string agentId, List profiles) + { + if (profiles.IsNullOrEmpty()) return; + + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.Profiles = profiles; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + + private void UpdateAgentRoutingRules(string agentId, List rules) + { + if (rules.IsNullOrEmpty()) return; + + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.RoutingRules = rules; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + private void UpdateAgentInstruction(string agentId, string instruction) { if (string.IsNullOrEmpty(instruction)) return; @@ -396,6 +457,10 @@ public class FileRepository : IBotSharpRepository agent.Name = inputAgent.Name; agent.Description = inputAgent.Description; agent.IsPublic = inputAgent.IsPublic; + agent.Disabled = inputAgent.Disabled; + agent.AllowRouting = inputAgent.AllowRouting; + agent.Profiles = inputAgent.Profiles; + agent.RoutingRules = inputAgent.RoutingRules; agent.UpdatedDateTime = DateTime.UtcNow; var json = JsonSerializer.Serialize(agent, _options); File.WriteAllText(agentFile, json); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Prompts/reasoning_functions.liquid b/src/Infrastructure/BotSharp.Core/Routing/Prompts/reasoning_functions.liquid new file mode 100644 index 00000000..44b29104 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Prompts/reasoning_functions.liquid @@ -0,0 +1,22 @@ +# retrieve_data_from_agent +Retrieve data from appropriate agent. +Parameters: + 1. agent_name: the name of the agent; + 2. question: the question you will ask the agent to get the necessary data + 3. args: required parameters extracted from question and hand over to the next agent. The args should be in JSON format. + +# continue_execute_task +Continue to execute user's request without further information retrival. +Parameters: + 1. agent_name: the name of the agent; + 2. args: required parameters extracted from question. + +# interrupt_task_execution +Can't continue user's request becauase the requirements are not met or you have already known the answer. +Parameters: + 1. reason: the reason why the request is interrupted; + +# response_to_user +You have already known the answer according the dialogs. +Parameters: + 1. answer: the answer of user's question; \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Routing/Prompts/router_prompt.liquid b/src/Infrastructure/BotSharp.Core/Routing/Prompts/router_prompt.liquid new file mode 100644 index 00000000..e118dd71 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Routing/Prompts/router_prompt.liquid @@ -0,0 +1,31 @@ +You're a Agent Router with reasoning, you can dispatch request to different agent to complete the task. + +{% for agent in routing_records %} +# Agent: {{ agent.name }} +{{ agent.description }} +{% if agent.required_fields != empty -%}Required information: {{ agent.required_fields }}.{%- endif %} +{% endfor %} + +### Function instructions +# route_to_agent +Route request to appropriate agent. +Parameters: + 1. agent_name: the name of the agent; + +# task_end +Call this function when current task is completed. +Parameters: + 1. abandoned_arguments: the arguments next task can't reuse; + +# conversation_end +Call this function when user wants to end this conversation or all tasks have been completed. + +# transfer_to_csr +Reach out to a real customer representative to help. + +{{ reasoning_functions }} + +### Your response must meet below requirements strictly +* If you can find an appropriate Agent, you must call appropriate function with required arguments. + +### Below are the dialogs between user and different agents: \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Routing/Reasoner.cs b/src/Infrastructure/BotSharp.Core/Routing/Reasoner.cs deleted file mode 100644 index 182bedb6..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/Reasoner.cs +++ /dev/null @@ -1,14 +0,0 @@ -using BotSharp.Abstraction.Routing.Settings; - -namespace BotSharp.Core.Routing; - -public class Reasoner : Router -{ - public override string AgentId => _settings.ReasonerId; - - public Reasoner(IServiceProvider services, - ILogger logger, - RoutingSettings settings) : base(services, logger, settings) - { - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingHook.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingHook.cs deleted file mode 100644 index 4cbeae48..00000000 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingHook.cs +++ /dev/null @@ -1,30 +0,0 @@ -using BotSharp.Abstraction.Repositories; -using BotSharp.Abstraction.Routing.Models; - -namespace BotSharp.Core.Routing; - -public class RoutingHook : AgentHookBase -{ - public RoutingHook(IServiceProvider services, AgentSettings settings) - : base(services, settings) - { - } - - public override bool OnInstructionLoaded(string template, Dictionary dict) - { - var db = _services.GetRequiredService(); - var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray(); - - var router = _services.GetRequiredService(); - dict["routing_records"] = agents.Select(x => new RoutingItem - { - AgentId = x.Id, - Description = x.Description, - Name = x.Name, - RequiredFields = x.RoutingRules.Where(x => x.Required) - .Select(x => x.Field) - .ToArray() - }).ToArray(); - return true; - } -} diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs index f0566827..61f68c5a 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.cs @@ -4,19 +4,26 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Repositories; using BotSharp.Abstraction.Routing; using BotSharp.Abstraction.Routing.Models; +using BotSharp.Abstraction.Routing.Settings; +using BotSharp.Abstraction.Templating; +using System.IO; namespace BotSharp.Core.Routing; public class RoutingService : IRoutingService { private readonly IServiceProvider _services; + private readonly RoutingSettings _settings; private readonly ILogger _logger; private List _dialogs; public List Dialogs => _dialogs; - public RoutingService(IServiceProvider services, ILogger logger) + public RoutingService(IServiceProvider services, + RoutingSettings settings, + ILogger logger) { _services = services; + _settings = settings; _logger = logger; } @@ -90,7 +97,9 @@ public class RoutingService : IRoutingService new RoleDialogModel(AgentRole.User, inst.Parameters.Question) }); - response.Content += $"\r\nDo you want to continue current task?"; + inst.Parameters.Answer = response.Content; + response.Content += $"\r\nDo you want to continue current task?"; + _dialogs.Add(new RoleDialogModel(AgentRole.Function, $"{record.Name}: {response.Content}") { FunctionName = inst.Function, @@ -111,9 +120,10 @@ public class RoutingService : IRoutingService private async Task GetNextInstructionFromReasoner(Agent reasoner) { + var responseFormat = "{\"function\": \"\", \"parameters\": {\"agent_name\": \"\", \"args\":{}}"; var wholeDialogs = new List { - new RoleDialogModel(AgentRole.User, @"What's the next step? Response in JSON format with ""function"" and ""parameters"".") + new RoleDialogModel(AgentRole.User, $"What's the next step? Response in JSON format {responseFormat}.") }; var chatCompletion = CompletionProvider.GetChatCompletion(_services); @@ -132,6 +142,8 @@ public class RoutingService : IRoutingService args.Function = args.Function.Split('.').Last(); + _logger.LogInformation($"Next Instruction: {args}"); + return args; } @@ -180,4 +192,39 @@ public class RoutingService : IRoutingService } } } + + public Agent LoadRouter() + { + var db = _services.GetRequiredService(); + + var router = new Agent() + { + Id = _settings.RouterId, + }; + var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray(); + + var dict = new Dictionary(); + dict["routing_records"] = agents.Select(x => new RoutingItem + { + AgentId = x.Id, + Description = x.Description, + Name = x.Name, + RequiredFields = x.RoutingRules.Where(x => x.Required) + .Select(x => x.Field) + .ToArray() + }).ToArray(); + + var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Routing", "Prompts"); + var template = File.ReadAllText(Path.Combine(dir, "router_prompt.liquid")); + + if (_settings.EnableReasoning) + { + dict["reasoning_functions"] = File.ReadAllText(Path.Combine(dir, "reasoning_functions.liquid")); + } + + var render = _services.GetRequiredService(); + router.Instruction = render.Render(template, dict); + + return router; + } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj index bbbf3ddf..cef8a0e6 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj +++ b/src/Infrastructure/BotSharp.OpenAPI/BotSharp.OpenAPI.csproj @@ -5,7 +5,7 @@ enable enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index b5cf73fb..7baaa16a 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -66,6 +66,38 @@ public class AgentController : ControllerBase, IApiAdapter await _agentService.UpdateAgent(model, AgentField.IsPublic); } + [HttpPut("/agent/{agentId}/disabled")] + public async Task UpdateAgentDisabled([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + { + var model = agent.ToAgent(); + model.Id = agentId; + await _agentService.UpdateAgent(model, AgentField.Disabled); + } + + [HttpPut("/agent/{agentId}/allow-routing")] + public async Task UpdateAgentAllowRouting([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + { + var model = agent.ToAgent(); + model.Id = agentId; + await _agentService.UpdateAgent(model, AgentField.AllowRouting); + } + + [HttpPut("/agent/{agentId}/profiles")] + public async Task UpdateAgentProfiles([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + { + var model = agent.ToAgent(); + model.Id = agentId; + await _agentService.UpdateAgent(model, AgentField.Profiles); + } + + [HttpPut("/agent/{agentId}/routing-rules")] + public async Task UpdateAgentRoutingRules([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + { + var model = agent.ToAgent(); + model.Id = agentId; + await _agentService.UpdateAgent(model, AgentField.RoutingRules); + } + [HttpPut("/agent/{agentId}/instruction")] public async Task UpdateAgentInstruction([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) { @@ -83,7 +115,7 @@ public class AgentController : ControllerBase, IApiAdapter } [HttpPut("/agent/{agentId}/templates")] - public async Task UpdateAgenttemplates([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + public async Task UpdateAgentTemplates([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) { var model = agent.ToAgent(); model.Id = agentId; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs index 3eeac672..d29fc4f2 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/InstructModeController.cs @@ -20,7 +20,7 @@ public class InstructModeController : ControllerBase, IApiAdapter } [HttpPost("/instruct/{agentId}")] - public async Task NewConversation([FromRoute] string agentId, + public async Task InstructCompletion([FromRoute] string agentId, [FromBody] InstructMessageModel input) { var instructor = _services.GetRequiredService(); @@ -28,13 +28,17 @@ public class InstructModeController : ControllerBase, IApiAdapter Agent agent = await agentService.LoadAgent(agentId); // switch to different instruction template - if (!string.IsNullOrEmpty(input.TemplateName)) + if (!string.IsNullOrEmpty(input.Template)) { var agentSettings = _services.GetRequiredService(); - var filePath = Path.Combine(agentService.GetAgentDataDir(agentId), $"{input.TemplateName}.{agentSettings.TemplateFormat}"); + var filePath = Path.Combine(agentService.GetAgentDataDir(agentId), $"{input.Template}.{agentSettings.TemplateFormat}"); agent.Instruction = System.IO.File.ReadAllText(filePath); } + var conv = _services.GetRequiredService(); + conv.States.SetState("provider", input.Provider) + .SetState("model", input.Model); + return await instructor.ExecuteInstruction(agent, new RoleDialogModel(AgentRole.User, input.Text), fn => Task.CompletedTask, diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs index a8e233fd..3857d82c 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Routing.Models; namespace BotSharp.OpenAPI.ViewModels.Agents; @@ -11,6 +12,10 @@ public class AgentCreationModel public List Functions { get; set; } public List Responses { get; set; } public bool IsPublic { get; set; } + public bool AllowRouting { get; set; } + public bool Disabled { get; set; } + public List Profiles { get; set; } + public List RoutingRules { get; set; } public Agent ToAgent() { @@ -22,7 +27,13 @@ public class AgentCreationModel Templates = Templates, Functions = Functions, Responses = Responses, - IsPublic = IsPublic + IsPublic = IsPublic, + AllowRouting = AllowRouting, + Disabled = Disabled, + Profiles = Profiles, + RoutingRules = RoutingRules? + .Select(x => RoutingRuleUpdateModel.ToDomainElement(x))? + .ToList() ?? new List() }; } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs index 3052e5b6..38452740 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Routing.Models; namespace BotSharp.OpenAPI.ViewModels.Agents; @@ -32,12 +33,32 @@ public class AgentUpdateModel /// public List? Responses { get; set; } + public bool IsPublic { get; set; } + + public bool AllowRouting { get; set; } + + public bool Disabled { get; set; } + + /// + /// Profile by channel + /// + public List? Profiles { get; set; } + + public List? RoutingRules { get; set; } + public Agent ToAgent() { var agent = new Agent() { Name = Name ?? string.Empty, Description = Description ?? string.Empty, + IsPublic = IsPublic, + Disabled = Disabled, + AllowRouting = AllowRouting, + Profiles = Profiles ?? new List(), + RoutingRules = RoutingRules? + .Select(x => RoutingRuleUpdateModel.ToDomainElement(x))? + .ToList() ?? new List(), Instruction = Instruction ?? string.Empty, Templates = Templates ?? new List(), Functions = Functions ?? new List(), diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs index ec9c29ad..bf25ec64 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Abstraction.Routing.Models; namespace BotSharp.OpenAPI.ViewModels.Agents; @@ -12,6 +13,11 @@ public class AgentViewModel public List Functions { get; set; } public List Responses { get; set; } public bool IsPublic { get; set; } + public bool AllowRouting { get; set; } + public bool Disabled { get; set; } + public List Profiles { get; set; } + public List RoutingRules { get; set; } + public DateTime CreatedDateTime { get; set; } public DateTime UpdatedDateTime { get; set; } @@ -27,6 +33,10 @@ public class AgentViewModel Functions = agent.Functions, Responses = agent.Responses, IsPublic= agent.IsPublic, + Disabled = agent.Disabled, + AllowRouting = agent.AllowRouting, + Profiles = agent.Profiles, + RoutingRules = agent.RoutingRules, CreatedDateTime = agent.CreatedDateTime, UpdatedDateTime = agent.UpdatedDateTime }; diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs new file mode 100644 index 00000000..9736db19 --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs @@ -0,0 +1,25 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.OpenAPI.ViewModels.Agents; + +public class RoutingRuleUpdateModel +{ + public string Field { get; set; } + public bool Required { get; set; } + public string? RedirectTo { get; set; } + + public RoutingRuleUpdateModel() + { + + } + + public static RoutingRule ToDomainElement(RoutingRuleUpdateModel model) + { + return new RoutingRule + { + Field = model.Field, + Required = model.Required, + RedirectTo = model.RedirectTo + }; + } +} diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs index c11494bf..6da68895 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Instructs/InstructMessageModel.cs @@ -4,5 +4,5 @@ namespace BotSharp.OpenAPI.ViewModels.Instructs; public class InstructMessageModel : IncomingMessageModel { public override string Channel { get; set; } = "openapi"; - public string? TemplateName { get; set; } + public string? Template { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/AzureOpenAiPlugin.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/AzureOpenAiPlugin.cs index b966d167..1232e668 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/AzureOpenAiPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/AzureOpenAiPlugin.cs @@ -23,6 +23,5 @@ public class AzureOpenAiPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); - services.AddScoped(); } } \ No newline at end of file diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/BotSharp.Plugin.AzureOpenAI.csproj b/src/Plugins/BotSharp.Plugin.AzureOpenAI/BotSharp.Plugin.AzureOpenAI.csproj index bc3a8a0d..2fdd480e 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/BotSharp.Plugin.AzureOpenAI.csproj +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/BotSharp.Plugin.AzureOpenAI.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs index 1f71192a..5434d586 100644 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/ChatCompletionProvider.cs @@ -20,11 +20,12 @@ namespace BotSharp.Plugin.AzureOpenAI.Providers; public class ChatCompletionProvider : IChatCompletion { - protected readonly AzureOpenAiSettings _settings; - protected readonly IServiceProvider _services; - protected readonly ILogger _logger; + private readonly AzureOpenAiSettings _settings; + private readonly IServiceProvider _services; + private readonly ILogger _logger; + private string _model; - public virtual string Provider => "azure-gpt-3.5"; + public virtual string Provider => "azure-openai"; public ChatCompletionProvider(AzureOpenAiSettings settings, ILogger logger, @@ -37,8 +38,16 @@ public class ChatCompletionProvider : IChatCompletion protected virtual (OpenAIClient, string) GetClient() { - var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey)); - return (client, _settings.DeploymentModel.ChatCompletionModel); + if (_model == "gpt-4") + { + var client = new OpenAIClient(new Uri(_settings.GPT4.Endpoint), new AzureKeyCredential(_settings.GPT4.ApiKey)); + return (client, _settings.GPT4.DeploymentModel); + } + else + { + var client = new OpenAIClient(new Uri(_settings.Endpoint), new AzureKeyCredential(_settings.ApiKey)); + return (client, _settings.DeploymentModel.ChatCompletionModel); + } } public List GetChatSamples(string sampleText) @@ -243,4 +252,9 @@ public class ChatCompletionProvider : IChatCompletion return chatCompletionsOptions; } + + public void SetModelName(string model) + { + _model = model; + } } diff --git a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/GPT4CompletionProvider.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/GPT4CompletionProvider.cs deleted file mode 100644 index 63c0da53..00000000 --- a/src/Plugins/BotSharp.Plugin.AzureOpenAI/Providers/GPT4CompletionProvider.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Azure; -using Azure.AI.OpenAI; -using BotSharp.Plugin.AzureOpenAI.Settings; -using Microsoft.Extensions.Logging; -using System; - -namespace BotSharp.Plugin.AzureOpenAI.Providers; - -public class GPT4CompletionProvider : ChatCompletionProvider -{ - public override string Provider => "azure-gpt-4"; - - public GPT4CompletionProvider(AzureOpenAiSettings settings, - ILogger logger, - IServiceProvider services) : base(settings, logger, services) - { - } - - protected override (OpenAIClient, string) GetClient() - { - var client = new OpenAIClient(new Uri(_settings.GPT4.Endpoint), new AzureKeyCredential(_settings.GPT4.ApiKey)); - return (client, _settings.GPT4.DeploymentModel); - } -} diff --git a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/GPT4Settings.cs b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Settings/GPT4Settings.cs similarity index 76% rename from src/Infrastructure/BotSharp.Abstraction/Routing/Settings/GPT4Settings.cs rename to src/Plugins/BotSharp.Plugin.AzureOpenAI/Settings/GPT4Settings.cs index 21925c1c..eab41763 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Routing/Settings/GPT4Settings.cs +++ b/src/Plugins/BotSharp.Plugin.AzureOpenAI/Settings/GPT4Settings.cs @@ -1,4 +1,4 @@ -namespace BotSharp.Abstraction.Routing.Settings; +namespace BotSharp.Plugin.AzureOpenAI.Settings; public class GPT4Settings { diff --git a/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj b/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj index 1ce0ac4d..78b077dd 100644 --- a/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj +++ b/src/Plugins/BotSharp.Plugin.ChatbotUI/BotSharp.Plugin.ChatbotUI.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.HuggingFace/BotSharp.Plugin.HuggingFace.csproj b/src/Plugins/BotSharp.Plugin.HuggingFace/BotSharp.Plugin.HuggingFace.csproj index 7c6b51fe..d0c56c27 100644 --- a/src/Plugins/BotSharp.Plugin.HuggingFace/BotSharp.Plugin.HuggingFace.csproj +++ b/src/Plugins/BotSharp.Plugin.HuggingFace/BotSharp.Plugin.HuggingFace.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs index ceac5320..4e39ff7b 100644 --- a/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.HuggingFace/Providers/ChatCompletionProvider.cs @@ -13,6 +13,7 @@ public class ChatCompletionProvider : IChatCompletion private readonly IServiceProvider _services; private readonly HuggingFaceSettings _settings; private readonly ILogger _logger; + private string _model; public ChatCompletionProvider(IServiceProvider services, HuggingFaceSettings settings, @@ -69,4 +70,9 @@ public class ChatCompletionProvider : IChatCompletion { return true; } + + public void SetModelName(string model) + { + _model = model; + } } diff --git a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj index a66f1f28..acbfa4fd 100644 --- a/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj +++ b/src/Plugins/BotSharp.Plugin.KnowledgeBase/BotSharp.Plugin.KnowledgeBase.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.LLamaSharp/BotSharp.Plugin.LLamaSharp.csproj b/src/Plugins/BotSharp.Plugin.LLamaSharp/BotSharp.Plugin.LLamaSharp.csproj index df8c0e41..0a75a201 100644 --- a/src/Plugins/BotSharp.Plugin.LLamaSharp/BotSharp.Plugin.LLamaSharp.csproj +++ b/src/Plugins/BotSharp.Plugin.LLamaSharp/BotSharp.Plugin.LLamaSharp.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs b/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs index 02ab50e7..dbdaef4d 100644 --- a/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs +++ b/src/Plugins/BotSharp.Plugin.LLamaSharp/Providers/ChatCompletionProvider.cs @@ -23,6 +23,7 @@ public class ChatCompletionProvider : IChatCompletion private readonly IServiceProvider _services; private readonly ILogger _logger; private readonly LlamaSharpSettings _settings; + private string _model; public ChatCompletionProvider(IServiceProvider services, ILogger logger, @@ -118,4 +119,9 @@ public class ChatCompletionProvider : IChatCompletion return true; } + + public void SetModelName(string model) + { + _model = model; + } } diff --git a/src/Plugins/BotSharp.Plugin.MetaAI/BotSharp.Plugin.MetaAI.csproj b/src/Plugins/BotSharp.Plugin.MetaAI/BotSharp.Plugin.MetaAI.csproj index fd3b01ef..1e234769 100644 --- a/src/Plugins/BotSharp.Plugin.MetaAI/BotSharp.Plugin.MetaAI.csproj +++ b/src/Plugins/BotSharp.Plugin.MetaAI/BotSharp.Plugin.MetaAI.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.MetaMessenger/BotSharp.Plugin.MetaMessenger.csproj b/src/Plugins/BotSharp.Plugin.MetaMessenger/BotSharp.Plugin.MetaMessenger.csproj index 289cdcc3..8c0499e5 100644 --- a/src/Plugins/BotSharp.Plugin.MetaMessenger/BotSharp.Plugin.MetaMessenger.csproj +++ b/src/Plugins/BotSharp.Plugin.MetaMessenger/BotSharp.Plugin.MetaMessenger.csproj @@ -3,7 +3,7 @@ netstandard2.1 $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj index 57385741..680c4126 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj @@ -3,7 +3,7 @@ netstandard2.1 $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs index aa84af03..ff555750 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs @@ -1,4 +1,5 @@ using BotSharp.Abstraction.Agents.Models; +using BotSharp.Plugin.MongoStorage.Models; namespace BotSharp.Plugin.MongoStorage.Collections; @@ -11,6 +12,10 @@ public class AgentCollection : MongoBase public List Functions { get; set; } public List Responses { get; set; } public bool IsPublic { get; set; } + public bool AllowRouting { get; set; } + public bool Disabled { get; set; } + public List Profiles { get; set; } + public List RoutingRules { get; set; } public DateTime CreatedTime { get; set; } public DateTime UpdatedTime { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs deleted file mode 100644 index 63208306..00000000 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingItemCollection.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace BotSharp.Plugin.MongoStorage.Collections; - -public class RoutingItemCollection : MongoBase -{ - public Guid AgentId { get; set; } - public string Name { get; set; } - public string Description { get; set; } - public List RequiredFields { get; set; } - public Guid? RedirectTo { get; set; } - public bool Disabled { get; set; } -} diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingProfileCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingProfileCollection.cs deleted file mode 100644 index 3b41ab7a..00000000 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/RoutingProfileCollection.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace BotSharp.Plugin.MongoStorage.Collections; - -public class RoutingProfileCollection : MongoBase -{ - public string Name { get; set; } - public List AgentIds { get; set; } -} diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs new file mode 100644 index 00000000..c2144870 --- /dev/null +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs @@ -0,0 +1,37 @@ +using BotSharp.Abstraction.Routing.Models; + +namespace BotSharp.Plugin.MongoStorage.Models; + +public class RoutingRuleMongoElement +{ + public string Field { get; set; } + public bool Required { get; set; } + public Guid? RedirectTo { get; set; } + + public RoutingRuleMongoElement() + { + + } + + public static RoutingRuleMongoElement ToMongoElement(RoutingRule routingRule) + { + return new RoutingRuleMongoElement + { + Field = routingRule.Field, + Required = routingRule.Required, + RedirectTo = !string.IsNullOrEmpty(routingRule.RedirectTo) ? Guid.Parse(routingRule.RedirectTo) : null + }; + } + + public static RoutingRule ToDomainElement(string agentId, string agentName, RoutingRuleMongoElement rule) + { + return new RoutingRule + { + AgentId = agentId, + AgentName = agentName, + Field = rule.Field, + Required = rule.Required, + RedirectTo = rule.RedirectTo?.ToString() + }; + } +} diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs index 4782a5b3..4c8479dd 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs @@ -42,10 +42,4 @@ public class MongoDbContext public IMongoCollection UserAgents => Database.GetCollection($"{_collectionPrefix}_UserAgents"); - - public IMongoCollection RoutingItems - => Database.GetCollection($"{_collectionPrefix}_RoutingItems"); - - public IMongoCollection RoutingProfiles - => Database.GetCollection($"{_collectionPrefix}_RoutingProfiles"); } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 6f3ece02..0e919fcb 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -1,7 +1,9 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Conversations.Models; +using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Users.Models; using BotSharp.Plugin.MongoStorage.Collections; +using BotSharp.Plugin.MongoStorage.Models; namespace BotSharp.Plugin.MongoStorage.Repository; @@ -42,6 +44,12 @@ public class MongoRepository : IBotSharpRepository Functions = x.Functions, Responses = x.Responses, IsPublic = x.IsPublic, + Disabled = x.Disabled, + AllowRouting = x.AllowRouting, + Profiles = x.Profiles, + RoutingRules = x.RoutingRules? + .Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id.ToString(), x.Name, r))? + .ToList() ?? new List(), CreatedDateTime = x.CreatedTime, UpdatedDateTime = x.UpdatedTime }).ToList(); @@ -206,6 +214,12 @@ public class MongoRepository : IBotSharpRepository Functions = x.Functions, Responses = x.Responses, IsPublic = x.IsPublic, + AllowRouting = x.AllowRouting, + Disabled = x.Disabled, + Profiles = x.Profiles, + RoutingRules = x.RoutingRules? + .Select(r => RoutingRuleMongoElement.ToMongoElement(r))? + .ToList() ?? new List(), CreatedTime = x.CreatedDateTime, UpdatedTime = x.UpdatedDateTime }).ToList(); @@ -221,6 +235,10 @@ public class MongoRepository : IBotSharpRepository .Set(x => x.Functions, agent.Functions) .Set(x => x.Responses, agent.Responses) .Set(x => x.IsPublic, agent.IsPublic) + .Set(x => x.AllowRouting, agent.AllowRouting) + .Set(x => x.Disabled, agent.Disabled) + .Set(x => x.Profiles, agent.Profiles) + .Set(x => x.RoutingRules, agent.RoutingRules) .Set(x => x.CreatedTime, agent.CreatedTime) .Set(x => x.UpdatedTime, agent.UpdatedTime); _dc.Agents.UpdateOne(filter, update, _options); @@ -299,6 +317,18 @@ public class MongoRepository : IBotSharpRepository case AgentField.IsPublic: UpdateAgentIsPublic(agent.Id, agent.IsPublic); break; + case AgentField.Disabled: + UpdateAgentDisabled(agent.Id, agent.Disabled); + break; + case AgentField.AllowRouting: + UpdateAgentAllowRouting(agent.Id, agent.AllowRouting); + break; + case AgentField.Profiles: + UpdateAgentProfiles(agent.Id, agent.Profiles); + break; + case AgentField.RoutingRules: + UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); + break; case AgentField.Instruction: UpdateAgentInstruction(agent.Id, agent.Instruction); break; @@ -354,6 +384,51 @@ public class MongoRepository : IBotSharpRepository _dc.Agents.UpdateOne(filter, update); } + private void UpdateAgentDisabled(string agentId, bool disabled) + { + var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var update = Builders.Update + .Set(x => x.Disabled, disabled) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + + private void UpdateAgentAllowRouting(string agentId, bool allowRouting) + { + var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var update = Builders.Update + .Set(x => x.AllowRouting, allowRouting) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + + private void UpdateAgentProfiles(string agentId, List profiles) + { + if (profiles.IsNullOrEmpty()) return; + + var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var update = Builders.Update + .Set(x => x.Profiles, profiles) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + + private void UpdateAgentRoutingRules(string agentId, List rules) + { + if (rules.IsNullOrEmpty()) return; + + var ruleElements = rules.Select(x => RoutingRuleMongoElement.ToMongoElement(x)).ToList(); + var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var update = Builders.Update + .Set(x => x.RoutingRules, ruleElements) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + private void UpdateAgentInstruction(string agentId, string instruction) { if (string.IsNullOrEmpty(instruction)) return; @@ -408,6 +483,10 @@ public class MongoRepository : IBotSharpRepository var update = Builders.Update .Set(x => x.Name, agent.Name) .Set(x => x.Description, agent.Description) + .Set(x => x.Disabled, agent.Disabled) + .Set(x => x.AllowRouting, agent.AllowRouting) + .Set(x => x.Profiles, agent.Profiles) + .Set(x => x.RoutingRules, agent.RoutingRules.Select(x => RoutingRuleMongoElement.ToMongoElement(x)).ToList()) .Set(x => x.Instruction, agent.Instruction) .Set(x => x.Templates, agent.Templates) .Set(x => x.Functions, agent.Functions) diff --git a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj index 763b75a2..e02d4448 100644 --- a/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj +++ b/src/Plugins/BotSharp.Plugin.Qdrant/BotSharp.Plugin.Qdrant.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj index bd74b74d..aa8a9a2f 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/BotSharp.Plugin.RoutingSpeeder.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs index b6c1c6f9..5edebf56 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs @@ -53,7 +53,7 @@ public class RoutingConversationHook: ConversationHookBase public override async Task AfterCompletion(RoleDialogModel message) { var routerSettings = _services.GetRequiredService(); - bool saveFlag = (message.CurrentAgentId != routerSettings.RouterId) && (message.CurrentAgentId != routerSettings.ReasonerId); + bool saveFlag = message.CurrentAgentId != routerSettings.RouterId; if (saveFlag) { diff --git a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj index 59ae162a..fbff2484 100644 --- a/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj +++ b/src/Plugins/BotSharp.Plugin.WeChat/BotSharp.Plugin.WeChat.csproj @@ -3,7 +3,7 @@ netstandard2.1 $(LangVersion) - $(PackageVersion) + $(BotSharpVersion) $(GeneratePackageOnBuild) @@ -14,7 +14,6 @@ https://github.com/Oceania2018/botsharp-channel-weixin Apache 2.0 botsharp, wechat, wexin, chatbot - $(PackageVersion) diff --git a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs index 0e505d09..16d41784 100644 --- a/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs +++ b/tests/BotSharp.Plugin.PizzaBot/Functions/GetPizzaTypesFn.cs @@ -9,6 +9,12 @@ public class GetPizzaTypesFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { message.ExecutionResult = "Pepperoni Pizza, Cheese Pizza, Margherita Pizza"; + message.ExecutionData = new List + { + "Pepperoni Pizza", + "Cheese Pizza", + "Margherita Pizza" + }; return true; } }