diff --git a/service/Service/ServiceConfiguration.cs b/extensions/KM/KernelMemory/Internals/KernelMemoryComposer.cs
similarity index 74%
rename from service/Service/ServiceConfiguration.cs
rename to extensions/KM/KernelMemory/Internals/KernelMemoryComposer.cs
index 65c638c6a..a850099cb 100644
--- a/service/Service/ServiceConfiguration.cs
+++ b/extensions/KM/KernelMemory/Internals/KernelMemoryComposer.cs
@@ -16,78 +16,53 @@
using Microsoft.KernelMemory.Pipeline.Queue.DevTools;
using Microsoft.KernelMemory.Safety.AzureAIContentSafety;
-namespace Microsoft.KernelMemory.Service;
+namespace Microsoft.KernelMemory.Internals;
-internal sealed class ServiceConfiguration
+///
+/// Meta factory class responsible for configuring IKernelMemoryBuilder
+/// with the components selected in the configuration.
+///
+internal sealed class KernelMemoryComposer
{
- // Content of appsettings.json, used to access dynamic data under "Services"
- private IConfiguration _rawAppSettings;
-
- // Normalized configuration
- private KernelMemoryConfig _memoryConfiguration;
-
- // appsettings.json root node name
- private const string ConfigRoot = "KernelMemory";
-
- // ASP.NET env var
- private const string AspnetEnvVar = "ASPNETCORE_ENVIRONMENT";
-
- // OpenAI env var
- private const string OpenAIEnvVar = "OPENAI_API_KEY";
-
- public ServiceConfiguration(string? settingsDirectory = null)
- : this(ReadAppSettings(settingsDirectory))
- {
- }
+ // appsettings.json root node name (and prefix of env vars)
+ public const string ConfigRoot = "KernelMemory";
- public ServiceConfiguration(IConfiguration rawAppSettings)
- : this(rawAppSettings,
- rawAppSettings.GetSection(ConfigRoot).Get()
- ?? throw new ConfigurationException($"Unable to load Kernel Memory settings from the given configuration. " +
- $"There should be a '{ConfigRoot}' root node, " +
- $"with data mapping to '{nameof(KernelMemoryConfig)}'"))
- {
- }
-
- public ServiceConfiguration(
- IConfiguration rawAppSettings,
+ public KernelMemoryComposer(
+ IKernelMemoryBuilder builder,
+ IConfiguration globalSettings,
KernelMemoryConfig memoryConfiguration)
{
- this._rawAppSettings = rawAppSettings ?? throw new ConfigurationException("The given app settings configuration is NULL");
- this._memoryConfiguration = memoryConfiguration ?? throw new ConfigurationException("The given memory configuration is NULL");
+ this._builder = builder;
+ this._globalSettings = globalSettings;
+ this._memoryConfiguration = memoryConfiguration;
if (!this.MinimumConfigurationIsAvailable(false)) { this.SetupForOpenAI(); }
this.MinimumConfigurationIsAvailable(true);
}
- public IKernelMemoryBuilder PrepareBuilder(IKernelMemoryBuilder builder)
- {
- return this.BuildUsingConfiguration(builder);
- }
-
- private IKernelMemoryBuilder BuildUsingConfiguration(IKernelMemoryBuilder builder)
+ public void ConfigureBuilder()
{
if (this._memoryConfiguration == null)
{
throw new ConfigurationException("The given memory configuration is NULL");
}
- if (this._rawAppSettings == null)
+ if (this._globalSettings == null)
{
throw new ConfigurationException("The given app settings configuration is NULL");
}
// Required by ctors expecting KernelMemoryConfig via DI
- builder.AddSingleton(this._memoryConfiguration);
+ this._builder.AddSingleton(this._memoryConfiguration);
- this.ConfigureMimeTypeDetectionDependency(builder);
+ this.ConfigureMimeTypeDetectionDependency();
- this.ConfigureTextPartitioning(builder);
+ this.ConfigureTextPartitioning();
- this.ConfigureQueueDependency(builder);
+ this.ConfigureQueueDependency();
- this.ConfigureStorageDependency(builder);
+ this.ConfigureStorageDependency();
// The ingestion embedding generators is a list of generators that the "gen_embeddings" handler uses,
// to generate embeddings for each partition. While it's possible to use multiple generators (e.g. to compare embedding quality)
@@ -95,38 +70,46 @@ private IKernelMemoryBuilder BuildUsingConfiguration(IKernelMemoryBuilder builde
// - config.DataIngestion.EmbeddingGeneratorTypes => list of generators, embeddings to generate and store in memory DB
// - config.Retrieval.EmbeddingGeneratorType => one embedding generator, used to search, and usually injected into Memory DB constructor
- this.ConfigureIngestionEmbeddingGenerators(builder);
+ this.ConfigureIngestionEmbeddingGenerators();
- this.ConfigureContentModeration(builder);
+ this.ConfigureContentModeration();
- this.ConfigureSearchClient(builder);
+ this.ConfigureSearchClient();
- this.ConfigureRetrievalEmbeddingGenerator(builder);
+ this.ConfigureRetrievalEmbeddingGenerator();
// The ingestion Memory DBs is a list of DBs where handlers write records to. While it's possible
// to write to multiple DBs, e.g. for replication purpose, there is only one Memory DB used to
// read/search, and it doesn't come from this list. See "config.Retrieval.MemoryDbType".
// Note: use the aux service collection to avoid mixing ingestion and retrieval dependencies.
- this.ConfigureIngestionMemoryDb(builder);
-
- this.ConfigureRetrievalMemoryDb(builder);
+ this.ConfigureIngestionMemoryDb();
- this.ConfigureTextGenerator(builder);
+ this.ConfigureRetrievalMemoryDb();
- this.ConfigureImageOCR(builder);
+ this.ConfigureTextGenerator();
- return builder;
+ this.ConfigureImageOCR();
}
- private static IConfiguration ReadAppSettings(string? settingsDirectory)
- {
- var builder = new ConfigurationBuilder();
- builder.AddKMConfigurationSources(settingsDirectory: settingsDirectory);
- return builder.Build();
- }
+ #region private ===============================
+
+ // Builder to be configured with the required components
+ private readonly IKernelMemoryBuilder _builder;
+
+ // Content of appsettings.json, used to access dynamic data under "Services"
+ private IConfiguration _globalSettings;
+
+ // Normalized configuration
+ private KernelMemoryConfig _memoryConfiguration;
+
+ // ASP.NET env var
+ private const string AspnetEnvVar = "ASPNETCORE_ENVIRONMENT";
- private void ConfigureQueueDependency(IKernelMemoryBuilder builder)
+ // OpenAI env var
+ private const string OpenAIEnvVar = "OPENAI_API_KEY";
+
+ private void ConfigureQueueDependency()
{
if (string.Equals(this._memoryConfiguration.DataIngestion.OrchestrationType, "Distributed", StringComparison.OrdinalIgnoreCase))
{
@@ -135,18 +118,18 @@ private void ConfigureQueueDependency(IKernelMemoryBuilder builder)
case string y1 when y1.Equals("AzureQueue", StringComparison.OrdinalIgnoreCase):
case string y2 when y2.Equals("AzureQueues", StringComparison.OrdinalIgnoreCase):
// Check 2 keys for backward compatibility
- builder.Services.AddAzureQueuesOrchestration(this.GetServiceConfig("AzureQueues")
- ?? this.GetServiceConfig("AzureQueue"));
+ this._builder.Services.AddAzureQueuesOrchestration(this.GetServiceConfig("AzureQueues")
+ ?? this.GetServiceConfig("AzureQueue"));
break;
case string y when y.Equals("RabbitMQ", StringComparison.OrdinalIgnoreCase):
// Check 2 keys for backward compatibility
- builder.Services.AddRabbitMQOrchestration(this.GetServiceConfig("RabbitMQ")
- ?? this.GetServiceConfig("RabbitMq"));
+ this._builder.Services.AddRabbitMQOrchestration(this.GetServiceConfig("RabbitMQ")
+ ?? this.GetServiceConfig("RabbitMq"));
break;
case string y when y.Equals("SimpleQueues", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddSimpleQueues(this.GetServiceConfig("SimpleQueues"));
+ this._builder.Services.AddSimpleQueues(this.GetServiceConfig("SimpleQueues"));
break;
default:
@@ -156,27 +139,27 @@ private void ConfigureQueueDependency(IKernelMemoryBuilder builder)
}
}
- private void ConfigureStorageDependency(IKernelMemoryBuilder builder)
+ private void ConfigureStorageDependency()
{
switch (this._memoryConfiguration.DocumentStorageType)
{
case string x1 when x1.Equals("AzureBlob", StringComparison.OrdinalIgnoreCase):
case string x2 when x2.Equals("AzureBlobs", StringComparison.OrdinalIgnoreCase):
// Check 2 keys for backward compatibility
- builder.Services.AddAzureBlobsAsDocumentStorage(this.GetServiceConfig("AzureBlobs")
- ?? this.GetServiceConfig("AzureBlob"));
+ this._builder.Services.AddAzureBlobsAsDocumentStorage(this.GetServiceConfig("AzureBlobs")
+ ?? this.GetServiceConfig("AzureBlob"));
break;
case string x when x.Equals("AWSS3", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAWSS3AsDocumentStorage(this.GetServiceConfig("AWSS3"));
+ this._builder.Services.AddAWSS3AsDocumentStorage(this.GetServiceConfig("AWSS3"));
break;
case string x when x.Equals("MongoDbAtlas", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddMongoDbAtlasAsDocumentStorage(this.GetServiceConfig("MongoDbAtlas"));
+ this._builder.Services.AddMongoDbAtlasAsDocumentStorage(this.GetServiceConfig("MongoDbAtlas"));
break;
case string x when x.Equals("SimpleFileStorage", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddSimpleFileStorageAsDocumentStorage(this.GetServiceConfig("SimpleFileStorage"));
+ this._builder.Services.AddSimpleFileStorageAsDocumentStorage(this.GetServiceConfig("SimpleFileStorage"));
break;
default:
@@ -185,21 +168,21 @@ private void ConfigureStorageDependency(IKernelMemoryBuilder builder)
}
}
- private void ConfigureTextPartitioning(IKernelMemoryBuilder builder)
+ private void ConfigureTextPartitioning()
{
if (this._memoryConfiguration.DataIngestion.TextPartitioning != null)
{
this._memoryConfiguration.DataIngestion.TextPartitioning.Validate();
- builder.WithCustomTextPartitioningOptions(this._memoryConfiguration.DataIngestion.TextPartitioning);
+ this._builder.WithCustomTextPartitioningOptions(this._memoryConfiguration.DataIngestion.TextPartitioning);
}
}
- private void ConfigureMimeTypeDetectionDependency(IKernelMemoryBuilder builder)
+ private void ConfigureMimeTypeDetectionDependency()
{
- builder.WithDefaultMimeTypeDetection();
+ this._builder.WithDefaultMimeTypeDetection();
}
- private void ConfigureIngestionEmbeddingGenerators(IKernelMemoryBuilder builder)
+ private void ConfigureIngestionEmbeddingGenerators()
{
// Note: using multiple embeddings is not fully supported yet and could cause write errors or incorrect search results
if (this._memoryConfiguration.DataIngestion.EmbeddingGeneratorTypes.Count > 1)
@@ -216,40 +199,40 @@ private void ConfigureIngestionEmbeddingGenerators(IKernelMemoryBuilder builder)
case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase):
case string y when y.Equals("AzureOpenAIEmbedding", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddAzureOpenAIEmbeddingGeneration(
config: this.GetServiceConfig("AzureOpenAIEmbedding"),
textTokenizer: new GPT4oTokenizer()));
- builder.AddIngestionEmbeddingGenerator(instance);
+ this._builder.AddIngestionEmbeddingGenerator(instance);
break;
}
case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddOpenAITextEmbeddingGeneration(
config: this.GetServiceConfig("OpenAI"),
textTokenizer: new GPT4oTokenizer()));
- builder.AddIngestionEmbeddingGenerator(instance);
+ this._builder.AddIngestionEmbeddingGenerator(instance);
break;
}
case string x when x.Equals("Ollama", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddOllamaTextEmbeddingGeneration(
config: this.GetServiceConfig("Ollama"),
textTokenizer: new GPT4oTokenizer()));
- builder.AddIngestionEmbeddingGenerator(instance);
+ this._builder.AddIngestionEmbeddingGenerator(instance);
break;
}
case string x when x.Equals("LlamaSharp", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddLlamaSharpTextEmbeddingGeneration(
config: this.GetServiceConfig("LlamaSharp").EmbeddingModel));
- builder.AddIngestionEmbeddingGenerator(instance);
+ this._builder.AddIngestionEmbeddingGenerator(instance);
break;
}
@@ -260,7 +243,7 @@ private void ConfigureIngestionEmbeddingGenerators(IKernelMemoryBuilder builder)
}
}
- private void ConfigureIngestionMemoryDb(IKernelMemoryBuilder builder)
+ private void ConfigureIngestionMemoryDb()
{
foreach (var type in this._memoryConfiguration.DataIngestion.MemoryDbTypes)
{
@@ -278,94 +261,94 @@ private void ConfigureIngestionMemoryDb(IKernelMemoryBuilder builder)
case string x when x.Equals("AzureAISearch", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddAzureAISearchAsMemoryDb(this.GetServiceConfig("AzureAISearch"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("Elasticsearch", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddElasticsearchAsMemoryDb(this.GetServiceConfig("Elasticsearch"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("MongoDbAtlas", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddMongoDbAtlasAsMemoryDb(this.GetServiceConfig("MongoDbAtlas"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("Postgres", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddPostgresAsMemoryDb(this.GetServiceConfig("Postgres"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("Qdrant", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddQdrantAsMemoryDb(this.GetServiceConfig("Qdrant"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("Redis", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddRedisAsMemoryDb(this.GetServiceConfig("Redis"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("SimpleVectorDb", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddSimpleVectorDbAsMemoryDb(this.GetServiceConfig("SimpleVectorDb"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("SimpleTextDb", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddSimpleTextDbAsMemoryDb(this.GetServiceConfig("SimpleTextDb"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
case string x when x.Equals("SqlServer", StringComparison.OrdinalIgnoreCase):
{
- var instance = this.GetServiceInstance(builder,
+ var instance = this.GetServiceInstance(
s => s.AddSqlServerAsMemoryDb(this.GetServiceConfig("SqlServer"))
);
- builder.AddIngestionMemoryDb(instance);
+ this._builder.AddIngestionMemoryDb(instance);
break;
}
}
}
}
- private void ConfigureContentModeration(IKernelMemoryBuilder builder)
+ private void ConfigureContentModeration()
{
switch (this._memoryConfiguration.ContentModerationType)
{
case string x when x.Equals("AzureAIContentSafety", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAzureAIContentSafetyModeration(config: this.GetServiceConfig("AzureAIContentSafety"));
+ this._builder.Services.AddAzureAIContentSafetyModeration(config: this.GetServiceConfig("AzureAIContentSafety"));
break;
default:
@@ -374,38 +357,38 @@ private void ConfigureContentModeration(IKernelMemoryBuilder builder)
}
}
- private void ConfigureSearchClient(IKernelMemoryBuilder builder)
+ private void ConfigureSearchClient()
{
// Search settings
- builder.WithSearchClientConfig(this._memoryConfiguration.Retrieval.SearchClient);
+ this._builder.WithSearchClientConfig(this._memoryConfiguration.Retrieval.SearchClient);
}
- private void ConfigureRetrievalEmbeddingGenerator(IKernelMemoryBuilder builder)
+ private void ConfigureRetrievalEmbeddingGenerator()
{
// Retrieval embeddings - ITextEmbeddingGeneration interface
switch (this._memoryConfiguration.Retrieval.EmbeddingGeneratorType)
{
case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase):
case string y when y.Equals("AzureOpenAIEmbedding", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAzureOpenAIEmbeddingGeneration(
+ this._builder.Services.AddAzureOpenAIEmbeddingGeneration(
config: this.GetServiceConfig("AzureOpenAIEmbedding"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddOpenAITextEmbeddingGeneration(
+ this._builder.Services.AddOpenAITextEmbeddingGeneration(
config: this.GetServiceConfig("OpenAI"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("Ollama", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddOllamaTextEmbeddingGeneration(
+ this._builder.Services.AddOllamaTextEmbeddingGeneration(
config: this.GetServiceConfig("Ollama"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("LlamaSharp", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddLlamaSharpTextEmbeddingGeneration(
+ this._builder.Services.AddLlamaSharpTextEmbeddingGeneration(
config: this.GetServiceConfig("LlamaSharp").EmbeddingModel);
break;
@@ -415,45 +398,45 @@ private void ConfigureRetrievalEmbeddingGenerator(IKernelMemoryBuilder builder)
}
}
- private void ConfigureRetrievalMemoryDb(IKernelMemoryBuilder builder)
+ private void ConfigureRetrievalMemoryDb()
{
// Retrieval Memory DB - IMemoryDb interface
switch (this._memoryConfiguration.Retrieval.MemoryDbType)
{
case string x when x.Equals("AzureAISearch", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAzureAISearchAsMemoryDb(this.GetServiceConfig("AzureAISearch"));
+ this._builder.Services.AddAzureAISearchAsMemoryDb(this.GetServiceConfig("AzureAISearch"));
break;
case string x when x.Equals("Elasticsearch", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddElasticsearchAsMemoryDb(this.GetServiceConfig("Elasticsearch"));
+ this._builder.Services.AddElasticsearchAsMemoryDb(this.GetServiceConfig("Elasticsearch"));
break;
case string x when x.Equals("MongoDbAtlas", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddMongoDbAtlasAsMemoryDb(this.GetServiceConfig("MongoDbAtlas"));
+ this._builder.Services.AddMongoDbAtlasAsMemoryDb(this.GetServiceConfig("MongoDbAtlas"));
break;
case string x when x.Equals("Postgres", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddPostgresAsMemoryDb(this.GetServiceConfig("Postgres"));
+ this._builder.Services.AddPostgresAsMemoryDb(this.GetServiceConfig("Postgres"));
break;
case string x when x.Equals("Qdrant", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddQdrantAsMemoryDb(this.GetServiceConfig("Qdrant"));
+ this._builder.Services.AddQdrantAsMemoryDb(this.GetServiceConfig("Qdrant"));
break;
case string x when x.Equals("Redis", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddRedisAsMemoryDb(this.GetServiceConfig("Redis"));
+ this._builder.Services.AddRedisAsMemoryDb(this.GetServiceConfig("Redis"));
break;
case string x when x.Equals("SimpleVectorDb", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddSimpleVectorDbAsMemoryDb(this.GetServiceConfig("SimpleVectorDb"));
+ this._builder.Services.AddSimpleVectorDbAsMemoryDb(this.GetServiceConfig("SimpleVectorDb"));
break;
case string x when x.Equals("SimpleTextDb", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddSimpleTextDbAsMemoryDb(this.GetServiceConfig("SimpleTextDb"));
+ this._builder.Services.AddSimpleTextDbAsMemoryDb(this.GetServiceConfig("SimpleTextDb"));
break;
case string x when x.Equals("SqlServer", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddSqlServerAsMemoryDb(this.GetServiceConfig("SqlServer"));
+ this._builder.Services.AddSqlServerAsMemoryDb(this.GetServiceConfig("SqlServer"));
break;
default:
@@ -462,38 +445,38 @@ private void ConfigureRetrievalMemoryDb(IKernelMemoryBuilder builder)
}
}
- private void ConfigureTextGenerator(IKernelMemoryBuilder builder)
+ private void ConfigureTextGenerator()
{
// Text generation
switch (this._memoryConfiguration.TextGeneratorType)
{
case string x when x.Equals("AzureOpenAI", StringComparison.OrdinalIgnoreCase):
case string y when y.Equals("AzureOpenAIText", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAzureOpenAITextGeneration(
+ this._builder.Services.AddAzureOpenAITextGeneration(
config: this.GetServiceConfig("AzureOpenAIText"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("OpenAI", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddOpenAITextGeneration(
+ this._builder.Services.AddOpenAITextGeneration(
config: this.GetServiceConfig("OpenAI"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("Anthropic", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAnthropicTextGeneration(
+ this._builder.Services.AddAnthropicTextGeneration(
config: this.GetServiceConfig("Anthropic"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("Ollama", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddOllamaTextGeneration(
+ this._builder.Services.AddOllamaTextGeneration(
config: this.GetServiceConfig("Ollama"),
textTokenizer: new GPT4oTokenizer());
break;
case string x when x.Equals("LlamaSharp", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddLlamaSharpTextGeneration(
+ this._builder.Services.AddLlamaSharpTextGeneration(
config: this.GetServiceConfig("LlamaSharp").TextModel);
break;
@@ -503,7 +486,7 @@ private void ConfigureTextGenerator(IKernelMemoryBuilder builder)
}
}
- private void ConfigureImageOCR(IKernelMemoryBuilder builder)
+ private void ConfigureImageOCR()
{
// Image OCR
switch (this._memoryConfiguration.DataIngestion.ImageOcrType)
@@ -513,7 +496,7 @@ private void ConfigureImageOCR(IKernelMemoryBuilder builder)
break;
case string x when x.Equals("AzureAIDocIntel", StringComparison.OrdinalIgnoreCase):
- builder.Services.AddAzureAIDocIntel(this.GetServiceConfig("AzureAIDocIntel"));
+ this._builder.Services.AddAzureAIDocIntel(this.GetServiceConfig("AzureAIDocIntel"));
break;
default:
@@ -616,11 +599,11 @@ private void SetupForOpenAI()
};
var newAppSettings = new ConfigurationBuilder();
- newAppSettings.AddConfiguration(this._rawAppSettings);
+ newAppSettings.AddConfiguration(this._globalSettings);
newAppSettings.AddInMemoryCollection(inMemoryConfig);
- this._rawAppSettings = newAppSettings.Build();
- this._memoryConfiguration = this._rawAppSettings.GetSection(ConfigRoot).Get()!;
+ this._globalSettings = newAppSettings.Build();
+ this._memoryConfiguration = this._globalSettings.GetSection(ConfigRoot).Get()!;
}
///
@@ -630,14 +613,13 @@ private void SetupForOpenAI()
/// Return an instance of T built using the definition provided by
/// the action.
///
- /// KM builder
/// Action used to configure the service collection
/// Target type/interface
- private T GetServiceInstance(IKernelMemoryBuilder builder, Action addCustomService)
+ private T GetServiceInstance(Action addCustomService)
{
// Clone the list of service descriptors, skipping T descriptor
IServiceCollection services = new ServiceCollection();
- foreach (ServiceDescriptor d in builder.Services)
+ foreach (ServiceDescriptor d in this._builder.Services)
{
if (d.ServiceType == typeof(T)) { continue; }
@@ -671,6 +653,8 @@ private T GetServiceInstance(IKernelMemoryBuilder builder, ActionConfiguration instance, settings for the dependency specified
private T GetServiceConfig(string serviceName)
{
- return this._memoryConfiguration.GetServiceConfig(this._rawAppSettings, serviceName);
+ return this._memoryConfiguration.GetServiceConfig(this._globalSettings, serviceName);
}
+
+ #endregion
}
diff --git a/extensions/KM/KernelMemory/KernelMemoryBuilderExtensions.cs b/extensions/KM/KernelMemory/KernelMemoryBuilderExtensions.cs
new file mode 100644
index 000000000..5937d6384
--- /dev/null
+++ b/extensions/KM/KernelMemory/KernelMemoryBuilderExtensions.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.KernelMemory.Internals;
+
+// ReSharper disable once CheckNamespace - reduce number of "using" statements
+namespace Microsoft.KernelMemory;
+
+///
+/// Kernel Memory builder extensions for ASP.NET apps using settings in appsettings.json
+/// and using IConfiguration. The following methods allow to fully configure KM via
+/// IConfiguration, without having to change the code using KernelMemoryBuilder and recompile.
+///
+public static partial class KernelMemoryBuilderExtensions
+{
+ ///
+ /// Configure the builder using settings from the given IConfiguration instance.
+ ///
+ /// KernelMemory builder instance
+ /// App settings, which might include KM settings
+ /// Optional KM settings, overriding those in appsettings
+ public static IKernelMemoryBuilder ConfigureDependencies(
+ this IKernelMemoryBuilder builder,
+ IConfiguration appSettings,
+ KernelMemoryConfig? memoryConfig = null)
+ {
+ if (appSettings is null)
+ {
+ throw new ConfigurationException("The given app settings configuration is NULL");
+ }
+
+ if (memoryConfig is null)
+ {
+ memoryConfig = appSettings.GetSection(KernelMemoryComposer.ConfigRoot).Get();
+ }
+
+ if (memoryConfig is null)
+ {
+ throw new ConfigurationException($"Unable to load Kernel Memory settings from the given configuration. " +
+ $"There should be a '{KernelMemoryComposer.ConfigRoot}' root node, " +
+ $"with data mapping to '{nameof(KernelMemoryConfig)}'");
+ }
+
+ var composer = new KernelMemoryComposer(builder, appSettings, memoryConfig);
+ composer.ConfigureBuilder();
+
+ return builder;
+ }
+}
diff --git a/service/Service/ConfigurationBuilderExtensions.cs b/service/Core/Configuration/ConfigurationBuilderExtensions.cs
similarity index 83%
rename from service/Service/ConfigurationBuilderExtensions.cs
rename to service/Core/Configuration/ConfigurationBuilderExtensions.cs
index ba3ea5293..194e61481 100644
--- a/service/Service/ConfigurationBuilderExtensions.cs
+++ b/service/Core/Configuration/ConfigurationBuilderExtensions.cs
@@ -5,22 +5,27 @@
using System.Reflection;
using Microsoft.Extensions.Configuration;
-namespace Microsoft.KernelMemory.Service;
+#pragma warning disable IDE0130 // reduce number of "using" statements
+// ReSharper disable once CheckNamespace - reduce number of "using" statements
+namespace Microsoft.KernelMemory;
-internal static class ConfigurationBuilderExtensions
+public static partial class ConfigurationBuilderExtensions
{
// ASP.NET env var
- private const string AspnetEnvVar = "ASPNETCORE_ENVIRONMENT";
+ private const string AspNetCoreEnvVar = "ASPNETCORE_ENVIRONMENT";
- public static void AddKMConfigurationSources(
+ // .NET env var
+ private const string DotNetEnvVar = "DOTNET_ENVIRONMENT";
+
+ public static void AddKernelMemoryConfigurationSources(
this IConfigurationBuilder builder,
bool useAppSettingsFiles = true,
bool useEnvVars = true,
bool useSecretManager = true,
string? settingsDirectory = null)
{
- // Load env var name, either Development or Production
- var env = Environment.GetEnvironmentVariable(AspnetEnvVar) ?? string.Empty;
+ // ASPNETCORE_ENVIRONMENT env var takes precedence. Env should be either Development or Production.
+ var env = Environment.GetEnvironmentVariable(AspNetCoreEnvVar) ?? Environment.GetEnvironmentVariable(DotNetEnvVar) ?? string.Empty;
// Detect the folder containing configuration files
settingsDirectory ??= Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
diff --git a/service/Service/Auth/HttpAuthEndpointFilter.cs b/service/Service/HttpFilters/HttpAuthEndpointFilter.cs
similarity index 100%
rename from service/Service/Auth/HttpAuthEndpointFilter.cs
rename to service/Service/HttpFilters/HttpAuthEndpointFilter.cs
diff --git a/service/Service/Auth/HttpErrorsEndpointFilter.cs b/service/Service/HttpFilters/HttpErrorsEndpointFilter.cs
similarity index 100%
rename from service/Service/Auth/HttpErrorsEndpointFilter.cs
rename to service/Service/HttpFilters/HttpErrorsEndpointFilter.cs
diff --git a/service/Service/OpenAPI.cs b/service/Service/Internals/OpenAPI.cs
similarity index 100%
rename from service/Service/OpenAPI.cs
rename to service/Service/Internals/OpenAPI.cs
diff --git a/service/Service/KernelMemoryBuilderExtensions.cs b/service/Service/KernelMemoryBuilderExtensions.cs
deleted file mode 100644
index ca2f6e43e..000000000
--- a/service/Service/KernelMemoryBuilderExtensions.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using Microsoft.Extensions.Configuration;
-using Microsoft.KernelMemory.Service;
-
-// ReSharper disable once CheckNamespace - reduce number of "using" statements
-namespace Microsoft.KernelMemory;
-
-///
-/// Kernel Memory builder extensions for ASP.NET apps using settings in appsettings.json
-/// and using IConfiguration. The following methods allow to fully configure KM via
-/// IConfiguration, without having to change the code using KernelMemoryBuilder and recompile.
-///
-public static partial class KernelMemoryBuilderExtensions
-{
- ///
- /// Configure the builder using settings stored in the specified directory.
- /// If the directory is empty, use the current assembly folder
- ///
- /// KernelMemory builder instance
- /// Directory containing appsettings.json (incl. dev/prod)
- public static IKernelMemoryBuilder FromAppSettings(
- this IKernelMemoryBuilder builder,
- string? settingsDirectory = null)
- {
- return new ServiceConfiguration(settingsDirectory).PrepareBuilder(builder);
- }
-
- ///
- /// Configure the builder using settings from the given IConfiguration instance.
- ///
- /// KernelMemory builder instance
- /// KM configuration + Dependencies configuration
- public static IKernelMemoryBuilder FromIConfiguration(
- this IKernelMemoryBuilder builder,
- IConfiguration servicesConfiguration)
- {
- return new ServiceConfiguration(servicesConfiguration).PrepareBuilder(builder);
- }
-
- ///
- /// Configure the builder using settings from the given KernelMemoryConfig and IConfiguration instances.
- ///
- /// KernelMemory builder instance
- /// KM configuration
- /// Dependencies configuration, e.g. queue, embedding, storage, etc.
- public static IKernelMemoryBuilder FromMemoryConfiguration(
- this IKernelMemoryBuilder builder,
- KernelMemoryConfig memoryConfiguration,
- IConfiguration servicesConfiguration)
- {
- return new ServiceConfiguration(servicesConfiguration, memoryConfiguration).PrepareBuilder(builder);
- }
-}
diff --git a/service/Service/Program.cs b/service/Service/Program.cs
index f0db0bed2..4be864ef4 100644
--- a/service/Service/Program.cs
+++ b/service/Service/Program.cs
@@ -57,7 +57,7 @@ public static void Main(string[] args)
// *************************** CONFIG WIZARD ***************************
- // Run `dotnet run setup` to run this code and setup the service
+ // Run `dotnet run setup` to run this code and set up the service
if (new[] { "setup", "-setup", "config" }.Contains(args.FirstOrDefault(), StringComparer.OrdinalIgnoreCase))
{
InteractiveSetup.Main.InteractiveSetup(args.Skip(1).ToArray());
@@ -77,7 +77,8 @@ public static void Main(string[] args)
appBuilder.Services.AddApplicationInsightsTelemetry();
}
- appBuilder.Configuration.AddKMConfigurationSources();
+ // Add config files, user secretes, and env vars
+ appBuilder.Configuration.AddKernelMemoryConfigurationSources();
// Read KM settings, needed before building the app.
KernelMemoryConfig config = appBuilder.Configuration.GetSection("KernelMemory").Get()
@@ -90,7 +91,8 @@ public static void Main(string[] args)
// Internally build the memory client and make it available for dependency injection
appBuilder.AddKernelMemory(memoryBuilder =>
{
- memoryBuilder.FromAppSettings().WithoutDefaultHandlers();
+ // Prepare the builder with settings from config files
+ memoryBuilder.ConfigureDependencies(appBuilder.Configuration).WithoutDefaultHandlers();
// When using distributed orchestration, handlers are hosted in the current app and need to be con
asyncHandlersCount = AddHandlersAsHostedServices(config, memoryBuilder, appBuilder);