From 43882b52bc1f4b6240c16580d7e50d15ae12d182 Mon Sep 17 00:00:00 2001 From: Jicheng Lu <103353@smsassist.com> Date: Mon, 4 Nov 2024 16:44:41 -0600 Subject: [PATCH] refine side car --- BotSharp.sln | 11 ++ .../BotSharp.Abstraction.csproj | 3 +- .../Repositories/IBotSharpRepository.cs | 3 +- .../Shared/IHaveServiceProvider.cs | 6 + .../SideCar/Attributes/SideCarAspect.cs | 168 ++++++++++++++++++ .../SideCar/Attributes/SideCarAttribute.cs | 13 ++ .../IConversationSideCar.cs | 6 +- .../BotSharp.Core.SideCar.csproj | 16 ++ .../BotSharpSideCarPlugin.cs | 28 +++ .../Services/BotSharpConversationSideCar.cs} | 69 +++---- .../Settings/SideCarSettings.cs | 11 ++ .../BotSharp.Core.SideCar/Using.cs | 20 +++ .../Conversations/ConversationPlugin.cs | 1 - .../ConversationService.UpdateBreakpoint.cs | 10 +- .../Services/ConversationService.cs | 7 +- .../Services/ConversationStorage.cs | 14 +- .../Repository/BotSharpDbContext.cs | 6 + .../FileRepository.Conversation.cs | 4 + .../FileRepository/FileRepository.cs | 2 + src/Infrastructure/BotSharp.Core/Using.cs | 1 + .../Hooks/ChatHubConversationHook.cs | 1 + .../MongoRepository.Conversation.cs | 4 + .../Repository/MongoRepository.cs | 2 + .../BotSharp.Plugin.MongoStorage/Using.cs | 1 + src/WebStarter/WebStarter.csproj | 1 + src/WebStarter/appsettings.json | 7 + 26 files changed, 341 insertions(+), 74 deletions(-) create mode 100644 src/Infrastructure/BotSharp.Abstraction/Shared/IHaveServiceProvider.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAspect.cs create mode 100644 src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAttribute.cs rename src/Infrastructure/BotSharp.Abstraction/{Conversations => SideCar}/IConversationSideCar.cs (65%) create mode 100644 src/Infrastructure/BotSharp.Core.SideCar/BotSharp.Core.SideCar.csproj create mode 100644 src/Infrastructure/BotSharp.Core.SideCar/BotSharpSideCarPlugin.cs rename src/Infrastructure/{BotSharp.Core/Conversations/Services/ConversationSideCar.cs => BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs} (69%) create mode 100644 src/Infrastructure/BotSharp.Core.SideCar/Settings/SideCarSettings.cs create mode 100644 src/Infrastructure/BotSharp.Core.SideCar/Using.cs diff --git a/BotSharp.sln b/BotSharp.sln index a1c1ddb9..93f289ba 100644 --- a/BotSharp.sln +++ b/BotSharp.sln @@ -117,6 +117,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.Graph", "sr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BotSharp.Plugin.AudioHandler", "src\Plugins\BotSharp.Plugin.AudioHandler\BotSharp.Plugin.AudioHandler.csproj", "{F57F4862-F8D4-44A1-AC12-5C131B5C9785}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BotSharp.Core.SideCar", "src\Infrastructure\BotSharp.Core.SideCar\BotSharp.Core.SideCar.csproj", "{6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -469,6 +471,14 @@ Global {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|Any CPU.Build.0 = Release|Any CPU {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.ActiveCfg = Release|Any CPU {F57F4862-F8D4-44A1-AC12-5C131B5C9785}.Release|x64.Build.0 = Release|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x64.ActiveCfg = Debug|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Debug|x64.Build.0 = Debug|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|Any CPU.Build.0 = Release|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x64.ActiveCfg = Release|Any CPU + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -525,6 +535,7 @@ Global {97A0B191-64D7-4F8A-BFE8-1BFCC5E247E1} = {2635EC9B-2E5F-4313-AC21-0B847F31F36C} {EBFE97DA-D0BA-48BA-8B5D-083B60348D1D} = {97A0B191-64D7-4F8A-BFE8-1BFCC5E247E1} {F57F4862-F8D4-44A1-AC12-5C131B5C9785} = {51AFE054-AE99-497D-A593-69BAEFB5106F} + {6D3A54F9-4792-41DB-BE7D-4F7B1D918EAE} = {E29DC6C4-5E57-48C5-BCB0-6B8F84782749} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {A9969D89-C98B-40A5-A12B-FC87E55B3A19} diff --git a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj index 474dcf56..5be126b8 100644 --- a/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj +++ b/src/Infrastructure/BotSharp.Abstraction/BotSharp.Abstraction.csproj @@ -1,4 +1,4 @@ - + $(TargetFramework) @@ -38,6 +38,7 @@ + diff --git a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs index 4f604dc4..57900aa0 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs +++ b/src/Infrastructure/BotSharp.Abstraction/Repositories/IBotSharpRepository.cs @@ -1,6 +1,7 @@ using BotSharp.Abstraction.Loggers.Models; using BotSharp.Abstraction.Plugins.Models; using BotSharp.Abstraction.Repositories.Filters; +using BotSharp.Abstraction.Shared; using BotSharp.Abstraction.Tasks.Models; using BotSharp.Abstraction.Translation.Models; using BotSharp.Abstraction.Users.Models; @@ -8,7 +9,7 @@ using BotSharp.Abstraction.VectorStorage.Models; namespace BotSharp.Abstraction.Repositories; -public interface IBotSharpRepository +public interface IBotSharpRepository : IHaveServiceProvider { #region Plugin PluginConfig GetPluginConfig(); diff --git a/src/Infrastructure/BotSharp.Abstraction/Shared/IHaveServiceProvider.cs b/src/Infrastructure/BotSharp.Abstraction/Shared/IHaveServiceProvider.cs new file mode 100644 index 00000000..0a68cadd --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/Shared/IHaveServiceProvider.cs @@ -0,0 +1,6 @@ +namespace BotSharp.Abstraction.Shared; + +public interface IHaveServiceProvider +{ + IServiceProvider ServiceProvider { get; } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAspect.cs b/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAspect.cs new file mode 100644 index 00000000..6580c56c --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAspect.cs @@ -0,0 +1,168 @@ +using AspectInjector.Broker; +using BotSharp.Abstraction.Shared; +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; + +namespace BotSharp.Abstraction.SideCar.Attributes; + +[Aspect(Scope.PerInstance)] +public class SideCarAspect +{ + [Advice(Kind.Around)] + public object Handle( + [Argument(Source.Target)] Func target, + [Argument(Source.Arguments)] object[] args, + [Argument(Source.Instance)] object instance, + [Argument(Source.ReturnType)] Type retType, + [Argument(Source.Name)] string name, + [Argument(Source.Metadata)] MethodBase metaData, + [Argument(Source.Triggers)] Attribute[] triggers) + { + object value; + var serviceProvider = ((IHaveServiceProvider)instance).ServiceProvider; + + if (typeof(Task).IsAssignableFrom(retType)) + { + var syncResultType = retType.IsConstructedGenericType ? retType.GenericTypeArguments[0] : typeof(void); + value = CallAsyncMethod(serviceProvider, syncResultType, name, target, args); + } + else + { + value = CallSyncMethod(serviceProvider, retType, name, target, args); + } + + return value; + } + + + private static MethodInfo GetMethod(string name) + { + return typeof(SideCarAspect).GetMethod(name, BindingFlags.NonPublic | BindingFlags.Static); + } + + private object CallAsyncMethod(IServiceProvider serviceProvider, Type retType, string methodName, Func target, object[] args) + { + var sidecar = serviceProvider.GetService(); + var sidecarMethod = sidecar?.GetType()?.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance); + + object value; + var enabled = sidecar != null && sidecar.IsEnabled() && sidecarMethod != null; + + if (retType == typeof(void)) + { + if (enabled) + { + + value = GetMethod(nameof(CallAsync)).Invoke(this, [sidecar, sidecarMethod, args]); + } + else + { + value = GetMethod(nameof(WrapAsync)).Invoke(this, [target, args]); + } + } + else + { + if (enabled) + { + value = GetMethod(nameof(CallGenericAsync)).MakeGenericMethod(retType).Invoke(this, [sidecar, sidecarMethod, args]); + } + else + { + value = GetMethod(nameof(WrapGenericAsync)).MakeGenericMethod(retType).Invoke(this, [target, args]); + } + } + + return value; + } + + private object CallSyncMethod(IServiceProvider serviceProvider, Type retType, string methodName, Func target, object[] args) + { + var sidecar = serviceProvider.GetService(); + var sidecarMethod = sidecar?.GetType()?.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance); + + object value; + var enabled = sidecar != null && sidecarMethod != null && sidecar.IsEnabled(); + + if (retType == typeof(void)) + { + if (enabled) + { + value = GetMethod(nameof(CallSync)).Invoke(this, [sidecar, sidecarMethod, args]); + } + else + { + value = GetMethod(nameof(WrapSync)).Invoke(this, [target, args]); + } + } + else + { + if (enabled) + { + value = GetMethod(nameof(CallGenericSync)).MakeGenericMethod(retType).Invoke(this, [sidecar, sidecarMethod, args]); + } + else + { + value = GetMethod(nameof(WrapGenericSync)).MakeGenericMethod(retType).Invoke(this, [target, args]); + } + } + + return value; + } + + + #region Call Side car method + private static async Task CallGenericAsync(object instance, MethodInfo method, object[] args) + { + var res = await (Task)method.Invoke(instance, args); + return res; + } + + private static async Task CallAsync(object instance, MethodInfo method, object[] args) + { + await (Task)method.Invoke(instance, args); + return; + } + + private static T CallGenericSync(object instance, MethodInfo method, object[] args) + { + var res = (T)method.Invoke(instance, args); + return res; + } + + private static void CallSync(object instance, MethodInfo method, object[] args) + { + method.Invoke(instance, args); + return; + } + #endregion + + + #region Call original method + private static T WrapGenericSync(Func target, object[] args) + { + T res; + res = (T)target(args); + return res; + } + + private static async Task WrapGenericAsync(Func target, object[] args) + { + T res; + res = await (Task)target(args); + return res; + } + + + private static void WrapSync(Func target, object[] args) + { + target(args); + return; + } + + private static async Task WrapAsync(Func target, object[] args) + { + await (Task)target(args); + return; + } + #endregion +} diff --git a/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAttribute.cs b/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAttribute.cs new file mode 100644 index 00000000..2c5c259f --- /dev/null +++ b/src/Infrastructure/BotSharp.Abstraction/SideCar/Attributes/SideCarAttribute.cs @@ -0,0 +1,13 @@ +using AspectInjector.Broker; + +namespace BotSharp.Abstraction.SideCar.Attributes; + +[AttributeUsage(AttributeTargets.Method, Inherited = true)] +[Injection(typeof(SideCarAspect))] +public class SideCarAttribute : Attribute +{ + public SideCarAttribute() + { + + } +} diff --git a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationSideCar.cs b/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs similarity index 65% rename from src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationSideCar.cs rename to src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs index 8dab52e1..9a1316fb 100644 --- a/src/Infrastructure/BotSharp.Abstraction/Conversations/IConversationSideCar.cs +++ b/src/Infrastructure/BotSharp.Abstraction/SideCar/IConversationSideCar.cs @@ -1,11 +1,13 @@ -namespace BotSharp.Abstraction.Conversations; +namespace BotSharp.Abstraction.SideCar; public interface IConversationSideCar { + string Provider { get; } + bool IsEnabled(); void AppendConversationDialogs(string conversationId, List messages); List GetConversationDialogs(string conversationId); void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint); ConversationBreakpoint? GetConversationBreakpoint(string conversationId); - Task Execute(string agentId, string text, PostbackMessageModel? postback = null, List? states = null); + Task SendMessage(string agentId, string text, PostbackMessageModel? postback = null, List? states = null); } diff --git a/src/Infrastructure/BotSharp.Core.SideCar/BotSharp.Core.SideCar.csproj b/src/Infrastructure/BotSharp.Core.SideCar/BotSharp.Core.SideCar.csproj new file mode 100644 index 00000000..4b661c2a --- /dev/null +++ b/src/Infrastructure/BotSharp.Core.SideCar/BotSharp.Core.SideCar.csproj @@ -0,0 +1,16 @@ + + + + $(TargetFramework) + $(LangVersion) + $(BotSharpVersion) + $(GeneratePackageOnBuild) + $(SolutionDir)packages + enable + + + + + + + diff --git a/src/Infrastructure/BotSharp.Core.SideCar/BotSharpSideCarPlugin.cs b/src/Infrastructure/BotSharp.Core.SideCar/BotSharpSideCarPlugin.cs new file mode 100644 index 00000000..efacd308 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core.SideCar/BotSharpSideCarPlugin.cs @@ -0,0 +1,28 @@ +using BotSharp.Abstraction.Plugins; +using BotSharp.Abstraction.Settings; +using BotSharp.Core.SideCar.Services; +using Microsoft.Extensions.Configuration; + +namespace BotSharp.Core.SideCar; + +public class BotSharpSideCarPlugin : IBotSharpPlugin +{ + public string Id => "06e5a276-bba0-45af-9625-889267c341c9"; + public string Name => "Side car"; + public string Description => "Provides side car for calling agent cluster in conversation"; + + public SettingsMeta Settings => new SettingsMeta("SideCar"); + public object GetNewSettingsInstance() => new SideCarSettings(); + + public void RegisterDI(IServiceCollection services, IConfiguration config) + { + var settings = new SideCarSettings(); + config.Bind("SideCar", settings); + services.AddSingleton(settings); + + if (settings.Conversation.Provider == "botsharp") + { + services.AddScoped(); + } + } +} diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationSideCar.cs b/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs similarity index 69% rename from src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationSideCar.cs rename to src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs index ae72fbdb..fda96b17 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationSideCar.cs +++ b/src/Infrastructure/BotSharp.Core.SideCar/Services/BotSharpConversationSideCar.cs @@ -1,20 +1,19 @@ -using BotSharp.Abstraction.Conversations.Enums; -using BotSharp.Abstraction.Models; +namespace BotSharp.Core.SideCar.Services; -namespace BotSharp.Core.Conversations.Services; - -public class ConversationSideCar : IConversationSideCar +public class BotSharpConversationSideCar : IConversationSideCar { private readonly IServiceProvider _services; - private readonly ILogger _logger; + private readonly ILogger _logger; private Stack contextStack = new(); private bool enabled = false; - public ConversationSideCar( + public string Provider => "botsharp"; + + public BotSharpConversationSideCar( IServiceProvider services, - ILogger logger) + ILogger logger) { _services = services; _logger = logger; @@ -27,60 +26,42 @@ public class ConversationSideCar : IConversationSideCar public void AppendConversationDialogs(string conversationId, List messages) { - if (enabled) - { - var top = contextStack.Peek(); - top.Dialogs.AddRange(messages); - } - else - { - var db = _services.GetRequiredService(); - db.AppendConversationDialogs(conversationId, messages); - } + if (contextStack.IsNullOrEmpty()) return; + + var top = contextStack.Peek(); + top.Dialogs.AddRange(messages); } public List GetConversationDialogs(string conversationId) { - if (enabled) + if (contextStack.IsNullOrEmpty()) { - return contextStack.Peek().Dialogs; - } - else - { - var db = _services.GetRequiredService(); - return db.GetConversationDialogs(conversationId); + return new List(); } + + return contextStack.Peek().Dialogs; } public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint) { - if (enabled) - { - var top = contextStack.Peek().Breakpoints; - top.Add(breakpoint); - } - else - { - var db = _services.GetRequiredService(); - db.UpdateConversationBreakpoint(conversationId, breakpoint); - } + if (contextStack.IsNullOrEmpty()) return; + + var top = contextStack.Peek().Breakpoints; + top.Add(breakpoint); } public ConversationBreakpoint? GetConversationBreakpoint(string conversationId) { - if (enabled) + if (contextStack.IsNullOrEmpty()) { - var top = contextStack.Peek().Breakpoints; - return top.LastOrDefault(); - } - else - { - var db = _services.GetRequiredService(); - return db.GetConversationBreakpoint(conversationId); + return null; } + + var top = contextStack.Peek().Breakpoints; + return top.LastOrDefault(); } - public async Task Execute(string agentId, string text, + public async Task SendMessage(string agentId, string text, PostbackMessageModel? postback = null, List? states = null) { BeforeExecute(); diff --git a/src/Infrastructure/BotSharp.Core.SideCar/Settings/SideCarSettings.cs b/src/Infrastructure/BotSharp.Core.SideCar/Settings/SideCarSettings.cs new file mode 100644 index 00000000..24b60b2a --- /dev/null +++ b/src/Infrastructure/BotSharp.Core.SideCar/Settings/SideCarSettings.cs @@ -0,0 +1,11 @@ +namespace BotSharp.Core.SideCar.Settings; + +public class SideCarSettings +{ + public BaseSetting Conversation { get; set; } +} + +public class BaseSetting +{ + public string Provider { get; set; } +} \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core.SideCar/Using.cs b/src/Infrastructure/BotSharp.Core.SideCar/Using.cs new file mode 100644 index 00000000..d047ee15 --- /dev/null +++ b/src/Infrastructure/BotSharp.Core.SideCar/Using.cs @@ -0,0 +1,20 @@ +global using System; +global using System.Collections.Generic; +global using System.Text; +global using System.Threading.Tasks; +global using System.Linq; +global using System.Text.Json; +global using System.Net.Mime; +global using System.Net.Http; +global using System.Threading; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Extensions.Logging; +global using BotSharp.Abstraction.Agents.Enums; +global using BotSharp.Abstraction.Conversations; +global using BotSharp.Abstraction.Conversations.Enums; +global using BotSharp.Abstraction.Conversations.Models; +global using BotSharp.Abstraction.Models; +global using BotSharp.Abstraction.Routing; +global using BotSharp.Abstraction.SideCar; +global using BotSharp.Abstraction.Utilities; +global using BotSharp.Core.SideCar.Settings; \ No newline at end of file diff --git a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs index 7db04623..a9be6fd2 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/ConversationPlugin.cs @@ -43,7 +43,6 @@ public class ConversationPlugin : IBotSharpPlugin services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddScoped(); services.AddScoped(); // Rich content messaging diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs index 618095e4..8f88f44f 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.UpdateBreakpoint.cs @@ -10,15 +10,7 @@ public partial class ConversationService : IConversationService var routingCtx = _services.GetRequiredService(); var messageId = routingCtx.MessageId; - //db.UpdateConversationBreakpoint(_conversationId, new ConversationBreakpoint - //{ - // MessageId = messageId, - // Breakpoint = DateTime.UtcNow, - // Reason = reason - //}); - - var sidecar = _services.GetRequiredService(); - sidecar.UpdateConversationBreakpoint(_conversationId, new ConversationBreakpoint + db.UpdateConversationBreakpoint(_conversationId, new ConversationBreakpoint { MessageId = messageId, Breakpoint = DateTime.UtcNow, diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs index 302107ab..6c856591 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationService.cs @@ -140,11 +140,8 @@ public partial class ConversationService : IConversationService if (fromBreakpoint) { - //var db = _services.GetRequiredService(); - //var breakpoint = db.GetConversationBreakpoint(_conversationId); - - var sidecar = _services.GetRequiredService(); - var breakpoint = sidecar.GetConversationBreakpoint(_conversationId); + var db = _services.GetRequiredService(); + var breakpoint = db.GetConversationBreakpoint(_conversationId); if (breakpoint != null) { diff --git a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs index 1ce112ca..ea145ac0 100644 --- a/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs +++ b/src/Infrastructure/BotSharp.Core/Conversations/Services/ConversationStorage.cs @@ -91,21 +91,13 @@ public class ConversationStorage : IConversationStorage }); } - //db.AppendConversationDialogs(conversationId, dialogElements); - - var sidecar = _services.GetRequiredService(); - sidecar.AppendConversationDialogs(conversationId, dialogElements); - + db.AppendConversationDialogs(conversationId, dialogElements); } public List GetDialogs(string conversationId) { - //var db = _services.GetRequiredService(); - //var dialogs = db.GetConversationDialogs(conversationId); - - var sidecar = _services.GetRequiredService(); - var dialogs = sidecar.GetConversationDialogs(conversationId); - + var db = _services.GetRequiredService(); + var dialogs = db.GetConversationDialogs(conversationId); var hooks = _services.GetServices(); var results = new List(); diff --git a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs index 80c37f7a..d2c519eb 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/BotSharpDbContext.cs @@ -8,6 +8,8 @@ namespace BotSharp.Core.Repository; public class BotSharpDbContext : Database, IBotSharpRepository { + public IServiceProvider ServiceProvider => throw new NotImplementedException(); + #region Plugin public PluginConfig GetPluginConfig() => throw new NotImplementedException(); public void SavePluginConfig(PluginConfig config) => throw new NotImplementedException(); @@ -90,12 +92,14 @@ public class BotSharpDbContext : Database, IBotSharpRepository public List GetIdleConversations(int batchSize, int messageLimit, int bufferHours, IEnumerable excludeAgentIds) => throw new NotImplementedException(); + [SideCar] public List GetConversationDialogs(string conversationId) => throw new NotImplementedException(); public ConversationState GetConversationStates(string conversationId) => throw new NotImplementedException(); + [SideCar] public void AppendConversationDialogs(string conversationId, List dialogs) => throw new NotImplementedException(); @@ -108,9 +112,11 @@ public class BotSharpDbContext : Database, IBotSharpRepository public bool UpdateConversationMessage(string conversationId, UpdateMessageRequest request) => throw new NotImplementedException(); + [SideCar] public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint) => throw new NotImplementedException(); + [SideCar] public ConversationBreakpoint? GetConversationBreakpoint(string conversationId) => 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 7da6c849..28d0a6cc 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.Conversation.cs @@ -57,6 +57,7 @@ namespace BotSharp.Core.Repository return true; } + [SideCar] public List GetConversationDialogs(string conversationId) { var dialogs = new List(); @@ -78,6 +79,7 @@ namespace BotSharp.Core.Repository return dialogs; } + [SideCar] public void AppendConversationDialogs(string conversationId, List dialogs) { var convDir = FindConversationDirectory(conversationId); @@ -182,6 +184,7 @@ namespace BotSharp.Core.Repository return true; } + [SideCar] public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint) { var convDir = FindConversationDirectory(conversationId); @@ -220,6 +223,7 @@ namespace BotSharp.Core.Repository } } + [SideCar] public ConversationBreakpoint? GetConversationBreakpoint(string conversationId) { var convDir = FindConversationDirectory(conversationId); diff --git a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs index 46f39aaa..f3e1fddf 100644 --- a/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs +++ b/src/Infrastructure/BotSharp.Core/Repository/FileRepository/FileRepository.cs @@ -171,6 +171,8 @@ public partial class FileRepository : IBotSharpRepository } } + public IServiceProvider ServiceProvider => _services; + #region Private methods private void DeleteBeforeCreateDirectory(string dir) diff --git a/src/Infrastructure/BotSharp.Core/Using.cs b/src/Infrastructure/BotSharp.Core/Using.cs index e28eed72..8a0ca2af 100644 --- a/src/Infrastructure/BotSharp.Core/Using.cs +++ b/src/Infrastructure/BotSharp.Core/Using.cs @@ -33,6 +33,7 @@ global using BotSharp.Abstraction.Files.Utilities; global using BotSharp.Abstraction.Translation.Attributes; global using BotSharp.Abstraction.Messaging.Enums; global using BotSharp.Abstraction.Knowledges.Models; +global using BotSharp.Abstraction.SideCar.Attributes; global using BotSharp.Core.Repository; global using BotSharp.Core.Routing; global using BotSharp.Core.Agents.Services; diff --git a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs index 2d693603..a99538ab 100644 --- a/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs +++ b/src/Plugins/BotSharp.Plugin.ChatHub/Hooks/ChatHubConversationHook.cs @@ -1,3 +1,4 @@ +using BotSharp.Abstraction.SideCar; using Microsoft.AspNetCore.SignalR; namespace BotSharp.Plugin.ChatHub.Hooks; diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs index d8159da1..85fa1033 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.Conversation.cs @@ -70,6 +70,7 @@ public partial class MongoRepository || contentLogDeleted.DeletedCount > 0 || stateLogDeleted.DeletedCount > 0; } + [SideCar] public List GetConversationDialogs(string conversationId) { var dialogs = new List(); @@ -83,6 +84,7 @@ public partial class MongoRepository return formattedDialog ?? new List(); } + [SideCar] public void AppendConversationDialogs(string conversationId, List dialogs) { if (string.IsNullOrEmpty(conversationId)) return; @@ -159,6 +161,7 @@ public partial class MongoRepository return true; } + [SideCar] public void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint) { if (string.IsNullOrEmpty(conversationId)) return; @@ -176,6 +179,7 @@ public partial class MongoRepository _dc.ConversationStates.UpdateOne(filterState, updateState); } + [SideCar] public ConversationBreakpoint? GetConversationBreakpoint(string conversationId) { if (string.IsNullOrEmpty(conversationId)) diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs index 689c06be..258c1883 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Repository/MongoRepository.cs @@ -22,4 +22,6 @@ public partial class MongoRepository : IBotSharpRepository IsUpsert = true, }; } + + public IServiceProvider ServiceProvider => _services; } diff --git a/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs b/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs index 7c74b648..13b2739b 100644 --- a/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs +++ b/src/Plugins/BotSharp.Plugin.MongoStorage/Using.cs @@ -8,6 +8,7 @@ global using BotSharp.Abstraction.Agents.Enums; global using BotSharp.Abstraction.Utilities; global using BotSharp.Abstraction.Plugins; global using BotSharp.Abstraction.Translation.Models; +global using BotSharp.Abstraction.SideCar.Attributes; global using Microsoft.Extensions.Configuration; global using Microsoft.Extensions.DependencyInjection; global using MongoDB.Bson; diff --git a/src/WebStarter/WebStarter.csproj b/src/WebStarter/WebStarter.csproj index 4bd62176..a8f819d6 100644 --- a/src/WebStarter/WebStarter.csproj +++ b/src/WebStarter/WebStarter.csproj @@ -29,6 +29,7 @@ + diff --git a/src/WebStarter/appsettings.json b/src/WebStarter/appsettings.json index 7f43ba28..8c4cd9aa 100644 --- a/src/WebStarter/appsettings.json +++ b/src/WebStarter/appsettings.json @@ -151,6 +151,12 @@ } }, + "SideCar": { + "Conversation": { + "Provider": "botsharp" + } + }, + "WebBrowsing": { "Driver": "Playwright" }, @@ -321,6 +327,7 @@ "PluginLoader": { "Assemblies": [ "BotSharp.Core", + "BotSharp.Core.SideCar", "BotSharp.Logger", "BotSharp.Plugin.MongoStorage", "BotSharp.Plugin.Dashboard",