Skip to content

.NET: [Breaking] Structured Output improvements - #3761

Merged
SergeyMenshykh merged 20 commits into
mainfrom
feature-so
Feb 13, 2026
Merged

.NET: [Breaking] Structured Output improvements#3761
SergeyMenshykh merged 20 commits into
mainfrom
feature-so

Conversation

@SergeyMenshykh

@SergeyMenshykhSergeyMenshykh commented Feb 9, 2026

Copy link
Copy Markdown
Contributor

Motivation and Context

Currently, Structured Output (SO) in AF is supported by ChatClientAgent only and can be "enabled" either via the ResponseFormat property or the RunAsync<T> instance method.

However, if ChatClientAgent is decorated by, let's say, an Open Telemetry decorator, the agent users lose access to the RunAsync<T> methods because they are instance methods of ChatClientAgent rather than members of the AIAgent class.

Additionally, AF does not provide SO support for the other agents, i.e., A2A, which do not support SO natively.

Furthermore, there's no way to provide SO configuration via the ResponseFormat property to any agent except ChatClientAgent at agent invocation because AgentRunOptions don't have the property and it only exists on ChatClientAgentRunOptions.

Description

  • Add the ResponseFormat property to the AgentRunOptions to communicate the agent's SO configuration.
  • Add RunAsync<T> non-virtual methods to the AIAgent base abstract class.
  • Add the StructuredOutputAgent decorator to add SO support to agents that don't natively support SO.
  • Add the UseStructuredOutput extension method for the AIAgentBuilder, allowing easy registration of the decorator during the agent configuration step.
  • Restructure the SO sample to showcase different ways of working with SO in AF.

Closes: #2874, #1057, #1642, #2683, #3231

SergeyMenshykhand others added 7 commits January 30, 2026 14:30
* delete deserialize method of agent response
* order usings
* Update dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step05_StructuredOutput/Program.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/samples/GettingStarted/Workflows/_Foundational/08_WriterCriticWorkflow/Program.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/samples/GettingStarted/AGUI/Step05_StateManagement/Server/SharedStateAgent.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/samples/AGUIClientServer/AGUIDojoServer/SharedState/SharedStateAgent.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/samples/M365Agent/Agents/WeatherForecastAgent.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* add support for so
* restore lost xml comment part
* fix using ordering
* Update dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_SO_WithFormatResponseTests.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* addressw pr review comments
* address pr review feedback
* address pr review comments
* fix compilation issues after the latest merge with main
* remove unnecessry options
* remove RunAsync<object> methods
* address code review feedback
* address pr review feedback
* make copy constructor protected
* address pr review feedback
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* add decorator that adds structured output support to agents that don't natively support it.
* Update dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgentResponse.cs
Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
* Update dotnet/samples/GettingStarted/Agents/Agent_Step05_StructuredOutput/Program.cs
Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
* address pr review feedback
---------
Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
* wrap primitives and arrays
* fix file encoding
* address review comments
@SergeyMenshykhSergeyMenshykh self-assigned this Feb 9, 2026
CopilotAI review requested due to automatic review settings February 9, 2026 13:54
@SergeyMenshykhSergeyMenshykh moved this to In Review in Agent FrameworkFeb 9, 2026
@markwallace-microsoftMark Wallace (markwallace-microsoft) added documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs .NET Usage: [Issues, PRs], Target: .Net labels Feb 9, 2026

CopilotAI 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 broadens and standardizes Structured Output (SO) support across .NET Agent Framework agents by moving SO configuration onto the common AgentRunOptions surface and adding typed RunAsync<T> APIs to AIAgent, while also introducing a decorator-based fallback (StructuredOutputAgent) for agents that can’t produce SO natively.

Changes:

  • Add AgentRunOptions.ResponseFormat + cloning support, and implement AIAgent.RunAsync<T> that drives SO via ResponseFormat (including wrapping for primitives/arrays).
  • Introduce StructuredOutputAgent (+ options/response) and UseStructuredOutput builder extension to enable SO for non-native agents.
  • Update unit/integration tests, conformance tests, samples, and add an ADR documenting the design and tradeoffs.

Reviewed changes

Copilot reviewed 48 out of 48 changed files in this pull request and generated 4 comments.

Show a summary per file
FileDescription
dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.csAdds ResponseFormat and Clone() to make SO configuration available on the base options type.
dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgent.csMakes AIAgent partial to host new typed structured output APIs.
dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.csImplements AIAgent.RunAsync<T> via AgentRunOptions.ResponseFormat, including schema wrapping for non-object roots.
dotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponse.csRemoves Deserialize/TryDeserialize APIs and adds a copy constructor used by typed responses.
dotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponse{T}.csReworks typed responses to deserialize from Text, including unwrap logic for wrapped schemas.
dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgent.csAdds decorator that converts inner agent text into structured JSON using an IChatClient.
dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgentOptions.csAdds configuration surface for the SO decorator (system message + chat options).
dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgentResponse.csAdds response type that preserves the original (inner) response alongside SO output.
dotnet/src/Microsoft.Agents.AI/StructuredOutput/AIAgentBuilderExtensions.csAdds UseStructuredOutput to register the SO decorator via AIAgentBuilder.
dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.csPlumbs AgentRunOptions.ResponseFormat into ChatOptions.ResponseFormat during invocation.
dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentCustomOptions.csUpdates typed RunAsync<T> overloads to return AgentResponse<T> and removes legacy schema flag parameter.
dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentRunOptions.csAdds Clone() override to preserve derived options during typed runs.
dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentRunResponse{T}.csRemoves ChatClientAgentResponse<T> wrapper in favor of AgentResponse<T>.
dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAgentRunOptions.csMoves ResponseFormat usage to base options + adds Clone() override for derived durable options.
dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgent.csRemoves durable-specific RunAsync<T> in favor of base AIAgent typed APIs and base ResponseFormat.
dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgentProxy.csAligns response format selection with new base AgentRunOptions.ResponseFormat.
dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.mdAdds changelog entry noting the ResponseFormat migration for SO.
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AgentRunOptionsTests.csAdds clone tests including ResponseFormat.
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AgentResponseTests.csUpdates tests away from removed Deserialize/TryDeserialize helpers.
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AIAgentStructuredOutputTests.csAdds coverage for wrapping/unwrapping behavior and typed result extraction.
dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/TestJsonSerializerContext.csRegisters Species in the test source-generated serializer context.
dotnet/tests/Microsoft.Agents.AI.DurableTask.UnitTests/DurableAgentRunOptionsTests.csAdds clone tests ensuring ResponseFormat is carried via base options.
dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/StructuredOutputAgentTests.csAdds unit tests validating decorator behavior, option precedence, and error handling.
dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/StructuredOutputAgentResponseTests.csAdds tests for preservation of the original response.
dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/AIAgentBuilderExtensionsTests.csAdds tests for UseStructuredOutput DI resolution and configuration.
dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_StructuredOutput_WithRunAsyncTests.csAdds focused tests for generic RunAsync<T> behavior on ChatClientAgent.
dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_StructuredOutput_WithFormatResponseTests.csAdds tests for ResponseFormat precedence across initialization/invocation/run options.
dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentRunOptionsTests.csAdds clone tests for derived run options including deep-clone of nested ChatOptions.
dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.csRemoves older structured output test coverage now split into dedicated files.
dotnet/tests/Microsoft.Agents.AI.UnitTests/Models/Animal.csAdds model type used in structured output tests.
dotnet/tests/Microsoft.Agents.AI.UnitTests/Models/Species.csAdds enum model used in structured output tests.
dotnet/tests/AgentConformance.IntegrationTests/StructuredOutputRunTests.csAdds cross-agent conformance suite for ResponseFormat and typed RunAsync<T>.
dotnet/tests/AgentConformance.IntegrationTests/Support/Constants.csMakes constants public for cross-test-project reuse.
dotnet/tests/AgentConformance.IntegrationTests/Support/SessionCleanup.csMakes cleanup helper public for cross-test-project reuse.
dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantStructuredOutputRunTests.csAdds structured output conformance instantiation for OpenAI Assistant.
dotnet/tests/OpenAIChatCompletion.IntegrationTests/OpenAIChatCompletionStructuredOutputRunTests.csAdds structured output conformance instantiation for OpenAI ChatCompletion.
dotnet/tests/OpenAIResponse.IntegrationTests/OpenAIResponseStructuredOutputRunTests.csAdds structured output conformance instantiation for OpenAI Responses.
dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.csAdds structured output conformance instantiation for Azure AI Agents persistent variant.
dotnet/tests/AzureAI.IntegrationTests/AIProjectClientFixture.csEnables creating a ChatClientAgent with options for initialization-time SO configuration.
dotnet/tests/AzureAI.IntegrationTests/AIProjectClientAgentStructuredOutputRunTests.csAdds integration coverage for initialization-time ResponseFormat on AIProjectClient agents.
dotnet/samples/GettingStarted/Agents/Agent_Step05_StructuredOutput/Program.csRestructures sample to demonstrate multiple SO approaches including middleware/decorator.
dotnet/samples/GettingStarted/Agents/Agent_Step05_StructuredOutput/README.mdAdds documentation for the updated structured output sample and scenarios.
dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step05_StructuredOutput/Program.csUpdates sample to deserialize via JsonSerializer after removal of AgentResponse helpers.
dotnet/samples/GettingStarted/Workflows/_Foundational/08_WriterCriticWorkflow/Program.csUpdates workflow sample to use direct JsonSerializer.Deserialize with explicit error handling.
dotnet/samples/M365Agent/Agents/WeatherForecastAgent.csReplaces removed AgentResponse deserialization helpers with local JSON helper.
dotnet/samples/GettingStarted/AGUI/Step05_StateManagement/Server/SharedStateAgent.csReplaces removed AgentResponse deserialization helpers with local JSON helper.
dotnet/samples/AGUIClientServer/AGUIDojoServer/SharedState/SharedStateAgent.csReplaces removed AgentResponse deserialization helpers with local JSON helper.
docs/decisions/0015-structured-output.mdAdds ADR capturing motivation, options considered, and selected approach for SO improvements.
Comments suppressed due to low confidence (1)

dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.cs:158

Comment threaddotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponse{T}.cs Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

.NET: Structured Output calling does not work with lists/array if ResponseFormat is used, but works if .RunAsync<> is used

5 participants

@SergeyMenshykh@rwjdk@markwallace-microsoft@westey-m