.NET: Update to OpenAI 2.9.1 and Microsoft.Extensions.AI 10.4.0#4613
.NET: Update to OpenAI 2.9.1 and Microsoft.Extensions.AI 10.4.0#4613
Conversation
…changes - Rename FunctionApprovalRequestContent → ToolApprovalRequestContent - Rename FunctionApprovalResponseContent → ToolApprovalResponseContent - Rename UserInputRequestContent → ToolApprovalRequestContent - Rename UserInputResponseContent → ToolApprovalResponseContent - Update .FunctionCall property → .ToolCall with FunctionCallContent casts where needed - Update .Id property → .RequestId on the renamed types - Rename FunctionApprovalRequestEventGenerator → ToolApprovalRequestEventGenerator - Rename FunctionApprovalResponseEventGenerator → ToolApprovalResponseEventGenerator Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
…put→.Outputs Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
| switch (content) | ||
| { | ||
| case FunctionApprovalRequestContent approvalRequest: | ||
| case ToolApprovalRequestContent approvalRequest: |
There was a problem hiding this comment.
@copilot in this and similar cases, you can do:
case ToolApprovalRequestContent approvalRequest when approvalRequest.ToolCall is FunctionCallContent fcc:
and then use fcc rather than casting. This helps ensure that only FunctionCallContent-based approvals are handled, and it reduces the amount of unsafe casting.
There was a problem hiding this comment.
Done in eac339d. Updated both Client/Program.cs and ServerFunctionApprovalServerAgent.cs to use when approvalRequest.ToolCall is FunctionCallContent fcc pattern matching, eliminating all unsafe casts.
|
This will be broken until Azure.AI.OpenAI and Azure.AI.Projects update to OpenAI 2.9.1. |
…ionCallContent Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Updates the .NET Agent Framework codebase to align with newer OpenAI Responses client patterns (model passed per request / per chat client) and consolidates “approval required” flows under unified tool-approval content types across workflows, hosting, tests, and samples.
Changes:
- Switch OpenAI Responses usage to
GetResponsesClient()without a baked-in model, and plumb model IDs viaAsIChatClient(model)/ per-request parameters. - Replace function/MCP-specific approval content with
ToolApprovalRequestContent/ToolApprovalResponseContentacross workflows, hosting streaming events, tests, and samples. - Update MCP tool result handling from
OutputtoOutputs, and bump several .NET package versions.
Reviewed changes
Copilot reviewed 39 out of 39 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| dotnet/tests/OpenAIResponse.IntegrationTests/OpenAIResponseFixture.cs | Stores model name separately and passes it into AsIChatClient(model) after switching to model-less GetResponsesClient(). |
| dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/TestRequestAgent.cs | Updates unit-test agent session/request plumbing to use tool-approval request/response content types. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/AIAgentHostExecutorTests.cs | Adjusts request interception tests to expect ToolApprovalRequestContent. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/InvokeMcpToolExecutorTest.cs | Updates MCP approval tests to use tool-approval content + renames Output→Outputs in mocked results. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Events/ExternalInputResponseTest.cs | Updates serialization assertions for unified tool-approval response content. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Events/ExternalInputRequestTest.cs | Updates serialization assertions for unified tool-approval request content. |
| dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.IntegrationTests/InvokeToolWorkflowTest.cs | Updates integration test handling/logging for unified tool approvals. |
| dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/OpenAIResponsesIntegrationTests.cs | Updates tests for new ResponsesClient usage and per-call model passing. |
| dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/FunctionApprovalTests.cs | Renames regions and swaps approval content types to tool-approval equivalents. |
| dotnet/src/Shared/Workflows/Execution/WorkflowRunner.cs | Consolidates approval auto-response handling to a single tool-approval path. |
| dotnet/src/Microsoft.Agents.AI.Workflows/Specialized/AIAgentHostExecutor.cs | Switches “user input” interception path to tool-approval request/response content. |
| dotnet/src/Microsoft.Agents.AI.Workflows/AIAgentHostOptions.cs | Updates XML docs to reference ToolApprovalRequestContent. |
| dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeMcpToolExecutor.cs | Uses tool-approval request/response and migrates MCP result payload to Outputs. |
| dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeFunctionToolExecutor.cs | Emits tool-approval requests for function tools that require approval. |
| dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/ObjectModel/InvokeAzureAgentExecutor.cs | Treats tool-approval requests as “blocking” content when filtering responses. |
| dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.Mcp/DefaultMcpToolHandler.cs | Renames MCP tool result list from Output to Outputs and updates population logic. |
| dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIResponseClientExtensions.cs | Adds optional model plumbing to agent/chat-client helpers for plain ResponsesClient usage. |
| dotnet/src/Microsoft.Agents.AI.OpenAI/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResult.cs | Suppresses OPENAI001 experimental warnings at file scope. |
| dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Streaming/FunctionApprovalResponseEventGenerator.cs | Renames generator to tool-approval response generator and maps RequestId. |
| dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Streaming/FunctionApprovalRequestEventGenerator.cs | Renames generator to tool-approval request generator and handles non-function tool calls by skipping. |
| dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/AgentResponseUpdateExtensions.cs | Switches streaming event generator selection to tool-approval content types. |
| dotnet/samples/05-end-to-end/M365Agent/AFAgentApplication.cs | Updates sample approval card plumbing to deserialize/handle tool-approval content. |
| dotnet/samples/05-end-to-end/AgentWebChat/AgentWebChat.Web/OpenAIResponsesAgentClient.cs | Uses model-less ResponsesClient and passes model via AsIChatClient(agentName). |
| dotnet/samples/03-workflows/Agents/GroupChatToolApproval/Program.cs | Updates sample to read tool-approval requests and extract function call info via ToolCall. |
| dotnet/samples/02-agents/ModelContextProtocol/ResponseAgent_Hosted_MCP/Program.cs | Updates MCP approval loop to use unified tool-approval request content. |
| dotnet/samples/02-agents/ModelContextProtocol/FoundryAgent_Hosted_MCP/Program.cs | Updates MCP approval loop to use unified tool-approval request content. |
| dotnet/samples/02-agents/FoundryAgents/FoundryAgents_Step12_Middleware/Program.cs | Updates middleware example to use tool-approval request content. |
| dotnet/samples/02-agents/FoundryAgents/FoundryAgents_Step04_UsingFunctionToolsWithApprovals/Program.cs | Updates function-approval loop example to use tool-approval request content. |
| dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Server/ServerFunctionApprovalServerAgent.cs | Updates server-side approval translation to tool-approval content types. |
| dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/ServerFunctionApprovalClientAgent.cs | Updates client-side approval translation to tool-approval content types. |
| dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Client/Program.cs | Updates console client to display/answer tool-approval requests. |
| dotnet/samples/02-agents/AgentWithOpenAI/Agent_OpenAI_Step05_Conversation/Program.cs | Updates agent creation to pass model via AsIChatClient(model) with model-less GetResponsesClient(). |
| dotnet/samples/02-agents/AgentWithOpenAI/Agent_OpenAI_Step04_CreateFromOpenAIResponseClient/Program.cs | Updates sample agent instantiation to supply model separately. |
| dotnet/samples/02-agents/AgentWithOpenAI/Agent_OpenAI_Step04_CreateFromOpenAIResponseClient/OpenAIResponseClientAgent.cs | Adds optional model parameter and passes it into AsIChatClient(model). |
| dotnet/samples/02-agents/AgentWithOpenAI/Agent_OpenAI_Step02_Reasoning/Program.cs | Updates reasoning sample to pass model through AsIChatClient(model). |
| dotnet/samples/02-agents/Agents/Agent_Step11_Middleware/Program.cs | Updates middleware example to use tool-approval request content. |
| dotnet/samples/02-agents/Agents/Agent_Step01_UsingFunctionToolsWithApprovals/Program.cs | Updates function-approval loop example to use tool-approval request content. |
| dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIResponses/Program.cs | Updates provider example to pass model via .AsAIAgent(model: ...) with model-less GetResponsesClient(). |
| dotnet/Directory.Packages.props | Bumps multiple package versions (System., Microsoft.Extensions.AI, OpenAI). |
Comments suppressed due to low confidence (2)
dotnet/tests/Microsoft.Agents.AI.Workflows.UnitTests/TestRequestAgent.cs:216
- The
Invalid requestexception message inProcessResponseis misleading: it reports it expectsToolApprovalResponseContentwhen it is actually validating the request pulled fromUnservicedRequests. This makes debugging test failures harder; update the message (or remove the redundant type-check sincerequestis alreadyToolApprovalRequestContent).
dotnet/samples/02-agents/AGUI/Step04_HumanInLoop/Server/ServerFunctionApprovalServerAgent.cs:196 ToolApprovalRequestContentcan wrap approvals for non-function tool calls (e.g., MCP). This code unconditionally castsrequest.ToolCalltoFunctionCallContent, which will throwInvalidCastExceptionor incorrectly transform non-function approvals. Please guard withif (request.ToolCall is FunctionCallContent functionCall)and skip/handle other tool-call types.
#pragma warning disable MEAI001 // Type is for evaluation purposes only
if (content is ToolApprovalRequestContent request && request.ToolCall is FunctionCallContent functionCall)
{
updatedContents ??= [.. update.Contents];
var approvalId = request.RequestId;
var approvalData = new ApprovalRequest
{
ApprovalId = approvalId,
FunctionName = functionCall.Name,
FunctionArguments = functionCall.Arguments,
Message = $"Approve execution of '{functionCall.Name}'?"
};
| public ToolApprovalResponseContent CreatePairedResponse(ToolApprovalRequestContent request) | ||
| { | ||
| if (request is not FunctionApprovalRequestContent approvalRequest) | ||
| if (request is not ToolApprovalRequestContent approvalRequest) | ||
| { | ||
| throw new InvalidOperationException($"Invalid request: Expecting {typeof(FunctionApprovalResponseContent)}, got {request.GetType()}"); | ||
| throw new InvalidOperationException($"Invalid request: Expecting {typeof(ToolApprovalResponseContent)}, got {request.GetType()}"); | ||
| } | ||
|
|
||
| return new FunctionApprovalResponseContent(approvalRequest.Id, true, approvalRequest.FunctionCall); | ||
| return new ToolApprovalResponseContent(approvalRequest.RequestId, true, approvalRequest.ToolCall); |
There was a problem hiding this comment.
In CreatePairedResponse, the type-check is redundant (the parameter is already ToolApprovalRequestContent) and the exception message is incorrect: it says it's expecting ToolApprovalResponseContent even though this is validating a request. Please either remove the check or update it to validate the underlying ToolCall type (and fix the message accordingly).
This issue also appears on line 206 of the same file.
| if (!this._userInputHandler!.MarkRequestAsHandled(response.RequestId)) | ||
| { | ||
| throw new InvalidOperationException($"No pending UserInputRequest found with id '{response.Id}'."); | ||
| throw new InvalidOperationException($"No pending UserInputRequest found with id '{response.RequestId}'."); |
There was a problem hiding this comment.
The thrown error still refers to UserInputRequest even though this handler now processes ToolApprovalResponseContent. Consider updating the message to reference tool approval requests/responses so failures are actionable (e.g., "No pending ToolApprovalRequest found...").
| throw new InvalidOperationException($"No pending UserInputRequest found with id '{response.RequestId}'."); | |
| throw new InvalidOperationException($"No pending ToolApprovalRequest found with id '{response.RequestId}'."); |
Motivation and Context
OpenAI 2.9.1 and Microsoft.Extensions.AI 10.4.0 introduced breaking API changes requiring updates across the codebase.
Description
Package bumps
OpenAI2.8.0 → 2.9.1Microsoft.Extensions.AI/Microsoft.Extensions.AI.Abstractions/Microsoft.Extensions.AI.OpenAI10.3.0 → 10.4.0OpenAI 2.9.1: model moved from
GetResponsesClienttoAsIChatClient/AsAIAgentUpdated
OpenAIResponseClientExtensions, all samples, integration test fixtures, andOpenAIResponsesAgentClient.ME.AI 10.4.0: approval content type unification
FunctionApprovalRequestContent,FunctionApprovalResponseContent,UserInputRequestContent,UserInputResponseContent, andMcpServerToolApprovalRequestContent/McpServerToolApprovalResponseContentare all replaced byToolApprovalRequestContent/ToolApprovalResponseContent. Constructor paramid:→requestId:. Property.Id→.RequestId.Updated across ~30 files including sources, samples, and tests. Key behavioral changes:
WorkflowRunner: merged separateApproveFunction+ApproveMCPhandlers into a singleApproveToolCalldispatching onToolCalltype via switch expressionFunctionApprovalRequestEventGenerator: replaced hard cast(FunctionCallContent)approvalRequest.ToolCallwith pattern match; silently skips non-function approval requests (e.g., MCP) rather than throwingToolApprovalRequestContent.ToolCallis nowToolCallContent(base); must cast toMcpServerToolCallContentto access.Name(was.ToolName) and.ServerNameClient/Program.csandServerFunctionApprovalServerAgent.cs: replaced unsafe(FunctionCallContent)approvalRequest.ToolCallcasts with safewhen approvalRequest.ToolCall is FunctionCallContent fccpattern matching, ensuring only function-based approvals are handledME.AI 10.4.0:
McpServerToolResultContent.Output→.OutputsUpdated in
InvokeMcpToolExecutor,DefaultMcpToolHandler, and test mocks.Other
#pragma warning disable OPENAI001forAsOpenAIStreamingChatCompletionUpdatesAsync, newly marked experimental in 2.9.1CreateResponseAsync/CreateResponseStreamingAsyncsignatures updated in integration testsContribution Checklist
🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.