Uh oh!
There was an error while loading. Please reload this page.
.NET: [BREAKING] Replace Typed Base Providers with Composition - #3988
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors provider state management from an inheritance-based approach to a composition-based approach. The generic base classes ChatHistoryProvider<TState> and AIContextProvider<TState> are removed and replaced with a new ProviderSessionState<TState> helper class that providers use via composition.
Changes:
- Introduces
ProviderSessionState<TState>class to encapsulate state management logic for providers - Removes generic base classes
ChatHistoryProvider<TState>andAIContextProvider<TState>(breaking change) - Updates all provider implementations (TextSearchProvider, ChatHistoryMemoryProvider, WorkflowChatHistoryProvider, Mem0Provider, CosmosChatHistoryProvider, InMemoryChatHistoryProvider) to use composition
- Replaces generic base class tests with comprehensive tests for the new
ProviderSessionState<TState>class - Updates sample code to demonstrate the new composition pattern
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.Abstractions/ProviderSessionState{TState}.cs | New helper class that encapsulates state management logic for providers |
| dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider{TState}.cs | Removed generic base class - breaking change |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AIContextProvider{TState}.cs | Removed generic base class - breaking change |
| dotnet/src/Microsoft.Agents.AI.Abstractions/InMemoryChatHistoryProvider.cs | Updated to use composition with ProviderSessionState |
| dotnet/src/Microsoft.Agents.AI/TextSearchProvider.cs | Updated to use composition with ProviderSessionState |
| dotnet/src/Microsoft.Agents.AI/Memory/ChatHistoryMemoryProvider.cs | Updated to use composition with ProviderSessionState |
| dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowChatHistoryProvider.cs | Updated to use composition with ProviderSessionState |
| dotnet/src/Microsoft.Agents.AI.Mem0/Mem0Provider.cs | Updated to use composition with ProviderSessionState |
| dotnet/src/Microsoft.Agents.AI.CosmosNoSql/CosmosChatHistoryProvider.cs | Updated to use composition with ProviderSessionState |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/ProviderSessionStateTests.cs | New comprehensive test suite for ProviderSessionState class |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/ChatHistoryProviderTStateTests.cs | Removed tests for deleted generic base class |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AIContextProviderTStateTests.cs | Removed tests for deleted generic base class |
| dotnet/samples/GettingStarted/Agents/Agent_Step07_3rdPartyChatHistoryStorage/Program.cs | Updated sample to demonstrate composition pattern |
| dotnet/samples/GettingStarted/AgentWithMemory/AgentWithMemory_Step03_CustomMemory/Program.cs | Updated sample to demonstrate composition pattern |
Comments suppressed due to low confidence (1)
dotnet/src/Microsoft.Agents.AI.Abstractions/ChatHistoryProvider{TState}.cs:1
- This PR removes the public generic base classes
ChatHistoryProvider<TState>andAIContextProvider<TState>, which is a breaking change for users who may have derived from these classes. According to the contribution checklist, breaking changes should have "[BREAKING]" prefix in the PR title, but this PR title does not include it.
Uh oh!
There was an error while loading. Please reload this page.
Roger Barreto (rogerbarreto)
commented
Feb 17, 2026
Some observation I have, on maybe considering the interface approach. I prepared a quick AI investigation, if that make sense: One suggestion to consider: instead of (or on top of) the bare Looking at all 8 providers affected by this PR, the pattern is remarkably consistent — every single one does the same three things:
This consistency makes it a great candidate for a formalized interface contract: publicinterfaceIProviderSessionState<TState>whereTState:class{stringStateKey{get;}TStateGetOrInitializeState(AgentSession?session);voidSaveState(AgentSession?session,TStatestate);}
Providers would then implement the interface (delegating to the composed publicsealedclassInMemoryChatHistoryProvider:ChatHistoryProvider,IProviderSessionState<State>{privatereadonlyProviderSessionState<State>_sessionState;// Interface implementation (same code as today, just formalized)publicoverridestringStateKey=>_sessionState.StateKey;publicStateGetOrInitializeState(AgentSession?session)=>_sessionState.GetOrInitializeState(session);publicvoidSaveState(AgentSession?session,Statestate)=>_sessionState.SaveState(session,state);}Why this might be worth it:
|
westey (westey-m)
commented
Feb 17, 2026
The intention is for this functionality to be internal to the class, but interfaces make this explicitly public. Note that previously they were protected and now they are on a private property. It also means all provider implementers have to implement each of these methods, which is what I'm actually trying to avoid. The intention is to keep the provider implementations as lean as possible. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Motivation and Context
Switching from Inheritance to Composition to avoid code duplication
Description
Contribution Checklist