Description
I created a code that creates a subworkflow and a workflow based on the subworkflow.
What I expected because the documentation states, that Request and Responses are supported in Subworkflow (see below.)
https://learn.microsoft.com/en-us/agent-framework/workflows/advanced/sub-workflows?utm_source=copilot.com&pivots=programming-language-csharp
However, I have noticed that while the external request exists and is stored in the data of the ExecutorComplete and SuperStepComplete, the workflow does not continue because no RequestInfoEvent is fired. Therefore, the workflow is stuck.
Code Sample
public static Workflow Test()
{
RequestPort numberRequestPort = RequestPort.Create<NumberSignal, int>("GuessNumber");
JudgeExecutor judgeExecutor = new(42);
Workflow subWorkflow = new WorkflowBuilder(numberRequestPort)
.AddEdge(numberRequestPort, judgeExecutor) // RequestPort -> Judge (int guess)
.AddEdge(judgeExecutor, numberRequestPort) // Judge -> RequestPort (Above/Below signal)
.WithOutputFrom(judgeExecutor) // Output from Judge
.Build();
ExecutorOptions options = ExecutorOptions.Default;
options.AutoSendMessageHandlerResultObject = true;
options.AutoYieldOutputHandlerResultObject = true;
ExecutorBinding subworkflowBinding = subWorkflow.BindAsExecutor("Subworkflow", options);
Workflow workflow = new WorkflowBuilder(subworkflowBinding)
.WithOutputFrom(subworkflowBinding)
.Build();
return workflow;
}
internal enum NumberSignal
{
Init,
Above,
Below,
}
[SendsMessage(typeof(NumberSignal))]
[YieldsOutput(typeof(string))]
[YieldsOutput(typeof(ChatMessage))]
internal sealed class JudgeExecutor() : Executor<int>("Judge")
{
private readonly int _targetNumber;
private int _tries;
/// <summary>
/// Initializes a new instance of the <see cref="JudgeExecutor"/> class.
/// </summary>
/// <param name="targetNumber">The number to be guessed.</param>
public JudgeExecutor(int targetNumber) : this()
{
this._targetNumber = targetNumber;
}
public override async ValueTask HandleAsync(int message, IWorkflowContext context, CancellationToken cancellationToken = default)
{
this._tries++;
if (message == this._targetNumber)
{
string gameResult = $"Congratulations! You found the number {this._targetNumber} in {this._tries} tries!";
Console.WriteLine(gameResult);
//await context.YieldOutputAsync(gameResult, cancellationToken);
await context.YieldOutputAsync(new ChatMessage(ChatRole.Assistant, gameResult), cancellationToken);
}
else if (message < this._targetNumber)
{
await context.SendMessageAsync(NumberSignal.Below, cancellationToken: cancellationToken);
}
else
{
await context.SendMessageAsync(NumberSignal.Above, cancellationToken: cancellationToken);
}
}
}
Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI" Version="1.3.0", "Microsoft.Agents.AI.Workflows" Version="1.3.0", Microsoft.Extensions.AI.Abstractions" Version="10.5.0"
.NET Version
.Net 10,
Additional Context
Those are the executor fired, when I started my application.
[WorkflowStarted]
[SuperStepStarted] Step #Microsoft.Agents.AI.Workflows.SuperStepStartInfo | Senders: Subworkflow | HasExternalMessages: False
[ExecutorInvoked] Subworkflow
[ExecutorCompleted] Subworkflow:
[ExecutorInvoked] Subworkflow
[ExecutorCompleted] Subworkflow:
[ExecutorInvoked] GuessNumber
[ExecutorCompleted] GuessNumber: ExternalRequest { PortInfo = RequestPortInfo { RequestType = AgentTestSystem.Services.WorkflowService.HITLTest.GuessingGame+NumberSignal, AgentTestSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, ResponseType = System.Int32, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, PortId = GuessNumber }, RequestId = 0edcd6ed30f44cf1808ce4491c0200fe, Data = Microsoft.Agents.AI.Workflows.PortableValue }
[SuperStepCompleted] Step #Microsoft.Agents.AI.Workflows.SuperStepCompletionInfo | StateUpdated: False | PendingMessages: False | PendingRequests: True
Description
I created a code that creates a subworkflow and a workflow based on the subworkflow.
What I expected because the documentation states, that Request and Responses are supported in Subworkflow (see below.)
https://learn.microsoft.com/en-us/agent-framework/workflows/advanced/sub-workflows?utm_source=copilot.com&pivots=programming-language-csharp
However, I have noticed that while the external request exists and is stored in the data of the ExecutorComplete and SuperStepComplete, the workflow does not continue because no RequestInfoEvent is fired. Therefore, the workflow is stuck.
Code Sample
public static Workflow Test() { RequestPort numberRequestPort = RequestPort.Create<NumberSignal, int>("GuessNumber"); JudgeExecutor judgeExecutor = new(42); Workflow subWorkflow = new WorkflowBuilder(numberRequestPort) .AddEdge(numberRequestPort, judgeExecutor) // RequestPort -> Judge (int guess) .AddEdge(judgeExecutor, numberRequestPort) // Judge -> RequestPort (Above/Below signal) .WithOutputFrom(judgeExecutor) // Output from Judge .Build(); ExecutorOptions options = ExecutorOptions.Default; options.AutoSendMessageHandlerResultObject = true; options.AutoYieldOutputHandlerResultObject = true; ExecutorBinding subworkflowBinding = subWorkflow.BindAsExecutor("Subworkflow", options); Workflow workflow = new WorkflowBuilder(subworkflowBinding) .WithOutputFrom(subworkflowBinding) .Build(); return workflow; } internal enum NumberSignal { Init, Above, Below, } [SendsMessage(typeof(NumberSignal))] [YieldsOutput(typeof(string))] [YieldsOutput(typeof(ChatMessage))] internal sealed class JudgeExecutor() : Executor<int>("Judge") { private readonly int _targetNumber; private int _tries; /// <summary> /// Initializes a new instance of the <see cref="JudgeExecutor"/> class. /// </summary> /// <param name="targetNumber">The number to be guessed.</param> public JudgeExecutor(int targetNumber) : this() { this._targetNumber = targetNumber; } public override async ValueTask HandleAsync(int message, IWorkflowContext context, CancellationToken cancellationToken = default) { this._tries++; if (message == this._targetNumber) { string gameResult = $"Congratulations! You found the number {this._targetNumber} in {this._tries} tries!"; Console.WriteLine(gameResult); //await context.YieldOutputAsync(gameResult, cancellationToken); await context.YieldOutputAsync(new ChatMessage(ChatRole.Assistant, gameResult), cancellationToken); } else if (message < this._targetNumber) { await context.SendMessageAsync(NumberSignal.Below, cancellationToken: cancellationToken); } else { await context.SendMessageAsync(NumberSignal.Above, cancellationToken: cancellationToken); } } }Error Messages / Stack Traces
Package Versions
Microsoft.Agents.AI" Version="1.3.0", "Microsoft.Agents.AI.Workflows" Version="1.3.0", Microsoft.Extensions.AI.Abstractions" Version="10.5.0"
.NET Version
.Net 10,
Additional Context
Those are the executor fired, when I started my application.
[WorkflowStarted]
[SuperStepStarted] Step #Microsoft.Agents.AI.Workflows.SuperStepStartInfo | Senders: Subworkflow | HasExternalMessages: False
[ExecutorInvoked] Subworkflow
[ExecutorCompleted] Subworkflow:
[ExecutorInvoked] Subworkflow
[ExecutorCompleted] Subworkflow:
[ExecutorInvoked] GuessNumber
[ExecutorCompleted] GuessNumber: ExternalRequest { PortInfo = RequestPortInfo { RequestType = AgentTestSystem.Services.WorkflowService.HITLTest.GuessingGame+NumberSignal, AgentTestSystem, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null, ResponseType = System.Int32, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, PortId = GuessNumber }, RequestId = 0edcd6ed30f44cf1808ce4491c0200fe, Data = Microsoft.Agents.AI.Workflows.PortableValue }
[SuperStepCompleted] Step #Microsoft.Agents.AI.Workflows.SuperStepCompletionInfo | StateUpdated: False | PendingMessages: False | PendingRequests: True