22
33using System ;
44using System . Collections . Generic ;
5+ using System . Linq ;
56using Microsoft . Extensions . DependencyInjection ;
67using Microsoft . KernelMemory . AI ;
78using Microsoft . KernelMemory . AppBuilders ;
@@ -116,16 +117,16 @@ public KernelMemoryBuilder(IServiceCollection? hostServiceCollection = null)
116117 }
117118
118119 ///<inheritdoc />
119- public IKernelMemory Build ( )
120+ public IKernelMemory Build ( KernelMemoryBuilderBuildOptions ? options = null )
120121 {
121122 var type = this . GetBuildType ( ) ;
122123 switch ( type )
123124 {
124125 case ClientTypes . SyncServerless :
125- return this . BuildServerlessClient ( ) ;
126+ return this . BuildServerlessClient ( options ) ;
126127
127128 case ClientTypes . AsyncService :
128- return this . BuildAsyncClient ( ) ;
129+ return this . BuildAsyncClient ( options ) ;
129130
130131 case ClientTypes . Undefined :
131132 throw new KernelMemoryException ( "Missing dependencies or insufficient configuration provided. " +
@@ -138,11 +139,11 @@ public IKernelMemory Build()
138139 }
139140
140141 ///<inheritdoc />
141- public T Build < T > ( ) where T : class , IKernelMemory
142+ public T Build < T > ( KernelMemoryBuilderBuildOptions ? options = null ) where T : class , IKernelMemory
142143 {
143144 if ( typeof ( T ) == typeof ( MemoryServerless ) )
144145 {
145- if ( this . BuildServerlessClient ( ) is not T result )
146+ if ( this . BuildServerlessClient ( options ) is not T result )
146147 {
147148 throw new InvalidOperationException ( $ "Unable to instantiate '{ typeof ( MemoryServerless ) } '. The instance is NULL.") ;
148149 }
@@ -152,7 +153,7 @@ public T Build<T>() where T : class, IKernelMemory
152153
153154 if ( typeof ( T ) == typeof ( MemoryService ) )
154155 {
155- if ( this . BuildAsyncClient ( ) is not T result )
156+ if ( this . BuildAsyncClient ( options ) is not T result )
156157 {
157158 throw new InvalidOperationException ( $ "Unable to instantiate '{ typeof ( MemoryService ) } '. The instance is NULL.") ;
158159 }
@@ -226,7 +227,7 @@ private static void CopyServiceCollection(
226227 }
227228 }
228229
229- private MemoryServerless BuildServerlessClient ( )
230+ private MemoryServerless BuildServerlessClient ( KernelMemoryBuilderBuildOptions ? options )
230231 {
231232 try
232233 {
@@ -240,6 +241,7 @@ private MemoryServerless BuildServerlessClient()
240241
241242 // Recreate the service provider, in order to have the latest dependencies just configured
242243 serviceProvider = this . _memoryServiceCollection . BuildServiceProvider ( ) ;
244+ this . CheckStoragePersistence ( options , serviceProvider ) ;
243245 var memoryClientInstance = ActivatorUtilities . CreateInstance < MemoryServerless > ( serviceProvider ) ;
244246
245247 // Load handlers in the memory client
@@ -257,7 +259,7 @@ private MemoryServerless BuildServerlessClient()
257259 }
258260 }
259261
260- private MemoryService BuildAsyncClient ( )
262+ private MemoryService BuildAsyncClient ( KernelMemoryBuilderBuildOptions ? options )
261263 {
262264 // Add handlers to DI service collection
263265 if ( this . _useDefaultHandlers )
@@ -282,9 +284,44 @@ private MemoryService BuildAsyncClient()
282284
283285 // Recreate the service provider, in order to have the latest dependencies just configured
284286 serviceProvider = this . _memoryServiceCollection . BuildServiceProvider ( ) ;
287+ this . CheckStoragePersistence ( options , serviceProvider ) ;
285288 return ActivatorUtilities . CreateInstance < MemoryService > ( serviceProvider ) ;
286289 }
287290
291+ private void CheckStoragePersistence ( KernelMemoryBuilderBuildOptions ? options , ServiceProvider serviceProvider )
292+ {
293+ if ( options is { AllowMixingVolatileAndPersistentData : true } ) { return ; }
294+
295+ ServiceDescriptor docStoreType = this . _memoryServiceCollection . Last < ServiceDescriptor > ( x => x . ServiceType == typeof ( IDocumentStorage ) ) ;
296+ ServiceDescriptor memStoreType = this . _memoryServiceCollection . Last < ServiceDescriptor > ( x => x . ServiceType == typeof ( IMemoryDb ) ) ;
297+ SimpleFileStorageConfig ? simpleFileStorageConfig = serviceProvider . GetService < SimpleFileStorageConfig > ( ) ;
298+ SimpleVectorDbConfig ? simpleVectorDbConfig = serviceProvider . GetService < SimpleVectorDbConfig > ( ) ;
299+ SimpleTextDbConfig ? simpleTextDbConfig = serviceProvider . GetService < SimpleTextDbConfig > ( ) ;
300+
301+ bool persistentDocStore = docStoreType . ImplementationType != typeof ( SimpleFileStorage ) || simpleFileStorageConfig ? . StorageType == FileSystemTypes . Disk ;
302+ bool persistentMemStore = memStoreType . ImplementationType != typeof ( SimpleVectorDb ) && memStoreType . ImplementationType != typeof ( SimpleTextDb )
303+ || ( memStoreType . ImplementationType == typeof ( SimpleVectorDb ) && simpleVectorDbConfig ? . StorageType == FileSystemTypes . Disk )
304+ || ( memStoreType . ImplementationType == typeof ( SimpleTextDb ) && simpleTextDbConfig ? . StorageType == FileSystemTypes . Disk ) ;
305+
306+ if ( persistentMemStore && ! persistentDocStore )
307+ {
308+ throw new ConfigurationException (
309+ "Using a persistent vector store with a volatile document store will lead to duplicate memory records over multiple executions. " +
310+ "Set up Kernel Memory to use a persistent document store like Azure Blobs, AWS S3, SimpleFileStorage on disk, etc. " +
311+ $ "Otherwise, use { nameof ( KernelMemoryBuilderBuildOptions ) } .{ nameof ( KernelMemoryBuilderBuildOptions . AllowMixingVolatileAndPersistentData ) } " +
312+ "to suppress this exception. " ) ;
313+ }
314+
315+ if ( persistentDocStore && ! persistentMemStore )
316+ {
317+ throw new ConfigurationException (
318+ "Using a volatile vector store with a persistent document store will lead to missing memory records over multiple executions. " +
319+ "Set up Kernel Memory to use a persistent vector store like Azure AI Search, Postgres, Qdrant, SimpleVectorDb on disk, etc. " +
320+ $ "Otherwise, use { nameof ( KernelMemoryBuilderBuildOptions ) } .{ nameof ( KernelMemoryBuilderBuildOptions . AllowMixingVolatileAndPersistentData ) } " +
321+ "to suppress this exception. " ) ;
322+ }
323+ }
324+
288325 private KernelMemoryBuilder CompleteServerlessClient ( ServiceProvider serviceProvider )
289326 {
290327 this . UseDefaultSearchClientIfNecessary ( serviceProvider ) ;
0 commit comments