diff --git a/sidecar/src/Aryx.AgentHost/Aryx.AgentHost.csproj b/sidecar/src/Aryx.AgentHost/Aryx.AgentHost.csproj
index be724dc..df2f4f8 100644
--- a/sidecar/src/Aryx.AgentHost/Aryx.AgentHost.csproj
+++ b/sidecar/src/Aryx.AgentHost/Aryx.AgentHost.csproj
@@ -9,10 +9,10 @@
-
-
-
-
+
+
+
+
diff --git a/sidecar/src/Aryx.AgentHost/Services/CopilotAgentBundle.cs b/sidecar/src/Aryx.AgentHost/Services/CopilotAgentBundle.cs
index 70c261b..e817984 100644
--- a/sidecar/src/Aryx.AgentHost/Services/CopilotAgentBundle.cs
+++ b/sidecar/src/Aryx.AgentHost/Services/CopilotAgentBundle.cs
@@ -226,19 +226,19 @@ internal sealed class CopilotAgentBundle : IAsyncDisposable
};
}
- internal static HandoffsWorkflowBuilder CreateHandoffWorkflowBuilder(
+ internal static HandoffWorkflowBuilder CreateHandoffWorkflowBuilder(
AIAgent entryAgent,
HandoffModeSettingsDto? settings = null)
{
HandoffModeSettingsDto effectiveSettings = settings ?? new HandoffModeSettingsDto();
- HandoffsWorkflowBuilder builder = AgentWorkflowBuilder.CreateHandoffBuilderWith(entryAgent)
+ HandoffWorkflowBuilder builder = AgentWorkflowBuilder.CreateHandoffBuilderWith(entryAgent)
.WithToolCallFilteringBehavior(MapHandoffToolCallFiltering(effectiveSettings.ToolCallFiltering))
.WithHandoffInstructions(NormalizeOptionalString(effectiveSettings.HandoffInstructions)
?? HandoffWorkflowGuidance.CreateWorkflowInstructions());
if (effectiveSettings.ReturnToPrevious)
{
- TryEnableReturnToPrevious(builder);
+ builder = builder.EnableReturnToPrevious();
}
return builder;
@@ -256,7 +256,7 @@ internal sealed class CopilotAgentBundle : IAsyncDisposable
WorkflowNodeDto triageNode = ResolveTriageAgentNode(workflowDefinition, agentNodes);
AIAgent triageAgent = ResolveAgentForNode(triageNode, agentsById);
HandoffModeSettingsDto? settings = workflowDefinition.Settings.ModeSettings?.Handoff;
- HandoffsWorkflowBuilder builder = CreateHandoffWorkflowBuilder(triageAgent, settings);
+ HandoffWorkflowBuilder builder = CreateHandoffWorkflowBuilder(triageAgent, settings);
List specialistNodes = agentNodes
.Where(node => !string.Equals(node.Id, triageNode.Id, StringComparison.Ordinal))
@@ -448,13 +448,6 @@ internal sealed class CopilotAgentBundle : IAsyncDisposable
};
}
- private static void TryEnableReturnToPrevious(HandoffsWorkflowBuilder builder)
- {
- builder.GetType()
- .GetMethod("EnableReturnToPrevious", Type.EmptyTypes)?
- .Invoke(builder, null);
- }
-
private static int ResolveGroupChatMaxRounds(WorkflowDefinitionDto workflowDefinition)
{
int? configuredMaxRounds = workflowDefinition.Settings.ModeSettings?.GroupChat?.MaxRounds;
diff --git a/sidecar/src/Aryx.AgentHost/Services/WorkflowRequestInfoInterpreter.cs b/sidecar/src/Aryx.AgentHost/Services/WorkflowRequestInfoInterpreter.cs
index 7f0f502..2e99906 100644
--- a/sidecar/src/Aryx.AgentHost/Services/WorkflowRequestInfoInterpreter.cs
+++ b/sidecar/src/Aryx.AgentHost/Services/WorkflowRequestInfoInterpreter.cs
@@ -175,7 +175,7 @@ internal static class WorkflowRequestInfoInterpreter
{
if (requestData.Is(out McpServerToolCallContent? mcpToolCall))
{
- toolName = NormalizeOptionalString(mcpToolCall.ToolName)
+ toolName = NormalizeOptionalString(mcpToolCall.Name)
?? NormalizeOptionalString(mcpToolCall.ServerName)
?? string.Empty;
toolCallId = NormalizeOptionalString(mcpToolCall.CallId);
diff --git a/sidecar/tests/Aryx.AgentHost.Tests/Aryx.AgentHost.Tests.csproj b/sidecar/tests/Aryx.AgentHost.Tests/Aryx.AgentHost.Tests.csproj
index 5223a35..002c9ba 100644
--- a/sidecar/tests/Aryx.AgentHost.Tests/Aryx.AgentHost.Tests.csproj
+++ b/sidecar/tests/Aryx.AgentHost.Tests/Aryx.AgentHost.Tests.csproj
@@ -8,10 +8,16 @@
-
-
-
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
diff --git a/sidecar/tests/Aryx.AgentHost.Tests/CopilotAgentBundleTests.cs b/sidecar/tests/Aryx.AgentHost.Tests/CopilotAgentBundleTests.cs
index d32b71f..dedc389 100644
--- a/sidecar/tests/Aryx.AgentHost.Tests/CopilotAgentBundleTests.cs
+++ b/sidecar/tests/Aryx.AgentHost.Tests/CopilotAgentBundleTests.cs
@@ -163,12 +163,12 @@ public sealed class CopilotAgentBundleTests
{
ChatClientAgent entryAgent = CreateChatClientAgent("agent-1", "Primary");
- HandoffsWorkflowBuilder builder = CopilotAgentBundle.CreateHandoffWorkflowBuilder(entryAgent);
+ HandoffWorkflowBuilder builder = CopilotAgentBundle.CreateHandoffWorkflowBuilder(entryAgent);
- FieldInfo field = typeof(HandoffsWorkflowBuilder).GetField(
+ FieldInfo field = GetInstanceField(
+ typeof(HandoffWorkflowBuilder),
"_toolCallFilteringBehavior",
- BindingFlags.Instance | BindingFlags.NonPublic)
- ?? throw new InvalidOperationException("Expected HandoffsWorkflowBuilder to expose a filtering field.");
+ "Expected HandoffWorkflowBuilder to expose a filtering field.");
HandoffToolCallFilteringBehavior behavior = Assert.IsType(field.GetValue(builder));
@@ -181,7 +181,7 @@ public sealed class CopilotAgentBundleTests
{
ChatClientAgent entryAgent = CreateChatClientAgent("agent-1", "Primary");
- HandoffsWorkflowBuilder builder = CopilotAgentBundle.CreateHandoffWorkflowBuilder(
+ HandoffWorkflowBuilder builder = CopilotAgentBundle.CreateHandoffWorkflowBuilder(
entryAgent,
new HandoffModeSettingsDto
{
@@ -190,12 +190,17 @@ public sealed class CopilotAgentBundleTests
HandoffInstructions = "Use custom delegation guidance.",
});
- FieldInfo filteringField = typeof(HandoffsWorkflowBuilder).GetField(
+ FieldInfo filteringField = GetInstanceField(
+ typeof(HandoffWorkflowBuilder),
"_toolCallFilteringBehavior",
- BindingFlags.Instance | BindingFlags.NonPublic)
- ?? throw new InvalidOperationException("Expected HandoffsWorkflowBuilder to expose a filtering field.");
+ "Expected HandoffWorkflowBuilder to expose a filtering field.");
+ FieldInfo returnToPreviousField = GetInstanceField(
+ typeof(HandoffWorkflowBuilder),
+ "_returnToPrevious",
+ "Expected HandoffWorkflowBuilder to expose a return-to-previous field.");
Assert.Equal(HandoffToolCallFilteringBehavior.All, filteringField.GetValue(builder));
+ Assert.Equal(true, returnToPreviousField.GetValue(builder));
Assert.Equal("Use custom delegation guidance.", builder.HandoffInstructions);
}
@@ -631,6 +636,20 @@ public sealed class CopilotAgentBundleTests
});
}
+ private static FieldInfo GetInstanceField(Type type, string name, string errorMessage)
+ {
+ for (Type? current = type; current is not null; current = current.BaseType)
+ {
+ FieldInfo? field = current.GetField(name, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
+ if (field is not null)
+ {
+ return field;
+ }
+ }
+
+ throw new InvalidOperationException(errorMessage);
+ }
+
private static AIFunctionDeclaration CreateHandoffDeclaration()
{
return AIFunctionFactory.CreateDeclaration(
diff --git a/sidecar/tests/Aryx.AgentHost.Tests/WorkflowRequestInfoInterpreterTests.cs b/sidecar/tests/Aryx.AgentHost.Tests/WorkflowRequestInfoInterpreterTests.cs
index 0e2ce15..1fd0080 100644
--- a/sidecar/tests/Aryx.AgentHost.Tests/WorkflowRequestInfoInterpreterTests.cs
+++ b/sidecar/tests/Aryx.AgentHost.Tests/WorkflowRequestInfoInterpreterTests.cs
@@ -317,8 +317,7 @@ public sealed class WorkflowRequestInfoInterpreterTests
Type type = Type.GetType(
"Microsoft.Extensions.AI.CodeInterpreterToolCallContent, Microsoft.Extensions.AI.Abstractions",
throwOnError: true)!;
- object instance = Activator.CreateInstance(type)!;
- type.GetProperty("CallId")!.SetValue(instance, callId);
+ object instance = Activator.CreateInstance(type, callId)!;
if (inputs.Length > 0)
{
Type aiContentType = Type.GetType(
@@ -363,7 +362,7 @@ public sealed class WorkflowRequestInfoInterpreterTests
Type type = Type.GetType(
"Microsoft.Extensions.AI.ImageGenerationToolCallContent, Microsoft.Extensions.AI.Abstractions",
throwOnError: true)!;
- return Activator.CreateInstance(type)!;
+ return Activator.CreateInstance(type, "image-call-1")!;
}
private static object CreateHandoffTarget(string id, string name)