Skip to content

Add ToolApprovalRequestContent.RequiresConfirmation#7549

Open
javiercn wants to merge 10 commits into
mainfrom
javiercn/invokerrequested
Open

Add ToolApprovalRequestContent.RequiresConfirmation#7549
javiercn wants to merge 10 commits into
mainfrom
javiercn/invokerrequested

Conversation

@javiercn

@javiercn javiercn commented Jun 9, 2026

Copy link
Copy Markdown
Member

Implements #7550.

Adds ToolApprovalRequestContent.RequiresConfirmation so consumers can distinguish approval requests where the underlying function genuinely needs approval (RequiresConfirmation = true, the default) from requests that FunctionInvokingChatClient added as a no-op because a peer call in the same response requires approval (RequiresConfirmation = false).

See #7550 for the full proposal (summary, motivation, goals, non-goals, detailed design). The name is still being iterated on in #7550; the property name in this PR may change to the agreed-upon name before merge.

Changes

  • Microsoft.Extensions.AI.Abstractions — new bool ToolApprovalRequestContent.RequiresConfirmation { get; set; } = true;, serialized like FunctionCallContent.InformationalOnly. Default true means any non-FICC producer that constructs a ToolApprovalRequestContent because the underlying tool genuinely requires approval is correct without code changes.
  • FunctionInvokingChatClient — both wrap sites now set the flag per call.
    • Non-streaming ReplaceFunctionCallsWithApprovalRequests uses FindTool + GetService<ApprovalRequiredAIFunction>() per FCC; the lookup is captured in the existing index list so the wrap site sets RequiresConfirmation without a second pass.
    • Streaming TryReplaceFunctionCallsWithApprovalRequests now takes the pre-computed approvalRequiredFunctions array (already computed at the caller for batch buffering) and matches by name, avoiding a second FindTool + GetService scan per FCC.
  • API baselineMicrosoft.Extensions.AI.Abstractions.json updated.

Tests

  • AssertExtensions.EqualMessageLists and the test-local CloneFcc propagate and assert the new flag.
  • Two existing FICC mixed-batch approval tests assert per-call polarity.
  • Two new FICC tests: (a) approval-required function nested inside another DelegatingAIFunction; (b) FCC whose name doesn't match any tool when a peer requires approval.
  • Two new unit tests on ToolApprovalRequestContent: default value, JSON round-trip.

40 approval tests, 161 FICC tests, and 21 ToolApprovalRequestContent unit tests pass on net9.0.

@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 91.95 🔻
Microsoft.Extensions.AI Line 89 88.56 🔻
Microsoft.Extensions.AI Branch 89 88.54 🔻
Microsoft.Extensions.AI.OpenAI Line 75 62.65 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 49.63 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 94.39 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.21 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 85
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 85
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1456605&view=codecoverage-tab

javiercn added a commit that referenced this pull request Jun 10, 2026
Renames the property added in #7549 to use Abstractions-neutral vocabulary (per @jozkee feedback on #7550) and flips the polarity so the default (true) is correct for any producer that constructs a ToolApprovalRequestContent because the underlying tool genuinely requires approval. FICC now explicitly sets RequiresConfirmation = false for requests it wraps as a no-op because a peer in the same response requires approval.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
javiercn added a commit that referenced this pull request Jun 10, 2026
1. Drop [Experimental(MEAI001)] from RequiresConfirmation; the rest of the approval surface is no longer experimental.

2. Streaming TryReplaceFunctionCallsWithApprovalRequests now takes the pre-computed approvalRequiredFunctions array instead of the raw tool lists, avoiding a second FindTool + GetService scan per FCC. Non-streaming path is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 91.95 🔻
Microsoft.Extensions.AI Line 89 88.57 🔻
Microsoft.Extensions.AI Branch 89 88.56 🔻
Microsoft.Extensions.AI.OpenAI Line 75 62.65 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 49.63 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 94.39 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 68.32 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.21 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 85
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 89
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1457358&view=codecoverage-tab

@javiercn javiercn changed the title Add ToolApprovalRequestContent.IsInvokerRequested Add ToolApprovalRequestContent.RequiresConfirmation Jun 10, 2026
@javiercn javiercn marked this pull request as ready for review June 10, 2026 11:02
@javiercn javiercn requested a review from a team as a code owner June 10, 2026 11:02
Copilot AI review requested due to automatic review settings June 10, 2026 11:02

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.

Pull request overview

This PR extends the AI abstractions approval envelope (ToolApprovalRequestContent) with a RequiresConfirmation boolean so downstream consumers can distinguish between approvals that are truly required by the underlying tool vs. “collateral” approval requests introduced by FunctionInvokingChatClient to keep mixed batches coherent.

Changes:

  • Add ToolApprovalRequestContent.RequiresConfirmation (default true) and include it in JSON round-tripping.
  • Populate RequiresConfirmation in FunctionInvokingChatClient for both non-streaming and streaming wrapping paths.
  • Update test helpers and add/adjust tests to assert the new per-call flag behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/ToolApprovalRequestContent.cs Adds the new RequiresConfirmation property and documentation.
src/Libraries/Microsoft.Extensions.AI/ChatCompletion/FunctionInvokingChatClient.cs Sets RequiresConfirmation when wrapping FCCs into approval requests (streaming + non-streaming).
src/Libraries/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.Abstractions.json Updates API baseline to include the new property.
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Contents/ToolApprovalRequestContentTests.cs Adds unit tests for default value and JSON round-trip.
test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs Extends message equality assertions to include RequiresConfirmation.
test/Libraries/Microsoft.Extensions.AI.Tests/ChatCompletion/FunctionInvokingChatClientApprovalsTests.cs Updates/extends FICC approval tests to validate per-call RequiresConfirmation.

@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 91.95 🔻
Microsoft.Extensions.AI Line 89 88.57 🔻
Microsoft.Extensions.AI Branch 89 88.56 🔻
Microsoft.Extensions.AI.OpenAI Line 75 62.65 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 49.63 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 94.39 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 68.32 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.96 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 85
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 84
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1457523&view=codecoverage-tab

@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 91.95 🔻
Microsoft.Extensions.AI Line 89 88.59 🔻
Microsoft.Extensions.AI Branch 89 88.57 🔻
Microsoft.Extensions.AI.OpenAI Line 75 62.65 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 49.63 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 94.39 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.21 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 85
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 84
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1457721&view=codecoverage-tab

@jozkee jozkee left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, thanks.

@javiercn javiercn requested a review from a team as a code owner June 10, 2026 16:13
javiercn and others added 8 commits June 10, 2026 18:15
Lets consumers distinguish approval requests raised because the underlying function is an ApprovalRequiredAIFunction (IsInvokerRequested = false, the default) from requests that FunctionInvokingChatClient added as collateral because a peer call in the same batch required approval (IsInvokerRequested = true).

Both FICC wrap sites set the flag using the existing FindTool + GetService<ApprovalRequiredAIFunction>() pattern so additional DelegatingAIFunction wrappers still classify correctly. The streaming helper now takes the tool lists symmetrically with the non-streaming path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
STJ source generator emits read/write code for ToolApprovalRequestContent.IsInvokerRequested, which is [Experimental(MEAI001)]. The generated code can't carry pragma suppressions, so suppress at the project level. Matches the existing pattern used by Microsoft.Extensions.AI.Abstractions and Microsoft.Extensions.AI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Renames the property added in #7549 to use Abstractions-neutral vocabulary (per @jozkee feedback on #7550) and flips the polarity so the default (true) is correct for any producer that constructs a ToolApprovalRequestContent because the underlying tool genuinely requires approval. FICC now explicitly sets RequiresConfirmation = false for requests it wraps as a no-op because a peer in the same response requires approval.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1. Drop [Experimental(MEAI001)] from RequiresConfirmation; the rest of the approval surface is no longer experimental.

2. Streaming TryReplaceFunctionCallsWithApprovalRequests now takes the pre-computed approvalRequiredFunctions array instead of the raw tool lists, avoiding a second FindTool + GetService scan per FCC. Non-streaming path is unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that RequiresConfirmation no longer carries [Experimental(MEAI001)], the STJ source-generated JsonContext for ToolApprovalRequestContent does not touch any experimental member, so the suppression added in 736f112 is no longer needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Frames the property in consumer terms and removes invoker/wrap-site detail that does not belong in the Abstractions surface.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Non-streaming wrap site now takes the precomputed approvalRequiredFunctions array and uses a name-set check, matching what the streaming wrap site does. Removes the small streaming/non-streaming divergence in RequiresConfirmation classification introduced earlier in this PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Spell out that a ToolApprovalResponseContent is still required even when RequiresConfirmation is false, so the underlying tool call can be invoked.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI and others added 2 commits June 10, 2026 18:15
RequiresConfirmation is again [Experimental(MEAI001)] after 566be62, so the STJ source-generated JsonContext for ToolApprovalRequestContent reaches an experimental member and the Reporting projects fail to build at Release without the suppression. Restores the same NoWarn that was in 736f112.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@javiercn javiercn force-pushed the javiercn/invokerrequested branch from bfb8335 to 2f56556 Compare June 10, 2026 16:15
@dotnet-comment-bot

Copy link
Copy Markdown
Collaborator

‼️ Found issues ‼️

Project Coverage Type Expected Actual
Microsoft.Extensions.Diagnostics.Testing Line 99 98.65 🔻
Microsoft.Extensions.Telemetry Line 93 91.95 🔻
Microsoft.Extensions.AI Line 89 88.64 🔻
Microsoft.Extensions.AI Branch 89 88.57 🔻
Microsoft.Extensions.AI.OpenAI Line 75 62.65 🔻
Microsoft.Extensions.AI.OpenAI Branch 75 49.63 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Line 75 4.46 🔻
Microsoft.Extensions.DataIngestion.MarkItDown Branch 75 0 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Line 99 96.03 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring Branch 99 94.39 🔻
Microsoft.Extensions.Diagnostics.ResourceMonitoring.Kubernetes Line 99 97.73 🔻
Microsoft.Extensions.ServiceDiscovery.Dns Line 75 69.93 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Line 75 42.11 🔻
Microsoft.Extensions.ServiceDiscovery.Abstractions Branch 75 42.86 🔻
Microsoft.Extensions.ServiceDiscovery Line 75 67.96 🔻
Microsoft.Extensions.ServiceDiscovery Branch 75 71.43 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Line 75 73.85 🔻
Microsoft.Extensions.ServiceDiscovery.Yarp Branch 75 70 🔻
Microsoft.Extensions.VectorData.Abstractions Line 75 37.39 🔻
Microsoft.Extensions.VectorData.Abstractions Branch 75 22.73 🔻

🎉 Good job! The coverage increased 🎉
Update MinCodeCoverage in the project files.

Project Expected Actual
Microsoft.Gen.BuildMetadata 97 100
Microsoft.Gen.MetadataExtractor 57 73
Microsoft.Gen.MetricsReports 67 69
Microsoft.Extensions.AI.Abstractions 82 85
Microsoft.Extensions.AI.Evaluation.NLP 0 78
Microsoft.Extensions.Caching.Hybrid 82 84
Microsoft.Extensions.DataIngestion 75 89
Microsoft.Extensions.DataIngestion.Markdig 75 90
Microsoft.Extensions.Http.Resilience 97 100

Full code coverage report: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1458062&view=codecoverage-tab

@javiercn

Copy link
Copy Markdown
Member Author

@jozkee It's been a while since I have done within extensions. What's the process. Do we merge now? Or do we want to go through API Review first or discuss it any further? Is there anyone else that needs to have a look?

@jeffhandley

Copy link
Copy Markdown
Member

@jozkee has inquired with the rest of the .NET AI crew to see if others want to review the API design before we merge. Let's leave it for @jozkee to merge once he's satisfied the crew has weighed in. Thanks for driving this though, @javiercn!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants