-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Labels
.NETv1.0Features being tracked for the version 1.0 GAFeatures being tracked for the version 1.0 GAworkflowsRelated to Workflows in agent-frameworkRelated to Workflows in agent-framework
Description
Description
When a workflow contains a subworkflow that has been bound as an executor using BindAsExecutor(), and the parent workflow is then run as an agent using AsAgent() and RunAsync(), the subworkflow executor is never invoked. Messages are not passed to the subworkflow, and executors within the subworkflow never execute.
Expected Behavior
When running a workflow as an agent that contains a subworkflow bound as an executor:
- The parent workflow's entry executor should execute
- Messages should be passed to the subworkflow executor
- The subworkflow should execute its internal executors
- Results should flow back through the workflow graph
Actual Behavior
Only the parent workflow's executors execute. The subworkflow executor is completely skipped:
- ✅ Parent workflow's
InputExecutorexecutes successfully - ❌ Subworkflow executor is never invoked
- ❌ Executors inside the subworkflow never execute
- ❌ No messages flow through the subworkflow
Minimal Reproducible Example
class Program
{
static async Task Main(string[] args)
{
// Setup logging
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
var logger = loggerFactory.CreateLogger<Program>();
logger.LogInformation("Starting workflow test with subworkflow as executor");
// Create a simple chat client (using a dummy implementation for testing)
IChatClient chatClient = new TestChatClient();
// Create the main workflow that uses a subworkflow as executor
var mainWorkflow = CreateMainWorkflow(chatClient, logger);
// Run the workflow as an agent
logger.LogInformation("Running workflow as agent...");
var agent = mainWorkflow.AsAgent();
var messages = new List<ChatMessage>
{
new ChatMessage(ChatRole.User, "Process this item")
};
logger.LogInformation("Invoking agent with message: '{Message}'", messages[0].Text);
try
{
var response = await agent.RunAsync(messages);
// Extract messages from response
var messagesProperty = response.GetType().GetProperty("Messages");
if (messagesProperty != null)
{
var responseMessages = messagesProperty.GetValue(response) as IEnumerable<ChatMessage>;
if (responseMessages != null)
{
foreach (var msg in responseMessages)
{
logger.LogInformation("Response message [{Role}]: {Text}", msg.Role, msg.Text);
}
}
}
logger.LogInformation("Workflow completed successfully!");
}
catch (Exception ex)
{
logger.LogError(ex, "Error running workflow: {Message}", ex.Message);
}
logger.LogInformation("Test complete");
}
static Workflow CreateMainWorkflow(IChatClient chatClient, ILogger logger)
{
logger.LogInformation("Creating main workflow with subworkflow executor");
// Create the subworkflow
var subWorkflow = CreateSubWorkflow(chatClient, logger);
// Bind the subworkflow as an executor
var subWorkflowExecutor = subWorkflow.BindAsExecutor("SubWorkflowExecutor");
logger.LogInformation("Subworkflow bound as executor with ID: {ExecutorId}", subWorkflowExecutor.Id);
// Create a simple input executor
var inputExecutor = new InputExecutor();
// Build the main workflow
var builder = new WorkflowBuilder(inputExecutor);
// Connect input executor to subworkflow executor
builder.AddEdge<List<ChatMessage>>(
source: inputExecutor,
target: subWorkflowExecutor
);
// Set output from subworkflow executor
builder.WithOutputFrom(subWorkflowExecutor);
var workflow = builder.WithName("MainWorkflow").Build();
var dotString = workflow.ToDotString();
logger.LogInformation("Main Workflow Graphviz:\n{DotString}", dotString);
return workflow;
}
static Workflow CreateSubWorkflow(IChatClient chatClient, ILogger logger)
{
logger.LogInformation("Creating subworkflow");
// Create a simple processing executor
var processingExecutor = new ProcessingExecutor();
var builder = new WorkflowBuilder(processingExecutor);
builder.WithOutputFrom(processingExecutor);
var workflow = builder.WithName("SubWorkflow").Build();
var dotString = workflow.ToDotString();
logger.LogInformation("SubWorkflow Graphviz:\n{DotString}", dotString);
return workflow;
}
}
// Simple test chat client implementation
class TestChatClient : IChatClient
{
public ChatClientMetadata Metadata { get; } = new ChatClientMetadata("TestClient");
public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
IEnumerable<ChatMessage> messages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
yield return new ChatResponseUpdate
{
Role = ChatRole.Assistant,
Contents = [new TextContent("Test streaming response")]
};
}
public async Task<ChatResponse> GetResponseAsync(
IEnumerable<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
return new ChatResponse(
new ChatMessage(ChatRole.Assistant, "Test response from chat client"));
}
public void Dispose()
{
}
public object? GetService(Type serviceType, object? serviceKey = null)
{
return null;
}Metadata
Metadata
Assignees
Labels
.NETv1.0Features being tracked for the version 1.0 GAFeatures being tracked for the version 1.0 GAworkflowsRelated to Workflows in agent-frameworkRelated to Workflows in agent-framework
Type
Projects
Status
Done