spring-projects / spring-projects/spring-ai
`ToolInputSchemaAugmenter` defaults `required` to false, unlike `JsonSchemaGenerator`
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
ToolInputSchemaAugmenter and JsonSchemaGenerator produce different required sets for the same record, and I can't tell from the code which one is intended.
What happens
record Bare(String plain, @ToolParam(description = "annotated") String annotated) {}
JsonSchemaGenerator.generateForType(Bare.class):
"required" : [ "annotated", "plain" ]
ToolInputSchemaAugmenter.augmentToolInputSchema("{}", toAugmentedArgumentTypes(Bare.class)):
"required" : [ "annotated" ]
plain is required on the main path and optional through the augmenter, so a model talking to an augmented tool may leave it out.
Where it comes from
ToolInputSchemaAugmenter:66-69:
return new AugmentedArgumentType(c.getName(), c.getGenericType(),
toolParam != null ? toolParam.description() : "no description",
toolParam != null ? toolParam.required() : false);
JsonSchemaGenerator:87 sets the opposite default, and the javadoc says it is the framework's rule:
/**
* ... all properties in the JSON Schema are considered required by default. This can
* be overridden by setting the {@link ToolParam#required()}, ...
*/
private static final boolean PROPERTY_REQUIRED_BY_DEFAULT = true;
ToolParam.required() is itself default true, so the two branches disagree in a way that reads oddly: writing @ToolParam(description = "…") makes a field required, and leaving it unannotated makes it optional.
The description default has the same shape. Unannotated fields get the literal string "no description", which ends up in the schema as the property's description, whereas JsonSchemaGenerator just omits description for plain.
Why I'm asking rather than sending a patch
ToolInputSchemaAugmenterTest asserts the current behaviour explicitly:
for (AugmentedArgumentType argType : argumentTypes) {
assertEquals("no description", argType.description());
assertFalse(argType.required());
}
So either the augmenter is deliberately more permissive than the main path and the tests are right, or the defaults were an oversight and the tests were written around them. Changing it means rewriting those assertions and changing the schema existing AugmentedToolCallback users get, which didn't feel like my call.
Happy to send a PR for whichever you prefer — aligning both defaults with PROPERTY_REQUIRED_BY_DEFAULT and dropping the "no description" placeholder, or leaving the behaviour and documenting that the augmenter defaults differ.
Measured on main (bf122ac).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with ToolInputSchemaAugmenter:66-69 and JsonSchemaGenerator:87, then read ToolInputSchemaAugmenterTest and the ToolParam defaults. Compare the required and description behavior for annotated and unannotated record components. Done means the intended default is decided with maintainers and the implementation, tests, and documentation consistently reflect it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100