From 600bc91c848187f6e73c61b57d4dbce629246246 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 22:46:21 +0000 Subject: [PATCH] Add ProgressLedger_Max_Retries_Triggers_Reset E2E test Agent-Logs-Url: https://github.com/microsoft/agent-framework/sessions/125f6628-6b3b-4c51-9a51-ae84baece6bb Co-authored-by: lokitoth <6936551+lokitoth@users.noreply.github.com> --- .../MagenticOrchestrationTests.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs index 4d0a5e9b7c..0c96752bee 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/MagenticOrchestrationTests.cs @@ -763,6 +763,59 @@ public class MagenticOrchestrationTests runResult.Result![0].Text.Should().Contain("Completed after ledger retry"); } + [Fact] + public async Task ProgressLedger_Max_Retries_Triggers_Reset() + { + // Arrange: All 3 progress ledger retry attempts return invalid JSON → exception → ResetAndReplanAsync. + // After reset: new plan, valid ledger (satisfied), final answer. + // Turn sequence: facts1, plan1, invalidJSON×3, facts2, plan2, validLedger(satisfied), finalAnswer + List factsResponse1 = CreatePlanResponse("Initial facts"); + List planResponse1 = CreatePlanResponse("Initial plan"); + List invalidLedger1 = CreatePlanResponse("not json at all"); + List invalidLedger2 = CreatePlanResponse("still not json"); + List invalidLedger3 = CreatePlanResponse("definitely not json"); + + // After reset: ResetAndReplanAsync → UpdatePlanAndDelegateAsync → new plan + List factsResponse2 = CreatePlanResponse("Fresh facts after reset"); + List planResponse2 = CreatePlanResponse("Fresh plan after reset"); + List validLedger = CreateProgressLedgerResponse( + isRequestSatisfied: true, + isInLoop: false, + isProgressBeingMade: true, + nextSpeaker: "Worker", + instructionOrQuestion: "Done after reset"); + List finalAnswerResponse = CreateFinalAnswerResponse("Recovered after max retries reset"); + + TestReplayAgent manager = new( + [factsResponse1, planResponse1, invalidLedger1, invalidLedger2, invalidLedger3, + factsResponse2, planResponse2, validLedger, finalAnswerResponse], + 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: Parse failure warnings emitted, reset triggered (ReplannedEvent), workflow completes + collectedEvents.OfType() + .Where(e => e.Data?.ToString()?.Contains("Progress ledger JSON parse failed") == true) + .Should().HaveCountGreaterThanOrEqualTo(3, "all 3 retry attempts should emit warnings"); + collectedEvents.OfType() + .Should().Contain(e => e.Data != null && e.Data.ToString()!.Contains("triggering reset")); + collectedEvents.OfType().Should().NotBeEmpty("reset triggers replan"); + runResult.Result.Should().NotBeNull(); + runResult.Result![0].Text.Should().Contain("Recovered after max retries reset"); + } + #region Helper Methods private sealed record WorkflowRunResult(