Description
The old implementation (MethodInvokingFunctionCallback) skips ToolContext when generating JSON schemas for method inputs, but the new implementation (JsonSchemaGenerator) does not.
Old implementation:
protected String generateJsonSchema(Map<String, Class<?>> namedClasses) {
try {
JsonSchemaGenerator schemaGen = new JsonSchemaGenerator(this.mapper);
ObjectNode rootNode = this.mapper.createObjectNode();
rootNode.put("$schema", "https://json-schema.org/draft/2020-12/schema");
rootNode.put("type", "object");
ObjectNode propertiesNode = rootNode.putObject("properties");
for (Map.Entry<String, Class<?>> entry : namedClasses.entrySet()) {
String className = entry.getKey();
Class<?> clazz = entry.getValue();
if (ClassUtils.isAssignable(clazz, ToolContext.class)) {
this.isToolContextMethod = true;
continue;
}
JsonSchema schema = schemaGen.generateSchema(/clazz);
JsonNode schemaNode = this.mapper.valueToTree(schema);
propertiesNode.set(className, schemaNode);
}
return this.mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
New implementation:
public static String generateForMethodInput(Method method, SchemaOption... schemaOptions) {
ObjectNode schema = JsonParser.getObjectMapper().createObjectNode();
schema.put("$schema", SchemaVersion.DRAFT_2020_12.getIdentifier());
schema.put("type", "object");
ObjectNode properties = schema.putObject("properties");
List<String> required = new ArrayList<>();
for (int i = 0; i < method.getParameterCount(); i++) {
String parameterName = method.getParameters()[i].getName();
Type parameterType = method.getGenericParameterTypes()[i];
if (isMethodParameterRequired(method, i)) {
required.add(parameterName);
}
ObjectNode parameterNode = SUBTYPE_SCHEMA_GENERATOR.generateSchema(parameterType);
String parameterDescription = getMethodParameterDescription(method, i);
if (StringUtils.hasText(parameterDescription)) {
parameterNode.put("description", parameterDescription);
}
properties.set(parameterName, parameterNode);
}
var requiredArray = schema.putArray("required");
required.forEach(requiredArray::add);
processSchemaOptions(schemaOptions, schema);
return schema.toPrettyString();
}
Refer to the documentation (Spring AI ToolContext Documentation), which shows ToolContext is meant for passing user-provided or framework-managed context to tools, not as part of the input schema for the AI model. Including it might mislead users into thinking they need to provide it, potentially causing errors or confusion.
This change could lead to inconsistent behavior compared to previous versions, confuse users who expect ToolContext to be handled externally, or cause errors if users don't provide it when it's included in the schema.