diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs index 884ba9c0d..0fb164c6c 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationService.cs @@ -35,6 +35,12 @@ Task SendMessage(string agentId, Func onFunctionExecuting, Func onFunctionExecuted); - List GetDialogHistory(int lastCount = 50); + List GetDialogHistory(int lastCount = 50, bool fromBreakpoint = true); Task CleanHistory(string agentId); + + /// + /// Use this feature when you want to hide some context from LLM. + /// + /// + Task UpdateBreakpoint(); } diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs index 45dbc2280..cf5e3fd34 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Conversations/Models/Conversation.cs @@ -26,6 +26,12 @@ public class Conversation public DateTime UpdatedTime { get; set; } = DateTime.UtcNow; public DateTime CreatedTime { get; set; } = DateTime.UtcNow; + + /// + /// The default value will be same as CreatedTime + /// It used to insert a breakpoint in the conversation to hide the previous dialogs. + /// + public DateTime Breakpoint { get; set; } = DateTime.UtcNow.AddMilliseconds(-100); } public class DialogElement diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index fdefb0699..174388e87 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -58,6 +58,7 @@ public interface IBotSharpRepository Conversation GetConversation(string conversationId); PagedItems GetConversations(ConversationFilter filter); void UpdateConversationTitle(string conversationId, string title); + void UpdateConversationBreakpoint(string conversationId, DateTime breakpoint); List GetLastConversations(); List GetIdleConversations(int batchSize, int messageLimit, int bufferHours); bool TruncateConversation(string conversationId, string messageId, bool cleanLog = false); diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs index 8c82eb1f4..e4b81f31b 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.TruncateMessage.cs @@ -1,5 +1,3 @@ -using BotSharp.Abstraction.Repositories; - namespace BotSharp.Core.Conversations.Services; public partial class ConversationService : IConversationService diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs new file mode 100644 index 000000000..b4a4671cc --- /dev/null +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs @@ -0,0 +1,10 @@ +namespace BotSharp.Core.Conversations.Services; + +public partial class ConversationService : IConversationService +{ + public async Task UpdateBreakpoint() + { + var db = _services.GetRequiredService(); + db.UpdateConversationBreakpoint(_conversationId, DateTime.UtcNow); + } +} diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index afc264444..82096f70a 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -99,7 +99,7 @@ public Task CleanHistory(string agentId) throw new NotImplementedException(); } - public List GetDialogHistory(int lastCount = 50) + public List GetDialogHistory(int lastCount = 50, bool fromBreakpoint = true) { if (string.IsNullOrEmpty(_conversationId)) { @@ -107,6 +107,14 @@ public List GetDialogHistory(int lastCount = 50) } var dialogs = _storage.GetDialogs(_conversationId); + + if (fromBreakpoint) + { + var db = _services.GetRequiredService(); + var conversation = db.GetConversation(_conversationId); + dialogs = dialogs.Where(x => x.CreatedAt >= conversation.Breakpoint).ToList(); + } + return dialogs .TakeLast(lastCount) .ToList(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 6fa7fdc16..6316c3d09 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -157,74 +157,51 @@ public bool DeleteAgentTasks() #region Conversation public void CreateNewConversation(Conversation conversation) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public bool DeleteConversations(IEnumerable conversationIds) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public Conversation GetConversation(string conversationId) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public PagedItems GetConversations(ConversationFilter filter) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public List GetLastConversations() - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public List GetIdleConversations(int batchSize, int messageLimit, int bufferHours) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public List GetConversationDialogs(string conversationId) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public void UpdateConversationDialogElements(string conversationId, List updateElements) - { - throw new NotImplementedException(); - } + => new NotImplementedException(); public ConversationState GetConversationStates(string conversationId) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); public void AppendConversationDialogs(string conversationId, List dialogs) - { - throw new NotImplementedException(); - } + => new NotImplementedException(); + public void UpdateConversationTitle(string conversationId, string title) - { - throw new NotImplementedException(); - } + => new NotImplementedException(); + + public void UpdateConversationBreakpoint(string conversationId, DateTime breakpoint) + => new NotImplementedException(); + public void UpdateConversationStates(string conversationId, List states) - { - throw new NotImplementedException(); - } + => new NotImplementedException(); public void UpdateConversationStatus(string conversationId, string status) - { - throw new NotImplementedException(); - } + => new NotImplementedException(); public bool TruncateConversation(string conversationId, string messageId, bool cleanLog = false) - { - throw new NotImplementedException(); - } + => throw new NotImplementedException(); #endregion - + #region User public User? GetUserByEmail(string email) => 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 d9ea0b5c0..2f054e9df 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs @@ -141,6 +141,23 @@ public void UpdateConversationTitle(string conversationId, string title) } } + public void UpdateConversationBreakpoint(string conversationId, DateTime breakpoint) + { + 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.UpdatedTime = DateTime.UtcNow; + record.Breakpoint = breakpoint; + File.WriteAllText(convFile, JsonSerializer.Serialize(record, _options)); + } + } + } + public ConversationState GetConversationStates(string conversationId) { var states = new List(); diff --git a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs index 2e2d3eac1..6e856b9f6 100644 --- a/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs +++ b/src/Infrastructure/BotSharp.Core/Users/Services/UserService.cs @@ -146,10 +146,10 @@ private string GenerateJwtToken(User user) new Claim(JwtRegisteredClaimNames.NameId, user.Id), new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName), new Claim(JwtRegisteredClaimNames.Email, user.Email), - new Claim(JwtRegisteredClaimNames.GivenName, user.FirstName), - new Claim(JwtRegisteredClaimNames.FamilyName, user.LastName), + new Claim(JwtRegisteredClaimNames.GivenName, user?.FirstName ?? string.Empty), + new Claim(JwtRegisteredClaimNames.FamilyName, user?.LastName ?? string.Empty), new Claim("source", user.Source), - new Claim("external_id", user.ExternalId??string.Empty), + new Claim("external_id", user.ExternalId ?? string.Empty), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; diff --git a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid index 80aba1b97..6f61802f2 100644 --- a/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid +++ b/src/Infrastructure/BotSharp.Core/data/agents/01fcc3e5-9af7-49e6-ad7a-a760bd12dc4a/templates/planner_prompt.naive.liquid @@ -1,5 +1,5 @@ What is the next step based on the CONVERSATION? -Route to the appropriate agent last handled agent based on the context. +Route to the last handling agent in priority. {% if expected_next_action_agent != empty -%} Expected next action agent is {{ expected_next_action_agent }}. {%- endif %} diff --git a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs index 8ef208aff..3aae318a4 100644 --- a/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs +++ b/src/Infrastructure/BotSharp.OpenAPI/Controllers/ConversationController.cs @@ -66,7 +66,7 @@ public async Task> GetDialogs([FromRoute] string { var conv = _services.GetRequiredService(); conv.SetConversationId(conversationId, new List()); - var history = conv.GetDialogHistory(); + var history = conv.GetDialogHistory(fromBreakpoint: false); var userService = _services.GetRequiredService(); var agentService = _services.GetRequiredService(); diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs index b14ca62fc..46db2ae56 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Collections/ConversationDocument.cs @@ -10,4 +10,5 @@ public class ConversationDocument : MongoBase public string Status { get; set; } public DateTime CreatedTime { get; set; } public DateTime UpdatedTime { get; set; } + public DateTime Breakpoint { 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 3ff1b9253..824998e53 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs @@ -22,8 +22,9 @@ public void CreateNewConversation(Conversation conversation) Channel = conversation.Channel, TaskId = conversation.TaskId, Status = conversation.Status, - CreatedTime = DateTime.UtcNow, - UpdatedTime = DateTime.UtcNow, + CreatedTime = conversation.CreatedTime, + UpdatedTime = conversation.UpdatedTime, + Breakpoint = conversation.Breakpoint, }; var dialogDoc = new ConversationDialogDocument @@ -140,6 +141,18 @@ public void UpdateConversationTitle(string conversationId, string title) _dc.Conversations.UpdateOne(filterConv, updateConv); } + public void UpdateConversationBreakpoint(string conversationId, DateTime breakpoint) + { + 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.Breakpoint, breakpoint); + + _dc.Conversations.UpdateOne(filterConv, updateConv); + } + public ConversationState GetConversationStates(string conversationId) { var states = new ConversationState(); @@ -208,7 +221,8 @@ public Conversation GetConversation(string conversationId) Dialogs = dialogElements, States = curStates, CreatedTime = conv.CreatedTime, - UpdatedTime = conv.UpdatedTime + UpdatedTime = conv.UpdatedTime, + Breakpoint = conv.Breakpoint }; } @@ -273,7 +287,8 @@ public PagedItems GetConversations(ConversationFilter filter) Channel = conv.Channel, Status = conv.Status, CreatedTime = conv.CreatedTime, - UpdatedTime = conv.UpdatedTime + UpdatedTime = conv.UpdatedTime, + Breakpoint = conv.Breakpoint }); } @@ -299,7 +314,8 @@ public List GetLastConversations() Channel = c.Channel, Status = c.Status, CreatedTime = c.CreatedTime, - UpdatedTime = c.UpdatedTime + UpdatedTime = c.UpdatedTime, + Breakpoint = c.Breakpoint }).ToList(); }