Allow empty and null ToolContext in tool method invocation#6557
Open
kuntal1461 wants to merge 2 commits into
Open
Allow empty and null ToolContext in tool method invocation#6557kuntal1461 wants to merge 2 commits into
ToolContext in tool method invocation#6557kuntal1461 wants to merge 2 commits into
Conversation
When a tool method declares a `ToolContext` parameter, callers were
previously required to supply a non-empty context map or the call
failed immediately with `IllegalArgumentException` from
`MethodToolCallback.validateToolContextSupport()`. This forced
workarounds such as injecting fake placeholder entries
(e.g. `Map.of("foo","bar")`) even when the real context was empty
or optional.
Separately, `ChatClientRequestSpec.toolContext()` rejected any map
containing `null` values, making it impossible to represent optional
context entries (e.g. an `orderNumber` that may not always be
present) without pre-filtering them in application code.
Changes in `spring-ai-model` (`MethodToolCallback`):
- Remove `validateToolContextSupport()`, which incorrectly treated
an empty `ToolContext` the same as a missing one. Empty context is
valid; the tool method itself decides which keys it requires.
- In `buildMethodArguments()`, convert a `null` `ToolContext` to
`new ToolContext(Map.of())` so tool methods that declare the
parameter never receive `null`, preventing `NullPointerException`
without throwing at the framework level.
- Remove now-unused imports `ClassUtils` and `CollectionUtils`.
Changes in `spring-ai-client-chat` (`DefaultChatClient`):
- Remove the `Assert.noNullElements()` guard on context map values.
Callers can now pass `null` values to represent optional entries.
Guards for a null map reference, null keys, and blank keys are
preserved unchanged.
Closes spring-projects#6545
Signed-off-by: kuntal1461 <kuntal.1461@gmail.com>
The existing guard that rejects null values in the toolContext map was
correct and intentional — null values are ambiguous, break getOrDefault
semantics, and can cause serialization issues in MCP contexts. However,
the previous error message did not explain what to do instead:
Before: "context values cannot contain null elements"
After: "context values cannot contain null elements; to represent an
optional entry, omit the key rather than setting it to null"
The improved message guides callers toward the correct pattern: omit
the key entirely when a value is absent rather than setting it to null.
This is already possible now that an empty ToolContext is accepted by
MethodToolCallback (see companion fix in the previous commit).
Also adds two tests to DefaultChatClientTests covering edge cases that
were not previously exercised: a map with multiple values where one is
null (mixed case), and an empty map (which succeeds).
Closes spring-projects#6545
Signed-off-by: kuntal1461 <kuntal.1461@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Fixes #6545
Two related but independent bugs prevent callers from expressing an optional or absent tool context:
Bug 1 —
MethodToolCallback(spring-ai-model)validateToolContextSupport()treated an emptyToolContextthe same as a missing one, and threwIllegalArgumentExceptionin both cases. This forced callers to inject fake placeholder entries (e.g.Map.of("foo", "bar")) just to satisfy the guard, even when no real context was needed:Bug 2 —
DefaultChatClient(spring-ai-client-chat)ChatClientRequestSpec.toolContext()rejected maps that containednullvalues viaAssert.noNullElements(), making it impossible to represent optional context entries asnull.Changes
spring-ai-model—MethodToolCallbackvalidateToolContextSupport(). Empty context is valid; the tool method decides which keys it requires.buildMethodArguments(), convert anullToolContexttonew ToolContext(Map.of())so tool methods that declare the parameter never receivenull, preventing NPE without throwing.ClassUtilsandCollectionUtils.spring-ai-client-chat—DefaultChatClientAssert.noNullElements()guard on context map values only.nullmap reference → still rejectednullkeys → still rejectedBehaviour matrix
ToolContext+nullcontextToolContext(Map.of())ToolContext+ empty contextToolContext+ non-empty contextToolContext+ any contexttoolContext(map)withnullvaluetoolContext(null)map referencetoolContext(map)withnullkeyTests
New:
MethodToolCallbackToolContextTests— 13 tests covering:nullcontext (implicit viacall(input)) → tool receives emptyToolContextnullcontext → tool receives emptyToolContextHashMapandMap.of()are acceptednullvalue in context map is forwarded to the toolToolContextparam:null/ empty / non-empty context are all silently ignored (original behaviour preserved)nullcontext wraps correctly inToolExecutionExceptionUpdated:
DefaultChatClientTests— 2 tests renamed from*ThenThrowto*ThenSucceedto reflect the new allowed behaviour fornullmap values.Test results
spring-ai-modelspring-ai-client-chat