Skip to content

Commit 53f27c6

Browse files
authored
KnowPro.NET Language Search (#1760)
* Hooking up natural language search pipeline * Memory<T> updates * Standard mechanism for Noise terms * Refactor, Bug fixes
1 parent e57293a commit 53f27c6

25 files changed

+421
-41
lines changed

dotnet/typeagent/examples/examplesLib/CommandLine/NamedArgs.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace TypeAgent.ExamplesLib.CommandLine;
55

6-
public class NamedArgs
6+
public class NamedArgs : INamedArgs
77
{
88
string _argPrefix;
99
ParseResult _args;

dotnet/typeagent/examples/knowProConsole/MemoryCommands.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public IList<Command> GetCommands()
1919
SearchTermsDef(),
2020
MessagesDef(),
2121
AliasesDef(),
22+
SearchDef(),
2223
SearchRagDef()
2324
];
2425
}
@@ -108,6 +109,22 @@ private async Task AliasesAsync(ParseResult parseResult, CancellationToken cance
108109
}
109110
}
110111

112+
private Command SearchDef()
113+
{
114+
Command command = new("kpSearch")
115+
{
116+
Options.Arg<string>("query"),
117+
};
118+
command.SetAction(this.SearchAsync);
119+
return command;
120+
}
121+
private Task SearchAsync(ParseResult args, CancellationToken cancellationToken)
122+
{
123+
IConversation conversation = EnsureConversation();
124+
KnowProWriter.WriteError("Not impl");
125+
return Task.CompletedTask;
126+
}
127+
111128
private Command SearchRagDef()
112129
{
113130
Command command = new("kpSearchRag")

dotnet/typeagent/examples/knowProConsole/TestCommands.cs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public IList<Command> GetCommands()
2222
SearchMessagesTermsDef(),
2323
TestEmbeddingsDef(),
2424
SearchQueryTermsDef(),
25+
SearchLangDef(),
2526
KnowledgeDef(),
2627
BuildIndexDef(),
2728
];
@@ -295,7 +296,7 @@ private Command SearchQueryTermsDef()
295296

296297
private async Task SearchQueryTermsAsync(ParseResult args, CancellationToken cancellationToken)
297298
{
298-
// IConversation conversation = EnsureConversation();
299+
// IConversation conversation = EnsureConversation();
299300

300301
NamedArgs namedArgs = new NamedArgs(args);
301302
var query = namedArgs.Get("query");
@@ -309,6 +310,38 @@ private async Task SearchQueryTermsAsync(ParseResult args, CancellationToken can
309310
KnowProWriter.WriteJson(result);
310311
}
311312

313+
private Command SearchLangDef()
314+
{
315+
Command cmd = new("kpTestSearchLang")
316+
{
317+
Args.Arg<string>("query")
318+
};
319+
cmd.TreatUnmatchedTokensAsErrors = false;
320+
cmd.SetAction(this.SearchLangAsync);
321+
return cmd;
322+
}
323+
324+
private async Task SearchLangAsync(ParseResult args, CancellationToken cancellationToken)
325+
{
326+
IConversation conversation = EnsureConversation();
327+
328+
NamedArgs namedArgs = new NamedArgs(args);
329+
var query = namedArgs.Get("query");
330+
if (string.IsNullOrEmpty(query))
331+
{
332+
return;
333+
}
334+
if (conversation is IMemory memory)
335+
{
336+
IList<ConversationSearchResult> results = await memory.SearchAsync(query, null, null, null, cancellationToken);
337+
foreach(var result in results)
338+
{
339+
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, result);
340+
}
341+
}
342+
}
343+
344+
312345
private Command KnowledgeDef()
313346
{
314347
Command cmd = new("kpTestKnowledge")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace TypeAgent.Common;
5+
6+
public interface INamedArgs
7+
{
8+
string? Get(string name);
9+
10+
string GetRequired(string name);
11+
12+
T? Get<T>(string name);
13+
}

dotnet/typeagent/src/common/ListExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ public static int GetCount<T>(this IList<T>? list)
2121
return list is not null ? list.Count : 0;
2222
}
2323

24+
public static void AddRange<T>(this IList<T> list, IEnumerable<T> items)
25+
{
26+
ArgumentVerify.ThrowIfNull(items, nameof(items));
27+
28+
foreach (var item in items)
29+
{
30+
list.Add(item);
31+
}
32+
}
33+
2434
public static void Shift<T>(this IList<T> list)
2535
{
2636
if (list.Count > 0)

dotnet/typeagent/src/common/SetExtensions.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ namespace TypeAgent.Common;
55

66
public static class SetExtensions
77
{
8+
public static bool IsNullOrEmpty<T>(this ISet<T> set)
9+
{
10+
return set is null || set.Count == 0;
11+
}
12+
813
public static void LoadFromFile(this HashSet<string> set, string filePath)
914
{
1015
foreach(var line in File.ReadLines(filePath))
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace TypeAgent.ConversationMemory;
5+
6+
public interface IMemory
7+
{
8+
ValueTask<IList<ConversationSearchResult>> SearchAsync(
9+
string searchText,
10+
LangSearchOptions? options = null,
11+
LangSearchFilter? filter = null,
12+
LangSearchDebugContext? debugContext = null,
13+
CancellationToken cancellationToken = default
14+
);
15+
}

dotnet/typeagent/src/conversationMemory/Includes.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
global using System.Text.Json;
99
global using System.Text.Json.Serialization;
1010

11+
global using Microsoft.TypeChat;
12+
1113
global using TypeAgent.Common;
1214
global using TypeAgent.KnowPro;
1315
global using TypeAgent.KnowPro.Lang;

dotnet/typeagent/src/conversationMemory/Memory.cs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
namespace TypeAgent.ConversationMemory;
55

6-
public class Memory<TMessage> : Conversation<TMessage>
6+
public class Memory<TMessage> : Conversation<TMessage>, IMemory
77
where TMessage : class, IMessage, new()
88
{
99

@@ -18,4 +18,69 @@ public Memory(MemorySettings settings, IStorageProvider<TMessage> storageProvide
1818
public string Name { get; set; }
1919

2020
public IList<string> Tags { get; set; }
21+
22+
public NoiseText NoiseTerms { get; set; }
23+
24+
private bool UseScoped => Settings.UseScopedSearch is not null && Settings.UseScopedSearch.Value;
25+
26+
public async ValueTask<IList<ConversationSearchResult>> SearchAsync(
27+
string searchText,
28+
LangSearchOptions? options = null,
29+
LangSearchFilter? filter = null,
30+
LangSearchDebugContext? debugContext = null,
31+
CancellationToken cancellationToken = default
32+
)
33+
{
34+
options = AdjustLanguageSearchOptions(options);
35+
if (UseScoped)
36+
{
37+
// Using Structured Tags for scoping
38+
throw new NotImplementedException();
39+
}
40+
else
41+
{
42+
IConversation conversation = this;
43+
return await conversation.SearchAsync(
44+
searchText,
45+
Settings.QueryTranslator,
46+
options,
47+
filter,
48+
debugContext,
49+
cancellationToken
50+
).ConfigureAwait(false);
51+
}
52+
}
53+
54+
public virtual IList<PromptSection>? GetModelInstructions()
55+
{
56+
return null;
57+
}
58+
59+
private LangSearchOptions AdjustLanguageSearchOptions(LangSearchOptions? options)
60+
{
61+
// Clone options so we can edit them
62+
options = options is null
63+
? LangSearchOptions.CreateTypical()
64+
: new LangSearchOptions(options);
65+
66+
var instructions = GetModelInstructions();
67+
if (!instructions.IsNullOrEmpty())
68+
{
69+
if (!options.ModelInstructions.IsNullOrEmpty())
70+
{
71+
options.ModelInstructions.AddRange(instructions);
72+
}
73+
else
74+
{
75+
options.ModelInstructions = instructions;
76+
}
77+
}
78+
// Filter noise terms
79+
options.CompilerSettings.TermFilter = (t) =>
80+
{
81+
return NoiseTerms.IsNullOrEmpty() || !NoiseTerms.Contains(t);
82+
};
83+
84+
return options;
85+
}
2186
}

dotnet/typeagent/src/conversationMemory/MemorySettings.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public MemorySettings(
1616
ConversationSettings conversationSettings,
1717
int embeddingCacheSize = 64,
1818
IChatModel? chatModel = null,
19-
ITextEmbeddingModel? embeddingModel = null
19+
ITextEmbeddingModel? embeddingModel = null,
20+
NoiseText? noiseTerms = null
2021
)
2122
{
2223
ArgumentVerify.ThrowIfNull(conversationSettings, nameof(conversationSettings));
@@ -26,6 +27,12 @@ public MemorySettings(
2627
EmbeddingModel = new TextEmbeddingModelWithCache(embeddingCacheSize);
2728
QueryTranslator = new SearchQueryTranslator(ChatModel);
2829
KnowledgeExtractor = new KnowledgeExtractor(ChatModel);
30+
31+
NoiseTerms = noiseTerms ?? new NoiseText(
32+
typeof(MemorySettings).Assembly,
33+
"TypeAgent.ConversationMemory.noiseTerms.txt"
34+
);
35+
2936
}
3037

3138
public IChatModel ChatModel { get; }
@@ -37,4 +44,9 @@ public MemorySettings(
3744
public ISearchQueryTranslator? QueryTranslator { get; set; }
3845

3946
public IKnowledgeExtractor KnowledgeExtractor { get; set; }
47+
48+
public NoiseText? NoiseTerms { get; set; }
49+
50+
// Setting this to true leverages Structured Tags
51+
public bool? UseScopedSearch { get; set; } = null;
4052
}

0 commit comments

Comments
 (0)