From 90c0e2ce370bed209b547a85adc4023d9e6e429b Mon Sep 17 00:00:00 2001 From: Peter Ibekwe Date: Wed, 25 Mar 2026 08:20:16 -0700 Subject: [PATCH 1/3] Clarify IResettableExecutor usage comment in workflow sample --- .../Agents/WorkflowAsAnAgent/Program.cs | 15 +++++++++++-- .../WorkflowAsAnAgent/WorkflowFactory.cs | 21 ++++++++++++++++++- 2 files changed, 33 insertions(+), 3 deletions(-) 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..adb1b22cef 100644 --- a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs +++ b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs @@ -10,6 +10,12 @@ internal static class WorkflowFactory { /// /// Creates a workflow that uses two language agents to process input concurrently. + /// + /// The executors in this workflow are provided as shared instances, meaning the same + /// executor objects are reused across multiple workflow runs. Stateful 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 +46,15 @@ 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 stateful executor instances would throw an . /// [YieldsOutput(typeof(string))] private sealed class ConcurrentAggregationExecutor() : @@ -65,7 +80,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(); From 26eb2f3bf638eb068cd41688492268754c4d47c3 Mon Sep 17 00:00:00 2001 From: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:43:19 -0700 Subject: [PATCH 2/3] Update dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../Agents/WorkflowAsAnAgent/WorkflowFactory.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs index adb1b22cef..fd402b7946 100644 --- a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs +++ b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs @@ -11,11 +11,13 @@ internal static class WorkflowFactory /// /// Creates a workflow that uses two language agents to process input concurrently. /// - /// The executors in this workflow are provided as shared instances, meaning the same - /// executor objects are reused across multiple workflow runs. Stateful executors must - /// implement so the framework can clear their state - /// between runs. Framework-provided executors like - /// already implement this interface. + /// 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 From 2b0dc2f8c527b5267956d89b880db6e2379a1f28 Mon Sep 17 00:00:00 2001 From: Peter Ibekwe <109177538+peibekwe@users.noreply.github.com> Date: Wed, 25 Mar 2026 08:43:37 -0700 Subject: [PATCH 3/3] Update dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs index fd402b7946..bcac8894ab 100644 --- a/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs +++ b/dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs @@ -56,7 +56,8 @@ private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClie /// between runs, clearing accumulated state so each run starts fresh. /// /// Without , attempting to reuse a workflow containing - /// shared stateful executor instances would throw an . + /// shared executor instances that do not implement this interface would throw an + /// . /// [YieldsOutput(typeof(string))] private sealed class ConcurrentAggregationExecutor() :