Replace Typed Base Providers with Composition (#3988)

This commit is contained in:
westey
2026-02-17 15:06:43 +00:00
committed by GitHub
Unverified
parent 8015e00f56
commit cd4e36ebf7
14 changed files with 381 additions and 615 deletions
@@ -86,25 +86,31 @@ namespace SampleApp
/// <summary>
/// Sample memory component that can remember a user's name and age.
/// </summary>
internal sealed class UserInfoMemory : AIContextProvider<UserInfo>
internal sealed class UserInfoMemory : AIContextProvider
{
private readonly ProviderSessionState<UserInfo> _sessionState;
private readonly IChatClient _chatClient;
public UserInfoMemory(IChatClient chatClient, Func<AgentSession?, UserInfo>? stateInitializer = null)
: base(stateInitializer ?? (_ => new UserInfo()), null, null, null, null)
: base(null, null)
{
this._sessionState = new ProviderSessionState<UserInfo>(
stateInitializer ?? (_ => new UserInfo()),
this.GetType().Name);
this._chatClient = chatClient;
}
public override string StateKey => this._sessionState.StateKey;
public UserInfo GetUserInfo(AgentSession session)
=> this.GetOrInitializeState(session);
=> this._sessionState.GetOrInitializeState(session);
public void SetUserInfo(AgentSession session, UserInfo userInfo)
=> this.SaveState(session, userInfo);
=> this._sessionState.SaveState(session, userInfo);
protected override async ValueTask StoreAIContextAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
var userInfo = this.GetOrInitializeState(context.Session);
var userInfo = this._sessionState.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))
@@ -121,12 +127,12 @@ namespace SampleApp
userInfo.UserAge ??= result.Result.UserAge;
}
this.SaveState(context.Session, userInfo);
this._sessionState.SaveState(context.Session, userInfo);
}
protected override ValueTask<AIContext> ProvideAIContextAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var userInfo = this.GetOrInitializeState(context.Session);
var userInfo = this._sessionState.GetOrInitializeState(context.Session);
StringBuilder instructions = new();
@@ -76,25 +76,31 @@ namespace SampleApp
/// State (the session DB key) is stored in the <see cref="AgentSession.StateBag"/> so it roundtrips
/// automatically with session serialization.
/// </summary>
internal sealed class VectorChatHistoryProvider : ChatHistoryProvider<VectorChatHistoryProvider.State>
internal sealed class VectorChatHistoryProvider : ChatHistoryProvider
{
private readonly ProviderSessionState<State> _sessionState;
private readonly VectorStore _vectorStore;
public VectorChatHistoryProvider(
VectorStore vectorStore,
Func<AgentSession?, State>? stateInitializer = null,
string? stateKey = null)
: base(stateInitializer: stateInitializer ?? (_ => new State(Guid.NewGuid().ToString("N"))), stateKey: stateKey, jsonSerializerOptions: null, provideOutputMessageFilter: null, storeInputMessageFilter: null)
: base(provideOutputMessageFilter: null, storeInputMessageFilter: null)
{
this._sessionState = new ProviderSessionState<State>(
stateInitializer ?? (_ => new State(Guid.NewGuid().ToString("N"))),
stateKey ?? this.GetType().Name);
this._vectorStore = vectorStore ?? throw new ArgumentNullException(nameof(vectorStore));
}
public override string StateKey => this._sessionState.StateKey;
public string GetSessionDbKey(AgentSession session)
=> this.GetOrInitializeState(session).SessionDbKey;
=> this._sessionState.GetOrInitializeState(session).SessionDbKey;
protected override async ValueTask<IEnumerable<ChatMessage>> ProvideChatHistoryAsync(InvokingContext context, CancellationToken cancellationToken = default)
{
var state = this.GetOrInitializeState(context.Session);
var state = this._sessionState.GetOrInitializeState(context.Session);
var collection = this._vectorStore.GetCollection<string, ChatHistoryItem>("ChatHistory");
await collection.EnsureCollectionExistsAsync(cancellationToken);
@@ -112,7 +118,7 @@ namespace SampleApp
protected override async ValueTask StoreChatHistoryAsync(InvokedContext context, CancellationToken cancellationToken = default)
{
var state = this.GetOrInitializeState(context.Session);
var state = this._sessionState.GetOrInitializeState(context.Session);
var collection = this._vectorStore.GetCollection<string, ChatHistoryItem>("ChatHistory");
await collection.EnsureCollectionExistsAsync(cancellationToken);