Skip to content

Conversation

@ttmunyunguma
Copy link
Member

Resolves #33562

Comment on lines 35 to 51
/**
* Tool Arguments are NOT required if:
*
* ToolArg.required is set to false
* ToolArg.defaultValue is set, and
* the argument return type is optional
*/
public static boolean isRequiredArgument(ArgumentMetadata argMetadata) {

if (argMetadata.defaultValue() != null && !argMetadata.defaultValue().isEmpty()) {
return false;
}
if (isOptionalType(argMetadata.type())) {
return false;
}
return argMetadata.required();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to do these checks before we create the argument metadata, and then set ArgumentMetadata.required according to these rules.

Then every other part of the code can just call argMetadata.required().

In general, the Metadata objects should reflect our final decisions about an object. For example, when we work out a tool name we look at the @Tool annotation, and if that doesn't set a value we look at the method name. Whatever we decide is what goes into the ToolMetadata so that nothing else has to worry about whether the name came from the annotation or from the method.

Comment on lines +74 to +81
public static Object resolveDefaultValue(ArgumentMetadata argMetadata) {
if (argMetadata.defaultValue() != null && !argMetadata.defaultValue().isEmpty()) {
try {
return convertDefaultValue(argMetadata.defaultValue(), argMetadata.type());
} catch (Exception e) {
throw new IllegalStateException("Failed to convert default value"); //TODO nlsprops
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this fail if the argument type is Optional<Something> and defaultValue is set?

* @throws IllegalStateException if default value conversion fails
*/
public static Object resolveDefaultValue(ArgumentMetadata argMetadata) {
if (argMetadata.defaultValue() != null && !argMetadata.defaultValue().isEmpty()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't want to do this check like this. If null and empty string should both be interpreted as not having a default value, we should turn them both into null before it's added to ArgumentMetadata and document what null means for defaultValue.

Comment on lines 57 to 59
if (providedArgs.containsKey(argName)) {
return providedArgs.get(argName);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (providedArgs.containsKey(argName)) {
return providedArgs.get(argName);
}
Object providedValue = providedArgs.get(argName);
if (providedValue != null) {
return providedValue;
}

Don't call containsKey and get back to back like this.

try {
return convertDefaultValue(argMetadata.defaultValue(), argMetadata.type());
} catch (Exception e) {
throw new IllegalStateException("Failed to convert default value"); //TODO nlsprops
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of the nls messages you might need were added in #33511 - McpToolCallParams.convertDefaultValueToArgType

I think moving all the logic for default values into their own class is a good idea, remember to take a look at what was done in #33511 and clean up any methods which are no longer called.

Comment on lines -95 to +107
argsArray[i] = t.args().get(name);
ArgumentMetadata argMetadata = arguments.get(name);
if (argMetadata != null) {
argsArray[i] = ArgumentResolver.resolveArgumentValue(argMetadata, name, providedArgs);
} else {
argsArray[i] = providedArgs.get(name);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make ToolArguments contain the resolved argument values.

At the moment it doesn't make difference, but the interface for registering tools programatically allow a default value to be provided:

/**
*
* @param name
* @param description
* @param required
* @param type
* @param defaultValue
* @return self
*/
ToolDefinition addArgument(String name, String description, boolean required, java.lang.reflect.Type type,
String defaultValue);

This only makes sense if the ToolArguments object provided to the handler already has these default values resolved.

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

Successfully merging this pull request may close these issues.

2 participants