diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowSession.cs b/dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowSession.cs
index fcdefcfd22..db3d299ee9 100644
--- a/dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowSession.cs
+++ b/dotnet/src/Microsoft.Agents.AI.Workflows/WorkflowSession.cs
@@ -279,8 +279,8 @@ internal sealed class WorkflowSession : AgentSession
{
ExternalRequest externalRequest when externalRequest.TryGetDataAs(out FunctionCallContent? functionCallContent)
=> CloneFunctionCallContent(functionCallContent, externalRequest.RequestId),
- ExternalRequest externalRequest when externalRequest.TryGetDataAs(out UserInputRequestContent? userInputRequestContent)
- => CloneUserInputRequestContent(userInputRequestContent, externalRequest.RequestId),
+ ExternalRequest externalRequest when externalRequest.TryGetDataAs(out ToolApprovalRequestContent? toolApprovalRequestContent)
+ => CloneToolApprovalRequestContent(toolApprovalRequestContent, externalRequest.RequestId),
ExternalRequest externalRequest
=> externalRequest.ToFunctionCall(),
};
@@ -292,8 +292,8 @@ internal sealed class WorkflowSession : AgentSession
{
FunctionResultContent functionResultContent when request.TryGetDataAs(out FunctionCallContent? functionCallContent)
=> CloneFunctionResultContent(functionResultContent, functionCallContent.CallId),
- UserInputResponseContent userInputResponseContent when request.TryGetDataAs(out UserInputRequestContent? userInputRequestContent)
- => CloneUserInputResponseContent(userInputResponseContent, userInputRequestContent.Id),
+ ToolApprovalResponseContent toolApprovalResponseContent when request.TryGetDataAs(out ToolApprovalRequestContent? toolApprovalRequestContent)
+ => CloneToolApprovalResponseContent(toolApprovalResponseContent, toolApprovalRequestContent.RequestId),
_ => content,
};
@@ -303,7 +303,7 @@ internal sealed class WorkflowSession : AgentSession
private static string? GetResponseContentId(AIContent content) => content switch
{
FunctionResultContent functionResultContent => functionResultContent.CallId,
- UserInputResponseContent userInputResponseContent => userInputResponseContent.Id,
+ ToolApprovalResponseContent toolApprovalResponseContent => toolApprovalResponseContent.RequestId,
_ => null
};
@@ -509,39 +509,22 @@ internal sealed class WorkflowSession : AgentSession
}
///
- /// Clones a with a workflow-facing request ID.
+ /// Clones a with a workflow-facing request ID.
///
- private static UserInputRequestContent CloneUserInputRequestContent(UserInputRequestContent content, string id)
+ private static ToolApprovalRequestContent CloneToolApprovalRequestContent(ToolApprovalRequestContent content, string id)
{
- UserInputRequestContent clone = content switch
- {
- FunctionApprovalRequestContent functionApprovalRequestContent =>
- new FunctionApprovalRequestContent(id, functionApprovalRequestContent.FunctionCall),
- McpServerToolApprovalRequestContent mcpApprovalRequestContent =>
- new McpServerToolApprovalRequestContent(id, mcpApprovalRequestContent.ToolCall),
- _ => throw new NotSupportedException(
- $"Unsupported user input request content type '{content.GetType().Name}' for workflow request ID rewriting."),
- };
-
+ ToolApprovalRequestContent clone = new(id, content.ToolCall);
return CopyContentMetadata(content, clone);
}
///
- /// Clones a with an agent-owned request ID.
+ /// Clones a with an agent-owned request ID.
///
- private static UserInputResponseContent CloneUserInputResponseContent(UserInputResponseContent content, string id)
+ private static ToolApprovalResponseContent CloneToolApprovalResponseContent(ToolApprovalResponseContent content, string id)
{
- UserInputResponseContent clone = content switch
+ ToolApprovalResponseContent clone = new(id, content.Approved, content.ToolCall)
{
- FunctionApprovalResponseContent functionApprovalResponseContent =>
- new FunctionApprovalResponseContent(id, functionApprovalResponseContent.Approved, functionApprovalResponseContent.FunctionCall)
- {
- Reason = functionApprovalResponseContent.Reason,
- },
- McpServerToolApprovalResponseContent mcpApprovalResponseContent =>
- new McpServerToolApprovalResponseContent(id, mcpApprovalResponseContent.Approved),
- _ => throw new NotSupportedException(
- $"Unsupported user input response content type '{content.GetType().Name}' for workflow response ID rewriting."),
+ Reason = content.Reason,
};
return CopyContentMetadata(content, clone);
diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/WorkflowHostSmokeTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/WorkflowHostSmokeTests.cs
index 0d543acec3..1920a57cb1 100644
--- a/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/WorkflowHostSmokeTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/WorkflowHostSmokeTests.cs
@@ -29,7 +29,7 @@ public sealed class ExpectedException : Exception
}
///
-/// A simple agent that emits a FunctionCallContent or UserInputRequestContent request.
+/// A simple agent that emits a FunctionCallContent or ToolApprovalRequestContent request.
/// Used to test that RequestInfoEvent handling preserves the original content type.
///
internal sealed class RequestEmittingAgent : AIAgent
@@ -44,7 +44,7 @@ internal sealed class RequestEmittingAgent : AIAgent
///
/// When , the agent emits a text completion instead of re-emitting
/// the request when the incoming messages contain a
- /// or . This models realistic agent behaviour
+ /// or . This models realistic agent behaviour
/// where the agent processes the tool result and produces a final answer.
///
public RequestEmittingAgent(AIContent requestContent, bool completeOnResponse = false)
@@ -73,7 +73,7 @@ internal sealed class RequestEmittingAgent : AIAgent
protected override async IAsyncEnumerable RunCoreStreamingAsync(IEnumerable messages, AgentSession? session = null, AgentRunOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (this._completeOnResponse && messages.Any(m => m.Contents.Any(c =>
- c is FunctionResultContent || c is UserInputResponseContent)))
+ c is FunctionResultContent || c is ToolApprovalResponseContent)))
{
yield return new AgentResponseUpdate(ChatRole.Assistant, [new TextContent("Request processed")]);
}
@@ -328,16 +328,16 @@ public class WorkflowHostSmokeTests
}
///
- /// Tests that when a workflow emits a RequestInfoEvent with UserInputRequestContent data,
- /// the AgentResponseUpdate preserves the original UserInputRequestContent type.
+ /// Tests that when a workflow emits a RequestInfoEvent with ToolApprovalRequestContent data,
+ /// the AgentResponseUpdate preserves the original ToolApprovalRequestContent type.
///
[Fact]
- public async Task Test_AsAgent_UserInputRequestContentPreservedInRequestInfoAsync()
+ public async Task Test_AsAgent_ToolApprovalRequestContentPreservedInRequestInfoAsync()
{
// Arrange
const string RequestId = "test-request-id";
McpServerToolCallContent mcpCall = new("call-id", "testToolName", "http://localhost");
- UserInputRequestContent originalContent = new McpServerToolApprovalRequestContent(RequestId, mcpCall);
+ ToolApprovalRequestContent originalContent = new(RequestId, mcpCall);
RequestEmittingAgent requestAgent = new(originalContent);
ExecutorBinding agentBinding = requestAgent.BindAsExecutor(
new AIAgentHostOptions { InterceptUserInputRequests = false, EmitAgentUpdateEvents = true });
@@ -350,17 +350,17 @@ public class WorkflowHostSmokeTests
// Assert
AgentResponseUpdate? updateWithUserInput = updates.FirstOrDefault(u =>
- u.RawRepresentation is RequestInfoEvent && u.Contents.Any(c => c is UserInputRequestContent));
+ u.RawRepresentation is RequestInfoEvent && u.Contents.Any(c => c is ToolApprovalRequestContent));
- updateWithUserInput.Should().NotBeNull("a UserInputRequestContent should be present in the response updates");
- UserInputRequestContent retrievedContent = updateWithUserInput!.Contents
- .OfType()
+ updateWithUserInput.Should().NotBeNull("a ToolApprovalRequestContent should be present in the response updates");
+ ToolApprovalRequestContent retrievedContent = updateWithUserInput!.Contents
+ .OfType()
.Should().ContainSingle()
.Which;
- retrievedContent.Should().BeOfType();
- retrievedContent.Id.Should().NotBe(RequestId);
- retrievedContent.Id.Should().EndWith($":{RequestId}");
+ retrievedContent.Should().NotBeNull();
+ retrievedContent.RequestId.Should().NotBe(RequestId);
+ retrievedContent.RequestId.Should().EndWith($":{RequestId}");
}
///
@@ -414,41 +414,40 @@ public class WorkflowHostSmokeTests
}
///
- /// Tests the full roundtrip for UserInputRequestContent: workflow emits request, external caller responds.
- /// Verifying inbound UserInputResponseContent conversion.
+ /// Tests the full roundtrip for ToolApprovalRequestContent: workflow emits request, external caller responds.
+ /// Verifying inbound ToolApprovalResponseContent conversion.
///
[Fact]
- public async Task Test_AsAgent_UserInputRoundtrip_ResponseIsProcessedAsync()
+ public async Task Test_AsAgent_ToolApprovalRoundtrip_ResponseIsProcessedAsync()
{
- // Arrange: Create an agent that emits a UserInputRequestContent request
+ // Arrange: Create an agent that emits a ToolApprovalRequestContent request
const string RequestId = "roundtrip-request-id";
McpServerToolCallContent mcpCall = new("mcp-call-id", "testMcpTool", "http://localhost");
- McpServerToolApprovalRequestContent requestContent = new(RequestId, mcpCall);
+ ToolApprovalRequestContent requestContent = new(RequestId, mcpCall);
RequestEmittingAgent requestAgent = new(requestContent, completeOnResponse: true);
ExecutorBinding agentBinding = requestAgent.BindAsExecutor(
new AIAgentHostOptions { InterceptUserInputRequests = false, EmitAgentUpdateEvents = true });
Workflow workflow = new WorkflowBuilder(agentBinding).Build();
AIAgent agent = workflow.AsAIAgent("WorkflowAgent");
- // Act 1: First call - should receive the UserInputRequestContent request
+ // Act 1: First call - should receive the ToolApprovalRequestContent request
AgentSession session = await agent.CreateSessionAsync();
List firstCallUpdates = await agent.RunStreamingAsync(
new ChatMessage(ChatRole.User, "Start"),
session).ToListAsync();
- // Assert 1: We should have received a UserInputRequestContent
+ // Assert 1: We should have received a ToolApprovalRequestContent
AgentResponseUpdate? updateWithRequest = firstCallUpdates.FirstOrDefault(u =>
- u.RawRepresentation is RequestInfoEvent && u.Contents.Any(c => c is UserInputRequestContent));
- updateWithRequest.Should().NotBeNull("a UserInputRequestContent should be present in the response updates");
+ u.RawRepresentation is RequestInfoEvent && u.Contents.Any(c => c is ToolApprovalRequestContent));
+ updateWithRequest.Should().NotBeNull("a ToolApprovalRequestContent should be present in the response updates");
- UserInputRequestContent receivedRequest = updateWithRequest!.Contents
- .OfType()
+ ToolApprovalRequestContent receivedRequest = updateWithRequest!.Contents
+ .OfType()
.First();
- receivedRequest.Id.Should().EndWith($":{RequestId}");
- receivedRequest.Should().BeOfType();
+ receivedRequest.RequestId.Should().EndWith($":{RequestId}");
// Act 2: Send the response back - use CreateResponse to get the right response type
- UserInputResponseContent responseContent = ((McpServerToolApprovalRequestContent)receivedRequest).CreateResponse(approved: true);
+ ToolApprovalResponseContent responseContent = receivedRequest.CreateResponse(approved: true);
ChatMessage responseMessage = new(ChatRole.User, [responseContent]);
// Act 2: Run the workflow again with the response and capture the updates
@@ -458,8 +457,8 @@ public class WorkflowHostSmokeTests
secondCallUpdates.Should().NotBeEmpty("handling the user input response should produce follow-up updates");
bool requestStillPresent = secondCallUpdates.Any(u =>
u.RawRepresentation is RequestInfoEvent
- && u.Contents.OfType().Any(r => r.Id == receivedRequest.Id));
- requestStillPresent.Should().BeFalse("the original UserInputRequestContent should not be re-emitted after its response is processed");
+ && u.Contents.OfType().Any(r => r.RequestId == receivedRequest.RequestId));
+ requestStillPresent.Should().BeFalse("the original ToolApprovalRequestContent should not be re-emitted after its response is processed");
}
///