forked from microsoft/agent-framework
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
140 lines (126 loc) · 4.74 KB
/
Program.cs
File metadata and controls
140 lines (126 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Copyright (c) Microsoft. All rights reserved.
using Microsoft.Agents.AI.Workflows;
using Microsoft.Agents.AI.Workflows.Reflection;
namespace WorkflowLoopSample;
/// <summary>
/// This sample demonstrates a simple number guessing game using a workflow with looping behavior.
///
/// The workflow consists of two executors that are connected in a feedback loop:
/// 1. GuessNumberExecutor: Makes a guess based on the current known bounds.
/// 2. JudgeExecutor: Evaluates the guess and provides feedback.
/// The workflow continues until the correct number is guessed.
/// </summary>
/// <remarks>
/// Pre-requisites:
/// - Foundational samples should be completed first.
/// </remarks>
public static class Program
{
private static async Task Main()
{
// Create the executors
GuessNumberExecutor guessNumberExecutor = new("GuessNumber", 1, 100);
JudgeExecutor judgeExecutor = new("Judge", 42);
// Build the workflow by connecting executors in a loop
var workflow = await new WorkflowBuilder(guessNumberExecutor)
.AddEdge(guessNumberExecutor, judgeExecutor)
.AddEdge(judgeExecutor, guessNumberExecutor)
.WithOutputFrom(judgeExecutor)
.BuildAsync<NumberSignal>();
// Execute the workflow
StreamingRun run = await InProcessExecution.StreamAsync(workflow, NumberSignal.Init).ConfigureAwait(false);
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
{
if (evt is WorkflowOutputEvent outputEvent)
{
Console.WriteLine($"Result: {outputEvent}");
}
}
}
}
/// <summary>
/// Signals used for communication between GuessNumberExecutor and JudgeExecutor.
/// </summary>
internal enum NumberSignal
{
Init,
Above,
Below,
}
/// <summary>
/// Executor that makes a guess based on the current bounds.
/// </summary>
internal sealed class GuessNumberExecutor : ReflectingExecutor<GuessNumberExecutor>, IMessageHandler<NumberSignal>
{
/// <summary>
/// The lower bound of the guessing range.
/// </summary>
public int LowerBound { get; private set; }
/// <summary>
/// The upper bound of the guessing range.
/// </summary>
public int UpperBound { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="GuessNumberExecutor"/> class.
/// </summary>
/// <param name="id">A unique identifier for the executor.</param>
/// <param name="lowerBound">The initial lower bound of the guessing range.</param>
/// <param name="upperBound">The initial upper bound of the guessing range.</param>
public GuessNumberExecutor(string id, int lowerBound, int upperBound) : base(id)
{
this.LowerBound = lowerBound;
this.UpperBound = upperBound;
}
private int NextGuess => (this.LowerBound + this.UpperBound) / 2;
public async ValueTask HandleAsync(NumberSignal message, IWorkflowContext context)
{
switch (message)
{
case NumberSignal.Init:
await context.SendMessageAsync(this.NextGuess).ConfigureAwait(false);
break;
case NumberSignal.Above:
this.UpperBound = this.NextGuess - 1;
await context.SendMessageAsync(this.NextGuess).ConfigureAwait(false);
break;
case NumberSignal.Below:
this.LowerBound = this.NextGuess + 1;
await context.SendMessageAsync(this.NextGuess).ConfigureAwait(false);
break;
}
}
}
/// <summary>
/// Executor that judges the guess and provides feedback.
/// </summary>
internal sealed class JudgeExecutor : ReflectingExecutor<JudgeExecutor>, IMessageHandler<int>
{
private readonly int _targetNumber;
private int _tries;
/// <summary>
/// Initializes a new instance of the <see cref="JudgeExecutor"/> class.
/// </summary>
/// <param name="id">A unique identifier for the executor.</param>
/// <param name="targetNumber">The number to be guessed.</param>
public JudgeExecutor(string id, int targetNumber) : base(id)
{
this._targetNumber = targetNumber;
}
public async ValueTask HandleAsync(int message, IWorkflowContext context)
{
this._tries++;
if (message == this._targetNumber)
{
await context.YieldOutputAsync($"{this._targetNumber} found in {this._tries} tries!")
.ConfigureAwait(false);
}
else if (message < this._targetNumber)
{
await context.SendMessageAsync(NumberSignal.Below).ConfigureAwait(false);
}
else
{
await context.SendMessageAsync(NumberSignal.Above).ConfigureAwait(false);
}
}
}