Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dotnet/samples/02-agents/AGUI/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ An interactive client that handles approval requests from the server. Demonstrat

- Detecting `ToolApprovalRequestContent` in the streamed response
- Displaying approval details to the user and prompting for approval or rejection
- Sending the decision back as a `ToolApprovalResponseContent` created with `approvalRequest.CreateResponse(approved)`
- Sending the decision back as a `ToolApprovalResponseContent` created with `approvalRequest.CreateResponse(...)`. When the user rejects the call, the sample includes a reason telling the model not to retry it
- Resuming the run so the server continues after the decision is received

**Run the client:**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@
string? userInput = Console.ReadLine();
bool approved = userInput?.ToUpperInvariant() is "YES" or "Y";

ToolApprovalResponseContent approvalResponse = approvalRequest.CreateResponse(approved);
// When rejecting, tell the model not to retry the call.
ToolApprovalResponseContent approvalResponse = approved
? approvalRequest.CreateResponse(approved: true)
: approvalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.");

approvalResponses.Add(approvalResponse);
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ static string GetWeather([Description("The location to get the weather for.")] s
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? functionApprovalRequest.CreateResponse(approved: true)
: functionApprovalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
});

response = await agent.RunAsync(userInputMessages, session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,11 @@ async Task<AgentResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMes
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? functionApprovalRequest.CreateResponse(approved: true)
: functionApprovalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
});

agentResponse = await innerAgent.RunAsync(agentResponse.Messages, session, options, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,11 @@
var toolCall = (FunctionCallContent)functionApprovalRequest.ToolCall;
Console.WriteLine($"Approval required for: {toolCall.Name}. Reply Y to approve:");
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? functionApprovalRequest.CreateResponse(approved: true)
: functionApprovalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
});

response = await agent.RunAsync(userInputResponses, session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ static string GetWeather([Description("The location to get the weather for.")] s
.ConvertAll(functionApprovalRequest =>
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]);
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? functionApprovalRequest.CreateResponse(approved: true)
: functionApprovalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
});

// Pass the user input responses back to the agent for further processing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,12 @@ async Task<AgentResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMes
.ConvertAll(functionApprovalRequest =>
{
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {((FunctionCallContent)functionApprovalRequest.ToolCall).Name}");
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]);
bool approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? functionApprovalRequest.CreateResponse(approved: true)
: functionApprovalRequest.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
});

response = await innerAgent.RunAsync(response.Messages, session, options, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ private ChoiceFollowUpQuestion BuildApprovalQuestion(ToolApprovalRequestContent
{
"Always approve this tool (any arguments)" => request.CreateAlwaysApproveToolResponse("User chose to always approve this tool"),
"Always approve this tool with these arguments" => request.CreateAlwaysApproveToolWithArgumentsResponse("User chose to always approve this tool with these arguments"),
"Deny" => request.CreateResponse(approved: false, reason: "User denied"),
"Deny" => request.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it."),
_ => request.CreateResponse(approved: true, reason: "User approved"),
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,12 +163,15 @@ Type a message or 'quit' to exit.
bool approved = Console.ReadLine()?.Trim().Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
// Hosted MCP approval IDs use the mcpr_ wire prefix. They need the native OpenAI
// response item; CreateResponse produces the Agent Framework function-tool shape.
// When rejecting a function tool, tell the model not to retry the call.
AIContent decision = approval.RequestId.StartsWith("mcpr_", StringComparison.Ordinal)
? new AIContent
{
RawRepresentation = new McpToolCallApprovalResponseItem(approval.RequestId, approved),
}
: approval.CreateResponse(approved);
: approved
? approval.CreateResponse(approved: true)
: approval.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.");
return new ChatMessage(ChatRole.User, [decision]);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,12 @@ private static ChatMessage HandleUserInput(ITurnContext turnContext)
{
var requestContent = JsonSerializer.Deserialize<ToolApprovalRequestContent>(requestJsonElement.GetString()!, JsonUtilities.DefaultOptions);

return new ChatMessage(ChatRole.User, [requestContent!.CreateResponse(approvedJsonElement.ValueKind == JsonValueKind.True)]);
bool approved = approvedJsonElement.ValueKind == JsonValueKind.True;

// When rejecting, tell the model not to retry the call.
return new ChatMessage(ChatRole.User, [approved
? requestContent!.CreateResponse(approved: true)
: requestContent!.CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it.")]);
}

return new ChatMessage(ChatRole.User, turnContext.Activity.Text);
Expand Down
Loading