diff --git a/src/Infrastructure/BotSharp.Abstraction/Models/MessageState.cs b/src/Infrastructure/BotSharp.Abstraction/Models/MessageState.cs index a87098105..074be848a 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Models/MessageState.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Models/MessageState.cs @@ -8,20 +8,24 @@ public class MessageState [JsonPropertyName("active_rounds")] public int ActiveRounds { get; set; } = -1; + [JsonPropertyName("global")] + public bool Global { get; set; } + public MessageState() { } - public MessageState(string key, object value, int activeRounds = -1) + public MessageState(string key, object value, int activeRounds = -1, bool isGlobal = false) { Key = key; Value = value; ActiveRounds = activeRounds; + Global = isGlobal; } public override string ToString() { - return $"Key: {Key} => Value: {Value}, ActiveRounds: {ActiveRounds}"; + return $"Key: {Key} => Value: {Value}, ActiveRounds: {ActiveRounds}, Global: {Global}"; } } diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 6eaeb1674..676ea362d 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -178,7 +178,7 @@ public void SetConversationId(string conversationId, List states, { _conversationId = conversationId; _state.Load(_conversationId, isReadOnly); - states.ForEach(x => _state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, source: StateSource.External)); + states.ForEach(x => _state.SetState(x.Key, x.Value, activeRounds: x.ActiveRounds, isNeedVersion: !x.Global, source: StateSource.External)); } public async Task GetConversationRecordOrCreateNew(string agentId) diff --git a/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs b/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs index 4752f6d61..02cafbd08 100644 --- a/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs +++ b/src/Infrastructure/BotSharp.Logger/Hooks/RateLimitConversationHook.cs @@ -1,9 +1,6 @@ using BotSharp.Abstraction.Agents.Enums; using BotSharp.Abstraction.Conversations.Enums; using BotSharp.Abstraction.Repositories.Filters; -using BotSharp.Abstraction.Statistics.Enums; -using BotSharp.Abstraction.Statistics.Models; -using BotSharp.Abstraction.Statistics.Services; using BotSharp.Abstraction.Users; namespace BotSharp.Logger.Hooks; diff --git a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs index de58dca60..b5dbfb2e5 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/Controllers/TwilioInboundController.cs @@ -166,16 +166,16 @@ protected Dictionary ParseStates(List states) var states = new List { - new("channel", ConversationChannel.Phone), - new("calling_phone", request.From), - new("phone_direction", request.Direction), - new("twilio_call_sid", request.CallSid), + new("channel", ConversationChannel.Phone, isGlobal: true), + new("calling_phone", request.From, isGlobal: true), + new("phone_direction", request.Direction, isGlobal: true), + new("twilio_call_sid", request.CallSid, isGlobal: true), }; if (request.Direction == "inbound") { - states.Add(new MessageState("calling_phone_from", request.From)); - states.Add(new MessageState("calling_phone_to", request.To)); + states.Add(new MessageState("calling_phone_from", request.From, isGlobal: true)); + states.Add(new MessageState("calling_phone_to", request.To, isGlobal: true)); } var requestStates = ParseStates(request.States); diff --git a/src/Plugins/BotSharp.Plugin.Twilio/OutboundPhoneCallHandler/Functions/OutboundPhoneCallFn.cs b/src/Plugins/BotSharp.Plugin.Twilio/OutboundPhoneCallHandler/Functions/OutboundPhoneCallFn.cs index 8d34dd22b..3c5532bdb 100644 --- a/src/Plugins/BotSharp.Plugin.Twilio/OutboundPhoneCallHandler/Functions/OutboundPhoneCallFn.cs +++ b/src/Plugins/BotSharp.Plugin.Twilio/OutboundPhoneCallHandler/Functions/OutboundPhoneCallFn.cs @@ -9,6 +9,7 @@ using BotSharp.Plugin.Twilio.Models; using BotSharp.Plugin.Twilio.OutboundPhoneCallHandler.LlmContexts; using Twilio.Rest.Api.V2010.Account; +using Twilio.TwiML.Messaging; using Twilio.Types; using Conversation = BotSharp.Abstraction.Conversations.Models.Conversation; using Task = System.Threading.Tasks.Task; @@ -176,7 +177,7 @@ private async Task ForkConversation( }); var utcNow = DateTime.UtcNow; - var excludStates = new List + var excludeStates = new List { "provider", "model", @@ -185,22 +186,34 @@ private async Task ForkConversation( "llm_total_cost" }; - var curStates = state.GetStates().Select(x => new MessageState(x.Key, x.Value)).ToList(); + var curConvStates = state.GetStates().Select(x => new MessageState(x.Key, x.Value)).ToList(); var subConvStates = new List { - new(StateConst.ORIGIN_CONVERSATION_ID, originConversationId), - new("channel", "phone"), - new("phone_from", call.From), - new("phone_direction", call.Direction), - new("phone_number", call.To), - new("twilio_call_sid", call.Sid) + new(StateConst.ORIGIN_CONVERSATION_ID, originConversationId, isGlobal: true), + new("channel", "phone", isGlobal: true), + new("phone_from", call.From, isGlobal: true), + new("phone_direction", call.Direction, isGlobal: true), + new("phone_number", call.To, isGlobal: true), + new("twilio_call_sid", call.Sid, isGlobal: true) }; var subStateKeys = subConvStates.Select(x => x.Key).ToList(); - var included = curStates.Where(x => !subStateKeys.Contains(x.Key) && !excludStates.Contains(x.Key)); - var newStates = subConvStates.Concat(included).Select(x => new StateKeyValue + var included = curConvStates.Where(x => !subStateKeys.Contains(x.Key) && !excludeStates.Contains(x.Key)); + + var mappedCurConvStates = MapStates(included, messageId, utcNow); + var mappedSubConvStates = MapStates(subConvStates, messageId, utcNow); + var allStates = mappedCurConvStates.Concat(mappedSubConvStates).ToList(); + + db.UpdateConversationStates(newConversationId, allStates); + } + + private IEnumerable MapStates(IEnumerable states, string messageId, DateTime updateTime) + { + if (states.IsNullOrEmpty()) return []; + + return states.Select(x => new StateKeyValue { Key = x.Key, - Versioning = true, + Versioning = !x.Global, Values = [ new StateValue { @@ -209,11 +222,9 @@ private async Task ForkConversation( Active = true, ActiveRounds = x.ActiveRounds, Source = StateSource.Application, - UpdateTime = utcNow + UpdateTime = updateTime } ] }).ToList(); - - db.UpdateConversationStates(newConversationId, newStates); } }