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/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.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.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/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/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..4391f970 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); @@ -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/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.LoadAgent.cs b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs index 396a7d15..0e9c2e3c 100644 --- a/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs +++ b/src/Infrastructure/BotSharp.Core/Agents/Services/AgentService.LoadAgent.cs @@ -5,7 +5,7 @@ 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) @@ -106,14 +106,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(); } 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.SendMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.SendMessage.cs index 375cf3e6..f60d32cf 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); @@ -173,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; - } } 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..7e498afe 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(); @@ -103,7 +111,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 @@ -153,7 +162,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 +204,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/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.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index d2c519eb..719f3177 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) @@ -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.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.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.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/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/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/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/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.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(); 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) diff --git a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs index f2e79b21..e2c4f8c2 100644 --- a/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs +++ b/src/Plugins/BotSharp.Plugin.FileHandler/Functions/ReadImageFn.cs @@ -23,8 +23,9 @@ 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 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(), @@ -38,7 +39,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 +67,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" ] 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/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/Collections/CrontabItemDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/CrontabItemDocument.cs index 10e633d7..39622d4c 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; } 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 }; 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 }; } } 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)); 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(); diff --git a/tests/UnitTest/MainTest.cs b/tests/UnitTest/MainTest.cs new file mode 100644 index 00000000..307855e4 --- /dev/null +++ b/tests/UnitTest/MainTest.cs @@ -0,0 +1,63 @@ +using Microsoft.Extensions.DependencyInjection; +using BotSharp.Abstraction.Conversations; + +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()); + + 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 TestHookB() + { + Priority = 2; + } + } + + class TestHookC : ConversationHookBase + { + public TestHookC() + { + Priority = 3; + } + } + } +} \ No newline at end of file diff --git a/tests/UnitTest/UnitTest.csproj b/tests/UnitTest/UnitTest.csproj index be924573..67e7d504 100644 --- a/tests/UnitTest/UnitTest.csproj +++ b/tests/UnitTest/UnitTest.csproj @@ -13,10 +13,14 @@ + + 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