.NET: [BREAKING] Add ability to mark the source of Agent request messages and use that for filtering (#3540)

* Add ability to mark the source of Agent request messages and use that for filtering

* Add support for source, in addition to source type, and add unit tests for automatic stamping

* Address PR comments.

* Add merge fixes

* Address PR comments
This commit is contained in:
westey
2026-02-09 16:53:01 +00:00
committed by GitHub
Unverified
parent 390f93344c
commit ad0dac3c86
34 changed files with 1718 additions and 384 deletions
@@ -62,7 +62,7 @@ namespace SampleApp
List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.Name).ToList();
// Notify the session of the input and output messages.
var invokedContext = new ChatHistoryProvider.InvokedContext(this, session, messages, storeMessages)
var invokedContext = new ChatHistoryProvider.InvokedContext(this, session, messages)
{
ResponseMessages = responseMessages
};
@@ -94,7 +94,7 @@ namespace SampleApp
List<ChatMessage> responseMessages = CloneAndToUpperCase(messages, this.Name).ToList();
// Notify the session of the input and output messages.
var invokedContext = new ChatHistoryProvider.InvokedContext(this, session, messages, storeMessages)
var invokedContext = new ChatHistoryProvider.InvokedContext(this, session, messages)
{
ResponseMessages = responseMessages
};
@@ -104,7 +104,7 @@ namespace SampleApp
public UserInfo UserInfo { get; set; }
public override async ValueTask InvokedAsync(InvokedContext context, CancellationToken cancellationToken = default)
protected override async ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
// Try and extract the user name and age from the message if we don't have it already and it's a user message.
if ((this.UserInfo.UserName is null || this.UserInfo.UserAge is null) && context.RequestMessages.Any(x => x.Role == ChatRole.User))
@@ -122,7 +122,7 @@ namespace SampleApp
}
}
public override ValueTask<AIContext> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
StringBuilder instructions = new();
@@ -89,7 +89,7 @@ namespace SampleApp
public string? SessionDbKey { get; private set; }
public override async ValueTask<IEnumerable<ChatMessage>> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override async ValueTask<IEnumerable<ChatMessage>> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var collection = this._vectorStore.GetCollection<string, ChatHistoryItem>("ChatHistory");
await collection.EnsureCollectionExistsAsync(cancellationToken);
@@ -107,7 +107,7 @@ namespace SampleApp
return messages;
}
public override async ValueTask InvokedAsync(InvokedContext context, CancellationToken cancellationToken = default)
protected override async ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
// Don't store messages if the request failed.
if (context.InvokeException is not null)
@@ -122,7 +122,7 @@ namespace SampleApp
// Add both request and response messages to the store
// Optionally messages produced by the AIContextProvider can also be persisted (not shown).
var allNewMessages = context.RequestMessages.Concat(context.AIContextProviderMessages ?? []).Concat(context.ResponseMessages ?? []);
var allNewMessages = context.RequestMessages.Concat(context.ResponseMessages ?? []);
await collection.UpsertAsync(allNewMessages.Select(x => new ChatHistoryItem()
{
@@ -92,7 +92,7 @@ namespace SampleApp
}
}
public override ValueTask<AIContext> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
StringBuilder outputMessageBuilder = new();
outputMessageBuilder.AppendLine("Your todo list contains the following items:");
@@ -132,7 +132,7 @@ namespace SampleApp
/// </summary>
internal sealed class CalendarSearchAIContextProvider(Func<Task<string[]>> loadNextThreeCalendarEvents) : AIContextProvider
{
public override async ValueTask<AIContext> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override async ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var events = await loadNextThreeCalendarEvents();
@@ -179,7 +179,7 @@ namespace SampleApp
.ToList();
}
public override async ValueTask<AIContext> InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override async ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
// Invoke all the sub providers.
var tasks = this._providers.Select(provider => provider.InvokingAsync(context, cancellationToken).AsTask());