-
Notifications
You must be signed in to change notification settings - Fork 850
Description
Description
Currently, parameters annotated with [Required] are treated the same as optional parameters if they had a default value or were otherwise non-optional, which can be surprising and is undocumented. This came up quite recently while investigating what looked to be an [inconsistency with tool parameter schema generation]. There, it wasn't clear why [Required] had no effect on the generated schema.
Motivation
It is extremely natural to expect that the [Required] attribute would mark a tool parameter as required. We already respect parameter annotations such as [Description], so it’s reasonable to expect [Required] to be honored as well. This inconsistency can lead to confusion, especially considering how other annotations are handled. Furthermore, SemanticKernel, which uses its own pipeline, honors the [Required] attribute when generating function schemas, meaning that this change could make developer expectations more consistent throughout libraries. This is especially true for SK users migrating to Agent Framework, which uses the same underlying schema generation logic from Microsoft.Extensions.AI.Abstractions.
Current Behavior
string MyTool([Required] int count = 1) { ... }
// produces
{
"properties": {
"count": { "type": "integer", "default": 1 }
}
}Expected Behavior
string MyTool([Required] int count = 1) { ... }
// SHOULD produce
{
"required": ["count"],
"properties": {
"count": { "type": "integer", "default": 1 }
}
}Root Cause
The code determining whether a parameter is required can be seen below: (link):
// ...
if (!parameter.IsOptional && !hasDefaultValue)
{
(requiredProperties ??= []).Add((JsonNode)parameter.Name);
}A potential change would be to detect the presence of [Required], treating the parameter as required, regardless of whether its using optional syntax or has a default value. Of course, we would keep the existing logic if [Required] is not present, keeping existing client code unaffected. This change would only affect schema generation, keeping other steps untouched (invocation, reflection, or runtime execution behavior).