diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs index d82e8602c..0a8b38e81 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs @@ -9,9 +9,10 @@ public enum AgentField Disabled, AllowRouting, Profiles, - RoutingRules, + RoutingRule, Instruction, Function, Template, - Response + Response, + Sample } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 96a36721a..97c336485 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -4,22 +4,21 @@ namespace BotSharp.Abstraction.Repositories; public interface IBotSharpRepository { - IQueryable Users { get; } - IQueryable Agents { get; } - IQueryable UserAgents { get; } - IQueryable Conversations { get; } - int Transaction(Action action); void Add(object entity); #region User User? GetUserByEmail(string email); + User? GetUserByExternalId(string externalId); void CreateUser(User user); #endregion #region Agent void UpdateAgent(Agent agent, AgentField field); Agent? GetAgent(string agentId); + List GetAgents(string? name = null, bool? disabled = null, bool? allowRouting = null, + bool? isPublic = null, List? agentIds = null); + List GetAgentsByUser(string userId); void BulkInsertAgents(List agents); void BulkInsertUserAgents(List userAgents); bool DeleteAgents(); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs index 113f2da16..5e29d9a8f 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.CreateAgent.cs @@ -1,7 +1,6 @@ using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Repositories; -using BotSharp.Abstraction.Utilities; using System.IO; namespace BotSharp.Core.Agents.Services; @@ -10,11 +9,7 @@ public partial class AgentService { public async Task CreateAgent(Agent agent) { - var agentRecord = (from a in _db.Agents - join ua in _db.UserAgents on a.Id equals ua.AgentId - join u in _db.Users on ua.UserId equals u.Id - where u.ExternalId == _user.Id && a.Name == agent.Name - select a).FirstOrDefault(); + var agentRecord = _db.GetAgentsByUser(_user.Id).FirstOrDefault(x => x.Name.IsEqualTo(agent.Name)); if (agentRecord != null) { @@ -47,7 +42,7 @@ join u in _db.Users on ua.UserId equals u.Id .SetResponses(foundAgent.Responses); } - var user = _db.Users.FirstOrDefault(x => x.Id == _user.Id || x.ExternalId == _user.Id); + var user = _db.GetUserByExternalId(_user.Id); var userAgentRecord = new UserAgent { Id = Guid.NewGuid().ToString(), @@ -78,10 +73,12 @@ private Agent FetchAgentFileByName(string agentName, string filePath) var instruction = FetchInstructionFromFile(dir); var responses = FetchResponsesFromFile(dir); var templates = FetchTemplatesFromFile(dir); + var samples = FetchSamplesFromFile(dir); return agent.SetInstruction(instruction) .SetTemplates(templates) .SetFunctions(functions) - .SetResponses(responses); + .SetResponses(responses) + .SetSamples(samples); } } @@ -146,4 +143,13 @@ private List FetchResponsesFromFile(string fileDir) } return responses; } + + private List FetchSamplesFromFile(string fileDir) + { + var file = Path.Combine(fileDir, "samples.txt"); + if (!File.Exists(file)) return new List(); + + var samples = File.ReadAllLines(file); + return samples?.ToList() ?? new List(); + } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs index 1a65bb2cc..d9d3cd401 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.GetAgents.cs @@ -9,12 +9,8 @@ public partial class AgentService #endif public async Task> GetAgents() { - var query = from a in _db.Agents - join ua in _db.UserAgents on a.Id equals ua.AgentId - join u in _db.Users on ua.UserId equals u.Id - where ua.UserId == _user.Id || u.ExternalId == _user.Id || a.IsPublic - select a; - return query.ToList(); + var agents = _db.GetAgentsByUser(_user.Id); + return await Task.FromResult(agents); } #if !DEBUG diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs index 769ae7c1f..fa24f4043 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.RefreshAgents.cs @@ -13,7 +13,7 @@ public async Task RefreshAgents() var dbSettings = _services.GetRequiredService(); var agentDir = Path.Combine(dbSettings.FileRepository, _agentSettings.DataDir); - var user = _db.Users.FirstOrDefault(x => x.Id == _user.Id || x.ExternalId == _user.Id); + var user = _db.GetUserByExternalId(_user.Id); var agents = new List(); var userAgents = new List(); @@ -27,10 +27,12 @@ public async Task RefreshAgents() var instruction = FetchInstructionFromFile(dir); var responses = FetchResponsesFromFile(dir); var templates = FetchTemplatesFromFile(dir); + var samples = FetchSamplesFromFile(dir); agent.SetInstruction(instruction) .SetTemplates(templates) .SetFunctions(functions) - .SetResponses(responses); + .SetResponses(responses) + .SetSamples(samples); var userAgent = new UserAgent { diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs index b6c9dbae8..292b83bbe 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs @@ -12,7 +12,7 @@ public async Task UpdateAgent(Agent agent, AgentField updateField) { if (agent == null || string.IsNullOrEmpty(agent.Id)) return; - var record = FindAgent(agent.Id); + var record = _db.GetAgent(agent.Id); if (record == null) return; record.Name = agent.Name ?? string.Empty; @@ -26,25 +26,15 @@ public async Task UpdateAgent(Agent agent, AgentField updateField) record.Functions = agent.Functions ?? new List(); record.Templates = agent.Templates ?? new List(); record.Responses = agent.Responses ?? new List(); + record.Samples = agent.Samples ?? new List(); _db.UpdateAgent(record, updateField); await Task.CompletedTask; } - private Agent FindAgent(string agentId) - { - var record = (from a in _db.Agents - join ua in _db.UserAgents on a.Id equals ua.AgentId - join u in _db.Users on ua.UserId equals u.Id - where (ua.UserId == _user.Id || u.ExternalId == _user.Id) && - a.Id == agentId - select a).FirstOrDefault(); - return record; - } - public async Task UpdateAgentFromFile(string id) { - var agent = _db.Agents?.FirstOrDefault(x => x.Id == id); + var agent = _db.GetAgent(id); if (agent == null) return; @@ -67,7 +57,8 @@ public async Task UpdateAgentFromFile(string id) .SetInstruction(foundAgent.Instruction) .SetTemplates(foundAgent.Templates) .SetFunctions(foundAgent.Functions) - .SetResponses(foundAgent.Responses); + .SetResponses(foundAgent.Responses) + .SetSamples(foundAgent.Samples); _db.UpdateAgent(clonedAgent, AgentField.All); } @@ -87,10 +78,12 @@ private Agent FetchAgentFileById(string agentId, string filePath) var instruction = FetchInstructionFromFile(dir); var responses = FetchResponsesFromFile(dir); var templates = FetchTemplatesFromFile(dir); + var samples = FetchSamplesFromFile(dir); return agent.SetInstruction(instruction) .SetTemplates(templates) .SetFunctions(functions) - .SetResponses(responses); + .SetResponses(responses) + .SetSamples(samples); } } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs index 28f9bdd21..090059cda 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.Agents.Models; using BotSharp.Abstraction.Repositories; using System.IO; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 51e4e24ac..8f3a865ec 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -46,7 +46,7 @@ public async Task GetConversation(string id) public async Task> GetConversations() { var db = _services.GetRequiredService(); - var user = db.Users.FirstOrDefault(x => x.ExternalId == _user.Id); + var user = db.GetUserByExternalId(_user.Id); var conversations = db.GetConversations(user?.Id); return conversations.OrderByDescending(x => x.CreatedTime).ToList(); } @@ -56,7 +56,7 @@ public async Task NewConversation(Conversation sess) var db = _services.GetRequiredService(); var dbSettings = _services.GetRequiredService(); var conversationSettings = _services.GetRequiredService(); - var user = db.Users.FirstOrDefault(x => x.ExternalId == _user.Id); + var user = db.GetUserByExternalId(_user.Id); var foundUserId = user?.Id ?? string.Empty; var record = sess; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index d22f1c0c2..f0b28d3b2 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -47,7 +47,7 @@ public void Append(string conversationId, RoleDialogModel dialog) else { var routingSetting = _services.GetRequiredService(); - var agentName = routingSetting.RouterId == agentId ? "Router" : db.Agents.First(x => x.Id == agentId).Name; + var agentName = routingSetting.RouterId == agentId ? "Router" : db.GetAgent(agentId)?.Name; sb.AppendLine($"{dialog.CreatedAt}|{dialog.Role}|{agentId}|{agentName}|"); var content = dialog.Content.Replace("\r", " ").Replace("\n", " ").Trim(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 2f0c85e2e..9cd8ab757 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -72,6 +72,17 @@ public Agent GetAgent(string agentId) throw new NotImplementedException(); } + public List GetAgents(string? name = null, bool? disabled = null, bool? allowRouting = null, + bool? isPublic = null, List? agentIds = null) + { + throw new NotImplementedException(); + } + + public List GetAgentsByUser(string userId) + { + throw new NotImplementedException(); + } + public void UpdateAgent(Agent agent, AgentField field) { throw new NotImplementedException(); @@ -148,6 +159,11 @@ public void UpdateConversationStates(string conversationId, List throw new NotImplementedException(); } + public User? GetUserByExternalId(string externalId) + { + throw new NotImplementedException(); + } + public void CreateUser(User user) { throw new NotImplementedException(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs index b585b7646..e8f00994d 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository.cs @@ -5,6 +5,8 @@ using BotSharp.Abstraction.Agents.Models; using MongoDB.Driver; using BotSharp.Abstraction.Routing.Models; +using Amazon.Util; + namespace BotSharp.Core.Repository; public class FileRepository : IBotSharpRepository @@ -32,7 +34,11 @@ public FileRepository( } private List _users = new List(); - public IQueryable Users + private List _agents = new List(); + private List _userAgents = new List(); + private List _conversations = new List(); + + private IQueryable Users { get { @@ -55,8 +61,7 @@ public IQueryable Users } } - private List _agents = new List(); - public IQueryable Agents + private IQueryable Agents { get { @@ -78,7 +83,8 @@ public IQueryable Agents agent = agent.SetInstruction(FetchInstruction(d)) .SetTemplates(FetchTemplates(d)) .SetFunctions(FetchFunctions(d)) - .SetResponses(FetchResponses(d)); + .SetResponses(FetchResponses(d)) + .SetSamples(FetchSamples(d)); _agents.Add(agent); } } @@ -87,8 +93,7 @@ public IQueryable Agents } } - private List _userAgents = new List(); - public IQueryable UserAgents + private IQueryable UserAgents { get { @@ -115,34 +120,6 @@ public IQueryable UserAgents } } - private List _conversations = new List(); - public IQueryable Conversations - { - get - { - if (!_conversations.IsNullOrEmpty()) - { - return _conversations.AsQueryable(); - } - - var dir = Path.Combine(_dbSettings.FileRepository, _conversationSettings.DataDir); - _conversations = new List(); - if (Directory.Exists(dir)) - { - foreach (var d in Directory.GetDirectories(dir)) - { - var path = Path.Combine(d, "conversation.json"); - if (File.Exists(path)) - { - var json = File.ReadAllText(path); - _conversations.Add(JsonSerializer.Deserialize(json, _options)); - } - } - } - return _conversations.AsQueryable(); - } - } - public void Add(object entity) { if (entity is Conversation conversation) @@ -261,7 +238,7 @@ public void UpdateAgent(Agent agent, AgentField field) case AgentField.Profiles: UpdateAgentProfiles(agent.Id, agent.Profiles); break; - case AgentField.RoutingRules: + case AgentField.RoutingRule: UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); break; case AgentField.Instruction: @@ -276,6 +253,9 @@ public void UpdateAgent(Agent agent, AgentField field) case AgentField.Response: UpdateAgentResponses(agent.Id, agent.Responses); break; + case AgentField.Sample: + UpdateAgentSamples(agent.Id, agent.Samples); + break; case AgentField.All: UpdateAgentAllFields(agent); break; @@ -456,6 +436,17 @@ private void UpdateAgentResponses(string agentId, List responses) } } + private void UpdateAgentSamples(string agentId, List samples) + { + if (samples.IsNullOrEmpty()) return; + + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + var file = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, "samples.txt"); + File.WriteAllLines(file, samples); + } + private void UpdateAgentAllFields(Agent inputAgent) { var (agent, agentFile) = GetAgentFromFile(inputAgent.Id); @@ -476,6 +467,7 @@ private void UpdateAgentAllFields(Agent inputAgent) UpdateAgentResponses(inputAgent.Id, inputAgent.Responses); UpdateAgentTemplates(inputAgent.Id, inputAgent.Templates); UpdateAgentFunctions(inputAgent.Id, inputAgent.Functions); + UpdateAgentSamples(inputAgent.Id, inputAgent.Samples); } #endregion @@ -532,6 +524,50 @@ public List GetAgentResponses(string agentId, string prefix, string inte return null; } + public List GetAgents(string? name = null, bool? disabled = null, bool? allowRouting = null, + bool? isPublic = null, List? agentIds = null) + { + var query = Agents; + if (!string.IsNullOrEmpty(name)) + { + query = query.Where(x => x.Name.ToLower() == name.ToLower()); + } + + if (disabled.HasValue) + { + query = query.Where(x => x.Disabled == disabled); + } + + if (allowRouting.HasValue) + { + query = query.Where(x => x.AllowRouting == allowRouting); + } + + if (isPublic.HasValue) + { + query = query.Where(x => x.IsPublic == isPublic); + } + + if (agentIds != null) + { + query = query.Where(x => agentIds.Contains(x.Id)); + } + + return query.ToList(); + } + + public List GetAgentsByUser(string userId) + { + var agentIds = (from ua in UserAgents + join u in Users on ua.UserId equals u.Id + where ua.UserId == userId || u.ExternalId == userId + select ua.AgentId).ToList(); + + var agents = GetAgents(isPublic: true, agentIds: agentIds); + return agents; + } + + public string GetAgentTemplate(string agentId, string templateName) { var dir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir, agentId, "templates"); @@ -719,6 +755,11 @@ public List GetConversations(string userId) return Users.FirstOrDefault(x => x.Email == email); } + public User? GetUserByExternalId(string externalId) + { + return Users.FirstOrDefault(x => x.ExternalId == externalId); + } + public void CreateUser(User user) { var userId = Guid.NewGuid().ToString(); @@ -778,7 +819,7 @@ private List FetchSamples(string fileDir) var file = Path.Combine(fileDir, "samples.txt"); if (!File.Exists(file)) return new List(); - return File.ReadAllLines(file).ToList(); + return File.ReadAllLines(file)?.ToList() ?? new List(); } private List FetchTemplates(string fileDir) diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs index aaeba5d72..29d640e3e 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/RouteToAgentFn.cs @@ -29,7 +29,7 @@ public async Task Execute(RoleDialogModel message) if (!string.IsNullOrEmpty(args.OriginalAgent) && args.OriginalAgent.Length < 32) { var db = _services.GetRequiredService(); - var originalAgent = db.Agents.FirstOrDefault(x => x.Name.ToLower() == args.OriginalAgent.ToLower()); + var originalAgent = db.GetAgents(args.OriginalAgent).FirstOrDefault(); if (originalAgent != null) { _context.Push(originalAgent.Id); @@ -48,7 +48,7 @@ public async Task Execute(RoleDialogModel message) else { var db = _services.GetRequiredService(); - var targetAgent = db.Agents.FirstOrDefault(x => x.Name.ToLower() == args.AgentName.ToLower()); + var targetAgent = db.GetAgents(args.AgentName).FirstOrDefault(); if (targetAgent == null) { message.ExecutionData = JsonSerializer.Deserialize(message.FunctionArgs); @@ -138,7 +138,7 @@ private bool HasMissingRequiredField(RoleDialogModel message, out string agentId if (!string.IsNullOrEmpty(routingRule.RedirectTo)) { var db = _services.GetRequiredService(); - var record = db.Agents.First(x => x.Id == routingRule.RedirectTo); + var record = db.GetAgent(routingRule.RedirectTo); // Add redirected agent message.FunctionArgs = AppendPropertyToArgs(message.FunctionArgs, "redirect_to", record.Name); diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs index 6673f339e..984651f06 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/ContinueExecuteTaskRoutingHandler.cs @@ -29,7 +29,7 @@ public ContinueExecuteTaskRoutingHandler(IServiceProvider services, ILogger Handle(IRoutingService routing, FunctionCallFromLlm inst) { var db = _services.GetRequiredService(); - var record = db.Agents.First(x => x.Name.ToLower() == inst.AgentName.ToLower()); + var record = db.GetAgents(inst.AgentName).FirstOrDefault(); var result = new RoleDialogModel(AgentRole.Function, inst.Question) { diff --git a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs index 81435fc46..d4492d2bf 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Handlers/RetrieveDataFromAgentRoutingHandler.cs @@ -31,7 +31,7 @@ public async Task Handle(IRoutingService routing, FunctionCallF { // Retrieve information from specific agent var db = _services.GetRequiredService(); - var record = db.Agents.First(x => x.Name.ToLower() == inst.AgentName.ToLower()); + var record = db.GetAgents(inst.AgentName).FirstOrDefault(); var response = await routing.InvokeAgent(record.Id); inst.Response = response.Content; diff --git a/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs b/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs index f1452dfba..fb5d20392 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RouterInstance.cs @@ -62,7 +62,7 @@ protected RoutingRule[] GetRoutingRecords() { var db = _services.GetRequiredService(); - var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray(); + var agents = db.GetAgents(disabled: false, allowRouting: true); var records = agents.SelectMany(x => { x.RoutingRules.ForEach(r => @@ -92,7 +92,7 @@ public RoutingItem[] GetRoutingItems() { var db = _services.GetRequiredService(); - var agents = db.Agents.Where(x => !x.Disabled && x.AllowRouting).ToArray(); + var agents = db.GetAgents(disabled: false, allowRouting: true); return agents.Select(x => new RoutingItem { AgentId = x.Id, diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index a34a1a8a2..30fa131fe 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -44,7 +44,7 @@ public async Task GetToken(string authorization) var (userEmail, password) = base64.SplitAsTuple(":"); var db = _services.GetRequiredService(); - var record = db.Users.FirstOrDefault(x => x.Email == userEmail); + var record = db.GetUserByEmail(userEmail); if (record == null) { return default; @@ -97,19 +97,7 @@ private string GenerateJwtToken(User user) public async Task GetMyProfile() { var db = _services.GetRequiredService(); - var user = (from u in db.Users - where u.ExternalId == _user.Id - select new User - { - Id = u.Id, - Email = u.Email, - FirstName = u.FirstName, - LastName = u.LastName, - CreatedTime = u.CreatedTime, - UpdatedTime = u.UpdatedTime, - Password = u.Password, - }).FirstOrDefault(); - + var user = db.GetUserByExternalId(_user.Id); return user; } } diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs index b68a0bf42..99949ce2d 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/AgentController.cs @@ -111,7 +111,7 @@ public async Task UpdateAgentRoutingRules([FromRoute] string agentId, [FromBody] { var model = agent.ToAgent(); model.Id = agentId; - await _agentService.UpdateAgent(model, AgentField.RoutingRules); + await _agentService.UpdateAgent(model, AgentField.RoutingRule); } [HttpPut("/agent/{agentId}/instruction")] @@ -145,4 +145,12 @@ public async Task UpdateAgentResponses([FromRoute] string agentId, [FromBody] Ag model.Id = agentId; await _agentService.UpdateAgent(model, AgentField.Response); } + + [HttpPut("/agent/{agentId}/samples")] + public async Task UpdateAgentSamples([FromRoute] string agentId, [FromBody] AgentUpdateModel agent) + { + var model = agent.ToAgent(); + model.Id = agentId; + await _agentService.UpdateAgent(model, AgentField.Sample); + } } \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs index d2a0a7a55..9af1dda69 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs @@ -17,7 +17,7 @@ public class AgentCreationModel /// /// LLM extensible Instructions in addition to the default Instructions /// - public List? Templates { get; set; } + public List Templates { get; set; } = new List(); /// /// LLM callable function definition @@ -27,7 +27,8 @@ public class AgentCreationModel /// /// Response template /// - public List? Responses { get; set; } + public List Responses { get; set; } = new List(); + public List Samples { get; set; } = new List(); public bool IsPublic { get; set; } @@ -53,6 +54,7 @@ public Agent ToAgent() Templates = Templates, Functions = Functions, Responses = Responses, + Samples = Samples, IsPublic = IsPublic, AllowRouting = AllowRouting, Disabled = Disabled, diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs index 8c78ebbe9..3ff1f0694 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs @@ -13,6 +13,7 @@ public class AgentViewModel public List Templates { get; set; } public List Functions { get; set; } public List Responses { get; set; } + public List Samples { get; set; } public bool IsPublic { get; set; } public bool AllowRouting { get; set; } public bool Disabled { get; set; } @@ -33,6 +34,7 @@ public static AgentViewModel FromAgent(Agent agent) Templates = agent.Templates, Functions = agent.Functions, Responses = agent.Responses, + Samples = agent.Samples, IsPublic= agent.IsPublic, Disabled = agent.Disabled, AllowRouting = agent.AllowRouting, diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs index 9736db19d..1f77416e9 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/RoutingRuleUpdateModel.cs @@ -5,6 +5,7 @@ namespace BotSharp.OpenAPI.ViewModels.Agents; public class RoutingRuleUpdateModel { public string Field { get; set; } + public string Description { get; set; } public bool Required { get; set; } public string? RedirectTo { get; set; } @@ -18,6 +19,7 @@ public static RoutingRule ToDomainElement(RoutingRuleUpdateModel model) return new RoutingRule { Field = model.Field, + Description = model.Description, Required = model.Required, RedirectTo = model.RedirectTo }; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj index b74045480..3a568db7e 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/BotSharp.Plugin.MongoStorage.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs index f6d368d33..39d77a078 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentCollection.cs @@ -10,6 +10,7 @@ public class AgentCollection : MongoBase public List Templates { get; set; } public List Functions { get; set; } public List Responses { get; set; } + public List Samples { get; set; } public bool IsPublic { get; set; } public bool AllowRouting { get; set; } public bool Disabled { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs index 7dbb51af5..f4d778de7 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationCollection.cs @@ -4,8 +4,8 @@ namespace BotSharp.Plugin.MongoStorage.Collections; public class ConversationCollection : MongoBase { - public Guid AgentId { get; set; } - public Guid UserId { get; set; } + public string AgentId { get; set; } + public string UserId { get; set; } public string Title { get; set; } public List States { get; set; } public DateTime CreatedTime { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogCollection.cs index 802bf21c6..3c605e0ef 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDialogCollection.cs @@ -2,6 +2,6 @@ namespace BotSharp.Plugin.MongoStorage.Collections; public class ConversationDialogCollection : MongoBase { - public Guid ConversationId { get; set; } + public string ConversationId { get; set; } public string Dialog { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserAgentCollection.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserAgentCollection.cs index 562cea139..3e9f4043d 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserAgentCollection.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/UserAgentCollection.cs @@ -2,8 +2,8 @@ namespace BotSharp.Plugin.MongoStorage.Collections; public class UserAgentCollection : MongoBase { - public Guid UserId { get; set; } - public Guid AgentId { get; set; } + public string UserId { get; set; } + public string AgentId { get; set; } public DateTime CreatedTime { get; set; } public DateTime UpdatedTime { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs index 6a473078c..9f644c680 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Models/RoutingRuleMongoElement.cs @@ -7,7 +7,7 @@ public class RoutingRuleMongoElement public string Field { get; set; } public string Description { get; set; } public bool Required { get; set; } - public Guid? RedirectTo { get; set; } + public string? RedirectTo { get; set; } public RoutingRuleMongoElement() { @@ -21,7 +21,7 @@ public static RoutingRuleMongoElement ToMongoElement(RoutingRule routingRule) Field = routingRule.Field, Description = routingRule.Description, Required = routingRule.Required, - RedirectTo = !string.IsNullOrEmpty(routingRule.RedirectTo) ? Guid.Parse(routingRule.RedirectTo) : null + RedirectTo = routingRule.RedirectTo }; } @@ -34,7 +34,7 @@ public static RoutingRule ToDomainElement(string agentId, string agentName, Rout Field = rule.Field, Description = rule.Description, Required = rule.Required, - RedirectTo = rule.RedirectTo?.ToString() + RedirectTo = rule.RedirectTo }; } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoBase.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoBase.cs index 7a0c1ef0a..6fcd93486 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoBase.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoBase.cs @@ -6,6 +6,6 @@ namespace BotSharp.Plugin.MongoStorage; [BsonIgnoreExtraElements(Inherited = true)] public class MongoBase { - [BsonId(IdGenerator = typeof(GuidGenerator))] - public Guid Id { get; set; } + [BsonId(IdGenerator = typeof(StringObjectIdGenerator))] + public string Id { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs index 30aff9357..5b92f40a1 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoDbContext.cs @@ -1,4 +1,3 @@ -using BotSharp.Abstraction.Utilities; using BotSharp.Plugin.MongoStorage.Collections; namespace BotSharp.Plugin.MongoStorage; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoStoragePlugin.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoStoragePlugin.cs index 5fd26d156..e41704b8c 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/MongoStoragePlugin.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/MongoStoragePlugin.cs @@ -1,4 +1,6 @@ using BotSharp.Plugin.MongoStorage.Repository; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; namespace BotSharp.Plugin.MongoStorage; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 2d621c01d..108fb111b 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -3,9 +3,9 @@ using BotSharp.Abstraction.Functions.Models; using BotSharp.Abstraction.Routing.Models; using BotSharp.Abstraction.Users.Models; -using BotSharp.Abstraction.Utilities; using BotSharp.Plugin.MongoStorage.Collections; using BotSharp.Plugin.MongoStorage.Models; +using Aspects.Cache; namespace BotSharp.Plugin.MongoStorage.Repository; @@ -26,133 +26,11 @@ public MongoRepository(MongoDbContext dc, IServiceProvider services) } private List _agents = new List(); - public IQueryable Agents - { - get - { - if (!_agents.IsNullOrEmpty()) - { - return _agents.AsQueryable(); - } - - var agentDocs = _dc.Agents?.AsQueryable()?.ToList() ?? new List(); - _agents = agentDocs.Select(x => new Agent - { - Id = x.Id.ToString(), - Name = x.Name, - Description = x.Description, - Instruction = x.Instruction, - Templates = x.Templates? - .Select(t => AgentTemplateMongoElement.ToDomainElement(t))? - .ToList() ?? new List(), - Functions = x.Functions? - .Select(f => FunctionDefMongoElement.ToDomainElement(f))? - .ToList() ?? new List(), - Responses = x.Responses? - .Select(r => AgentResponseMongoElement.ToDomainElement(r))? - .ToList() ?? new List(), - 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(); - - return _agents.AsQueryable(); - } - } - private List _users = new List(); - public IQueryable Users - { - get - { - if (!_users.IsNullOrEmpty()) - { - return _users.AsQueryable(); - } - - var userDocs = _dc.Users?.AsQueryable()?.ToList() ?? new List(); - _users = userDocs.Select(x => new User - { - Id = x.Id.ToString(), - FirstName = x.FirstName, - LastName = x.LastName, - Email = x.Email, - Password = x.Password, - Salt = x.Salt, - ExternalId = x.ExternalId, - CreatedTime = x.CreatedTime, - UpdatedTime = x.UpdatedTime - }).ToList(); - - return _users.AsQueryable(); - } - } - private List _userAgents = new List(); - public IQueryable UserAgents - { - get - { - if (!_userAgents.IsNullOrEmpty()) - { - return _userAgents.AsQueryable(); - } - - var userDocs = _dc.UserAgents?.AsQueryable()?.ToList() ?? new List(); - _userAgents = userDocs.Select(x => new UserAgent - { - Id = x.Id.ToString(), - AgentId = x.AgentId.ToString(), - UserId = x.UserId.ToString(), - CreatedTime = x.CreatedTime, - UpdatedTime = x.UpdatedTime - }).ToList(); - - return _userAgents.AsQueryable(); - } - } - private List _conversations = new List(); - public IQueryable Conversations - { - get - { - if (!_conversations.IsNullOrEmpty()) - { - return _conversations.AsQueryable(); - } - - _conversations = new List(); - var conversationDocs = _dc.Conversations?.AsQueryable()?.ToList() ?? new List(); - - foreach (var conv in conversationDocs) - { - var convId = conv.Id.ToString(); - var dialog = GetConversationDialog(convId); - _conversations.Add(new Conversation - { - Id = convId, - AgentId = conv.AgentId.ToString(), - UserId = conv.UserId.ToString(), - Title = conv.Title, - Dialog = dialog, - States = new ConversationState(conv.States), - CreatedTime = conv.CreatedTime, - UpdatedTime = conv.UpdatedTime - }); - } - - return _conversations.AsQueryable(); - } - } - List _changedTableNames = new List(); + public void Add(object entity) { if (entity is Conversation conversation) @@ -188,9 +66,9 @@ public int Transaction(Action action) { var conversations = _conversations.Select(x => new ConversationCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), - AgentId = Guid.Parse(x.AgentId), - UserId = !string.IsNullOrEmpty(x.UserId) && Guid.TryParse(x.UserId, out var _) ? Guid.Parse(x.UserId) : Guid.Empty, + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), + AgentId = x.AgentId, + UserId = !string.IsNullOrEmpty(x.UserId) ? x.UserId : string.Empty, Title = x.Title, States = x.States?.ToKeyValueList() ?? new List(), CreatedTime = x.CreatedTime, @@ -214,7 +92,7 @@ public int Transaction(Action action) { var agents = _agents.Select(x => new AgentCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), Name = x.Name, Description = x.Description, Instruction = x.Instruction, @@ -227,6 +105,7 @@ public int Transaction(Action action) Responses = x.Responses? .Select(r => AgentResponseMongoElement.ToMongoElement(r))? .ToList() ?? new List(), + Samples = x.Samples ?? new List(), IsPublic = x.IsPublic, AllowRouting = x.AllowRouting, Disabled = x.Disabled, @@ -248,6 +127,7 @@ public int Transaction(Action action) .Set(x => x.Templates, agent.Templates) .Set(x => x.Functions, agent.Functions) .Set(x => x.Responses, agent.Responses) + .Set(x => x.Samples, agent.Samples) .Set(x => x.IsPublic, agent.IsPublic) .Set(x => x.AllowRouting, agent.AllowRouting) .Set(x => x.Disabled, agent.Disabled) @@ -262,7 +142,7 @@ public int Transaction(Action action) { var users = _users.Select(x => new UserCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), FirstName = x.FirstName, LastName = x.LastName, Salt = x.Salt, @@ -292,9 +172,9 @@ public int Transaction(Action action) { var userAgents = _userAgents.Select(x => new UserAgentCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), - AgentId = Guid.Parse(x.AgentId), - UserId = !string.IsNullOrEmpty(x.UserId) && Guid.TryParse(x.UserId, out var _) ? Guid.Parse(x.UserId) : Guid.Empty, + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), + AgentId = x.AgentId, + UserId = !string.IsNullOrEmpty(x.UserId) ? x.UserId : string.Empty, CreatedTime = x.CreatedTime, UpdatedTime = x.UpdatedTime }).ToList(); @@ -340,7 +220,7 @@ public void UpdateAgent(Agent agent, AgentField field) case AgentField.Profiles: UpdateAgentProfiles(agent.Id, agent.Profiles); break; - case AgentField.RoutingRules: + case AgentField.RoutingRule: UpdateAgentRoutingRules(agent.Id, agent.RoutingRules); break; case AgentField.Instruction: @@ -355,6 +235,9 @@ public void UpdateAgent(Agent agent, AgentField field) case AgentField.Response: UpdateAgentResponses(agent.Id, agent.Responses); break; + case AgentField.Sample: + UpdateAgentSamples(agent.Id, agent.Samples); + break; case AgentField.All: UpdateAgentAllFields(agent); break; @@ -368,7 +251,7 @@ private void UpdateAgentName(string agentId, string name) { if (string.IsNullOrEmpty(name)) return; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Name, name) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -380,7 +263,7 @@ private void UpdateAgentDescription(string agentId, string description) { if (string.IsNullOrEmpty(description)) return; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Description, description) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -390,7 +273,7 @@ private void UpdateAgentDescription(string agentId, string description) private void UpdateAgentIsPublic(string agentId, bool isPublic) { - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.IsPublic, isPublic) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -400,7 +283,7 @@ private void UpdateAgentIsPublic(string agentId, bool isPublic) private void UpdateAgentDisabled(string agentId, bool disabled) { - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Disabled, disabled) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -410,7 +293,7 @@ private void UpdateAgentDisabled(string agentId, bool disabled) private void UpdateAgentAllowRouting(string agentId, bool allowRouting) { - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.AllowRouting, allowRouting) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -422,7 +305,7 @@ private void UpdateAgentProfiles(string agentId, List profiles) { if (profiles.IsNullOrEmpty()) return; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Profiles, profiles) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -435,7 +318,7 @@ 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 filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.RoutingRules, ruleElements) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -447,7 +330,7 @@ private void UpdateAgentInstruction(string agentId, string instruction) { if (string.IsNullOrEmpty(instruction)) return; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Instruction, instruction) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -460,7 +343,7 @@ private void UpdateAgentFunctions(string agentId, List functions) if (functions.IsNullOrEmpty()) return; var functionsToUpdate = functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList(); - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Functions, functionsToUpdate) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -473,7 +356,7 @@ private void UpdateAgentTemplates(string agentId, List templates) if (templates.IsNullOrEmpty()) return; var templatesToUpdate = templates.Select(t => AgentTemplateMongoElement.ToMongoElement(t)).ToList(); - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Templates, templatesToUpdate) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -486,7 +369,7 @@ private void UpdateAgentResponses(string agentId, List responses) if (responses.IsNullOrEmpty()) return; var responsesToUpdate = responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList(); - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agentId)); + var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update .Set(x => x.Responses, responsesToUpdate) .Set(x => x.UpdatedTime, DateTime.UtcNow); @@ -494,9 +377,21 @@ private void UpdateAgentResponses(string agentId, List responses) _dc.Agents.UpdateOne(filter, update); } + private void UpdateAgentSamples(string agentId, List samples) + { + if (samples.IsNullOrEmpty()) return; + + var filter = Builders.Filter.Eq(x => x.Id, agentId); + var update = Builders.Update + .Set(x => x.Samples, samples) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + private void UpdateAgentAllFields(Agent agent) { - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(agent.Id)); + var filter = Builders.Filter.Eq(x => x.Id, agent.Id); var update = Builders.Update .Set(x => x.Name, agent.Name) .Set(x => x.Description, agent.Description) @@ -508,26 +403,119 @@ private void UpdateAgentAllFields(Agent agent) .Set(x => x.Templates, agent.Templates.Select(t => AgentTemplateMongoElement.ToMongoElement(t)).ToList()) .Set(x => x.Functions, agent.Functions.Select(f => FunctionDefMongoElement.ToMongoElement(f)).ToList()) .Set(x => x.Responses, agent.Responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList()) + .Set(x => x.Samples, agent.Samples) .Set(x => x.IsPublic, agent.IsPublic) .Set(x => x.UpdatedTime, DateTime.UtcNow); - _dc.Agents.UpdateOne(filter, update); + var res = _dc.Agents.UpdateOne(filter, update); + Console.WriteLine(); } #endregion + public Agent? GetAgent(string agentId) + { + var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId); + if (agent == null) return null; + return new Agent + { + Id = agent.Id, + Name = agent.Name, + Description = agent.Description, + Instruction = agent.Instruction, + Templates = !agent.Templates.IsNullOrEmpty() ? agent.Templates + .Select(t => AgentTemplateMongoElement.ToDomainElement(t)) + .ToList() : new List(), + Functions = !agent.Functions.IsNullOrEmpty() ? agent.Functions + .Select(f => FunctionDefMongoElement.ToDomainElement(f)) + .ToList() : new List(), + Responses = !agent.Responses.IsNullOrEmpty() ? agent.Responses + .Select(r => AgentResponseMongoElement.ToDomainElement(r)) + .ToList() : new List(), + Samples = agent.Samples ?? new List(), + IsPublic = agent.IsPublic, + Disabled = agent.Disabled, + AllowRouting = agent.AllowRouting, + Profiles = agent.Profiles, + RoutingRules = !agent.RoutingRules.IsNullOrEmpty() ? agent.RoutingRules + .Select(r => RoutingRuleMongoElement.ToDomainElement(agent.Id, agent.Name, r)) + .ToList() : new List() + }; + } - public Agent? GetAgent(string agentId) + public List GetAgents(string? name = null, bool? disabled = null, bool? allowRouting = null, + bool? isPublic = null, List? agentIds = null) { - var foundAgent = Agents.FirstOrDefault(x => x.Id == agentId); - return foundAgent; + var agents = new List(); + IQueryable query = _dc.Agents.AsQueryable(); + + if (!string.IsNullOrEmpty(name)) + { + query = query.Where(x => x.Name.ToLower() == name.ToLower()); + } + + if (disabled.HasValue) + { + query = query.Where(x => x.Disabled == disabled); + } + + if (allowRouting.HasValue) + { + query = query.Where(x => x.AllowRouting == allowRouting); + } + + if (isPublic.HasValue) + { + query = query.Where(x => x.IsPublic == isPublic); + } + + if (agentIds != null) + { + query = query.Where(x => agentIds.Contains(x.Id)); + } + + return query.ToList().Select(x => new Agent + { + Id = x.Id, + Name = x.Name, + Description = x.Description, + Instruction = x.Instruction, + Templates = !x.Templates.IsNullOrEmpty() ? x.Templates + .Select(t => AgentTemplateMongoElement.ToDomainElement(t)) + .ToList() : new List(), + Functions = !x.Functions.IsNullOrEmpty() ? x.Functions + .Select(f => FunctionDefMongoElement.ToDomainElement(f)) + .ToList() : new List(), + Responses = !x.Responses.IsNullOrEmpty() ? x.Responses + .Select(r => AgentResponseMongoElement.ToDomainElement(r)) + .ToList() : new List(), + Samples = x.Samples ?? new List(), + IsPublic = x.IsPublic, + Disabled = x.Disabled, + AllowRouting = x.AllowRouting, + Profiles = x.Profiles, + RoutingRules = !x.RoutingRules.IsNullOrEmpty() ? x.RoutingRules + .Select(r => RoutingRuleMongoElement.ToDomainElement(x.Id, x.Name, r)) + .ToList() : new List() + }).ToList(); + } + + public List GetAgentsByUser(string userId) + { + var agentIds = (from ua in _dc.UserAgents.AsQueryable() + join u in _dc.Users.AsQueryable() on ua.UserId equals u.Id + where ua.UserId == userId || u.ExternalId == userId + select ua.AgentId).ToList(); + + var agents = GetAgents(isPublic: true, agentIds: agentIds); + return agents; } public List GetAgentResponses(string agentId, string prefix, string intent) { var responses = new List(); - var agent = Agents.FirstOrDefault(x => x.Id == agentId); + var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId); if (agent == null) return responses; return agent.Responses.Where(x => x.Prefix == prefix && x.Intent == intent).Select(x => x.Content).ToList(); @@ -535,7 +523,7 @@ public List GetAgentResponses(string agentId, string prefix, string inte public string GetAgentTemplate(string agentId, string templateName) { - var agent = Agents.FirstOrDefault(x => x.Id == agentId); + var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId); if (agent == null) return string.Empty; return agent.Templates?.FirstOrDefault(x => x.Name == templateName.ToLower())?.Content ?? string.Empty; @@ -547,7 +535,7 @@ public void BulkInsertAgents(List agents) var agentDocs = agents.Select(x => new AgentCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), Name = x.Name, Description = x.Description, Instruction = x.Instruction, @@ -560,6 +548,7 @@ public void BulkInsertAgents(List agents) Responses = x.Responses? .Select(r => AgentResponseMongoElement.ToMongoElement(r))? .ToList() ?? new List(), + Samples = x.Samples ?? new List(), IsPublic = x.IsPublic, AllowRouting = x.AllowRouting, Disabled = x.Disabled, @@ -580,9 +569,9 @@ public void BulkInsertUserAgents(List userAgents) var userAgentDocs = userAgents.Select(x => new UserAgentCollection { - Id = string.IsNullOrEmpty(x.Id) ? Guid.NewGuid() : new Guid(x.Id), - AgentId = Guid.Parse(x.AgentId), - UserId = !string.IsNullOrEmpty(x.UserId) && Guid.TryParse(x.UserId, out var _) ? Guid.Parse(x.UserId) : Guid.Empty, + Id = !string.IsNullOrEmpty(x.Id) ? x.Id : Guid.NewGuid().ToString(), + AgentId = x.AgentId, + UserId = !string.IsNullOrEmpty(x.UserId) ? x.UserId : string.Empty, CreatedTime = x.CreatedTime, UpdatedTime = x.UpdatedTime }).ToList(); @@ -594,10 +583,8 @@ public bool DeleteAgents() { try { - var userAgentFilter = Builders.Filter.Empty; - var agentfilter = Builders.Filter.Empty; - _dc.UserAgents.DeleteMany(userAgentFilter); - _dc.Agents.DeleteMany(agentfilter); + _dc.UserAgents.DeleteMany(Builders.Filter.Empty); + _dc.Agents.DeleteMany(Builders.Filter.Empty); return true; } catch @@ -615,9 +602,9 @@ public void CreateNewConversation(Conversation conversation) var conv = new ConversationCollection { - Id = !string.IsNullOrEmpty(conversation.Id) ? Guid.Parse(conversation.Id) : Guid.NewGuid(), - AgentId = Guid.Parse(conversation.AgentId), - UserId = !string.IsNullOrEmpty(conversation.UserId) && Guid.TryParse(conversation.UserId, out var _) ? Guid.Parse(conversation.UserId) : Guid.Empty, + Id = !string.IsNullOrEmpty(conversation.Id) ? conversation.Id : Guid.NewGuid().ToString(), + AgentId = conversation.AgentId, + UserId = !string.IsNullOrEmpty(conversation.UserId) ? conversation.UserId : string.Empty, Title = conversation.Title, States = conversation.States?.ToKeyValueList() ?? new List(), CreatedTime = DateTime.UtcNow, @@ -626,7 +613,7 @@ public void CreateNewConversation(Conversation conversation) var dialog = new ConversationDialogCollection { - Id = Guid.NewGuid(), + Id = Guid.NewGuid().ToString(), ConversationId = conv.Id, Dialog = string.Empty }; @@ -639,7 +626,7 @@ public string GetConversationDialog(string conversationId) { if (string.IsNullOrEmpty(conversationId)) return string.Empty; - var filter = Builders.Filter.Eq(x => x.ConversationId, Guid.Parse(conversationId)); + var filter = Builders.Filter.Eq(x => x.ConversationId, conversationId); var foundDialog = _dc.ConversationDialogs.Find(filter).FirstOrDefault(); if (foundDialog == null) return string.Empty; @@ -650,11 +637,11 @@ public void UpdateConversationDialog(string conversationId, string dialogs) { if (string.IsNullOrEmpty(conversationId)) return; - var filterConv = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var filterConv = Builders.Filter.Eq(x => x.Id, conversationId); var foundConv = _dc.Conversations.Find(filterConv).FirstOrDefault(); if (foundConv == null) return; - var filterDialog = Builders.Filter.Eq(x => x.ConversationId, Guid.Parse(conversationId)); + var filterDialog = Builders.Filter.Eq(x => x.ConversationId, conversationId); var foundDialog = _dc.ConversationDialogs.Find(filterDialog).FirstOrDefault(); if (foundDialog == null) return; @@ -670,7 +657,7 @@ public List GetConversationStates(string conversationId) var states = new List(); if (string.IsNullOrEmpty(conversationId)) return states; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var filter = Builders.Filter.Eq(x => x.Id, conversationId); var foundConversation = _dc.Conversations.Find(filter).FirstOrDefault(); var savedStates = foundConversation?.States ?? new List(); return savedStates; @@ -680,7 +667,7 @@ public void UpdateConversationStates(string conversationId, List { if (string.IsNullOrEmpty(conversationId)) return; - var filter = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); + var filter = Builders.Filter.Eq(x => x.Id, conversationId); var foundConv = _dc.Conversations.Find(filter).FirstOrDefault(); if (foundConv == null) return; @@ -695,8 +682,8 @@ public Conversation GetConversation(string conversationId) { if (string.IsNullOrEmpty(conversationId)) return null; - var filterConv = Builders.Filter.Eq(x => x.Id, Guid.Parse(conversationId)); - var filterDialog = Builders.Filter.Eq(x => x.ConversationId, Guid.Parse(conversationId)); + var filterConv = Builders.Filter.Eq(x => x.Id, conversationId); + var filterDialog = Builders.Filter.Eq(x => x.ConversationId, conversationId); var conv = _dc.Conversations.Find(filterConv).FirstOrDefault(); var dialog = _dc.ConversationDialogs.Find(filterDialog).FirstOrDefault(); @@ -719,9 +706,9 @@ public Conversation GetConversation(string conversationId) public List GetConversations(string userId) { var records = new List(); - if (string.IsNullOrEmpty(userId) || !Guid.TryParse(userId, out var _)) return records; + if (string.IsNullOrEmpty(userId)) return records; - var filterByUserId = Builders.Filter.Eq(x => x.UserId, Guid.Parse(userId)); + var filterByUserId = Builders.Filter.Eq(x => x.UserId, userId); var conversations = _dc.Conversations.Find(filterByUserId).ToList(); foreach (var conv in conversations) @@ -745,18 +732,31 @@ public List GetConversations(string userId) #region User public User? GetUserByEmail(string email) { - var user = Users.FirstOrDefault(x => x.Email == email); + var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.Email == email); return user != null ? new User { - Id = user.Id.ToString(), + Id = user.Id, FirstName = user.FirstName, LastName = user.LastName, Email = user.Email, Password = user.Password, Salt = user.Salt, - ExternalId = user.ExternalId, - CreatedTime = user.CreatedTime, - UpdatedTime = user.UpdatedTime + ExternalId = user.ExternalId + } : null; + } + + public User? GetUserByExternalId(string externalId) + { + var user = _dc.Users.AsQueryable().FirstOrDefault(x => x.ExternalId == externalId); + return user != null ? new User + { + Id = user.Id, + FirstName = user.FirstName, + LastName = user.LastName, + Email = user.Email, + Password = user.Password, + Salt = user.Salt, + ExternalId = user.ExternalId } : null; } @@ -766,7 +766,7 @@ public void CreateUser(User user) var userCollection = new UserCollection { - Id = Guid.NewGuid(), + Id = Guid.NewGuid().ToString(), FirstName = user.FirstName, LastName = user.LastName, Salt = user.Salt,