Skip to content

Commit db16a9e

Browse files
peibekweCopilot
andauthored
.NET: Clarify IResettableExecutor usage comment in workflow sample (#4905)
* Clarify IResettableExecutor usage comment in workflow sample * Update dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent c012aac commit db16a9e

2 files changed

Lines changed: 36 additions & 3 deletions

File tree

dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/Program.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace WorkflowAsAnAgentSample;
1010

1111
/// <summary>
12-
/// This sample introduces the concepts workflows as agents, where a workflow can be
12+
/// This sample introduces the concept of workflows as agents, where a workflow can be
1313
/// treated as an <see cref="AIAgent"/>. This allows you to interact with a workflow
1414
/// as if it were a single agent.
1515
///
@@ -18,6 +18,14 @@ namespace WorkflowAsAnAgentSample;
1818
///
1919
/// You will interact with the workflow in an interactive loop, sending messages and receiving
2020
/// streaming responses from the workflow as if it were an agent who responds in both languages.
21+
///
22+
/// This sample also demonstrates <see cref="IResettableExecutor"/>, which is required
23+
/// for stateful executors that are shared across multiple workflow runs. Each iteration
24+
/// of the interactive loop triggers a new workflow run against the same workflow instance.
25+
/// Between runs, the framework automatically calls <see cref="IResettableExecutor.ResetAsync"/>
26+
/// on shared executors so that accumulated state (e.g., collected messages) is cleared
27+
/// before the next run begins. See <c>WorkflowFactory.ConcurrentAggregationExecutor</c>
28+
/// for the implementation.
2129
/// </summary>
2230
/// <remarks>
2331
/// Pre-requisites:
@@ -39,7 +47,10 @@ private static async Task Main()
3947
var agent = workflow.AsAIAgent("workflow-agent", "Workflow Agent");
4048
var session = await agent.CreateSessionAsync();
4149

42-
// Start an interactive loop to interact with the workflow as if it were an agent
50+
// Start an interactive loop to interact with the workflow as if it were an agent.
51+
// Each iteration runs the workflow again on the same workflow instance. Between runs,
52+
// the framework calls IResettableExecutor.ResetAsync() on shared stateful executors
53+
// (like ConcurrentAggregationExecutor) to clear accumulated state from the previous run.
4354
while (true)
4455
{
4556
Console.WriteLine();

dotnet/samples/03-workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ internal static class WorkflowFactory
1010
{
1111
/// <summary>
1212
/// Creates a workflow that uses two language agents to process input concurrently.
13+
///
14+
/// In this workflow, the <c>Start</c> <see cref="ChatForwardingExecutor"/> and the
15+
/// <see cref="ConcurrentAggregationExecutor"/> are provided as shared instances, meaning
16+
/// the same executor objects are reused across multiple workflow runs. The language agents
17+
/// (French and English) are created via a factory and instantiated per workflow run.
18+
/// Stateful shared executors must implement <see cref="IResettableExecutor"/> so the
19+
/// framework can clear their state between runs. Framework-provided executors like
20+
/// <see cref="ChatForwardingExecutor"/> already implement this interface.
1321
/// </summary>
1422
/// <param name="chatClient">The chat client to use for the agents</param>
1523
/// <returns>A workflow that processes input using two language agents</returns>
@@ -40,6 +48,16 @@ private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClie
4048

4149
/// <summary>
4250
/// Executor that aggregates the results from the concurrent agents.
51+
///
52+
/// This executor is stateful — it accumulates messages in <see cref="_messages"/>
53+
/// as they arrive from each agent. Because it is provided as a shared instance
54+
/// (not via a factory), the same object is reused across workflow runs. Implementing
55+
/// <see cref="IResettableExecutor"/> allows the framework to call <see cref="ResetAsync"/>
56+
/// between runs, clearing accumulated state so each run starts fresh.
57+
///
58+
/// Without <see cref="IResettableExecutor"/>, attempting to reuse a workflow containing
59+
/// shared executor instances that do not implement this interface would throw an
60+
/// <see cref="InvalidOperationException"/>.
4361
/// </summary>
4462
[YieldsOutput(typeof(string))]
4563
private sealed class ConcurrentAggregationExecutor() :
@@ -65,7 +83,11 @@ public override async ValueTask HandleAsync(List<ChatMessage> message, IWorkflow
6583
}
6684
}
6785

68-
/// <inheritdoc/>
86+
/// <summary>
87+
/// Resets the executor state between workflow runs by clearing accumulated messages.
88+
/// The framework calls this automatically when a workflow run completes, before the
89+
/// workflow can be used for another run.
90+
/// </summary>
6991
public ValueTask ResetAsync()
7092
{
7193
this._messages.Clear();

0 commit comments

Comments
 (0)