diff --git a/Directory.Packages.props b/Directory.Packages.props
index 0c674bf741..bd0fa48a3e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -88,9 +88,7 @@
-
-
-
+
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/AbpAIAbstractionsModule.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/AbpAIAbstractionsModule.cs
index cc478d8503..b535cf3235 100644
--- a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/AbpAIAbstractionsModule.cs
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/AbpAIAbstractionsModule.cs
@@ -1,7 +1,4 @@
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Volo.Abp.Modularity;
+using Volo.Abp.Modularity;
namespace Volo.Abp.AI;
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClient.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClient.cs
index e7458af657..8de74390ee 100644
--- a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClient.cs
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClient.cs
@@ -5,4 +5,5 @@ namespace Volo.Abp.AI;
public interface IChatClient : IChatClient
where TWorkSpace : class
{
+
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClientAccessor.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClientAccessor.cs
new file mode 100644
index 0000000000..b57aeae64d
--- /dev/null
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IChatClientAccessor.cs
@@ -0,0 +1,14 @@
+using Microsoft.Extensions.AI;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AI;
+
+public interface IChatClientAccessor
+{
+ IChatClient? ChatClient { get; }
+}
+
+public interface IChatClientAccessor : IChatClientAccessor
+ where TWorkSpace : class
+{
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IKernelAccessor.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IKernelAccessor.cs
index 7f55ad9e6f..4aae8fadb0 100644
--- a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IKernelAccessor.cs
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/IKernelAccessor.cs
@@ -11,4 +11,4 @@ public interface IKernelAccessor
public interface IKernelAccessor : IKernelAccessor
where TWorkSpace : class
{
-}
\ No newline at end of file
+}
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullChatClientAccessor.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullChatClientAccessor.cs
new file mode 100644
index 0000000000..0aa1ba52fc
--- /dev/null
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullChatClientAccessor.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.AI;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AI;
+
+[Dependency(TryRegister = true)]
+[ExposeServices(typeof(IChatClientAccessor))]
+public class NullChatClientAccessor : IChatClientAccessor
+{
+ public IChatClient? ChatClient => null;
+}
+
+[Dependency(TryRegister = true)]
+[ExposeServices(typeof(IChatClientAccessor<>))]
+public class NullChatClientAccessor : IChatClientAccessor
+ where TWorkSpace : class
+{
+ public IChatClient? ChatClient => null;
+}
diff --git a/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullKernelAccessor.cs b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullKernelAccessor.cs
new file mode 100644
index 0000000000..e05ad69553
--- /dev/null
+++ b/framework/src/Volo.Abp.AI.Abstractions/Volo/Abp/AI/NullKernelAccessor.cs
@@ -0,0 +1,20 @@
+
+using Microsoft.SemanticKernel;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AI;
+
+[Dependency(TryRegister = true)]
+[ExposeServices(typeof(IKernelAccessor))]
+public class NullKernelAccessor : IKernelAccessor
+{
+ public Kernel? Kernel => null;
+}
+
+[Dependency(TryRegister = true)]
+[ExposeServices(typeof(IKernelAccessor<>))]
+public class NullKernelAccessor : IKernelAccessor
+ where TWorkSpace : class
+{
+ public Kernel? Kernel => null;
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIModule.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIModule.cs
index f13a6e6f02..81d3866199 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIModule.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIModule.cs
@@ -5,7 +5,6 @@ using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.ChatCompletion;
using Volo.Abp.Modularity;
namespace Volo.Abp.AI;
@@ -17,80 +16,88 @@ public class AbpAIModule : AbpModule
{
public const string DefaultWorkspaceName = "Default";
- public override void PostConfigureServices(ServiceConfigurationContext context)
+ public override void ConfigureServices(ServiceConfigurationContext context)
{
- var options = context.Services.ExecutePreConfiguredActions();
+ var options = context.Services.ExecutePreConfiguredActions();
- context.Services.Configure(workspaceOptions =>
+ context.Services.Configure(workspaceOptions =>
{
- workspaceOptions.ConfiguredWorkspaceNames.UnionWith(options.Workspaces.Select(x => x.Key).ToArray());
+ workspaceOptions.ConfiguredWorkspaceNames.AddIfNotContains(
+ options.Workspaces.Select(x => x.Key)
+ );
});
foreach (var workspaceConfig in options.Workspaces.Values)
{
- if (workspaceConfig.ChatClient?.Builder is null)
- {
- continue;
- }
-
- foreach (var builderConfigurer in workspaceConfig.ChatClient.BuilderConfigurers)
- {
- builderConfigurer.Action(workspaceConfig.ChatClient.Builder!);
- }
-
- context.Services.AddKeyedChatClient(
- AbpAIOptions.GetChatClientServiceKeyName(workspaceConfig.Name),
- provider => workspaceConfig.ChatClient.Builder!.Build(provider),
- ServiceLifetime.Transient
+ ConfigureChatClient(context, workspaceConfig);
+ ConfigureKernel(context, workspaceConfig);
+ }
+
+ context.Services.TryAddTransient(typeof(IChatClient<>), typeof(TypedChatClient<>));
+ context.Services.TryAddTransient(typeof(IKernelAccessor<>), typeof(KernelAccessor<>));
+ }
+
+ private static void ConfigureKernel(ServiceConfigurationContext context, WorkspaceConfiguration workspaceConfig)
+ {
+ if (workspaceConfig.Kernel.Builder is null)
+ {
+ return;
+ }
+
+ foreach (var builderConfigurer in workspaceConfig.Kernel.BuilderConfigurers)
+ {
+ builderConfigurer.Action(workspaceConfig.Kernel.Builder!);
+ }
+
+ // TODO: Check if we can use transient instead of singleton for Kernel
+ context.Services.AddKeyedTransient(
+ AbpAIWorkspaceOptions.GetKernelServiceKeyName(workspaceConfig.Name),
+ (provider, _) => workspaceConfig.Kernel.Builder!.Build());
+
+ if (workspaceConfig.Name == DefaultWorkspaceName)
+ {
+ context.Services.AddTransient(sp => sp.GetRequiredKeyedService(
+ AbpAIWorkspaceOptions.GetKernelServiceKeyName(workspaceConfig.Name)
+ )
);
+ }
- if (workspaceConfig.Name == DefaultWorkspaceName)
- {
- context.Services.AddTransient(sp => sp.GetRequiredKeyedService(
- AbpAIOptions.GetChatClientServiceKeyName(workspaceConfig.Name)
- )
- );
- }
+ if (workspaceConfig.ChatClient?.Builder is null)
+ {
+ context.Services.AddKeyedTransient(
+ AbpAIWorkspaceOptions.GetChatClientServiceKeyName(workspaceConfig.Name),
+ (sp, _) => sp.GetKeyedService(AbpAIWorkspaceOptions.GetKernelServiceKeyName(workspaceConfig.Name))?
+ .GetRequiredService()
+ ?? throw new InvalidOperationException("Kernel or IChatClient not found with workspace name: " + workspaceConfig.Name)
+ );
}
+ }
- context.Services.TryAddTransient(typeof(IChatClient<>), typeof(TypedChatClient<>));
+ private static void ConfigureChatClient(ServiceConfigurationContext context, WorkspaceConfiguration workspaceConfig)
+ {
+ if (workspaceConfig.ChatClient.Builder is null)
+ {
+ return;
+ }
- foreach (var workspaceConfig in options.Workspaces.Values)
+ foreach (var builderConfigurer in workspaceConfig.ChatClient.BuilderConfigurers)
{
- if (workspaceConfig.Kernel?.Builder is null)
- {
- continue;
- }
-
- foreach (var builderConfigurer in workspaceConfig.Kernel.BuilderConfigurers)
- {
- builderConfigurer.Action(workspaceConfig.Kernel.Builder!);
- }
-
- // TODO: Check if we can use transient instead of singleton for Kernel
- context.Services.AddKeyedTransient(
- AbpAIOptions.GetKernelServiceKeyName(workspaceConfig.Name),
- (provider, _) => workspaceConfig.Kernel.Builder!.Build());
-
- if (workspaceConfig.Name == DefaultWorkspaceName)
- {
- context.Services.AddTransient(sp => sp.GetRequiredKeyedService(
- AbpAIOptions.GetKernelServiceKeyName(workspaceConfig.Name)
- )
- );
- }
-
- if (workspaceConfig.ChatClient?.Builder is null)
- {
- context.Services.AddKeyedTransient(
- AbpAIOptions.GetChatClientServiceKeyName(workspaceConfig.Name),
- (sp, _) => sp.GetKeyedService(AbpAIOptions.GetKernelServiceKeyName(workspaceConfig.Name))?
- .GetRequiredService()
- ?? throw new InvalidOperationException("Kernel or IChatClient not found with workspace name: " + workspaceConfig.Name)
- );
- }
+ builderConfigurer.Action(workspaceConfig.ChatClient.Builder);
}
- context.Services.TryAddTransient(typeof(IKernelAccessor<>), typeof(TypedKernelAccessor<>));
+ var serviceName = AbpAIWorkspaceOptions.GetChatClientServiceKeyName(workspaceConfig.Name);
+
+ context.Services.AddKeyedChatClient(
+ serviceName,
+ provider => workspaceConfig.ChatClient.Builder.Build(provider),
+ ServiceLifetime.Transient
+ );
+
+ if (workspaceConfig.Name == DefaultWorkspaceName)
+ {
+ context.Services.AddTransient(
+ sp => sp.GetRequiredKeyedService(serviceName)
+ );
+ }
}
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIOptions.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIOptions.cs
index b5639580d7..4efe59ed5c 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIOptions.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIOptions.cs
@@ -1,19 +1,8 @@
+using System.Collections.Generic;
+
namespace Volo.Abp.AI;
public class AbpAIOptions
{
- public const string ChatClientServiceKeyNamePrefix = "Abp.AI.ChatClient_";
- public const string KernelServiceKeyNamePrefix = "Abp.AI.Kernel_";
-
- public WorkspaceConfigurationDictionary Workspaces { get; } = new();
-
- public static string GetChatClientServiceKeyName(string name)
- {
- return $"{ChatClientServiceKeyNamePrefix}{name}";
- }
-
- public static string GetKernelServiceKeyName(string name)
- {
- return $"{KernelServiceKeyNamePrefix}{name}";
- }
+ public HashSet ConfiguredWorkspaceNames { get; } = new();
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIWorkspaceOptions.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIWorkspaceOptions.cs
index 1fad742c04..e027c185f6 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIWorkspaceOptions.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/AbpAIWorkspaceOptions.cs
@@ -1,8 +1,24 @@
-using System.Collections.Generic;
-
namespace Volo.Abp.AI;
+///
+/// Pre-configured options for the AI workspaces. Not used via Options pattern. Use it with 'PreConfigure' method in a Module class.
+/// In example:
+/// PreConfigure<AbpAIWorkspaceOptions>(options => { });
+///
public class AbpAIWorkspaceOptions
{
- public HashSet ConfiguredWorkspaceNames { get; } = new();
+ public const string ChatClientServiceKeyNamePrefix = "Abp.AI.ChatClient_";
+ public const string KernelServiceKeyNamePrefix = "Abp.AI.Kernel_";
+
+ public WorkspaceConfigurationDictionary Workspaces { get; } = new();
+
+ public static string GetChatClientServiceKeyName(string name)
+ {
+ return $"{ChatClientServiceKeyNamePrefix}{name}";
+ }
+
+ public static string GetKernelServiceKeyName(string name)
+ {
+ return $"{KernelServiceKeyNamePrefix}{name}";
+ }
}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientAccessor.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientAccessor.cs
new file mode 100644
index 0000000000..1a852838fc
--- /dev/null
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientAccessor.cs
@@ -0,0 +1,35 @@
+using System;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.DependencyInjection;
+
+namespace Volo.Abp.AI;
+
+[Dependency(ReplaceServices = true, TryRegister = true)]
+[ExposeServices(typeof(IChatClientAccessor))]
+public class ChatClientAccessor : IChatClientAccessor
+{
+ public IChatClient? ChatClient { get; }
+
+ public ChatClientAccessor(IServiceProvider serviceProvider)
+ {
+ ChatClient = serviceProvider.GetKeyedService(
+ AbpAIWorkspaceOptions.GetChatClientServiceKeyName(
+ AbpAIModule.DefaultWorkspaceName));
+ }
+}
+
+[Dependency(ReplaceServices = true, TryRegister = true)]
+[ExposeServices(typeof(IChatClientAccessor))]
+public class ChatClientAccessor : IChatClientAccessor
+ where TWorkSpace : class
+{
+ public IChatClient? ChatClient { get; }
+
+ public ChatClientAccessor(IServiceProvider serviceProvider)
+ {
+ ChatClient = serviceProvider.GetKeyedService(
+ AbpAIWorkspaceOptions.GetChatClientServiceKeyName(
+ WorkspaceNameAttribute.GetWorkspaceName()));
+ }
+}
\ No newline at end of file
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientConfiguration.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientConfiguration.cs
index 830d6fd87c..601a6bbe07 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientConfiguration.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/ChatClientConfiguration.cs
@@ -9,8 +9,6 @@ public class ChatClientConfiguration
public BuilderConfigurerList BuilderConfigurers { get; } = new();
- // TODO: Base chat client (for inheriting a chat client configuration from some other one)
-
public void ConfigureBuilder(Action configureAction)
{
BuilderConfigurers.Add(configureAction);
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedKernelAccessor.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/KernelAccessor.cs
similarity index 63%
rename from framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedKernelAccessor.cs
rename to framework/src/Volo.Abp.AI/Volo/Abp/AI/KernelAccessor.cs
index 09d0132676..ba9d305312 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedKernelAccessor.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/KernelAccessor.cs
@@ -4,15 +4,15 @@ using Microsoft.SemanticKernel;
namespace Volo.Abp.AI;
-public class TypedKernelAccessor : IKernelAccessor
+public class KernelAccessor : IKernelAccessor
where TWorkSpace : class
{
public Kernel? Kernel { get; }
- public TypedKernelAccessor(IServiceProvider serviceProvider)
+ public KernelAccessor(IServiceProvider serviceProvider)
{
Kernel = serviceProvider.GetKeyedService(
- AbpAIOptions.GetKernelServiceKeyName(
+ AbpAIWorkspaceOptions.GetKernelServiceKeyName(
WorkspaceNameAttribute.GetWorkspaceName()));
}
}
diff --git a/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedChatClient.cs b/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedChatClient.cs
index c75d9b0c97..72ccfdaf38 100644
--- a/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedChatClient.cs
+++ b/framework/src/Volo.Abp.AI/Volo/Abp/AI/TypedChatClient.cs
@@ -10,7 +10,7 @@ public class TypedChatClient : DelegatingChatClient, IChatClient(
- AbpAIOptions.GetChatClientServiceKeyName(
+ AbpAIWorkspaceOptions.GetChatClientServiceKeyName(
WorkspaceNameAttribute.GetWorkspaceName()))
)
{