Skip to content

Commit 7f12064

Browse files
Merge pull request #496 from jinnigu:feature/support-optional-parameter
PiperOrigin-RevId: 821782028
2 parents 04cd6ea + 9f56f3d commit 7f12064

File tree

4 files changed

+89
-9
lines changed

4 files changed

+89
-9
lines changed

core/src/main/java/com/google/adk/tools/Annotations.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ public final class Annotations {
3333
String name() default "";
3434

3535
String description() default "";
36+
37+
boolean optional() default false;
3638
}
3739

3840
private Annotations() {}

core/src/main/java/com/google/adk/tools/FunctionCallingUtils.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,10 @@ public static FunctionDeclaration buildFunctionDeclaration(
104104
if (ignoreParams.contains(paramName)) {
105105
continue;
106106
}
107-
required.add(paramName);
107+
Annotations.Schema schema = param.getAnnotation(Annotations.Schema.class);
108+
if (schema == null || !schema.optional()) {
109+
required.add(paramName);
110+
}
108111
properties.put(paramName, buildSchemaFromParameter(param));
109112
}
110113
builder.parameters(

core/src/main/java/com/google/adk/tools/FunctionTool.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -201,11 +201,17 @@ private Maybe<Map<String, Object>> call(Map<String, Object> args, ToolContext to
201201
arguments[i] = null;
202202
continue;
203203
}
204+
Annotations.Schema schema = parameters[i].getAnnotation(Annotations.Schema.class);
204205
if (!args.containsKey(paramName)) {
205-
throw new IllegalArgumentException(
206-
String.format(
207-
"The parameter '%s' was not found in the arguments provided by the model.",
208-
paramName));
206+
if (schema != null && schema.optional()) {
207+
arguments[i] = null;
208+
continue;
209+
} else {
210+
throw new IllegalArgumentException(
211+
String.format(
212+
"The parameter '%s' was not found in the arguments provided by the model.",
213+
paramName));
214+
}
209215
}
210216
Class<?> paramType = parameters[i].getType();
211217
Object argValue = args.get(paramName);
@@ -278,11 +284,17 @@ public Flowable<Map<String, Object>> callLive(
278284
}
279285
continue;
280286
}
287+
Annotations.Schema schema = parameters[i].getAnnotation(Annotations.Schema.class);
281288
if (!args.containsKey(paramName)) {
282-
throw new IllegalArgumentException(
283-
String.format(
284-
"The parameter '%s' was not found in the arguments provided by the model.",
285-
paramName));
289+
if (schema != null && schema.optional()) {
290+
arguments[i] = null;
291+
continue;
292+
} else {
293+
throw new IllegalArgumentException(
294+
String.format(
295+
"The parameter '%s' was not found in the arguments provided by the model.",
296+
paramName));
297+
}
286298
}
287299
Class<?> paramType = parameters[i].getType();
288300
Object argValue = args.get(paramName);

core/src/test/java/com/google/adk/tools/FunctionToolTest.java

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,50 @@ public void create_withRecursiveParam_avoidsInfiniteRecursion() {
472472
assertThat(tool.declaration().get().parameters()).hasValue(expectedParameters);
473473
}
474474

475+
@Test
476+
public void create_withOptionalParameter_excludesFromRequired() {
477+
FunctionTool tool = FunctionTool.create(Functions.class, "functionWithOptionalParam");
478+
479+
assertThat(tool).isNotNull();
480+
assertThat(tool.declaration().get().parameters())
481+
.hasValue(
482+
Schema.builder()
483+
.type("OBJECT")
484+
.properties(
485+
ImmutableMap.of(
486+
"requiredParam",
487+
Schema.builder().type("STRING").description("A required parameter").build(),
488+
"optionalParam",
489+
Schema.builder()
490+
.type("INTEGER")
491+
.description("An optional parameter")
492+
.build()))
493+
.required(ImmutableList.of("requiredParam"))
494+
.build());
495+
}
496+
497+
@Test
498+
public void call_withOptionalParameter_missingValue() throws Exception {
499+
FunctionTool tool = FunctionTool.create(Functions.class, "functionWithOptionalParam");
500+
501+
Map<String, Object> result =
502+
tool.runAsync(ImmutableMap.of("requiredParam", "test"), null).blockingGet();
503+
504+
assertThat(result)
505+
.containsExactly(
506+
"requiredParam", "test", "optionalParam", "null_value", "wasOptionalProvided", false);
507+
}
508+
509+
@Test
510+
public void call_withOptionalParameter_missingRequired_returnsError() {
511+
FunctionTool tool = FunctionTool.create(Functions.class, "functionWithOptionalParam");
512+
513+
Map<String, Object> result =
514+
tool.runAsync(ImmutableMap.of("optionalParam", "test"), null).blockingGet();
515+
516+
assertThat(result).containsExactly("status", "error", "message", "An internal error occurred.");
517+
}
518+
475519
@Test
476520
public void create_withMaybeMapReturnType() {
477521
FunctionTool tool = FunctionTool.create(Functions.class, "returnsMaybeMap");
@@ -719,6 +763,25 @@ public static ImmutableMap<String, Object> recursiveParam(Node param) {
719763
return ImmutableMap.of("param", param);
720764
}
721765

766+
public static ImmutableMap<String, Object> functionWithOptionalParam(
767+
@Annotations.Schema(name = "requiredParam", description = "A required parameter")
768+
String requiredParam,
769+
@Annotations.Schema(
770+
name = "optionalParam",
771+
description = "An optional parameter",
772+
optional = true)
773+
Integer optionalParam) {
774+
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
775+
builder.put("requiredParam", requiredParam);
776+
if (optionalParam != null) {
777+
builder.put("optionalParam", optionalParam);
778+
} else {
779+
builder.put("optionalParam", "null_value");
780+
}
781+
builder.put("wasOptionalProvided", optionalParam != null);
782+
return builder.buildOrThrow();
783+
}
784+
722785
public ImmutableMap<String, Object> nonStaticReturnAllSupportedParametersAsMap(
723786
String stringParam,
724787
boolean primitiveBoolParam,

0 commit comments

Comments
 (0)