From 04947ac3f6d94706eacf1d6ec78eb6d8c1050712 Mon Sep 17 00:00:00 2001 From: westey <164392973+westey-m@users.noreply.github.com> Date: Wed, 4 Nov 2026 14:23:05 +0000 Subject: [PATCH] Update approval samples to include reason --- dotnet/samples/02-agents/AGUI/README.md | 2 +- .../02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs | 5 ++++- .../Program.cs | 6 +++++- .../foundry/Agent_Step12_Middleware/Program.cs | 6 +++++- .../AgentSkills/Agent_Step07_SkillsAutoApproval/Program.cs | 6 +++++- .../Program.cs | 7 ++++++- .../02-agents/Agents/Agent_Step11_Middleware/Program.cs | 7 ++++++- .../Observers/ToolApprovalObserver.cs | 2 +- .../Hosted-Toolbox-AuthPaths-Client/Program.cs | 5 ++++- .../samples/05-end-to-end/M365Agent/AFAgentApplication.cs | 7 ++++++- 10 files changed, 43 insertions(+), 10 deletions(-) diff --git a/dotnet/samples/02-agents/AGUI/README.md b/dotnet/samples/02-agents/AGUI/README.md index 88cb43533dd..eb6d61ec4f3 100644 --- a/dotnet/samples/02-agents/AGUI/README.md +++ b/dotnet/samples/02-agents/AGUI/README.md @@ -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:** diff --git a/dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs b/dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs index c4ce0d3f54f..97843773545 100644 --- a/dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs +++ b/dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs @@ -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; diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step04_UsingFunctionToolsWithApprovals/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step04_UsingFunctionToolsWithApprovals/Program.cs index 4e470845b83..976b2f61a66 100644 --- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step04_UsingFunctionToolsWithApprovals/Program.cs +++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step04_UsingFunctionToolsWithApprovals/Program.cs @@ -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); diff --git a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step12_Middleware/Program.cs b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step12_Middleware/Program.cs index eaa7cbd07e0..99319ef7a8f 100644 --- a/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step12_Middleware/Program.cs +++ b/dotnet/samples/02-agents/AgentProviders/foundry/Agent_Step12_Middleware/Program.cs @@ -184,7 +184,11 @@ async Task ConsolePromptingApprovalMiddleware(IEnumerable { 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. diff --git a/dotnet/samples/02-agents/Agents/Agent_Step11_Middleware/Program.cs b/dotnet/samples/02-agents/Agents/Agent_Step11_Middleware/Program.cs index 92cbe6bc440..b82a35ef503 100644 --- a/dotnet/samples/02-agents/Agents/Agent_Step11_Middleware/Program.cs +++ b/dotnet/samples/02-agents/Agents/Agent_Step11_Middleware/Program.cs @@ -261,7 +261,12 @@ async Task ConsolePromptingApprovalMiddleware(IEnumerable { 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); diff --git a/dotnet/samples/02-agents/Harness/Harness_Shared_Console/Observers/ToolApprovalObserver.cs b/dotnet/samples/02-agents/Harness/Harness_Shared_Console/Observers/ToolApprovalObserver.cs index 20889d61fa1..bc1b47b1bcc 100644 --- a/dotnet/samples/02-agents/Harness/Harness_Shared_Console/Observers/ToolApprovalObserver.cs +++ b/dotnet/samples/02-agents/Harness/Harness_Shared_Console/Observers/ToolApprovalObserver.cs @@ -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"), }; diff --git a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/Hosted-Toolbox-AuthPaths-Client/Program.cs b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/Hosted-Toolbox-AuthPaths-Client/Program.cs index 9995f623736..b940592f414 100644 --- a/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/Hosted-Toolbox-AuthPaths-Client/Program.cs +++ b/dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/Hosted-Toolbox-AuthPaths-Client/Program.cs @@ -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]); }); diff --git a/dotnet/samples/05-end-to-end/M365Agent/AFAgentApplication.cs b/dotnet/samples/05-end-to-end/M365Agent/AFAgentApplication.cs index 502c57204e3..87d09ab53e1 100644 --- a/dotnet/samples/05-end-to-end/M365Agent/AFAgentApplication.cs +++ b/dotnet/samples/05-end-to-end/M365Agent/AFAgentApplication.cs @@ -124,7 +124,12 @@ private static ChatMessage HandleUserInput(ITurnContext turnContext) { var requestContent = JsonSerializer.Deserialize(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);