spring-ai
spring-ai copied to clipboard
feat: Extend ToolDefinition to Support Metadata
trafficstars
Close #4743
Extend ToolDefinition to Support Metadata
Create a ToolDefinitionWithMetadata Class
package org.springframework.ai.tool.definition;
import java.util.Map;
import org.springframework.util.Assert;
/**
* Tool definition with metadata support.
*/
public record ToolDefinitionWithMetadata(
String name,
String description,
String inputSchema,
Map<String, Object> metadata
) implements ToolDefinition {
public ToolDefinitionWithMetadata {
Assert.hasText(name, "name cannot be null or empty");
Assert.hasText(description, "description cannot be null or empty");
Assert.hasText(inputSchema, "inputSchema cannot be null or empty");
// Metadata can be empty
metadata = metadata != null ? Map.copyOf(metadata) : Map.of();
}
public static Builder builder() {
return new Builder();
}
public static final class Builder {
private String name;
private String description;
private String inputSchema;
private Map<String, Object> metadata = Map.of();
private Builder() {}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder description(String description) {
this.description = description;
return this;
}
public Builder inputSchema(String inputSchema) {
this.inputSchema = inputSchema;
return this;
}
public Builder metadata(Map<String, Object> metadata) {
this.metadata = metadata;
return this;
}
public Builder addMetadata(String key, Object value) {
if (this.metadata.isEmpty()) {
this.metadata = new java.util.HashMap<>();
} else if (!(this.metadata instanceof java.util.HashMap)) {
this.metadata = new java.util.HashMap<>(this.metadata);
}
this.metadata.put(key, value);
return this;
}
public ToolDefinitionWithMetadata build() {
return new ToolDefinitionWithMetadata(name, description, inputSchema, metadata);
}
}
}
Extend the @Tool Annotation
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Tool {
String name() default "";
String description() default "";
boolean returnDirect() default false;
Class<? extends ToolCallResultConverter> resultConverter() default DefaultToolCallResultConverter.class;
// New: Metadata support
/**
* Tool metadata for filtering and categorization.
* Format: "key1=value1,key2=value2"
* Example: "type=RealTimeAnalysis,priority=high"
*/
String metadata() default "";
}
Create a Dedicated @ToolMetadata Annotation (More Elegant Approach)
package org.springframework.ai.tool.annotation;
import java.lang.annotation.*;
/**
* Annotation to add metadata to a tool method.
* Can be used in conjunction with @Tool annotation.
*
* @author
* @since 1.0.0
*/
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ToolMetadata {
/**
* Metadata entries in key-value format.
* Example: {"type=RealTimeAnalysis", "category=analytics"}
*/
String[] value() default {};
/**
* Tool category for filtering purposes.
*/
String category() default "";
/**
* Tool type for classification.
*/
String type() default "";
/**
* Priority level (1–10, where 10 is the highest).
*/
int priority() default 5;
}
Usage Example
@Component
public class AnalysisTools {
@Tool(description = "Performs real-time data analysis")
@ToolMetadata(type = "RealTimeAnalysis", category = "analytics", priority = 8)
public String analyzeRealTimeData(String data) {
// Implementation
return "analysis result";
}
@Tool(description = "Performs historical data analysis")
@ToolMetadata(type = "HistoricalAnalysis", category = "analytics", priority = 5)
public String analyzeHistoricalData(String period) {
// Implementation
return "historical analysis";
}
}
Modify the Tool Registration Process
Modify MethodToolCallbackProvider to support metadata.
// Pseudocode example
private ToolDefinition createToolDefinition(Method method) {
ToolMetadata metadata = method.getAnnotation(ToolMetadata.class);
if (metadata != null) {
Map<String, Object> metadataMap = new HashMap<>();
if (!metadata.type().isEmpty()) {
metadataMap.put("type", metadata.type());
}
if (!metadata.category().isEmpty()) {
metadataMap.put("category", metadata.category());
}
metadataMap.put("priority", metadata.priority());
// Parse additional metadata from value entries
for (String entry : metadata.value()) {
String[] parts = entry.split("=", 2);
if (parts.length == 2) {
metadataMap.put(parts[0], parts[1]);
}
}
return ToolDefinitionWithMetadata.builder()
.name(getToolName(method))
.description(getToolDescription(method))
.inputSchema(generateSchema(method))
.metadata(metadataMap)
.build();
}
// Return the default ToolDefinition
return DefaultToolDefinition.builder()...build();
}
Summary: This proposal introduces metadata support for tool definitions, providing a standardized and extensible mechanism to annotate and categorize tools. It allows fine-grained filtering, better organization, and easier integration in complex AI systems.