Repository navigation
Description
Description
Hi westey (@westey-m), and thank you for investigating issue #8575. I saw that your fix has been included in version 1.23.0, and I can confirm that approval can now be re-sent after a failed resume. However, there is still a remaining issue, so I'm opening this new issue to give it visibility and better define the failing scenario.
The session can still become permanently unusable when the resume run is never executed. For example, the host fails before calling RunAsync with the approval response: a UI/transport error, the user closing the page, a validation exception, or a process restart before the user answers. In that case every later run on the session still throws:
var response = await agent.RunAsync("What time is it?", session); // approval requested + persisted
Console.WriteLine($"Approval requests: {GetApprovalRequests(response).Count}");
try
{
// Anything that fails before the approval response is sent back to the agent.
throw new InvalidOperationException("Something failed before sending the approval response.");
}
catch (Exception ex)
{
Console.WriteLine($"Host error: {ex.Message}");
}
response = await agent.RunAsync("Hello, tell me a joke.", session); // throws, and keeps throwingOutput:
Approval requests: 1
Host error: Something failed before sending the approval response.
System.InvalidOperationException: ToolApprovalRequestContent found with FunctionCall.CallId(s) 'call_pEtu9eNwav5SnGKRORXFtzyB' that have no matching ToolApprovalResponseContent.
So the underlying problem remains. A pending ToolApprovalRequestContent in the persisted history blocks every new user message. The host has no public way to enumerate or close it (#7867, #7872), unless it still holds the original request objects in memory. Could the framework handle a dangling request from history as a recoverable state? For example, it could auto-reject it with a synthetic response when a new user message arrives, or re-surface it to the caller, rather than throwing.
Package Versions
Microsoft.Agents.AI.OpenAI: 1.23.0
.NET Version
.NET 10
Additional Context
No response
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
github-actions commentedon Sep 29, 2026
🤖 Automated triage reproduction notes (agent-authored — trust but verify)
Agent analysis
Repro:
dotnet/src/Microsoft.Agents.AI/ChatClient/ApprovalResponseBindingChatClient.cs::ValidateInboundApprovalResponsesleaves persisted unanswered approval requests unchanged when a new turn contains no approval response; forwarding at line 90 then triggers the unmatched-request exception in FunctionInvokingChatClient. Trigger this by producing an approval request, serializing and deserializing the session without responding, then callingRunAsyncwith an unrelated user message. The minimal failing test isRunAsync_WhenApprovalResponseIsAbandoned_RestoredSessionCanProceedAsync.dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_ApprovalRetryTests.cs1.23.01.23.0westey-m commentedon Oct 1, 2026
Hi Marco Minerva (@marcominerva), thanks for logging the issue. Yes, I think auto-rejecting probably makes sense. I tried resurfacing elsewhere, but it becomes very complex very quickly, and if someone didn't provide a response deliberately I think it's reasonable to treat that as a rejection.
marcominerva commentedon Oct 1, 2026
I agree with implementing auto-reject. While addressing it this way, I wonder if we should also take this other issue into consideration for the auto-reject behavior: #8503.