diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs b/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs index 00e030448f..7142faad0b 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows/HandoffWorkflowBuilder.cs @@ -54,6 +54,8 @@ public class HandoffWorkflowBuilderCore where TBuilder : HandoffWorkfl private bool _emitAgentResponseUpdateEvents; private HandoffToolCallFilteringBehavior _toolCallFilteringBehavior = HandoffToolCallFilteringBehavior.HandoffOnly; private bool _returnToPrevious; + private string? _name; + private string? _description; /// /// Initializes a new instance of the class with no handoff relationships. @@ -97,6 +99,20 @@ public TBuilder WithHandoffInstructions(string? instructions) return (TBuilder)this; } + /// + public TBuilder WithName(string name) + { + this._name = name; + return (TBuilder)this; + } + + /// + public TBuilder WithDescription(string description) + { + this._description = description; + return (TBuilder)this; + } + /// /// Sets a value indicating whether agent streaming update events should be emitted during execution. /// If , the value will be taken from the @@ -330,7 +346,16 @@ public Workflow Build() builder.AddEdge(start, executors[this._initialAgent.Id]); } - // Build the workflow. + if (!string.IsNullOrWhiteSpace(this._name)) + { + builder.WithName(this._name); + } + + if (!string.IsNullOrWhiteSpace(this._description)) + { + builder.WithDescription(this._description); + } + return builder.WithOutputFrom(end).Build(); } } diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.UnitTests/HostApplicationBuilderWorkflowExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.UnitTests/HostApplicationBuilderWorkflowExtensionsTests.cs index 1c5649d17c..c17655bd29 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hosting.UnitTests/HostApplicationBuilderWorkflowExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.UnitTests/HostApplicationBuilderWorkflowExtensionsTests.cs @@ -103,6 +103,30 @@ public void AddWorkflow_MultipleCalls_RegistersMultipleWorkflows() Assert.Contains(workflowDescriptors, d => (string)d.ServiceKey! == "workflow3"); } + /// + /// Verifies that a handoff workflow can be named from the DI workflow key. + /// + [Fact] + public void AddWorkflow_HandoffWorkflowWithName_ResolvesWorkflow() + { + var builder = new HostApplicationBuilder(); + const string WorkflowName = "handoffWorkflow"; + + var mockAgent = new Mock(); + mockAgent.Setup(a => a.Name).Returns("handoffAgent"); + +#pragma warning disable MAAIW001 // This test covers hosting handoff workflows. + builder.AddWorkflow(WorkflowName, (sp, key) => + AgentWorkflowBuilder.CreateHandoffBuilderWith(mockAgent.Object) + .WithName(key) + .Build()); +#pragma warning restore MAAIW001 + + var workflow = builder.Build().Services.GetRequiredKeyedService(WorkflowName); + + Assert.Equal(WorkflowName, workflow.Name); + } + /// /// Verifies that AddWorkflow handles empty strings for name. /// diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/HandoffOrchestrationTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/HandoffOrchestrationTests.cs index deddeb0c79..c8abe4719c 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/HandoffOrchestrationTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/HandoffOrchestrationTests.cs @@ -86,6 +86,23 @@ public void BuildHandoffs_DelegatingAIAgent_DoesNotThrow() target.Reason.Should().Be("instructions"); } + [Fact] + public void BuildHandoffs_WithNameAndDescription_SetsWorkflowMetadata() + { + const string WorkflowName = "handoff-workflow"; + const string WorkflowDescription = "A handoff workflow"; + + DoubleEchoAgent agent = new("agent"); + + var workflow = AgentWorkflowBuilder.CreateHandoffBuilderWith(agent) + .WithName(WorkflowName) + .WithDescription(WorkflowDescription) + .Build(); + + Assert.Equal(WorkflowName, workflow.Name); + Assert.Equal(WorkflowDescription, workflow.Description); + } + [Fact] public async Task Handoffs_NoTransfers_ResponseServedByOriginalAgentAsync() {