66using System . Threading ;
77using System . Threading . Tasks ;
88using Microsoft . Extensions . Logging ;
9- using Microsoft . KernelMemory . Plugin ;
9+ using Microsoft . KernelMemory . Plugin . Internals ;
1010using Microsoft . SemanticKernel ;
1111
1212#pragma warning disable IDE0130 // reduce number of "using" statements
@@ -65,10 +65,9 @@ public class MemoryPlugin
6565 public const string MinRelevanceParam = "minRelevance" ;
6666
6767 /// <summary>
68- /// Default document ID. When null, a new value is generated every time some information
69- /// is saved into memory.
68+ /// Name of the input variable used to specify the maximum number of items to return.
7069 /// </summary>
71- private const string ? DefaultDocumentId = null ;
70+ public const string LimitParam = "limit" ;
7271
7372 /// <summary>
7473 /// Default index where to store and retrieve memory from. When null the service
@@ -100,7 +99,7 @@ public class MemoryPlugin
10099 /// <summary>
101100 /// Max time to wait for ingestion completion when <see cref="_waitForIngestionToComplete"/> is set to True.
102101 /// </summary>
103- private TimeSpan _maxIngestionWait = TimeSpan . FromSeconds ( 15 ) ;
102+ private readonly TimeSpan _maxIngestionWait = TimeSpan . FromSeconds ( 15 ) ;
104103
105104 /// <summary>
106105 /// Client to memory read/write. This is usually an instance of MemoryWebClient
@@ -135,6 +134,7 @@ public MemoryPlugin(
135134 defaultIngestionSteps ,
136135 waitForIngestionToComplete )
137136 {
137+ // TODO: add api key header name
138138 }
139139
140140 /// <summary>
@@ -186,7 +186,7 @@ public MemoryPlugin(
186186 /// </summary>
187187 /// <example>
188188 /// SKContext.Variables["input"] = "the capital of France is Paris"
189- /// {{memory.importText $input }}
189+ /// {{memory.save $input }}
190190 /// </example>
191191 /// <example>
192192 /// SKContext.Variables["input"] = "the capital of France is Paris"
@@ -199,10 +199,9 @@ public MemoryPlugin(
199199 /// {{memory.save $input }}
200200 /// </example>
201201 /// <returns>Document ID</returns>
202- [ SKFunction , Description ( "Store in memory the information extracted from the given text" ) ]
202+ [ SKFunction , Description ( "Store in memory the given text" ) ]
203203 public async Task < string > SaveAsync (
204- [ Description ( "The information to save" ) ]
205- string input ,
204+ [ Description ( "The text to save" ) ] string input ,
206205 [ SKName ( DocumentIdParam ) , Description ( "The document ID associated with the information to save" ) , DefaultValue ( null ) ]
207206 string ? documentId = null ,
208207 [ SKName ( IndexParam ) , Description ( "Memories index associated with the information to save" ) , DefaultValue ( null ) ]
@@ -214,6 +213,8 @@ public async Task<string> SaveAsync(
214213 ILoggerFactory ? loggerFactory = null ,
215214 CancellationToken cancellationToken = default )
216215 {
216+ // TODO: check if one has to use "input" or "documentId"
217+
217218 Task < string > Do ( CancellationToken token )
218219 {
219220 return this . _memory . ImportTextAsync (
@@ -228,16 +229,38 @@ Task<string> Do(CancellationToken token)
228229 if ( this . _waitForIngestionToComplete )
229230 {
230231 using var cs = new CancellationTokenSource ( this . _maxIngestionWait ) ;
231- return await Do ( cs . Token ) . ConfigureAwait ( false ) ;
232+ string id = await Do ( cs . Token ) . ConfigureAwait ( false ) ;
233+ // TODO CHECK IF DOC HAS BEEN IMPORTED
234+ return id ;
232235 }
233236
234237 return await Do ( cancellationToken ) . ConfigureAwait ( false ) ;
235238 }
236239
240+ /// <summary>
241+ /// Store a file content in long term memory.
242+ ///
243+ /// Usage from prompts: '{{memory.saveFile ...}}'
244+ /// </summary>
245+ /// <example>
246+ /// SKContext.Variables["input"] = "C:\Documents\presentation.pptx"
247+ /// {{memory.saveFile $input }}
248+ /// </example>
249+ /// <example>
250+ /// SKContext.Variables["input"] = "C:\Documents\presentation.pptx"
251+ /// SKContext.Variables[MemoryPlugin.IndexParam] = "work"
252+ /// {{memory.saveFile $input }}
253+ /// </example>
254+ /// <example>
255+ /// SKContext.Variables["input"] = "C:\Documents\presentation.pptx"
256+ /// SKContext.Variables[MemoryPlugin.DocumentIdParam] = "presentation001"
257+ /// {{memory.saveFile $input }}
258+ /// </example>
259+ /// <returns>Document ID</returns>
237260 [ SKFunction , Description ( "Store in memory the information extracted from a file" ) ]
238261 public async Task < string > SaveFileAsync (
239262 [ Description ( "Path of the file to save in memory" ) ]
240- string input ,
263+ string filePath ,
241264 [ SKName ( DocumentIdParam ) , Description ( "The document ID associated with the information to save" ) , DefaultValue ( null ) ]
242265 string ? documentId = null ,
243266 [ SKName ( IndexParam ) , Description ( "Memories index associated with the information to save" ) , DefaultValue ( null ) ]
@@ -252,34 +275,75 @@ public async Task<string> SaveFileAsync(
252275 Task < string > Do ( CancellationToken token )
253276 {
254277 return this . _memory . ImportDocumentAsync (
255- filePath : input ,
278+ filePath : filePath ,
256279 documentId : documentId ,
257- index : index ?? this . _defaultIndex ,
258280 tags : tags ?? this . _defaultIngestionTags ,
281+ index : index ?? this . _defaultIndex ,
259282 steps : steps ?? this . _defaultIngestionSteps ,
260283 cancellationToken : token ) ;
261284 }
262285
263286 if ( this . _waitForIngestionToComplete )
264287 {
265288 using var cs = new CancellationTokenSource ( this . _maxIngestionWait ) ;
266- return await Do ( cs . Token ) . ConfigureAwait ( false ) ;
289+ string id = await Do ( cs . Token ) . ConfigureAwait ( false ) ;
290+ // TODO CHECK IF DOC HAS BEEN IMPORTED
291+ return id ;
267292 }
268293
269294 return await Do ( cancellationToken ) . ConfigureAwait ( false ) ;
270295 }
271296
272297 [ SKFunction , Description ( "Store in memory the information extracted from a web page" ) ]
273- public async Task < string > SaveWebPageAsync ( )
298+ public async Task < string > SaveWebPageAsync (
299+ [ Description ( "Complete URL of the web page to save" ) ]
300+ string url ,
301+ [ SKName ( DocumentIdParam ) , Description ( "The document ID associated with the information to save" ) , DefaultValue ( null ) ]
302+ string ? documentId = null ,
303+ [ SKName ( IndexParam ) , Description ( "Memories index associated with the information to save" ) , DefaultValue ( null ) ]
304+ string ? index = null ,
305+ [ SKName ( TagsParam ) , Description ( "Memories index associated with the information to save" ) , DefaultValue ( null ) ]
306+ TagCollectionWrapper ? tags = null ,
307+ [ SKName ( StepsParam ) , Description ( "Steps to parse the information and store in memory" ) , DefaultValue ( null ) ]
308+ ListOfStringsWrapper ? steps = null ,
309+ ILoggerFactory ? loggerFactory = null ,
310+ CancellationToken cancellationToken = default )
274311 {
275- await Task . Delay ( 0 ) . ConfigureAwait ( false ) ;
276- throw new NotImplementedException ( ) ;
312+ Task < string > Do ( CancellationToken token )
313+ {
314+ return this . _memory . ImportWebPageAsync (
315+ url : url ,
316+ documentId : documentId ,
317+ tags : tags ?? this . _defaultIngestionTags ,
318+ index : index ?? this . _defaultIndex ,
319+ steps : steps ?? this . _defaultIngestionSteps ,
320+ cancellationToken : token ) ;
321+ }
322+
323+ if ( this . _waitForIngestionToComplete )
324+ {
325+ using var cs = new CancellationTokenSource ( this . _maxIngestionWait ) ;
326+ string id = await Do ( cs . Token ) . ConfigureAwait ( false ) ;
327+ // TODO CHECK IF DOC HAS BEEN IMPORTED
328+ return id ;
329+ }
330+
331+ return await Do ( cancellationToken ) . ConfigureAwait ( false ) ;
277332 }
278333
279334 [ SKFunction , Description ( "Return up to N memories related to the input text" ) ]
280- public async Task < string > SearchAsync ( )
335+ public async Task < string > SearchAsync (
336+ [ Description ( "The text to search" ) ] string query ,
337+ [ SKName ( IndexParam ) , Description ( "Memories index to search for information" ) , DefaultValue ( "" ) ]
338+ string ? index = null ,
339+ [ SKName ( MinRelevanceParam ) , Description ( "Minimum relevance of the memories to return" ) , DefaultValue ( 0d ) ]
340+ double minRelevance = 0 ,
341+ [ SKName ( LimitParam ) , Description ( "Maximum number of memories to return" ) , DefaultValue ( 0d ) ]
342+ int limit = 10 ,
343+ CancellationToken cancellationToken = default )
281344 {
282- await Task . Delay ( 0 ) . ConfigureAwait ( false ) ;
345+ await Task . Delay ( 0 , cancellationToken ) . ConfigureAwait ( false ) ;
346+ // TODO check the old Semantic Memory
283347 throw new NotImplementedException ( ) ;
284348 }
285349
@@ -288,43 +352,43 @@ public async Task<string> SearchAsync()
288352 ///
289353 /// Usage from prompts: '{{memory.ask ...}}'
290354 /// </summary>
291- /// <param name="input">The question to answer</param>
292355 /// <returns>The answer returned by the memory.</returns>
293356 [ SKFunction , Description ( "Use long term memory to answer a quesion" ) ]
294357 public async Task < string > AskAsync (
295358 [ Description ( "The question to answer" ) ]
296- string input ,
359+ string question ,
297360 [ SKName ( IndexParam ) , Description ( "Memories index to search for answers" ) , DefaultValue ( "" ) ]
298361 string ? index = null ,
299- [ SKName ( MinRelevanceParam ) , Description ( "Memories index to search for answers " ) , DefaultValue ( 0d ) ]
362+ [ SKName ( MinRelevanceParam ) , Description ( "Minimum relevance of the sources to consider " ) , DefaultValue ( 0d ) ]
300363 double minRelevance = 0 ,
301364 ILoggerFactory ? loggerFactory = null ,
302365 CancellationToken cancellationToken = default )
303366 {
304- Task < MemoryAnswer > Do ( CancellationToken token )
305- {
306- return this . _memory . AskAsync ( question : input , cancellationToken : token ) ;
307- }
308-
309- MemoryAnswer ? answer ;
310- if ( this . _waitForIngestionToComplete )
311- {
312- // using var cs = new CancellationTokenSource(this._maxIngestionWait);
313- using var cs = new CancellationTokenSource ( TimeSpan . FromMilliseconds ( 1 ) ) ;
314- answer = await Do ( cs . Token ) . ConfigureAwait ( false ) ;
315- }
316- else
317- {
318- answer = await Do ( cancellationToken ) . ConfigureAwait ( false ) ;
319- }
320-
321- return answer ? . Result ?? string . Empty ;
367+ // TODO: support filters
368+ MemoryAnswer answer = await this . _memory . AskAsync (
369+ question : question ,
370+ index : index ?? this . _defaultIndex ,
371+ minRelevance : minRelevance ,
372+ cancellationToken : cancellationToken ) . ConfigureAwait ( false ) ;
373+ return answer . Result ;
322374 }
323375
324- [ SKFunction , Description ( "Remobe from memory all the information extracted from the given document ID" ) ]
325- public async Task < string > DeleteAsync ( )
376+ /// <summary>
377+ /// Remove from memory all the information extracted from the given document ID
378+ ///
379+ /// Usage from prompts: '{{memory.delete ...}}'
380+ /// </summary>
381+ [ SKFunction , Description ( "Remove from memory all the information extracted from the given document ID" ) ]
382+ public Task DeleteAsync (
383+ [ Description ( "The document to delete" ) ]
384+ string documentId ,
385+ [ SKName ( IndexParam ) , Description ( "Memories index where the document is stored" ) , DefaultValue ( "" ) ]
386+ string ? index = null ,
387+ CancellationToken cancellationToken = default )
326388 {
327- await Task . Delay ( 0 ) . ConfigureAwait ( false ) ;
328- throw new NotImplementedException ( ) ;
389+ return this . _memory . DeleteDocumentAsync (
390+ documentId : documentId ,
391+ index : index ?? this . _defaultIndex ,
392+ cancellationToken : cancellationToken ) ;
329393 }
330394}
0 commit comments