diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs index fa57050433..5e1c596da5 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs @@ -142,6 +142,45 @@ public class MagenticOrchestrationTests planEvent.FullTaskLedger.Should().NotBeNull(); } + [Fact] + public async Task NextSpeaker_Invalid_Triggers_FinalAnswer() + { + // Arrange: ProgressLedger returns invalid next_speaker + List factsResponse = CreatePlanResponse("Facts about the task"); + List planResponse = CreatePlanResponse("Step 1: Execute"); + List invalidNextSpeakerLedger = CreateProgressLedgerResponse( + isRequestSatisfied: false, + isInLoop: false, + isProgressBeingMade: true, + nextSpeaker: "NonExistentAgent", // Invalid - doesn't match any team member + instructionOrQuestion: "Continue"); + List finalAnswer = CreateFinalAnswerResponse("Forced to conclude due to invalid speaker"); + + TestReplayAgent manager = new( + [factsResponse, planResponse, invalidNextSpeakerLedger, finalAnswer], + name: "Manager"); + TestEchoAgent worker = new(name: "Worker"); + + List collectedEvents = []; + + Workflow workflow = new MagenticWorkflowBuilder(manager) + .AddParticipants(worker) + .RequirePlanSignoff(false) + .Build(); + + // Act + WorkflowRunResult runResult = await RunMagenticWorkflowAsync( + workflow, + [new ChatMessage(ChatRole.User, "Do task")], + eventCollector: collectedEvents); + + // Assert: Warning should be emitted and final answer prepared + collectedEvents.OfType() + .Should().Contain(e => e.Data != null && e.Data.ToString()!.Contains("Invalid next speaker")); + runResult.Result.Should().NotBeNull(); + runResult.Result![0].Text.Should().Contain("Forced to conclude"); + } + [Fact] public async Task ProgressLedger_Updated_Event_Emitted() {