diff --git a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/Program.cs b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/Program.cs
index 07ba96989a..bc9faff3b0 100644
--- a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/Program.cs
+++ b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/Program.cs
@@ -9,7 +9,7 @@
namespace WorkflowAsAnAgentSample;
///
-/// This sample introduces the concepts workflows as agents, where a workflow can be
+/// This sample introduces the concept of workflows as agents, where a workflow can be
/// treated as an . This allows you to interact with a workflow
/// as if it were a single agent.
///
@@ -18,6 +18,14 @@ namespace WorkflowAsAnAgentSample;
///
/// You will interact with the workflow in an interactive loop, sending messages and receiving
/// streaming responses from the workflow as if it were an agent who responds in both languages.
+///
+/// This sample also demonstrates , which is required
+/// for stateful executors that are shared across multiple workflow runs. Each iteration
+/// of the interactive loop triggers a new workflow run against the same workflow instance.
+/// Between runs, the framework automatically calls
+/// on shared executors so that accumulated state (e.g., collected messages) is cleared
+/// before the next run begins. See WorkflowFactory.ConcurrentAggregationExecutor
+/// for the implementation.
///
///
/// Pre-requisites:
@@ -39,7 +47,10 @@ private static async Task Main()
var agent = workflow.AsAIAgent("workflow-agent", "Workflow Agent");
var session = await agent.CreateSessionAsync();
- // Start an interactive loop to interact with the workflow as if it were an agent
+ // Start an interactive loop to interact with the workflow as if it were an agent.
+ // Each iteration runs the workflow again on the same workflow instance. Between runs,
+ // the framework calls IResettableExecutor.ResetAsync() on shared stateful executors
+ // (like ConcurrentAggregationExecutor) to clear accumulated state from the previous run.
while (true)
{
Console.WriteLine();
diff --git a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
index 2fdfe703bf..bcac8894ab 100644
--- a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
+++ b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs
@@ -10,6 +10,14 @@ internal static class WorkflowFactory
{
///
/// Creates a workflow that uses two language agents to process input concurrently.
+ ///
+ /// In this workflow, the Start and the
+ /// are provided as shared instances, meaning
+ /// the same executor objects are reused across multiple workflow runs. The language agents
+ /// (French and English) are created via a factory and instantiated per workflow run.
+ /// Stateful shared executors must implement so the
+ /// framework can clear their state between runs. Framework-provided executors like
+ /// already implement this interface.
///
/// The chat client to use for the agents
/// A workflow that processes input using two language agents
@@ -40,6 +48,16 @@ private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClie
///
/// Executor that aggregates the results from the concurrent agents.
+ ///
+ /// This executor is stateful — it accumulates messages in
+ /// as they arrive from each agent. Because it is provided as a shared instance
+ /// (not via a factory), the same object is reused across workflow runs. Implementing
+ /// allows the framework to call
+ /// between runs, clearing accumulated state so each run starts fresh.
+ ///
+ /// Without , attempting to reuse a workflow containing
+ /// shared executor instances that do not implement this interface would throw an
+ /// .
///
[YieldsOutput(typeof(string))]
private sealed class ConcurrentAggregationExecutor() :
@@ -65,7 +83,11 @@ public override async ValueTask HandleAsync(List message, IWorkflow
}
}
- ///
+ ///
+ /// Resets the executor state between workflow runs by clearing accumulated messages.
+ /// The framework calls this automatically when a workflow run completes, before the
+ /// workflow can be used for another run.
+ ///
public ValueTask ResetAsync()
{
this._messages.Clear();