-
Notifications
You must be signed in to change notification settings - Fork 1.1k
.NET: [Breaking] Structured Output improvements #3761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
* 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
There was a problem hiding this comment.
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 implementAIAgent.RunAsync<T>that drives SO viaResponseFormat(including wrapping for primitives/arrays). - Introduce
StructuredOutputAgent(+ options/response) andUseStructuredOutputbuilder 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
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.Abstractions/AgentRunOptions.cs | Adds ResponseFormat and Clone() to make SO configuration available on the base options type. |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgent.cs | Makes AIAgent partial to host new typed structured output APIs. |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.cs | Implements AIAgent.RunAsync<T> via AgentRunOptions.ResponseFormat, including schema wrapping for non-object roots. |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponse.cs | Removes Deserialize/TryDeserialize APIs and adds a copy constructor used by typed responses. |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AgentResponse{T}.cs | Reworks typed responses to deserialize from Text, including unwrap logic for wrapped schemas. |
| dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgent.cs | Adds decorator that converts inner agent text into structured JSON using an IChatClient. |
| dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgentOptions.cs | Adds configuration surface for the SO decorator (system message + chat options). |
| dotnet/src/Microsoft.Agents.AI/StructuredOutput/StructuredOutputAgentResponse.cs | Adds response type that preserves the original (inner) response alongside SO output. |
| dotnet/src/Microsoft.Agents.AI/StructuredOutput/AIAgentBuilderExtensions.cs | Adds UseStructuredOutput to register the SO decorator via AIAgentBuilder. |
| dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs | Plumbs AgentRunOptions.ResponseFormat into ChatOptions.ResponseFormat during invocation. |
| dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentCustomOptions.cs | Updates typed RunAsync<T> overloads to return AgentResponse<T> and removes legacy schema flag parameter. |
| dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentRunOptions.cs | Adds Clone() override to preserve derived options during typed runs. |
| dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgentRunResponse{T}.cs | Removes ChatClientAgentResponse<T> wrapper in favor of AgentResponse<T>. |
| dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAgentRunOptions.cs | Moves ResponseFormat usage to base options + adds Clone() override for derived durable options. |
| dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgent.cs | Removes durable-specific RunAsync<T> in favor of base AIAgent typed APIs and base ResponseFormat. |
| dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgentProxy.cs | Aligns response format selection with new base AgentRunOptions.ResponseFormat. |
| dotnet/src/Microsoft.Agents.AI.DurableTask/CHANGELOG.md | Adds changelog entry noting the ResponseFormat migration for SO. |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AgentRunOptionsTests.cs | Adds clone tests including ResponseFormat. |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AgentResponseTests.cs | Updates tests away from removed Deserialize/TryDeserialize helpers. |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AIAgentStructuredOutputTests.cs | Adds coverage for wrapping/unwrapping behavior and typed result extraction. |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/TestJsonSerializerContext.cs | Registers Species in the test source-generated serializer context. |
| dotnet/tests/Microsoft.Agents.AI.DurableTask.UnitTests/DurableAgentRunOptionsTests.cs | Adds clone tests ensuring ResponseFormat is carried via base options. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/StructuredOutputAgentTests.cs | Adds unit tests validating decorator behavior, option precedence, and error handling. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/StructuredOutputAgentResponseTests.cs | Adds tests for preservation of the original response. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/StructuredOutput/AIAgentBuilderExtensionsTests.cs | Adds tests for UseStructuredOutput DI resolution and configuration. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_StructuredOutput_WithRunAsyncTests.cs | Adds focused tests for generic RunAsync<T> behavior on ChatClientAgent. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgent_StructuredOutput_WithFormatResponseTests.cs | Adds tests for ResponseFormat precedence across initialization/invocation/run options. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentRunOptionsTests.cs | Adds clone tests for derived run options including deep-clone of nested ChatOptions. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/ChatClient/ChatClientAgentTests.cs | Removes older structured output test coverage now split into dedicated files. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/Models/Animal.cs | Adds model type used in structured output tests. |
| dotnet/tests/Microsoft.Agents.AI.UnitTests/Models/Species.cs | Adds enum model used in structured output tests. |
| dotnet/tests/AgentConformance.IntegrationTests/StructuredOutputRunTests.cs | Adds cross-agent conformance suite for ResponseFormat and typed RunAsync<T>. |
| dotnet/tests/AgentConformance.IntegrationTests/Support/Constants.cs | Makes constants public for cross-test-project reuse. |
| dotnet/tests/AgentConformance.IntegrationTests/Support/SessionCleanup.cs | Makes cleanup helper public for cross-test-project reuse. |
| dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantStructuredOutputRunTests.cs | Adds structured output conformance instantiation for OpenAI Assistant. |
| dotnet/tests/OpenAIChatCompletion.IntegrationTests/OpenAIChatCompletionStructuredOutputRunTests.cs | Adds structured output conformance instantiation for OpenAI ChatCompletion. |
| dotnet/tests/OpenAIResponse.IntegrationTests/OpenAIResponseStructuredOutputRunTests.cs | Adds structured output conformance instantiation for OpenAI Responses. |
| dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentStructuredOutputRunTests.cs | Adds structured output conformance instantiation for Azure AI Agents persistent variant. |
| dotnet/tests/AzureAI.IntegrationTests/AIProjectClientFixture.cs | Enables creating a ChatClientAgent with options for initialization-time SO configuration. |
| dotnet/tests/AzureAI.IntegrationTests/AIProjectClientAgentStructuredOutputRunTests.cs | Adds integration coverage for initialization-time ResponseFormat on AIProjectClient agents. |
| dotnet/samples/GettingStarted/Agents/Agent_Step05_StructuredOutput/Program.cs | Restructures sample to demonstrate multiple SO approaches including middleware/decorator. |
| dotnet/samples/GettingStarted/Agents/Agent_Step05_StructuredOutput/README.md | Adds documentation for the updated structured output sample and scenarios. |
| dotnet/samples/GettingStarted/FoundryAgents/FoundryAgents_Step05_StructuredOutput/Program.cs | Updates sample to deserialize via JsonSerializer after removal of AgentResponse helpers. |
| dotnet/samples/GettingStarted/Workflows/_Foundational/08_WriterCriticWorkflow/Program.cs | Updates workflow sample to use direct JsonSerializer.Deserialize with explicit error handling. |
| dotnet/samples/M365Agent/Agents/WeatherForecastAgent.cs | Replaces removed AgentResponse deserialization helpers with local JSON helper. |
| dotnet/samples/GettingStarted/AGUI/Step05_StateManagement/Server/SharedStateAgent.cs | Replaces removed AgentResponse deserialization helpers with local JSON helper. |
| dotnet/samples/AGUIClientServer/AGUIDojoServer/SharedState/SharedStateAgent.cs | Replaces removed AgentResponse deserialization helpers with local JSON helper. |
| docs/decisions/0015-structured-output.md | Adds 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
- This foreach loop implicitly filters its target sequence - consider filtering the sequence explicitly using '.Where(...)'.
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
RunAsync<T>non-virtual methods to the AIAgent base abstract class.Closes: #2874, #1057, #1642, #2683, #3231