Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

init conv side car #712

Merged
merged 5 commits into from
Nov 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions BotSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
Expand Down Expand Up @@ -38,6 +38,7 @@
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Rougamo.Fody" Version="4.0.0" />
<PackageReference Include="AspectInjector" Version="2.8.2" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@ IConversationStateService SetState<T>(string name, T value, bool isNeedVersion =
bool RemoveState(string name);
void CleanStates(params string[] excludedStates);
void Save();

ConversationState GetCurrentState();
void SetCurrentState(ConversationState state);
void ResetCurrentState();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace BotSharp.Abstraction.Conversations.Models;

public class ConversationContext
{
public ConversationState State { get; set; }
public List<DialogElement> Dialogs { get; set; } = new();
public List<ConversationBreakpoint> Breakpoints { get; set; } = new();
public int RecursiveCounter { get; set; }
public Stack<string> RoutingStack { get; set; } = new();
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
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;
using BotSharp.Abstraction.VectorStorage.Models;

namespace BotSharp.Abstraction.Repositories;

public interface IBotSharpRepository
public interface IBotSharpRepository : IHaveServiceProvider
{
#region Plugin
PluginConfig GetPluginConfig();
Expand Down
11 changes: 11 additions & 0 deletions src/Infrastructure/BotSharp.Abstraction/Routing/IRoutingContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,15 @@ public interface IRoutingContext
void PopTo(string agentId, string reason);
void Replace(string agentId, string? reason = null);
void Empty(string? reason = null);


int CurrentRecursionDepth { get; }
int GetRecursiveCounter();
void IncreaseRecursiveCounter();
void SetRecursiveCounter(int counter);
void ResetRecursiveCounter();

Stack<string> GetAgentStack();
void SetAgentStack(Stack<string> stack);
void ResetAgentStack();
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ public interface IRoutingService
RoutingRule[] GetRulesByAgentId(string id);

List<RoutingHandlerDef> GetHandlers(Agent router);
void ResetRecursiveCounter();

//void ResetRecursiveCounter();
//int GetRecursiveCounter();
//void SetRecursiveCounter(int counter);

Task<bool> InvokeAgent(string agentId, List<RoleDialogModel> dialogs);
Task<bool> InvokeFunction(string name, RoleDialogModel messages);
Task<RoleDialogModel> InstructLoop(RoleDialogModel message, List<RoleDialogModel> dialogs);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BotSharp.Abstraction.Shared;

public interface IHaveServiceProvider
{
IServiceProvider ServiceProvider { get; }
}
Original file line number Diff line number Diff line change
@@ -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<object[], object> 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<object[], object> target, object[] args)
{
var sidecar = serviceProvider.GetService<IConversationSideCar>();
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<object[], object> target, object[] args)
{
var sidecar = serviceProvider.GetService<IConversationSideCar>();
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<T> CallGenericAsync<T>(object instance, MethodInfo method, object[] args)
{
var res = await (Task<T>)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<T>(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<T>(Func<object[], object> target, object[] args)
{
T res;
res = (T)target(args);
return res;
}

private static async Task<T> WrapGenericAsync<T>(Func<object[], object> target, object[] args)
{
T res;
res = await (Task<T>)target(args);
return res;
}


private static void WrapSync(Func<object[], object> target, object[] args)
{
target(args);
return;
}

private static async Task WrapAsync(Func<object[], object> target, object[] args)
{
await (Task)target(args);
return;
}
#endregion
}
Original file line number Diff line number Diff line change
@@ -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()
{

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace BotSharp.Abstraction.SideCar;

public interface IConversationSideCar
{
string Provider { get; }

bool IsEnabled();
void AppendConversationDialogs(string conversationId, List<DialogElement> messages);
List<DialogElement> GetConversationDialogs(string conversationId);
void UpdateConversationBreakpoint(string conversationId, ConversationBreakpoint breakpoint);
ConversationBreakpoint? GetConversationBreakpoint(string conversationId);
Task<RoleDialogModel> SendMessage(string agentId, string text, PostbackMessageModel? postback = null, List<MessageState>? states = null);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(TargetFramework)</TargetFramework>
<LangVersion>$(LangVersion)</LangVersion>
<VersionPrefix>$(BotSharpVersion)</VersionPrefix>
<GeneratePackageOnBuild>$(GeneratePackageOnBuild)</GeneratePackageOnBuild>
<OutputPath>$(SolutionDir)packages</OutputPath>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\BotSharp.Abstraction\BotSharp.Abstraction.csproj" />
</ItemGroup>

</Project>
28 changes: 28 additions & 0 deletions src/Infrastructure/BotSharp.Core.SideCar/BotSharpSideCarPlugin.cs
Original file line number Diff line number Diff line change
@@ -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<IConversationSideCar, BotSharpConversationSideCar>();
}
}
}
Loading