.NET: [BREAKING] Refactor providers to move common functionality to base (#3900)

* Move common functionality to provider base classes

Co-Authored-By: Copilot <175728472+Copilot@users.noreply.github.com>

* Address PR comments.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
westey
2026-02-16 19:02:47 +00:00
committed by GitHub
co-authored by Copilot
parent aab621f5eb
commit 54a67d96cd
23 changed files with 1593 additions and 482 deletions
@@ -86,27 +86,25 @@ namespace SampleApp
/// <summary>
/// Sample memory component that can remember a user's name and age.
/// </summary>
internal sealed class UserInfoMemory : AIContextProvider
internal sealed class UserInfoMemory : AIContextProvider<UserInfo>
{
private readonly IChatClient _chatClient;
private readonly Func<AgentSession?, UserInfo> _stateInitializer;
public UserInfoMemory(IChatClient chatClient, Func<AgentSession?, UserInfo>? stateInitializer = null)
: base(stateInitializer ?? (_ => new UserInfo()), null, null, null, null)
{
this._chatClient = chatClient;
this._stateInitializer = stateInitializer ?? (_ => new UserInfo());
}
public UserInfo GetUserInfo(AgentSession session)
=> session.StateBag.GetValue<UserInfo>(nameof(UserInfoMemory)) ?? new UserInfo();
=> this.GetOrInitializeState(session);
public void SetUserInfo(AgentSession session, UserInfo userInfo)
=> session.StateBag.SetValue(nameof(UserInfoMemory), userInfo);
=> this.SaveState(session, userInfo);
protected override async ValueTask InvokedCoreAsync(InvokedContext context, CancellationToken cancellationToken = default)
protected override async ValueTask StoreAIContextAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
var userInfo = context.Session?.StateBag.GetValue<UserInfo>(nameof(UserInfoMemory))
?? this._stateInitializer.Invoke(context.Session);
var userInfo = this.GetOrInitializeState(context.Session);
// 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 ((userInfo.UserName is null || userInfo.UserAge is null) && context.RequestMessages.Any(x => x.Role == ChatRole.User))
@@ -123,20 +121,14 @@ namespace SampleApp
userInfo.UserAge ??= result.Result.UserAge;
}
context.Session?.StateBag.SetValue(nameof(UserInfoMemory), userInfo);
this.SaveState(context.Session, userInfo);
}
protected override ValueTask<AIContext> InvokingCoreAsync(InvokingContext context, CancellationToken cancellationToken = default)
protected override ValueTask<AIContext> ProvideAIContextAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var inputContext = context.AIContext;
var userInfo = context.Session?.StateBag.GetValue<UserInfo>(nameof(UserInfoMemory))
?? this._stateInitializer.Invoke(context.Session);
var userInfo = this.GetOrInitializeState(context.Session);
StringBuilder instructions = new();
if (!string.IsNullOrEmpty(inputContext.Instructions))
{
instructions.AppendLine(inputContext.Instructions);
}
// If we don't already know the user's name and age, add instructions to ask for them, otherwise just provide what we have to the context.
instructions
@@ -151,9 +143,7 @@ namespace SampleApp
return new ValueTask<AIContext>(new AIContext
{
Instructions = instructions.ToString(),
Messages = inputContext.Messages,
Tools = inputContext.Tools
Instructions = instructions.ToString()
});
}
}