Skip to content

.NET: Add a do-not-retry reason when samples reject tool approvals - #10095

Merged
westey (westey-m) merged 1 commit into
microsoft:mainfrom
westey-m:approve-reject-reason-samples
Nov 4, 2026
Merged

westey (westey-m) merged 1 commit into
microsoft:mainfrom
westey-m:approve-reject-reason-samples

Conversation

@westey-m

Copy link
Copy Markdown
Collaborator

Motivation & Context

When a user rejects a tool call, the model sees a function result that says the call was rejected. Without a reason, some newer models read this as a temporary failure and ask for approval of the same call again (#8503).

Microsoft.Extensions.AI 10.11.0 tried to fix this by making the default rejection text say the call "must not be retried". That broke Agent Framework's automatic rejection of unanswered approval requests, because the model was then told never to retry a call that nobody actually rejected (#9656). That change has been reverted upstream (dotnet/extensions#7914). The guidance now is that the caller should say in the rejection reason what the model should do, because only the caller knows whether a retry makes sense.

Our .NET samples rejected tool calls without a reason, so they showed the pattern that leads to repeated approval prompts. This PR updates them to follow the new guidance.

Description & Review Guide

  • What are the major changes? Every .NET sample that turns a user's yes/no answer into a ToolApprovalResponseContent now adds a reason when the answer is no: CreateResponse(approved: false, reason: "The user rejected this tool call. Do not retry it."). Approvals are unchanged. Updated samples:
    • 02-agents/Agents/Agent_Step01_UsingFunctionToolsWithApprovals
    • 02-agents/Agents/Agent_Step11_Middleware
    • 02-agents/AgentProviders/foundry/Agent_Step04_UsingFunctionToolsWithApprovals
    • 02-agents/AgentProviders/foundry/Agent_Step12_Middleware
    • 02-agents/AgentSkills/Agent_Step07_SkillsAutoApproval
    • 02-agents/AGUI/Step04_HumanInLoop/Client (and its README)
    • 05-end-to-end/M365Agent
    • 04-hosting/.../Hosted-Toolbox-AuthPaths-Client (function-tool path only)
    • 02-agents/Harness/Harness_Shared_Console (the "Deny" reason now uses the same wording instead of "User denied")
  • What is the impact of these changes? Samples only; no library changes. The hosted MCP samples are left unchanged because those approvals are handled by the service. GroupChatToolApproval is also unchanged because it only ever approves.
  • What do you want reviewers to focus on? Whether the reason wording is right, and whether any other samples that reject tool calls were missed.

Related Issue

Fixes #9656
Fixes #8503

#9678 is also open for #9656. It changes the library so that automatic rejections of unanswered requests use different wording. This PR takes a different approach: the default rejection text stays neutral (now that the upstream change is reverted), and the samples show callers how to say "do not retry" in the rejection reason.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: Sample code updates, README wording, and this PR description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

Copilot AI balanced review requested due to automatic review settings November 4, 2026 14:24
@agent-framework-automation agent-framework-automation Bot added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net labels Nov 4, 2026
@westey-m
westey (westey-m) marked this pull request as ready for review November 4, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues block the sample updates that add explicit no-retry guidance for user-denied tool calls.

No open issues 🎉

What changed in this PR

Updates .NET samples to distinguish explicit user rejection from an unanswered approval request. Rejections now tell the model not to retry the tool call, addressing repeated approval prompts described in #8503 without changing library-level automatic rejection behavior.

Changes:

  • Add a consistent “The user rejected this tool call. Do not retry it.” reason to user-denied function-tool approvals.
  • Preserve approval behavior and service-managed hosted MCP responses.
  • Update the AGUI README to explain the rejection reason.
File Description
dotnet/​samples/​05-end-to-end/​M365Agent/​AFAgentApplication.cs Adds the rejection reason to user-submitted approval decisions.
dotnet/​samples/​04-hosting/​FoundryHostedAgents/​responses/​Using-Samples/​Hosted-Toolbox-AuthPaths-Client/​Program.cs Adds the reason for function tools; preserves hosted MCP handling.
dotnet/​samples/​02-agents/​Harness/​Harness_Shared_Console/​Observers/​ToolApprovalObserver.cs Standardizes the “Deny” response reason.
dotnet/​samples/​02-agents/​AGUI/​Step04_HumanInLoop/​Client/​Program.cs Adds the reason to interactive client rejections.
dotnet/​samples/​02-agents/​AGUI/​README.md Documents the client’s explicit no-retry reason.
dotnet/​samples/​02-agents/​AgentSkills/​Agent_Step07_SkillsAutoApproval/​Program.cs Adds the reason when manual approval is denied.
dotnet/​samples/​02-agents/​Agents/​Agent_Step11_Middleware/​Program.cs Adds the reason to middleware-generated rejections.
dotnet/​samples/​02-agents/​Agents/​Agent_Step01_UsingFunctionToolsWithApprovals/​Program.cs Demonstrates explicit rejection guidance in the introductory sample.
dotnet/​samples/​02-agents/​AgentProviders/​foundry/​Agent_Step12_Middleware/​Program.cs Adds the reason to Foundry middleware rejections.
dotnet/​samples/​02-agents/​AgentProviders/​foundry/​Agent_Step04_UsingFunctionToolsWithApprovals/​Program.cs Adds the reason to Foundry function-tool rejections.

Review effort: Balanced

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAF Automated Review — Iteration 1

Result: No findings
Scope: full PR (1 commit(s)): 04947ac3f6d9
Model: gpt-5.6-sol

Overview

This sample-only change consistently supplies explicit do-not-retry guidance when users reject Agent Framework function-tool calls while preserving approval behavior and the separate hosted MCP wire path. Existing framework binding logic preserves the reason, rejects forged responses, and consumes matched approval state. No Critical, High, or Medium defect was established.

Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.

@westey-m
westey (westey-m) added this pull request to the merge queue Nov 4, 2026
Merged via the queue into microsoft:main with commit 85d73a9 Nov 4, 2026
41 of 42 checks passed
@westey-m
westey (westey-m) deleted the approve-reject-reason-samples branch November 4, 2026 14:57

This branch was previously deployed

1 inactive deployment
github-app-auth — 04947ac3 Deployed Nov 4, 2026 by westey-m via team_check #8720
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

3 participants