Skip to content

.NET: expose pending tool approval requests from a restored AgentSession - #7867

Draft
Atharva Vichare (atty57) wants to merge 1 commit into
microsoft:mainfrom
atty57:atty57-issue-7862
Draft

.NET: expose pending tool approval requests from a restored AgentSession#7867
Atharva Vichare (atty57) wants to merge 1 commit into
microsoft:mainfrom
atty57:atty57-issue-7862

Conversation

@atty57

Copy link
Copy Markdown
Contributor

Motivation & Context

A host application with durable sessions has no supported way to discover that a conversation is paused on a human-in-the-loop tool approval.

ApprovalResponseBindingChatClient already records every model-originated ToolApprovalRequestContent into the session state bag under the internal _pendingApprovalRequests key, and consumes the entry once a matching ToolApprovalResponseContent is bound. That state is correct and durable — it just isn't reachable through a public API.

So when a user closes or refreshes a conversation that stopped at an approval request and later reopens it, the host can only recover the pending approval by parsing that private state bag field out of serialized session metadata. Field names and shapes there are not a public contract, which makes the workaround fragile. Hosts also end up maintaining a duplicate mirror of the same state purely to have a stable request id to submit against.

Without that recovery the host renders message history only, misses the pending approval, and can let the user send a new message after an unresolved assistant tool call — producing a sequence strict chat-completions providers reject with An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'.

Description & Review Guide

  • What are the major changes?

    Adds ToolApprovalAgentSessionExtensions.TryGetPendingToolApprovalRequests, an extension on AgentSession in Microsoft.Agents.AI:

    public static bool TryGetPendingToolApprovalRequests(
        this AgentSession session,
        [NotNullWhen(true)] out IReadOnlyList<ToolApprovalRequestContent>? requests);

    It reads the same state ApprovalResponseBindingChatClient writes, returning false when there is no pending approval. It follows the shape of the existing AgentSessionExtensions.TryGetInMemoryChatHistory. Three unit tests are added to ApprovalResponseBindingChatClientTests, the primary one covering a state bag serialize/deserialize round trip so the reload scenario from the issue is exercised end to end.

  • What is the impact of these changes?

    Purely additive and read-only. No behavioral change to approval binding, recording, or consumption, and no change to what gets persisted. A host can now, after DeserializeSessionAsync, detect the paused approval, restore its approval UI, and submit by request id — removing the need for a host-side mirror of the pending approval list.

    This addresses option 2 of the three remedies proposed in the issue. Option 1 (persisting ToolApprovalRequestContent into durable chat history rather than a bare FunctionCallContent) changes what goes into message history and affects replay across providers, so it is intentionally left out of this PR as a design decision for maintainers. I'm happy to follow up on it separately if you'd like it.

  • What do you want reviewers to focus on?

    Whether the API name, placement, and return shape are what you'd want long term — in particular whether this belongs as an AgentSession extension in Microsoft.Agents.AI or somewhere more discoverable, and whether it should also expose a way to correlate a pending request back to the FunctionCallContent already present in message history.

Related Issue

Fixes #7862

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 is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • 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.

Hosts with durable sessions had no supported way to discover that a
conversation is paused on a human-in-the-loop tool approval. The state
was already persisted by ApprovalResponseBindingChatClient under the
internal `_pendingApprovalRequests` state bag key, so the only working
approach was to parse that private field out of serialized session
metadata.

Adds AgentSession.TryGetPendingToolApprovalRequests(), which reads the
same recorded state through a supported API, so a host can restore its
approval UI after a reload and submit the approval by request id.

Addresses option 2 of microsoft#7862.
Copilot AI balanced review requested due to automatic review settings August 25, 2026 18:23
@agent-framework-automation agent-framework-automation Bot added the .NET Usage: [Issues, PRs], Target: .Net label Aug 25, 2026

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

Adds a public API for recovering pending tool approvals from durable .NET agent sessions.

Changes:

  • Adds TryGetPendingToolApprovalRequests.
  • Tests persistence round-trips, consumed approvals, and empty state.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
ToolApprovalAgentSessionExtensions.cs Exposes pending approvals from session state.
ApprovalResponseBindingChatClientTests.cs Tests approval recovery behavior.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

AgentJsonUtilities.DefaultOptions)
&& pending is { Count: > 0 })
{
requests = pending;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

.NET Usage: [Issues, PRs], Target: .Net

Projects

None yet

Development

Successfully merging this pull request may close these issues.

.NET: [Bug]: MAF approval-required function call is persisted as a dangling FunctionCallContent and pending approval state has no public read API

2 participants