Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 10, 2025

Motivation and Context

This change introduces a delegation pattern in the AIAgent class to enable adding common pre/post-processing logic in the base class without requiring all implementations to duplicate it. This follows the Template Method pattern, allowing future base class enhancements (telemetry, validation, middleware) without breaking existing implementations.

Description

Makes RunAsync and RunStreamingAsync non-virtual methods that delegate to new protected abstract RunCoreAsync and RunCoreStreamingAsync methods.

Changes

  • AIAgent.cs: Made RunAsync and RunStreamingAsync non-virtual (sealed from overriding); added protected abstract RunCoreAsync and RunCoreStreamingAsync
  • DelegatingAIAgent.cs: Override core methods instead of public methods to maintain delegation chain
  • All AIAgent implementations: Changed from overriding public methods to overriding protected core methods
  • Test files: Updated to mock protected core methods using Moq's Protected() API

Pattern

// Before
public abstract class AIAgent 
{
    public abstract Task<AgentRunResponse> RunAsync(...);
}

public class MyAgent : AIAgent
{
    public override Task<AgentRunResponse> RunAsync(...) { /* implementation */ }
}

// After
public abstract class AIAgent 
{
    public Task<AgentRunResponse> RunAsync(...) => this.RunCoreAsync(...);
    protected abstract Task<AgentRunResponse> RunCoreAsync(...);
}

public class MyAgent : AIAgent
{
    protected override Task<AgentRunResponse> RunCoreAsync(...) { /* implementation */ }
}

Key aspects:

  • RunAsync and RunStreamingAsync are now non-virtual methods (cannot be overridden), ensuring a consistent public API while allowing extensibility through the protected core methods
  • Classes that override the core methods and call the base implementation must use base.RunCoreAsync and base.RunCoreStreamingAsync

Contribute to: #2542

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.
Original prompt

Make the abstract RunAsync and RunStreaming methods of the AIAgent class non-abstract. Add identical abstract RunCoreAsync and RunCoreStreaming methods to the class, and modify the original methods to delegate to the core ones.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits December 10, 2025 13:05
…dd RunCoreAsync and RunCoreStreamingAsync

Co-authored-by: SergeyMenshykh <[email protected]>
Copilot AI changed the title [WIP] Make RunAsync and RunStreaming methods non-abstract Introduce RunCoreAsync/RunCoreStreamingAsync delegation pattern in AIAgent Dec 10, 2025
Copilot AI requested a review from SergeyMenshykh December 10, 2025 13:18
@markwallace-microsoft markwallace-microsoft added .NET workflows Related to Workflows in agent-framework labels Dec 10, 2025
@github-actions github-actions bot changed the title Introduce RunCoreAsync/RunCoreStreamingAsync delegation pattern in AIAgent .NET: Introduce RunCoreAsync/RunCoreStreamingAsync delegation pattern in AIAgent Dec 10, 2025
@SergeyMenshykh
Copy link
Member

@copilot Neither RunAsync nor RunStreamingAsync should be virtual

Copy link
Contributor Author

Copilot AI commented Dec 10, 2025

@copilot Neither RunAsync nor RunStreamingAsync should be virtual

Updated in commit cef4fa8. Both RunAsync and RunStreamingAsync are now non-virtual methods that delegate to the protected abstract RunCoreAsync and RunCoreStreamingAsync methods.

@SergeyMenshykh SergeyMenshykh marked this pull request as ready for review December 11, 2025 13:29
Copilot AI review requested due to automatic review settings December 11, 2025 13:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a breaking change that implements the Template Method pattern in the AIAgent class, enabling future extensibility while maintaining backward compatibility for consumers. The change makes RunAsync and RunStreamingAsync non-virtual public methods that delegate to new protected abstract methods RunCoreAsync and RunCoreStreamingAsync, allowing the base class to add common pre/post-processing logic in the future without breaking existing implementations.

Key Changes

  • AIAgent base class: Added delegation from public RunAsync/RunStreamingAsync to protected abstract RunCoreAsync/RunCoreStreamingAsync methods
  • All agent implementations: Updated to override the new protected core methods instead of public methods
  • Test infrastructure: Modified all unit tests to use Moq's Protected() API for mocking and verifying protected method calls

Reviewed changes

Copilot reviewed 44 out of 44 changed files in this pull request and generated no comments.

Show a summary per file
File Description
dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgent.cs Added public wrapper methods that delegate to new protected abstract RunCoreAsync and RunCoreStreamingAsync methods
dotnet/src/Microsoft.Agents.AI.Abstractions/DelegatingAIAgent.cs Changed to override protected core methods while calling public methods on inner agent
dotnet/src/Microsoft.Agents.AI/AnonymousDelegatingAIAgent.cs Updated to override protected core methods; maintains delegation to public methods on inner agent
dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs Changed method overrides from public to protected core methods
dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs Updated to override protected core methods while delegating to public methods on inner agent
dotnet/src/Microsoft.Agents.AI/LoggingAgent.cs Changed to override protected core methods with calls to base.RunCoreAsync/RunCoreStreamingAsync
dotnet/src/Microsoft.Agents.AI/OpenTelemetryAgent.cs Updated to override protected core methods
dotnet/src/Microsoft.Agents.AI/PurviewAgent.cs Changed method overrides from public to protected core methods
dotnet/src/Microsoft.Agents.AI.A2A/A2AAgent.cs Updated to override protected core methods
dotnet/src/Microsoft.Agents.AI.CopilotStudio/CopilotStudioAgent.cs Changed method overrides from public to protected core methods
dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgent.cs Updated to override protected core methods
dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgentProxy.cs Changed method overrides from public to protected core methods
dotnet/src/Microsoft.Agents.AI.DurableTask/EntityAgentWrapper.cs Updated to override protected core methods with calls to base.RunCoreAsync/RunCoreStreamingAsync
dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowHostAgent.cs Changed method overrides from public to protected core methods
dotnet/samples/M365Agent/Agents/WeatherForecastAgent.cs Updated sample to override protected core methods with base.RunCoreAsync call
dotnet/samples/GettingStarted/AgentWithOpenAI/Agent_OpenAI_Step03_CreateFromChatClient/OpenAIChatClientAgent.cs Changed sealed override from public to protected core methods
dotnet/samples/GettingStarted/AgentWithOpenAI/Agent_OpenAI_Step04_CreateFromOpenAIResponseClient/OpenAIResponseClientAgent.cs Updated sealed override to protected core methods with base.RunCoreAsync/RunCoreStreamingAsync calls
dotnet/samples/GettingStarted/AgentProviders/Agent_With_CustomImplementation/Program.cs Changed custom agent implementation to override protected core methods
dotnet/samples/GettingStarted/AGUI/Step04_HumanInLoop/Client/ServerFunctionApprovalClientAgent.cs Updated to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/GettingStarted/AGUI/Step04_HumanInLoop/Server/ServerFunctionApprovalServerAgent.cs Changed to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/GettingStarted/AGUI/Step05_StateManagement/Client/StatefulAgent.cs Updated to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/GettingStarted/AGUI/Step05_StateManagement/Server/SharedStateAgent.cs Changed to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/AGUIClientServer/AGUIDojoServer/AgenticUI/AgenticUIAgent.cs Updated to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/AGUIClientServer/AGUIDojoServer/PredictiveStateUpdates/PredictiveStateUpdatesAgent.cs Changed to override protected core methods with RunCoreStreamingAsync delegation
dotnet/samples/AGUIClientServer/AGUIDojoServer/SharedState/SharedStateAgent.cs Updated to override protected core methods with RunCoreStreamingAsync delegation
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AIAgentTests.cs Updated test mocks to use Protected() API for RunCoreAsync and RunCoreStreamingAsync
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/DelegatingAIAgentTests.cs Modified mock setup and verification to use Protected() API
dotnet/tests/Microsoft.Agents.AI.UnitTests/TestAIAgent.cs Changed test helper to override protected core methods
dotnet/tests/Microsoft.Agents.AI.UnitTests/AgentExtensionsTests.cs Updated test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.UnitTests/AnonymousDelegatingAIAgentTests.cs Added Moq.Protected import and updated all mocks to use Protected() API
dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs Modified mock setup and verification to use Protected() API
dotnet/tests/Microsoft.Agents.AI.Purview.UnitTests/PurviewWrapperTests.cs Updated all mock setups and verifications to use Protected() API
dotnet/tests/Microsoft.Agents.AI.Hosting.AzureFunctions.UnitTests/TestAgent.cs Changed test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/AGUIEndpointRouteBuilderExtensionsTests.cs Updated test agents to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/BasicStreamingTests.cs Changed test agents to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/ForwardedPropertiesTests.cs Updated test agent to override protected core methods with RunCoreStreamingAsync delegation
dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.IntegrationTests/SharedStateTests.cs Changed test agent to override protected core methods with RunCoreStreamingAsync delegation
dotnet/tests/Microsoft.Agents.AI.Declarative.UnitTests/AggregatorPromptAgentFactoryTests.cs Updated test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/TestEchoAgent.cs Changed test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AgentWorkflowBuilderTests.cs Updated test agents to override protected core methods; modified base delegation call
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/InProcessExecutionTests.cs Changed test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/RepresentationTests.cs Updated test agent to override protected core methods
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/Sample/06_GroupChat_Workflow.cs Changed test agent to override protected core methods with RunCoreStreamingAsync delegation
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/SpecializedExecutorSmokeTests.cs Updated test agent to override protected core methods

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET workflows Related to Workflows in agent-framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants