.NET: Throw if structured output is not supported#3726
.NET: Throw if structured output is not supported#3726SergeyMenshykh wants to merge 2 commits intomicrosoft:feature-sofrom
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds structured output support detection to the agent framework by introducing a SupportsStructuredOutput property to AIAgentMetadata. The goal is to fail early when users attempt to use RunAsync<T> with agents that don't natively support structured output, helping them understand they need to add structured output middleware.
Changes:
- Added
SupportsStructuredOutputboolean property toAIAgentMetadatawith a default value offalse - Added runtime validation in
RunAsync<T>methods to throwNotSupportedExceptionwhen structured output is not supported - Marked
ChatClientAgentandDurableAIAgentas supporting structured output
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentMetadata.cs | Added SupportsStructuredOutput property and constructor parameter with comprehensive XML documentation |
| dotnet/src/Microsoft.Agents.AI.Abstractions/AIAgentStructuredOutput.cs | Added validation to check metadata and throw NotSupportedException before processing structured output requests |
| dotnet/src/Microsoft.Agents.AI/ChatClient/ChatClientAgent.cs | Set supportsStructuredOutput: true when creating agent metadata |
| dotnet/src/Microsoft.Agents.AI.DurableTask/DurableAIAgent.cs | Added static metadata with supportsStructuredOutput: true, overrode GetService to return metadata, and added Name property override |
| dotnet/tests/Microsoft.Agents.AI.Abstractions.UnitTests/AIAgentTests.cs | Added comprehensive tests for structured output support detection and metadata behavior |
| dotnet/tests/Microsoft.Agents.AI.DurableTask.UnitTests/DurableAIAgentTests.cs | Added tests for DurableAIAgent metadata, GetService implementation, and name property |
| this._agentOptions = options?.Clone(); | ||
|
|
||
| this._agentMetadata = new AIAgentMetadata(chatClient.GetService<ChatClientMetadata>()?.ProviderName); | ||
| this._agentMetadata = new AIAgentMetadata(chatClient.GetService<ChatClientMetadata>()?.ProviderName, supportsStructuredOutput: true); |
There was a problem hiding this comment.
Given we don't know the capabilities of the model associated with the chatClient what is the thinking behind setting this to be true?
There was a problem hiding this comment.
I'm also in two minds whether it makes sense. Providing true here is technically misleading, and if the service/model does not support structured output the call will eventually fail anyway when we try and deserialize the results. If this property was only for our own consumption to fail early, it may not be as bad, but the fact that it is public to all users isn't great.
Consider for example, if a user uses this metadata to decide whether to decorate a random AIAgent from DI with a Structured Output Agent to add structured output capabilities. They would expect it to always work, but in some cases it may still fail, since we said true here, but the model may not actually support it.
There was a problem hiding this comment.
There's no way the functionality is going to work reliably with the chat client agent. Even if the chat client exposes a way to check if SO is supported and the chat client agent uses it, it will still be up to the developer to configure the particular chat client with the model and specify if SO is supported by the model or not. If the developer mistakenly specifies that the model supports SO but it does not, AF will fail in the same way as it would without this functionality at the point of accessing the agent's SO result - response.Result. Therefore, I would suggest keeping it simple and not adding this feature.
Motivation and Context
Currently, to use structured output (SO) with AF agents, users need to know whether a particular agent, or in the case of the ChatClientAgent, a particular chat client supports SO. If the agent supports SO, the
RunAsync<T>methods can be used safely. If the agent does not support SO, then SO middleware can be used; otherwise, the user may receive a plain text response instead of an SO response, causing deserialization (accessing the response.Result property) to fail.If users mistakenly try to get SO from an agent that does not natively support it and no SO middleware is used, it would be helpful to fail early and notify the
RunAsync<T>caller that SO is not supported. However, this can only be done with agents that AF "knows" do not support SO. It won't work with agents like the ChatClientAgent, whose SO capabilities depend on the chat client being used. In those cases, it is still the user's responsibility to either use an SO-capable chat client or use middleware.Description
truefor two agents: ChatClientAgent and DurableAIAgent.RunAsync<T>method if SO is not supported.