Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New JSON schema generation includes ToolContext, while old implementation skips it. #2366

Open
DamonBao opened this issue Mar 3, 2025 · 1 comment

Comments

@DamonBao
Copy link

DamonBao commented Mar 3, 2025

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.

@ThomasVitale
Copy link
Contributor

Good catch! Thanks for reporting this. I'll have a look and fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants