Skip to content

Commit a2ed9d9

Browse files
committed
WIP: fix: WorkflowAsAgent Sample
* Also makes ChatForwardingExecutor public MERGE PENDING #1781
1 parent b467ddf commit a2ed9d9

File tree

2 files changed

+22
-29
lines changed

2 files changed

+22
-29
lines changed

dotnet/samples/GettingStarted/Workflows/Agents/WorkflowAsAnAgent/WorkflowFactory.cs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ internal static class WorkflowFactory
1616
internal static Workflow BuildWorkflow(IChatClient chatClient)
1717
{
1818
// Create executors
19-
var startExecutor = new ConcurrentStartExecutor();
19+
var startExecutor = new ChatForwardingExecutor("Start");
2020
var aggregationExecutor = new ConcurrentAggregationExecutor();
2121
AIAgent frenchAgent = GetLanguageAgent("French", chatClient);
2222
AIAgent englishAgent = GetLanguageAgent("English", chatClient);
@@ -38,34 +38,11 @@ internal static Workflow BuildWorkflow(IChatClient chatClient)
3838
private static ChatClientAgent GetLanguageAgent(string targetLanguage, IChatClient chatClient) =>
3939
new(chatClient, instructions: $"You're a helpful assistant who always responds in {targetLanguage}.", name: $"{targetLanguage}Agent");
4040

41-
/// <summary>
42-
/// Executor that starts the concurrent processing by sending messages to the agents.
43-
/// </summary>
44-
private sealed class ConcurrentStartExecutor() :
45-
Executor<List<ChatMessage>>("ConcurrentStartExecutor")
46-
{
47-
/// <summary>
48-
/// Starts the concurrent processing by sending messages to the agents.
49-
/// </summary>
50-
/// <param name="message">The user message to process</param>
51-
/// <param name="context">Workflow context for accessing workflow services and adding events</param>
52-
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests.
53-
/// The default is <see cref="CancellationToken.None"/>.</param>
54-
public override async ValueTask HandleAsync(List<ChatMessage> message, IWorkflowContext context, CancellationToken cancellationToken = default)
55-
{
56-
// Broadcast the message to all connected agents. Receiving agents will queue
57-
// the message but will not start processing until they receive a turn token.
58-
await context.SendMessageAsync(message, cancellationToken: cancellationToken);
59-
// Broadcast the turn token to kick off the agents.
60-
await context.SendMessageAsync(new TurnToken(emitEvents: true), cancellationToken: cancellationToken);
61-
}
62-
}
63-
6441
/// <summary>
6542
/// Executor that aggregates the results from the concurrent agents.
6643
/// </summary>
6744
private sealed class ConcurrentAggregationExecutor() :
68-
Executor<ChatMessage>("ConcurrentAggregationExecutor")
45+
Executor<ChatMessage>("ConcurrentAggregationExecutor"), IResettableExecutor
6946
{
7047
private readonly List<ChatMessage> _messages = [];
7148

@@ -86,5 +63,12 @@ public override async ValueTask HandleAsync(ChatMessage message, IWorkflowContex
8663
await context.YieldOutputAsync(formattedMessages, cancellationToken);
8764
}
8865
}
66+
67+
/// <inheritdoc/>
68+
public ValueTask ResetAsync()
69+
{
70+
this._messages.Clear();
71+
return default;
72+
}
8973
}
9074
}
Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,26 @@
44
using System.Threading.Tasks;
55
using Microsoft.Extensions.AI;
66

7-
namespace Microsoft.Agents.AI.Workflows.Specialized;
7+
namespace Microsoft.Agents.AI.Workflows;
88

9-
/// <summary>Executor that forwards all messages.</summary>
10-
internal sealed class ChatForwardingExecutor(string id) : Executor(id, declareCrossRunShareable: true), IResettableExecutor
9+
/// <summary>
10+
/// A ChatProtocol executor that forwards all messages it receives. Useful for splitting inputs into parallel
11+
/// processing paths.
12+
/// </summary>
13+
/// <remarks>This executor is designed to be cross-run shareable and can be reset to its initial state. It handles
14+
/// multiple chat-related types, enabling flexible message forwarding scenarios. Thread safety and reusability are
15+
/// ensured by its design.</remarks>
16+
/// <param name="id">The unique identifier for the executor instance. Used to distinguish this executor within the system.</param>
17+
public sealed class ChatForwardingExecutor(string id) : Executor(id, declareCrossRunShareable: true), IResettableExecutor
1118
{
12-
protected override RouteBuilder ConfigureRoutes(RouteBuilder routeBuilder) =>
19+
/// <inheritdoc/>
20+
protected sealed override RouteBuilder ConfigureRoutes(RouteBuilder routeBuilder) =>
1321
routeBuilder
1422
.AddHandler<string>((message, context, cancellationToken) => context.SendMessageAsync(new ChatMessage(ChatRole.User, message), cancellationToken: cancellationToken))
1523
.AddHandler<ChatMessage>((message, context, cancellationToken) => context.SendMessageAsync(message, cancellationToken: cancellationToken))
1624
.AddHandler<List<ChatMessage>>((messages, context, cancellationToken) => context.SendMessageAsync(messages, cancellationToken: cancellationToken))
1725
.AddHandler<TurnToken>((turnToken, context, cancellationToken) => context.SendMessageAsync(turnToken, cancellationToken: cancellationToken));
1826

27+
/// <inheritdoc/>
1928
public ValueTask ResetAsync() => default;
2029
}

0 commit comments

Comments
 (0)