fix(tool): allow null for optional nested object fields#1170
fix(tool): allow null for optional nested object fields#1170JGoP-L wants to merge 2 commits intoagentscope-ai:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes tool input validation so that optional object fields explicitly set to null are treated the same as omitted fields, preventing brittle failures during JSON Schema validation (Fixes #1163).
Changes:
- Normalize tool-call JSON inputs by pruning
nullobject properties before running JSON Schema validation. - Add regression tests covering generated nested bean schemas accepting missing vs explicit-
nulloptional fields. - Add protection tests confirming nested bean parameter conversion already handles missing vs explicit-
nulloptional fields.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
agentscope-core/src/main/java/io/agentscope/core/tool/ToolValidator.java |
Adds pre-validation normalization that prunes null-valued object properties before schema validation. |
agentscope-core/src/test/java/io/agentscope/core/tool/ToolValidatorTest.java |
Adds regression tests for generated bean schemas around missing vs explicit null optional nested fields. |
agentscope-core/src/test/java/io/agentscope/core/tool/ToolMethodInvokerTest.java |
Adds conversion tests showing bean parameter conversion behaves correctly for missing vs explicit null optional fields. |
| /** | ||
| * Removes null-valued object properties before schema validation. | ||
| * | ||
| * <p>This treats explicit nulls the same as omitted optional fields, while still allowing | ||
| * required-field validation to fail naturally after the null-valued property is removed. |
There was a problem hiding this comment.
normalizeOptionalNullFields/pruneNullObjectFields removes all null-valued object properties before schema validation. This can inadvertently let invalid inputs pass when the schema is strict (e.g., additionalProperties: false): an unknown field provided as null will be removed prior to validation and therefore won't be reported as an additional/unknown property. Consider restricting pruning to schema-declared optional properties (schema-aware walk), or doing a two-pass validation where you only remove fields that failed specifically due to a null type mismatch and then re-validate (so additional-properties violations are still caught).
| if (node.isObject()) { | ||
| ObjectNode objectNode = (ObjectNode) node; | ||
| List<String> nullFieldNames = new java.util.ArrayList<>(); | ||
| objectNode |
There was a problem hiding this comment.
Avoid using fully-qualified collection types in new code (new java.util.ArrayList<>()). Please add an import java.util.ArrayList; and use new ArrayList<>() for consistency with the rest of the file and the project's Java standards.
|
|
||
| String result = ToolValidator.validateInput(input, toolSchema); | ||
| assertNull(result, "Explicit null optional nested field should be accepted"); | ||
| } |
There was a problem hiding this comment.
The new regression tests cover optional nested bean fields, but they don't assert the other half of the contract described in the PR: that a required nested bean field explicitly set to null still fails validation. Adding a test for {"payload":{"requiredField":null}} (or similar) would prevent future changes from accidentally making required-null pass due to pruning.
| } | |
| } | |
| @Test | |
| @DisplayName("Should reject explicit null required nested bean field") | |
| void testGeneratedBeanSchema_ExplicitNullRequiredField() throws Exception { | |
| Map<String, Object> toolSchema = buildBeanToolSchema(); | |
| String input = "{\"payload\":{\"requiredField\":null}}"; | |
| String result = ToolValidator.validateInput(input, toolSchema); | |
| assertNotNull(result, "Explicit null required nested field should be rejected"); | |
| } |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
AgentScope-Java Version
1.0.12-SNAPSHOT
Description
Fixes #1163
Background
When a tool parameter contains a nested object, AgentScope-Java currently treats these two cases differently for optional fields:
nullCase 1 passes validation, but case 2 fails during JSON Schema validation with an error like:
null found, string expectedThis makes tool calling brittle in practice, because LLMs often emit
nullfor optional fields instead of omitting them entirely.Purpose
Make optional nested object fields behave consistently:
null: also validRequired field validation should continue to work as before.
Changes made
1. Fix tool input validation for explicit
nulloptional fieldsUpdated
ToolValidator.validateInput(...)to normalize tool input before JSON Schema validation.It now recursively removes
null-valued object properties before validating the payload. This means:nullare treated the same as omitted fieldsnullstill fail validation, because the field is removed and then checked byrequiredModified file:
agentscope-core/src/main/java/io/agentscope/core/tool/ToolValidator.java2. Add regression tests for generated nested bean schema
Added tests to verify:
nulloptional nested bean field is acceptedModified file:
agentscope-core/src/test/java/io/agentscope/core/tool/ToolValidatorTest.java3. Add protection tests for object parameter conversion
Added tests to confirm that nested bean parameter conversion itself already works correctly for:
nulloptional fieldThis verifies the bug is in validation behavior rather than conversion behavior.
Modified file:
agentscope-core/src/test/java/io/agentscope/core/tool/ToolMethodInvokerTest.javaHow to test
Run:
mvn -pl agentscope-core -Dtest=ToolValidatorTest,ToolMethodInvokerTest test