fix: Address PR Comments

This commit is contained in:
Jacob Alber
2026-05-07 07:51:27 -04:00
Unverified
parent 69803f3db3
commit b8951641f2
4 changed files with 56 additions and 9 deletions
@@ -99,9 +99,11 @@ public class MagenticWorkflowBuilder(AIAgent managerAgent)
private WorkflowBuilder ReduceToWorkflowBuilder()
{
ExecutorFactoryFunc factory = this.CreateOrchestratorAsync;
ExecutorBinding orchestrator = factory.BindExecutor(nameof(MagenticOrchestrator));
// Create a copy of the team so that improper modifications by using the builder after .Build() do not affect the
// workflow in unexpected ways.
List<AIAgent> team = [.. this._team];
ExecutorBinding orchestrator = CreateOrchestratorBinding(managerAgent, team, this.Limits, this._requirePlanSignoff);
WorkflowBuilder result = new(orchestrator);
AIAgentHostOptions options = new()
@@ -111,7 +113,7 @@ public class MagenticWorkflowBuilder(AIAgent managerAgent)
};
List<ExecutorBinding> teamBindings = [];
foreach (AIAgent agent in this._team)
foreach (AIAgent agent in team)
{
ExecutorBinding binding = agent.BindAsExecutor(options);
teamBindings.Add(binding);
@@ -143,8 +145,14 @@ public class MagenticWorkflowBuilder(AIAgent managerAgent)
MaxResetCount: this._maxResets,
MaxStallCount: this._maxStalls);
private ValueTask<MagenticOrchestrator> CreateOrchestratorAsync(ExecutorConfig<ExecutorOptions> options, string sessionId)
private static ExecutorBinding CreateOrchestratorBinding(AIAgent managerAgent, List<AIAgent> team, TaskLimits limits, bool requirePlanSignoff)
{
return new(new MagenticOrchestrator(managerAgent, this._team, this.Limits, this._requirePlanSignoff));
ExecutorFactoryFunc factory = CreateOrchestratorAsync;
return factory.BindExecutor(nameof(MagenticOrchestrator));
ValueTask<MagenticOrchestrator> CreateOrchestratorAsync(ExecutorConfig<ExecutorOptions> options, string sessionId)
{
return new(new MagenticOrchestrator(managerAgent, team, limits, requirePlanSignoff));
}
}
}
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.Json;
@@ -112,9 +113,8 @@ internal static partial class ChatMessageExtensions
new(FencedJsonRegexPattern, RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
#endif
public static JsonElement ExtractJson(this ChatMessage message)
internal static JsonElement ExtractJson(string messageText)
{
string messageText = message.Text;
Match match = FencedJsonRegex().Match(messageText);
if (match.Success)
{
@@ -130,20 +130,35 @@ internal static partial class ChatMessageExtensions
}
int depth = 0;
bool inQuotes = false, inEscape = false;
for (; scanHead < messageText.Length && end is null; scanHead++)
{
if (inEscape)
{
inEscape = false;
continue;
}
switch (messageText[scanHead])
{
case '{':
case '{' when !inQuotes:
depth++;
break;
case '}':
case '}' when !inQuotes:
depth--;
if (depth == 0)
{
end = scanHead;
}
break;
case '\"':
// We already handled inEscape, so we can always flip inQuotes here
inQuotes = !inQuotes;
break;
case '\\':
Debug.Assert(!inEscape);
inEscape = true;
break;
}
}
@@ -155,4 +170,6 @@ internal static partial class ChatMessageExtensions
return JsonElement.Parse(messageText.Substring(start, end.Value - start + 1));
}
public static JsonElement ExtractJson(this ChatMessage message) => ExtractJson(message.Text);
}
@@ -101,6 +101,7 @@ internal static partial class WorkflowsJsonUtilities
[JsonSerializable(typeof(MagenticPlanReviewRequest))]
[JsonSerializable(typeof(MagenticPlanReviewResponse))]
[JsonSerializable(typeof(MagenticTaskState))]
[JsonSerializable(typeof(ResetChatSignal))]
// Event Types
//[JsonSerializable(typeof(WorkflowEvent))]
@@ -11,6 +11,7 @@ namespace Microsoft.Agents.AI.Workflows.UnitTests;
public class MagenticProgressLedgerTests
{
public record KVPair(string key);
public record AnswerReasonPair(bool answer, string reason);
[Theory]
[InlineData(false)]
@@ -92,6 +93,26 @@ public class MagenticProgressLedgerTests
action.Should().Throw();
}
[Fact]
public void Test_ExtractJson_SuceedsWithQuotesBrackets()
{
// Arrange
ChatMessage message = new(ChatRole.Assistant,
"""
{"reason":"the output contained }", "answer": false}
""");
// Act
JsonElement element = message.ExtractJson();
// Assert
AnswerReasonPair? result = element.Deserialize<AnswerReasonPair>();
result.Should().NotBeNull();
result.reason.Should().Be("the output contained }");
result.answer.Should().BeFalse();
}
public static readonly string TestTeamNames = string.Join(", ", ["CodingAgent", "CodeExecutor", "WebSurferAgent", "FileSurferAgent"]);
[Fact]