ToolContext is now excluded from JSON Schema Generation

When generating the JSON Schema for a tool input from a method, ToolContext is now excluded since it's not something we want the model to provide. The framework takes care of passing a value for it when actually executing the tool call.

Fixes gh-2366

Signed-off-by: Thomas Vitale <ThomasVitale@users.noreply.github.com>
This commit is contained in:
Thomas Vitale
2025-03-27 16:52:26 +01:00
committed by Christian Tzolov
parent 3c17750a00
commit 83294023cd
4 changed files with 48 additions and 2 deletions

View File

@@ -43,7 +43,7 @@ import org.springframework.ai.chat.messages.Message;
* @author Christian Tzolov
* @since 1.0.0
*/
public class ToolContext {
public final class ToolContext {
/**
* The key for the running, tool call history stored in the context map.

View File

@@ -31,10 +31,12 @@ import com.github.victools.jsonschema.module.jackson.JacksonModule;
import com.github.victools.jsonschema.module.jackson.JacksonOption;
import com.github.victools.jsonschema.module.swagger2.Swagger2Module;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.ai.util.json.JsonParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
@@ -125,6 +127,14 @@ public final class JsonSchemaGenerator {
for (int i = 0; i < method.getParameterCount(); i++) {
String parameterName = method.getParameters()[i].getName();
Type parameterType = method.getGenericParameterTypes()[i];
if (parameterType instanceof Class<?> parameterClass
&& ClassUtils.isAssignable(parameterClass, ToolContext.class)) {
// A ToolContext method parameter is not included in the JSON Schema
// generation.
// It's a special type used by Spring AI to pass contextual data to tools
// outside the model interaction flow.
continue;
}
if (isMethodParameterRequired(method, i)) {
required.add(parameterName);
}

View File

@@ -23,6 +23,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.media.Schema;
import org.junit.jupiter.api.Test;
import org.springframework.ai.chat.model.ToolContext;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.ai.util.json.schema.JsonSchemaGenerator;
import org.springframework.lang.Nullable;
@@ -347,6 +348,36 @@ class JsonSchemaGeneratorTests {
assertThat(schema).isEqualToIgnoringWhitespace(expectedJsonSchema);
}
@Test
void generateSchemaForMethodWithToolContext() throws Exception {
Method method = TestMethods.class.getDeclaredMethod("contextMethod", String.class, LocalDateTime.class,
ToolContext.class);
String schema = JsonSchemaGenerator.generateForMethodInput(method);
String expectedJsonSchema = """
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"deliveryStatus": {
"type": "string"
},
"expectedDelivery": {
"type": "string",
"format": "date-time"
}
},
"required": [
"deliveryStatus",
"expectedDelivery"
],
"additionalProperties": false
}
""";
assertThat(schema).isEqualToIgnoringWhitespace(expectedJsonSchema);
}
// TYPES
@Test
@@ -658,6 +689,9 @@ class JsonSchemaGeneratorTests {
public void timeMethod(Duration duration, LocalDateTime localDateTime, Instant instant) {
}
public void contextMethod(String deliveryStatus, LocalDateTime expectedDelivery, ToolContext toolContext) {
}
}
record TestData(int id, @ToolParam(description = "The special name") String name) {

View File

@@ -171,10 +171,12 @@ To use this automation:
This approach can save time and reduce the chance of errors when upgrading multiple projects or complex codebases.
== Upgrading to 1.0.0.M7
* The `ToolContext` class has now been marked as final and cannot be extended anymore. It was never supposed to be subclassed. You can add all the contextual data you need when instantiating a `ToolContext`, in the form of a `Map<String, Object>`. For more information, check the [documentation](https://docs.spring.io/spring-ai/reference/api/tools.html#_tool_context).
== Upgrading to 1.0.0.M6
=== Changes to Usage Interface and DefaultUsage Implementation
The `Usage` interface and its default implementation `DefaultUsage` have undergone the following changes: