From ba855bc7cc2706457777c2b9d12eae96e6f073fa Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Sat, 7 Dec 2024 13:47:17 -0800 Subject: [PATCH 01/15] introduce ConversationHookProvider to avoid ordering conversartion hooks in runtime --- .../Conversations/ConversationHookProvider.cs | 20 +++++++++++++++++++ .../ConversationService.TruncateMessage.cs | 2 +- .../ConversationService.UpdateBreakpoint.cs | 6 +++--- .../Services/ConversationService.cs | 3 ++- .../Functions/HumanInterventionNeededFn.cs | 6 +++--- .../Routing/RoutingService.InvokeFunction.cs | 6 +++--- .../BotSharp.Plugin.ChatHub/ChatHubPlugin.cs | 1 + 7 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookProvider.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookProvider.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookProvider.cs new file mode 100644 index 00000000..00393da4 --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookProvider.cs @@ -0,0 +1,20 @@ +namespace BotSharp.Abstraction.Conversations; + +public class ConversationHookProvider +{ + public IEnumerable Hooks { get; } + + private readonly Lazy> _hooksOrderByPriority; + + public IEnumerable HooksOrderByPriority + => _hooksOrderByPriority.Value; + + public ConversationHookProvider(IEnumerable conversationHooks) + { + Hooks = conversationHooks; + _hooksOrderByPriority = new Lazy>(() => + { + return conversationHooks.OrderBy(hook => hook.Priority).ToArray(); + }); + } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs index ccc074e8..1a75d717 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs @@ -9,7 +9,7 @@ public partial class ConversationService : IConversationService var deleteMessageIds = db.TruncateConversation(conversationId, messageId, cleanLog: true); fileStorage.DeleteMessageFiles(conversationId, deleteMessageIds, messageId, newMessageId); - var hooks = _services.GetServices().ToList(); + var hooks = _services.GetServices(); foreach (var hook in hooks) { await hook.OnMessageDeleted(conversationId, messageId); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs index 8f88f44f..75a0bbfb 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs @@ -31,9 +31,9 @@ public partial class ConversationService : IConversationService states.CleanStates(excludedStates); } - var hooks = _services.GetServices() - .OrderBy(x => x.Priority) - .ToList(); + var hooks = _services + .GetRequiredService() + .HooksOrderByPriority; // Before executing functions foreach (var hook in hooks) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 55d80c18..03ff8aa4 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -103,7 +103,8 @@ public partial class ConversationService : IConversationService db.CreateNewConversation(record); - var hooks = _services.GetServices().ToList(); + var hooks = _services.GetServices(); + foreach (var hook in hooks) { // If user connect agent first time diff --git a/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs b/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs index d0c26be0..719dd805 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/Functions/HumanInterventionNeededFn.cs @@ -15,9 +15,9 @@ public class HumanInterventionNeededFn : IFunctionCallback public async Task Execute(RoleDialogModel message) { - var hooks = _services.GetServices() - .OrderBy(x => x.Priority) - .ToList(); + var hooks = _services + .GetRequiredService() + .HooksOrderByPriority; foreach (var hook in hooks) { diff --git a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs index 64b96136..fb074dfc 100644 --- a/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs +++ b/src/Infrastructure/BotSharp.Core/Routing/RoutingService.InvokeFunction.cs @@ -18,9 +18,9 @@ public partial class RoutingService var clonedMessage = RoleDialogModel.From(message); clonedMessage.FunctionName = name; - var hooks = _services.GetServices() - .OrderBy(x => x.Priority) - .ToList(); + var hooks = _services + .GetRequiredService() + .HooksOrderByPriority; var progressService = _services.GetService(); diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs index 1eaad66d..e7cf082f 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/ChatHubPlugin.cs @@ -22,6 +22,7 @@ public class ChatHubPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); From 1e974441ff47ec43658492e15cb64549900b0dab Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Wed, 11 Dec 2024 17:16:59 -0800 Subject: [PATCH 02/15] ChatHubConversationHook priority --- .../Conversations/ConversationHookBase.cs | 18 +++++++----------- .../ConversationService.SendMessage.cs | 6 ++---- .../Hooks/ChatHubConversationHook.cs | 1 + 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs index 9239b865..da87646e 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/ConversationHookBase.cs @@ -2,27 +2,23 @@ namespace BotSharp.Abstraction.Conversations; public abstract class ConversationHookBase : IConversationHook { - protected Agent _agent; - public Agent Agent => _agent; + public Agent Agent { get; private set; } - protected Conversation _conversation; - public Conversation Conversation => _conversation; + public Conversation Conversation { get; private set; } - protected List _dialogs; - public List Dialogs => _dialogs; + public List Dialogs { get; private set; } - protected int _priority = 0; - public int Priority => _priority; + public int Priority { get; protected set; } = 0; public IConversationHook SetAgent(Agent agent) { - _agent = agent; + Agent = agent; return this; } public IConversationHook SetConversation(Conversation conversation) { - _conversation = conversation; + Conversation = conversation; return this; } @@ -37,7 +33,7 @@ public abstract class ConversationHookBase : IConversationHook public virtual Task OnDialogsLoaded(List dialogs) { - _dialogs = dialogs; + Dialogs = dialogs; return Task.CompletedTask; } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 375cf3e6..bdf43c8a 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -28,7 +28,7 @@ public partial class ConversationService var dialogs = conv.GetDialogHistory(); var statistics = _services.GetRequiredService(); - var hooks = _services.GetServices().ToList(); + var hookProvider = _services.GetRequiredService(); RoleDialogModel response = message; bool stopCompletion = false; @@ -44,9 +44,7 @@ public partial class ConversationService message.Payload = replyMessage.Payload; } - // Before chat completion hook - hooks = ReOrderConversationHooks(hooks); - foreach (var hook in hooks) + foreach (var hook in hookProvider.HooksOrderByPriority) { hook.SetAgent(agent) .SetConversation(conversation); diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index b282fa53..6b425b4b 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -29,6 +29,7 @@ public class ChatHubConversationHook : ConversationHookBase _chatHub = chatHub; _user = user; _options = options; + Priority = -1; // Make sure this hook is the top one. } public override async Task OnConversationInitialized(Conversation conversation) From 4489683eebbc82720d2ab676dde9660fc7ba8998 Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Wed, 11 Dec 2024 17:44:29 -0800 Subject: [PATCH 03/15] access public properties directly --- .../Evaluations/EvaluationConversationHook.cs | 22 +++++++++---------- .../Hooks/RateLimitConversationHook.cs | 2 +- .../RoutingConversationHook.cs | 6 ++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs index bfc0c1ec..b315b683 100644 --- a/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs +++ b/src/Infrastructure/BotSharp.Core/Evaluations/EvaluationConversationHook.cs @@ -15,45 +15,45 @@ public class EvaluationConversationHook : ConversationHookBase public override Task OnMessageReceived(RoleDialogModel message) { - if (_conversation != null && _convSettings.EnableExecutionLog) + if (Conversation != null && _convSettings.EnableExecutionLog) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.Content}"); + _logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.Content}"); } return base.OnMessageReceived(message); } public override Task OnFunctionExecuted(RoleDialogModel message) { - if (_conversation != null && _convSettings.EnableExecutionLog) + if (Conversation != null && _convSettings.EnableExecutionLog) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.FunctionName}({message.FunctionArgs}) => {message.Content}"); + _logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.FunctionName}({message.FunctionArgs}) => {message.Content}"); } return base.OnFunctionExecuted(message); } public override Task OnResponseGenerated(RoleDialogModel message) { - if (_conversation != null && _convSettings.EnableExecutionLog) + if (Conversation != null && _convSettings.EnableExecutionLog) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.Content}"); - } + _logger.Append(Conversation.Id, $"[{DateTime.Now}] {message.Role}: {message.Content}"); + } return base.OnResponseGenerated(message); } public override Task OnHumanInterventionNeeded(RoleDialogModel message) { - if (_conversation != null && _convSettings.EnableExecutionLog) + if (Conversation != null && _convSettings.EnableExecutionLog) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); + _logger.Append(Conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); } return base.OnHumanInterventionNeeded(message); } public override Task OnConversationEnding(RoleDialogModel message) { - if (_conversation != null && _convSettings.EnableExecutionLog) + if (Conversation != null && _convSettings.EnableExecutionLog) { - _logger.Append(_conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); + _logger.Append(Conversation.Id, $"[{DateTime.Now}] {AgentRole.Function}: trigger_event({{\"event\": \"{message.FunctionName}\"}})"); } return base.OnConversationEnding(message); } diff --git a/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs b/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs index 1cb09f3e..a9a9478f 100644 --- a/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs +++ b/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs @@ -34,7 +34,7 @@ public class RateLimitConversationHook : ConversationHookBase } // Check message sending frequency - var userSents = _dialogs.Where(x => x.Role == AgentRole.User) + var userSents = Dialogs.Where(x => x.Role == AgentRole.User) .TakeLast(2).ToList(); if (userSents.Count > 1) diff --git a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs index b7fab29e..b65e45c5 100644 --- a/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.RoutingSpeeder/RoutingConversationHook.cs @@ -42,7 +42,7 @@ public class RoutingConversationHook: ConversationHookBase // Render by template var templateService = _services.GetRequiredService(); - var response = await templateService.RenderIntentResponse(_agent.Id, message); + var response = await templateService.RenderIntentResponse(Agent.Id, message); if (!string.IsNullOrEmpty(response)) { @@ -54,7 +54,7 @@ public class RoutingConversationHook: ConversationHookBase public override async Task OnResponseGenerated(RoleDialogModel message) { var routerSettings = _services.GetRequiredService(); - bool saveFlag = _agent.Type != AgentType.Routing; + bool saveFlag = Agent.Type != AgentType.Routing; if (saveFlag) { @@ -63,7 +63,7 @@ public class RoutingConversationHook: ConversationHookBase var rootDataPath = agentService.GetDataDir(); string rawDataDir = Path.Combine(rootDataPath, "raw_data", $"agent.{message.CurrentAgentId}.txt"); - var lastThreeDialogs = _dialogs.Where(x => x.Role == AgentRole.User || x.Role == AgentRole.Assistant) + var lastThreeDialogs = Dialogs.Where(x => x.Role == AgentRole.User || x.Role == AgentRole.Assistant) .Select(x => x.Content.Replace('\r', ' ').Replace('\n', ' ')) .TakeLast(3) .ToArray(); From 96eac1f26ffcfa6c7013f923e8aac21c14e48ffc Mon Sep 17 00:00:00 2001 From: Gil Zhang Date: Thu, 12 Dec 2024 11:28:00 +0800 Subject: [PATCH 04/15] Add Conversation Title Alias --- .../Conversations/IConversationService.cs | 1 + .../Conversations/Models/Conversation.cs | 1 + .../Filters/ConversationFilter.cs | 1 + .../Repositories/IBotSharpRepository.cs | 1 + .../Services/ConversationService.cs | 8 +++++++ .../Repository/BotSharpDbContext.cs | 2 ++ .../FileRepository.Conversation.cs | 20 ++++++++++++++++ .../Controllers/ConversationController.cs | 24 +++++++++++++++++++ .../Conversations/ConversationViewModel.cs | 4 ++++ .../UpdateConversationTitleAliasModel.cs | 9 +++++++ .../Collections/ConversationDocument.cs | 1 + .../MongoRepository.Conversation.cs | 15 ++++++++++++ 12 files changed, 87 insertions(+) create mode 100644 src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/UpdateConversationTitleAliasModel.cs diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index ffb4986a..6a04e796 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -12,6 +12,7 @@ public interface IConversationService Task GetConversation(string id); Task> GetConversations(ConversationFilter filter); Task UpdateConversationTitle(string id, string title); + Task UpdateConversationTitleAlias(string id, string titleAlias); Task UpdateConversationTags(string conversationId, List tags); Task UpdateConversationMessage(string conversationId, UpdateMessageRequest request); Task> GetLastConversations(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs index 5ded2c7c..a485a9c4 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs @@ -13,6 +13,7 @@ public class Conversation /// public string? TaskId { get; set; } public string Title { get; set; } = string.Empty; + public string TitleAlias { get; set; } = string.Empty; [JsonIgnore] public List Dialogs { get; set; } = new(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs index ab1a0a9f..23543049 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/Filters/ConversationFilter.cs @@ -8,6 +8,7 @@ public class ConversationFilter /// public string? Id { get; set; } public string? Title { get; set; } + public string? TitleAlias { get; set; } public string? AgentId { get; set; } public string? Status { get; set; } public string? Channel { get; set; } diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 61982cc4..fa6f074c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -86,6 +86,7 @@ public interface IBotSharpRepository : IHaveServiceProvider Conversation GetConversation(string conversationId); PagedItems GetConversations(ConversationFilter filter); void UpdateConversationTitle(string conversationId, string title); + void UpdateConversationTitleAlias(string conversationId, string titleAlias); bool UpdateConversationTags(string conversationId, List tags); bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request); void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 55d80c18..67b0b1b0 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -51,6 +51,14 @@ public partial class ConversationService : IConversationService return conversation; } + public async Task UpdateConversationTitleAlias(string id, string titleAlias) + { + var db = _services.GetRequiredService(); + db.UpdateConversationTitleAlias(id, titleAlias); + var conversation = db.GetConversation(id); + return conversation; + } + public async Task UpdateConversationTags(string conversationId, List tags) { var db = _services.GetRequiredService(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index d2c519eb..165dc34b 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -105,6 +105,8 @@ public class BotSharpDbContext : Database, IBotSharpRepository public void UpdateConversationTitle(string conversationId, string title) => throw new NotImplementedException(); + public void UpdateConversationTitleAlias(string conversationId, string titleAlias) + => throw new NotImplementedException(); public bool UpdateConversationTags(string conversationId, List tags) => throw new NotImplementedException(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs index fd13936c..34345271 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs @@ -134,6 +134,22 @@ namespace BotSharp.Core.Repository } } } + public void UpdateConversationTitleAlias(string conversationId, string titleAlias) + { + var convDir = FindConversationDirectory(conversationId); + if (!string.IsNullOrEmpty(convDir)) + { + var convFile = Path.Combine(convDir, CONVERSATION_FILE); + var content = File.ReadAllText(convFile); + var record = JsonSerializer.Deserialize(content, _options); + if (record != null) + { + record.TitleAlias = titleAlias; + record.UpdatedTime = DateTime.UtcNow; + File.WriteAllText(convFile, JsonSerializer.Serialize(record, _options)); + } + } + } public bool UpdateConversationTags(string conversationId, List tags) { @@ -356,6 +372,10 @@ namespace BotSharp.Core.Repository { matched = matched && record.Title.Contains(filter.Title); } + if (filter?.TitleAlias != null) + { + matched = matched && record.TitleAlias.Contains(filter.TitleAlias); + } if (filter?.AgentId != null) { matched = matched && record.AgentId == filter.AgentId; diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 389bf96f..266c5ac5 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -223,6 +223,30 @@ public class ConversationController : ControllerBase return response != null; } + [HttpPut("/conversation/{conversationId}/update-title-alias")] + public async Task UpdateConversationTitleAlias([FromRoute] string conversationId, [FromBody] UpdateConversationTitleAliasModel newTile) + { + var userService = _services.GetRequiredService(); + var conversationService = _services.GetRequiredService(); + + var user = await userService.GetUser(_user.Id); + var filter = new ConversationFilter + { + Id = conversationId, + UserId = user.Role != UserRole.Admin ? user.Id : null + }; + var conversations = await conversationService.GetConversations(filter); + + if (conversations.Items.IsNullOrEmpty()) + { + return false; + } + + var response = await conversationService.UpdateConversationTitleAlias(conversationId, newTile.NewTitleAlias); + return response != null; + } + + [HttpPut("/conversation/{conversationId}/update-tags")] public async Task UpdateConversationTags([FromRoute] string conversationId, [FromBody] UpdateConversationRequest request) { diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs index 90b4ff67..a660a525 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/ConversationViewModel.cs @@ -15,6 +15,9 @@ public class ConversationViewModel [JsonPropertyName("title")] public string Title { get; set; } = string.Empty; + [JsonPropertyName("title_alias")] + public string TitleAlias { get; set; } = string.Empty; + public UserViewModel User { get; set; } = new UserViewModel(); public string Event { get; set; } @@ -48,6 +51,7 @@ public class ConversationViewModel }, AgentId = sess.AgentId, Title = sess.Title, + TitleAlias = sess.TitleAlias, Channel = sess.Channel, Status = sess.Status, TaskId = sess.TaskId, diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/UpdateConversationTitleAliasModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/UpdateConversationTitleAliasModel.cs new file mode 100644 index 00000000..5d9ac2fd --- /dev/null +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Conversations/UpdateConversationTitleAliasModel.cs @@ -0,0 +1,9 @@ +using System.ComponentModel.DataAnnotations; + +namespace BotSharp.OpenAPI.ViewModels.Conversations; + +public class UpdateConversationTitleAliasModel +{ + [Required] + public string NewTitleAlias { get; set; } +} diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs index 28b0391a..52c26b52 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs @@ -6,6 +6,7 @@ public class ConversationDocument : MongoBase public string UserId { get; set; } public string? TaskId { get; set; } public string Title { get; set; } + public string TitleAlias { get; set; } public string Channel { get; set; } public string ChannelId { get; set; } public string Status { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs index cdd78ae2..468f467a 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs @@ -114,6 +114,17 @@ public partial class MongoRepository _dc.Conversations.UpdateOne(filterConv, updateConv); } + public void UpdateConversationTitleAlias(string conversationId, string titleAlias) + { + if (string.IsNullOrEmpty(conversationId)) return; + + var filterConv = Builders.Filter.Eq(x => x.Id, conversationId); + var updateConv = Builders.Update + .Set(x => x.UpdatedTime, DateTime.UtcNow) + .Set(x => x.TitleAlias, titleAlias); + + _dc.Conversations.UpdateOne(filterConv, updateConv); + } public bool UpdateConversationTags(string conversationId, List tags) { @@ -301,6 +312,10 @@ public partial class MongoRepository { convFilters.Add(convBuilder.Regex(x => x.Title, new BsonRegularExpression(filter.Title, "i"))); } + if (!string.IsNullOrEmpty(filter?.TitleAlias)) + { + convFilters.Add(convBuilder.Regex(x => x.Title, new BsonRegularExpression(filter.TitleAlias, "i"))); + } if (!string.IsNullOrEmpty(filter?.AgentId)) { convFilters.Add(convBuilder.Eq(x => x.AgentId, filter.AgentId)); From 7f6845b2686b5a431f361dd17947afc85ee8ea11 Mon Sep 17 00:00:00 2001 From: "songguo.zeng" Date: Thu, 12 Dec 2024 16:02:09 +0800 Subject: [PATCH 05/15] AII-400 --- .../Agents/AgentHookBase.cs | 5 ++++ .../BotSharp.Abstraction/Agents/IAgentHook.cs | 2 ++ .../Agents/Services/AgentService.LoadAgent.cs | 27 ++++++++++++++++--- 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs index a3746ca8..f4d30523 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs @@ -56,4 +56,9 @@ public abstract class AgentHookBase : IAgentHook public virtual void OnAgentUtilityLoaded(Agent agent) { } + + public virtual void OnAgentLoadFilter(Agent agent) + { + + } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs index a3f53fb6..a329134b 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs @@ -33,4 +33,6 @@ public interface IAgentHook /// /// void OnAgentLoaded(Agent agent); + + void OnAgentLoadFilter(Agent agent); } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 396a7d15..3ae49385 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -5,9 +5,8 @@ namespace BotSharp.Core.Agents.Services; public partial class AgentService { - public static ConcurrentDictionary> AgentParameterTypes = new(); + public static ConcurrentDictionary> AgentParameterTypes = new(); - [MemoryCache(10 * 60, perInstanceCache: true)] public async Task LoadAgent(string id) { if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) @@ -15,6 +14,26 @@ public partial class AgentService return null; } + Agent agent = await GetLoadAgent(id); + OnAgentLoadFilter(agent); + return agent; + } + + private void OnAgentLoadFilter(Agent? agent) + { + if (agent != null && agent.Type == AgentType.Routing) + { + var hooks = _services.GetServices(); + foreach (var hook in hooks) + { + hook.OnAgentLoadFilter(agent); + } + } + } + + [MemoryCache(10 * 60, perInstanceCache: true)] + private async Task GetLoadAgent(string id) + { var hooks = _services.GetServices(); // Before agent is loaded. @@ -106,14 +125,14 @@ public partial class AgentService { var agentId = agent.Id ?? agent.Name; if (AgentParameterTypes.ContainsKey(agentId)) return; - + AddOrUpdateRoutesParameters(agentId, agent.RoutingRules); AddOrUpdateFunctionsParameters(agentId, agent.Functions); } private void AddOrUpdateRoutesParameters(string agentId, List routingRules) { - if(!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) + if (!AgentParameterTypes.TryGetValue(agentId, out var parameterTypes)) { parameterTypes = new(); } From 8d8fd758d934952f4f980b7b10ae71401d8f5a1a Mon Sep 17 00:00:00 2001 From: "songguo.zeng" Date: Thu, 12 Dec 2024 18:02:00 +0800 Subject: [PATCH 06/15] AII-400 --- .../Agents/AgentHookBase.cs | 5 ----- .../BotSharp.Abstraction/Agents/IAgentHook.cs | 2 -- .../Agents/Services/AgentService.LoadAgent.cs | 21 +------------------ 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs index f4d30523..a3746ca8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/AgentHookBase.cs @@ -56,9 +56,4 @@ public abstract class AgentHookBase : IAgentHook public virtual void OnAgentUtilityLoaded(Agent agent) { } - - public virtual void OnAgentLoadFilter(Agent agent) - { - - } } diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs index a329134b..a3f53fb6 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/IAgentHook.cs @@ -33,6 +33,4 @@ public interface IAgentHook /// /// void OnAgentLoaded(Agent agent); - - void OnAgentLoadFilter(Agent agent); } diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 3ae49385..0e9c2e3c 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -7,6 +7,7 @@ public partial class AgentService { public static ConcurrentDictionary> AgentParameterTypes = new(); + [MemoryCache(10 * 60, perInstanceCache: true)] public async Task LoadAgent(string id) { if (string.IsNullOrEmpty(id) || id == Guid.Empty.ToString()) @@ -14,26 +15,6 @@ public partial class AgentService return null; } - Agent agent = await GetLoadAgent(id); - OnAgentLoadFilter(agent); - return agent; - } - - private void OnAgentLoadFilter(Agent? agent) - { - if (agent != null && agent.Type == AgentType.Routing) - { - var hooks = _services.GetServices(); - foreach (var hook in hooks) - { - hook.OnAgentLoadFilter(agent); - } - } - } - - [MemoryCache(10 * 60, perInstanceCache: true)] - private async Task GetLoadAgent(string id) - { var hooks = _services.GetServices(); // Before agent is loaded. From 6efe291526cf0e7b8a747ae25a0821e7846aebbe Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 12 Dec 2024 17:20:27 -0600 Subject: [PATCH 07/15] allow image urls in image-reader --- .../Functions/ReadImageFn.cs | 18 +++++++++++++++--- .../LlmContexts/LlmContextIn.cs | 8 ++++++++ .../functions/util-file-read_image.json | 8 ++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs index f2e79b21..9918d5bf 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs @@ -23,8 +23,8 @@ public class ReadImageFn : IFunctionCallback var agentService = _services.GetRequiredService(); var wholeDialogs = conv.GetDialogHistory(); - var dialogs = AssembleFiles(conv.ConversationId, wholeDialogs); - var agent = await agentService.LoadAgent(BuiltInAgentId.UtilityAssistant); + var dialogs = AssembleFiles(conv.ConversationId, args?.ImageUrls, wholeDialogs); + var agent = await agentService.LoadAgent(message.CurrentAgentId ?? BuiltInAgentId.UtilityAssistant); var fileAgent = new Agent { Id = agent?.Id ?? Guid.Empty.ToString(), @@ -38,7 +38,7 @@ public class ReadImageFn : IFunctionCallback return true; } - private List AssembleFiles(string conversationId, List dialogs) + private List AssembleFiles(string conversationId, IEnumerable? imageUrls, List dialogs) { if (dialogs.IsNullOrEmpty()) { @@ -66,6 +66,18 @@ public class ReadImageFn : IFunctionCallback }).ToList(); } + if (!imageUrls.IsNullOrEmpty()) + { + var lastDialog = dialogs.Last(); + var files = lastDialog.Files ?? []; + var addnFiles = imageUrls.Select(x => x?.Trim()) + .Where(x => !string.IsNullOrWhiteSpace(x)) + .Select(x => new BotSharpFile { FileUrl = x }).ToList(); + + files.AddRange(addnFiles); + lastDialog.Files = files; + } + return dialogs; } diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/LlmContexts/LlmContextIn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/LlmContexts/LlmContextIn.cs index 9917cb74..a35e83bd 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/LlmContexts/LlmContextIn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/LlmContexts/LlmContextIn.cs @@ -11,4 +11,12 @@ public class LlmContextIn [JsonPropertyName("image_description")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public string? ImageDescription { get; set; } + + //[JsonPropertyName("image_url")] + //[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + //public string? ImageUrl { get; set; } + + [JsonPropertyName("image_urls")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public IEnumerable? ImageUrls { get; set; } } diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-file-read_image.json b/src/Plugins/BotSharp.Plugin.FileHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-file-read_image.json index a0f269a0..b8dda8b1 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-file-read_image.json +++ b/src/Plugins/BotSharp.Plugin.FileHandler/data/agents/6745151e-6d46-4a02-8de4-1c4f21c7da95/functions/util-file-read_image.json @@ -7,6 +7,14 @@ "user_request": { "type": "string", "description": "The request posted by user, which is related to analyzing requested images. User can request for multiple images to process at one time." + }, + "image_urls": { + "type": "array", + "description": "The image, photo or picture urls that user requests for analysis. They typically start with 'http' or 'https'. If user doesn't include any url, then leave this array empty. Please remove any duplicated urls", + "items": { + "type": "string", + "description": "The image, photo or picture url that user requests for analysis. It typically starts with http or https." + } } }, "required": [ "user_request" ] From 51a319a3bc3e3032e68ddb13e41168bbc7fe1ae1 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Thu, 12 Dec 2024 17:22:11 -0600 Subject: [PATCH 08/15] minor change --- .../BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs index 9918d5bf..e2c4f8c2 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs @@ -24,7 +24,8 @@ public class ReadImageFn : IFunctionCallback var wholeDialogs = conv.GetDialogHistory(); var dialogs = AssembleFiles(conv.ConversationId, args?.ImageUrls, wholeDialogs); - var agent = await agentService.LoadAgent(message.CurrentAgentId ?? BuiltInAgentId.UtilityAssistant); + var agentId = !string.IsNullOrWhiteSpace(message.CurrentAgentId) ? message.CurrentAgentId : BuiltInAgentId.UtilityAssistant; + var agent = await agentService.LoadAgent(agentId); var fileAgent = new Agent { Id = agent?.Id ?? Guid.Empty.ToString(), From f78425cffab83f0ccd86a034fbfa740bdf6542b5 Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Thu, 12 Dec 2024 20:44:26 -0800 Subject: [PATCH 09/15] added unit test --- tests/UnitTest/MainTest.cs | 30 ++++++++++++++++++++++++++++++ tests/UnitTest/UnitTest.csproj | 8 +++++++- tests/UnitTest/UnitTest1.cs | 11 ----------- 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 tests/UnitTest/MainTest.cs delete mode 100644 tests/UnitTest/UnitTest1.cs diff --git a/tests/UnitTest/MainTest.cs b/tests/UnitTest/MainTest.cs new file mode 100644 index 00000000..2e4c29bf --- /dev/null +++ b/tests/UnitTest/MainTest.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.DependencyInjection; +using BotSharp.Abstraction.Conversations; +using BotSharp.Core.Evaluations; +using BotSharp.Plugin.ChatHub.Hooks; + +namespace UnitTest +{ + [TestClass] + public class MainTest + { + [TestMethod] + public void TestConversationHookProvider() + { + var services = new ServiceCollection(); + + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + var serviceProvider = services.BuildServiceProvider(); + var conversationHookProvider = serviceProvider.GetService(); + + Assert.AreEqual(3, conversationHookProvider.Hooks.Count()); + + // ChatHubConversationHook has the top priority + Assert.IsInstanceOfType(conversationHookProvider.HooksOrderByPriority.FirstOrDefault()); + } + } +} \ No newline at end of file diff --git a/tests/UnitTest/UnitTest.csproj b/tests/UnitTest/UnitTest.csproj index be924573..3e1831ae 100644 --- a/tests/UnitTest/UnitTest.csproj +++ b/tests/UnitTest/UnitTest.csproj @@ -13,10 +13,16 @@ + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + + diff --git a/tests/UnitTest/UnitTest1.cs b/tests/UnitTest/UnitTest1.cs deleted file mode 100644 index ab3cd866..00000000 --- a/tests/UnitTest/UnitTest1.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace UnitTest -{ - [TestClass] - public class UnitTest1 - { - [TestMethod] - public void TestMethod1() - { - } - } -} \ No newline at end of file From 42ad511c7e3c58a0bc9a9d9ae6555b840783e8c3 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Fri, 13 Dec 2024 14:34:17 -0600 Subject: [PATCH 10/15] add agent max message count --- .../Agents/Enums/AgentField.cs | 3 ++- .../Agents/Models/Agent.cs | 8 ++++++ .../Repositories/IBotSharpRepository.cs | 2 +- .../Agents/Hooks/BasicAgentHook.cs | 2 +- .../Services/AgentService.UpdateAgent.cs | 1 + .../Services/ConversationService.cs | 17 +++++++++++- .../Repository/BotSharpDbContext.cs | 2 +- .../FileRepository/FileRepository.Agent.cs | 19 +++++++++++++- .../ViewModels/Agents/AgentCreationModel.cs | 3 +++ .../ViewModels/Agents/AgentUpdateModel.cs | 4 +++ .../ViewModels/Agents/AgentViewModel.cs | 5 ++++ .../Collections/AgentDocument.cs | 1 + .../Repository/MongoRepository.Agent.cs | 26 ++++++++++++++----- 13 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs index 1bb221d3..34e8ac19 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Enums/AgentField.cs @@ -17,7 +17,8 @@ public enum AgentField Response, Sample, LlmConfig, - Utility + Utility, + MaxMessageCount } public enum AgentTaskField diff --git a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs index e9fd7c5e..41b3800c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Agents/Models/Agent.cs @@ -104,6 +104,12 @@ public class Agent /// public string? InheritAgentId { get; set; } + /// + /// Maximum message count when load conversation + /// + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? MaxMessageCount { get; set; } + public List RoutingRules { get; set; } = new(); /// @@ -133,6 +139,8 @@ public class Agent Knowledges = agent.Knowledges, IsPublic = agent.IsPublic, Disabled = agent.Disabled, + MergeUtility = agent.MergeUtility, + MaxMessageCount = agent.MaxMessageCount, Profiles = agent.Profiles, RoutingRules = agent.RoutingRules, LlmConfig = agent.LlmConfig, diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 61982cc4..a848b619 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -53,7 +53,7 @@ public interface IBotSharpRepository : IHaveServiceProvider #region Agent void UpdateAgent(Agent agent, AgentField field); - Agent? GetAgent(string agentId); + Agent? GetAgent(string agentId, bool basicsOnly = false); List GetAgents(AgentFilter filter); List GetUserAgents(string userId); void BulkInsertAgents(List agents); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs index 2a4a7374..65d454c8 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Hooks/BasicAgentHook.cs @@ -47,7 +47,7 @@ public class BasicAgentHook : AgentHookBase var entryAgentId = routing.EntryAgentId; if (!string.IsNullOrEmpty(entryAgentId)) { - var entryAgent = db.GetAgent(entryAgentId); + var entryAgent = db.GetAgent(entryAgentId, basicsOnly: true); var (fns, tps) = GetUniqueContent(entryAgent?.Utilities); functionNames = functionNames.Concat(fns).Distinct().ToList(); templateNames = templateNames.Concat(tps).Distinct().ToList(); diff --git a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs index f871a2fe..ffea8f8d 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.UpdateAgent.cs @@ -28,6 +28,7 @@ public partial class AgentService record.IsPublic = agent.IsPublic; record.Disabled = agent.Disabled; record.MergeUtility = agent.MergeUtility; + record.MaxMessageCount = agent.MaxMessageCount; record.Type = agent.Type; record.Profiles = agent.Profiles ?? []; record.RoutingRules = agent.RoutingRules ?? []; diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 55d80c18..d586b421 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -153,7 +153,10 @@ public partial class ConversationService : IConversationService } } - return dialogs.TakeLast(lastCount).ToList(); + var agentMsgCount = GetAgentMessageCount(); + var count = agentMsgCount.HasValue && agentMsgCount.Value > 0 ? agentMsgCount.Value : lastCount; + + return dialogs.TakeLast(count).ToList(); } public void SetConversationId(string conversationId, List states, bool isReadOnly = false) @@ -192,4 +195,16 @@ public partial class ConversationService : IConversationService { return !string.IsNullOrWhiteSpace(_conversationId); } + + + private int? GetAgentMessageCount() + { + var db = _services.GetRequiredService(); + var routingCtx = _services.GetRequiredService(); + + if (string.IsNullOrEmpty(routingCtx.EntryAgentId)) return null; + + var agent = db.GetAgent(routingCtx.EntryAgentId, basicsOnly: true); + return agent?.MaxMessageCount; + } } diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index d2c519eb..ad2b19b8 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -16,7 +16,7 @@ public class BotSharpDbContext : Database, IBotSharpRepository #endregion #region Agent - public Agent GetAgent(string agentId) + public Agent GetAgent(string agentId, bool basicsOnly = false) => throw new NotImplementedException(); public List GetAgents(AgentFilter filter) diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs index 07915917..a838870f 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Agent.cs @@ -57,6 +57,9 @@ namespace BotSharp.Core.Repository case AgentField.Utility: UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities); break; + case AgentField.MaxMessageCount: + UpdateAgentMaxMessageCount(agent.Id, agent.MaxMessageCount); + break; case AgentField.All: UpdateAgentAllFields(agent); break; @@ -283,6 +286,17 @@ namespace BotSharp.Core.Repository File.WriteAllText(agentFile, json); } + private void UpdateAgentMaxMessageCount(string agentId, int? maxMessageCount) + { + var (agent, agentFile) = GetAgentFromFile(agentId); + if (agent == null) return; + + agent.MaxMessageCount = maxMessageCount; + agent.UpdatedDateTime = DateTime.UtcNow; + var json = JsonSerializer.Serialize(agent, _options); + File.WriteAllText(agentFile, json); + } + private void UpdateAgentAllFields(Agent inputAgent) { var (agent, agentFile) = GetAgentFromFile(inputAgent.Id); @@ -298,6 +312,7 @@ namespace BotSharp.Core.Repository agent.Utilities = inputAgent.Utilities; agent.RoutingRules = inputAgent.RoutingRules; agent.LlmConfig = inputAgent.LlmConfig; + agent.MaxMessageCount = inputAgent.MaxMessageCount; agent.UpdatedDateTime = DateTime.UtcNow; var json = JsonSerializer.Serialize(agent, _options); File.WriteAllText(agentFile, json); @@ -329,7 +344,7 @@ namespace BotSharp.Core.Repository return responses; } - public Agent? GetAgent(string agentId) + public Agent? GetAgent(string agentId, bool basicsOnly = false) { var agentDir = Path.Combine(_dbSettings.FileRepository, _agentSettings.DataDir); var dir = Directory.GetDirectories(agentDir).FirstOrDefault(x => x.Split(Path.DirectorySeparatorChar).Last() == agentId); @@ -342,6 +357,8 @@ namespace BotSharp.Core.Repository var record = JsonSerializer.Deserialize(json, _options); if (record == null) return null; + if (basicsOnly) return record; + var (defaultInstruction, channelInstructions) = FetchInstructions(dir); var functions = FetchFunctions(dir); var samples = FetchSamples(dir); diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs index 32b3fdce..44c257df 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentCreationModel.cs @@ -51,6 +51,8 @@ public class AgentCreationModel public bool MergeUtility { get; set; } + public int? MaxMessageCount { get; set; } + public List Utilities { get; set; } = new(); public List RoutingRules { get; set; } = new(); public AgentLlmConfig? LlmConfig { get; set; } @@ -72,6 +74,7 @@ public class AgentCreationModel Type = Type, Disabled = Disabled, MergeUtility = MergeUtility, + MaxMessageCount = MaxMessageCount, Profiles = Profiles, RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List(), LlmConfig = LlmConfig diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs index 30308c9f..141f0662 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentUpdateModel.cs @@ -57,6 +57,9 @@ public class AgentUpdateModel public bool Disabled { get; set; } + [JsonPropertyName("max_message_count")] + public int? MaxMessageCount { get; set; } + /// /// Profile by channel /// @@ -77,6 +80,7 @@ public class AgentUpdateModel IsPublic = IsPublic, Disabled = Disabled, MergeUtility = MergeUtility, + MaxMessageCount = MaxMessageCount, Type = Type, Profiles = Profiles ?? new List(), RoutingRules = RoutingRules?.Select(x => RoutingRuleUpdateModel.ToDomainElement(x))?.ToList() ?? new List(), diff --git a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs index 34b1bcc1..36a8900f 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/ViewModels/Agents/AgentViewModel.cs @@ -46,6 +46,10 @@ public class AgentViewModel [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public AgentLlmConfig? LlmConfig { get; set; } + [JsonPropertyName("max_message_count")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? MaxMessageCount { get; set; } + public PluginDef Plugin { get; set; } public IEnumerable? Actions { get; set; } @@ -75,6 +79,7 @@ public class AgentViewModel Disabled = agent.Disabled, MergeUtility = agent.MergeUtility, IconUrl = agent.IconUrl, + MaxMessageCount = agent.MaxMessageCount, Profiles = agent.Profiles ?? new List(), RoutingRules = agent.RoutingRules, LlmConfig = agent.LlmConfig, diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs index 76fee1b3..3a775025 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/AgentDocument.cs @@ -11,6 +11,7 @@ public class AgentDocument : MongoBase public bool IsPublic { get; set; } public bool Disabled { get; set; } public bool MergeUtility { get; set; } + public int? MaxMessageCount { get; set; } public List ChannelInstructions { get; set; } public List Templates { get; set; } public List Functions { get; set; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs index 7f216b6d..9bd72e3e 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Agent.cs @@ -9,7 +9,7 @@ public partial class MongoRepository { public void UpdateAgent(Agent agent, AgentField field) { - if (agent == null || string.IsNullOrEmpty(agent.Id)) return; + if (agent == null || string.IsNullOrWhiteSpace(agent.Id)) return; switch (field) { @@ -58,6 +58,9 @@ public partial class MongoRepository case AgentField.Utility: UpdateAgentUtilities(agent.Id, agent.MergeUtility, agent.Utilities); break; + case AgentField.MaxMessageCount: + UpdateAgentMaxMessageCount(agent.Id, agent.MaxMessageCount); + break; case AgentField.All: UpdateAgentAllFields(agent); break; @@ -158,10 +161,8 @@ public partial class MongoRepository private void UpdateAgentInstructions(string agentId, string instruction, List? channelInstructions) { - if (string.IsNullOrWhiteSpace(agentId)) return; - var instructionElements = channelInstructions?.Select(x => ChannelInstructionMongoElement.ToMongoElement(x))? - .ToList() ?? new List(); + .ToList() ?? []; var filter = Builders.Filter.Eq(x => x.Id, agentId); var update = Builders.Update @@ -200,7 +201,7 @@ public partial class MongoRepository private void UpdateAgentResponses(string agentId, List responses) { - if (responses == null) return; + if (responses == null || string.IsNullOrWhiteSpace(agentId)) return; var responsesToUpdate = responses.Select(r => AgentResponseMongoElement.ToMongoElement(r)).ToList(); var filter = Builders.Filter.Eq(x => x.Id, agentId); @@ -249,6 +250,16 @@ public partial class MongoRepository _dc.Agents.UpdateOne(filter, update); } + private void UpdateAgentMaxMessageCount(string agentId, int? maxMessageCount) + { + var filter = Builders.Filter.Eq(x => x.Id, agentId); + var update = Builders.Update + .Set(x => x.MaxMessageCount, maxMessageCount) + .Set(x => x.UpdatedTime, DateTime.UtcNow); + + _dc.Agents.UpdateOne(filter, update); + } + private void UpdateAgentAllFields(Agent agent) { var filter = Builders.Filter.Eq(x => x.Id, agent.Id); @@ -258,6 +269,7 @@ public partial class MongoRepository .Set(x => x.Disabled, agent.Disabled) .Set(x => x.MergeUtility, agent.MergeUtility) .Set(x => x.Type, agent.Type) + .Set(x => x.MaxMessageCount, agent.MaxMessageCount) .Set(x => x.Profiles, agent.Profiles) .Set(x => x.RoutingRules, agent.RoutingRules.Select(r => RoutingRuleMongoElement.ToMongoElement(r)).ToList()) .Set(x => x.Instruction, agent.Instruction) @@ -277,7 +289,7 @@ public partial class MongoRepository #endregion - public Agent? GetAgent(string agentId) + public Agent? GetAgent(string agentId, bool basicsOnly = false) { var agent = _dc.Agents.AsQueryable().FirstOrDefault(x => x.Id == agentId); if (agent == null) return null; @@ -420,6 +432,7 @@ public partial class MongoRepository InheritAgentId = x.InheritAgentId, Disabled = x.Disabled, MergeUtility = x.MergeUtility, + MaxMessageCount = x.MaxMessageCount, Profiles = x.Profiles, RoutingRules = x.RoutingRules?.Select(r => RoutingRuleMongoElement.ToMongoElement(r))?.ToList() ?? [], LlmConfig = AgentLlmConfigMongoElement.ToMongoElement(x.LlmConfig), @@ -513,6 +526,7 @@ public partial class MongoRepository Type = agentDoc.Type, InheritAgentId = agentDoc.InheritAgentId, Profiles = agentDoc.Profiles, + MaxMessageCount = agentDoc.MaxMessageCount }; } } From b2334decff0c714bfdb9c1a97a69e72a8a529a1c Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Sat, 14 Dec 2024 08:35:37 -0800 Subject: [PATCH 11/15] tried to fix the unit tests --- tests/UnitTest/MainTest.cs | 49 ++++++++++++++++++++++++++++------ tests/UnitTest/UnitTest.csproj | 2 -- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/tests/UnitTest/MainTest.cs b/tests/UnitTest/MainTest.cs index 2e4c29bf..4d2698d5 100644 --- a/tests/UnitTest/MainTest.cs +++ b/tests/UnitTest/MainTest.cs @@ -1,7 +1,5 @@ using Microsoft.Extensions.DependencyInjection; using BotSharp.Abstraction.Conversations; -using BotSharp.Core.Evaluations; -using BotSharp.Plugin.ChatHub.Hooks; namespace UnitTest { @@ -13,18 +11,53 @@ namespace UnitTest { var services = new ServiceCollection(); - services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); var serviceProvider = services.BuildServiceProvider(); var conversationHookProvider = serviceProvider.GetService(); - + Assert.AreEqual(3, conversationHookProvider.Hooks.Count()); - // ChatHubConversationHook has the top priority - Assert.IsInstanceOfType(conversationHookProvider.HooksOrderByPriority.FirstOrDefault()); + var prevHook = default(IConversationHook); + + // Assert priority + foreach (var hook in conversationHookProvider.HooksOrderByPriority) + { + if (prevHook != null) + { + Assert.IsTrue(prevHook.Priority < hook.Priority); + } + + prevHook = hook; + } + } + + class TestHookA : ConversationHookBase + { + public TestHookA() + { + Priority = 1; + } + } + + class TestHookB : ConversationHookBase + { + public TestHookA() + { + Priority = 2; + } + } + + class TestHookC : ConversationHookBase + { + public TestHookA() + { + Priority = 3; + } } } } \ No newline at end of file diff --git a/tests/UnitTest/UnitTest.csproj b/tests/UnitTest/UnitTest.csproj index 3e1831ae..67e7d504 100644 --- a/tests/UnitTest/UnitTest.csproj +++ b/tests/UnitTest/UnitTest.csproj @@ -22,7 +22,5 @@ - - From 4fde52456a18a9c12b503f3ff0073ac9577eaba2 Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Sat, 14 Dec 2024 08:35:45 -0800 Subject: [PATCH 12/15] removed unused code --- .../Services/ConversationService.SendMessage.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index bdf43c8a..f60d32cf 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs @@ -171,18 +171,4 @@ public partial class ConversationService // Add to dialog history _storage.Append(_conversationId, response); } - - private List ReOrderConversationHooks(List hooks) - { - var target = "ChatHubConversationHook"; - var chathub = hooks.FirstOrDefault(x => x.GetType().Name == target); - var otherHooks = hooks.Where(x => x.GetType().Name != target).ToList(); - - if (chathub != null) - { - var newHooks = new List { chathub }.Concat(otherHooks); - return newHooks.ToList(); - } - return hooks; - } } From 7089f8f39fcb0c7dcdcf5e6aa803c69b66157906 Mon Sep 17 00:00:00 2001 From: Kerry Jiang Date: Sat, 14 Dec 2024 09:25:19 -0800 Subject: [PATCH 13/15] tried to fix the unit tests --- tests/UnitTest/MainTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/UnitTest/MainTest.cs b/tests/UnitTest/MainTest.cs index 4d2698d5..307855e4 100644 --- a/tests/UnitTest/MainTest.cs +++ b/tests/UnitTest/MainTest.cs @@ -46,7 +46,7 @@ namespace UnitTest class TestHookB : ConversationHookBase { - public TestHookA() + public TestHookB() { Priority = 2; } @@ -54,7 +54,7 @@ namespace UnitTest class TestHookC : ConversationHookBase { - public TestHookA() + public TestHookC() { Priority = 3; } From 387bbe98c61e6826cc59f05460498b957ccb9b6a Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 16 Dec 2024 10:17:50 -0600 Subject: [PATCH 14/15] add count in cron tab --- .../BotSharp.Abstraction/Crontab/Models/CrontabItem.cs | 9 +++++++++ .../Collections/CrontabItemDocument.cs | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs index a8acdc79..6a9dd43a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Crontab/Models/CrontabItem.cs @@ -14,6 +14,15 @@ public class CrontabItem : ScheduleTaskArgs [JsonPropertyName("execution_result")] public string ExecutionResult { get; set; } = null!; + [JsonPropertyName("execution_count")] + public int ExecutionCount { get; set; } + + [JsonPropertyName("max_execution_count")] + public int MaxExecutionCount { get; set; } + + [JsonPropertyName("expire_seconds")] + public int ExpireSeconds { get; set; } = 60; + [JsonPropertyName("created_time")] public DateTime CreatedTime { get; set; } = DateTime.UtcNow; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs index 10e633d7..dc04d2e4 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs @@ -11,6 +11,9 @@ public class CrontabItemDocument : MongoBase public string Cron { get; set; } public string Title { get; set; } public string Description { get; set; } + public int ExecutionCount { get; set; } + public int MaxExecutionCount { get; set; } + public int ExpireSeconds { get; set; } = 60; public IEnumerable Tasks { get; set; } = []; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; @@ -25,6 +28,9 @@ public class CrontabItemDocument : MongoBase Cron = item.Cron, Title = item.Title, Description = item.Description, + ExecutionCount = item.ExecutionCount, + MaxExecutionCount = item.MaxExecutionCount, + ExpireSeconds = item.ExpireSeconds, Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToDomainElement(x))?.ToArray() ?? [], CreatedTime = item.CreatedTime }; @@ -41,6 +47,9 @@ public class CrontabItemDocument : MongoBase Cron = item.Cron, Title = item.Title, Description = item.Description, + ExecutionCount = item.ExecutionCount, + MaxExecutionCount = item.MaxExecutionCount, + ExpireSeconds = item.ExpireSeconds, Tasks = item.Tasks?.Select(x => CronTaskMongoElement.ToMongoElement(x))?.ToList() ?? [], CreatedTime = item.CreatedTime }; From 47135c8fb45086c4d6b1d584dfd67c45928376b9 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 16 Dec 2024 10:18:50 -0600 Subject: [PATCH 15/15] revert --- .../Collections/CrontabItemDocument.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs index dc04d2e4..39622d4c 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs @@ -13,7 +13,7 @@ public class CrontabItemDocument : MongoBase public string Description { get; set; } public int ExecutionCount { get; set; } public int MaxExecutionCount { get; set; } - public int ExpireSeconds { get; set; } = 60; + public int ExpireSeconds { get; set; } public IEnumerable Tasks { get; set; } = []; public DateTime CreatedTime { get; set; } = DateTime.UtcNow;