Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/src/main/java/com/google/adk/tools/FunctionTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,12 @@ private Object castValue(Object value, Class<?> type) {
}
}
if (type.equals(Long.class) || type.equals(long.class)) {
if (value instanceof Long || value instanceof Integer) {
if (value instanceof Long) {
return value;
}
if (value instanceof Integer i) {
return i.longValue();
}
} else if (type.equals(Double.class) || type.equals(double.class)) {
if (value instanceof Double d) {
return d.doubleValue();
Expand Down
33 changes: 33 additions & 0 deletions core/src/test/java/com/google/adk/tools/FunctionToolTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,31 @@ public void call_withAllSupportedParameterTypes() throws Exception {
.buildOrThrow());
}

@Test
public void call_withPrimitiveLongParam_whenModelProvidesInteger_succeeds() throws Exception {
// When the model returns a small integer (e.g. 42), Jackson deserializes it as Integer.
// Primitive long was never broken — Java reflection auto-widens int to long.
FunctionTool tool = FunctionTool.create(Functions.class, "echoPrimitiveLong");

Map<String, Object> result =
tool.runAsync(ImmutableMap.of("value", Integer.valueOf(42)), toolContext).blockingGet();

assertThat(result).containsExactly("value", 42L);
}

@Test
public void call_withBoxedLongParam_whenModelProvidesInteger_succeeds() throws Exception {
// When the model returns a small integer (e.g. 42), Jackson deserializes it as Integer.
// Boxed Long was broken before the fix — castValue() returned the raw Integer, causing
// reflection to throw IllegalArgumentException (Integer is not assignable to Long).
FunctionTool tool = FunctionTool.create(Functions.class, "echoBoxedLong");

Map<String, Object> result =
tool.runAsync(ImmutableMap.of("value", Integer.valueOf(42)), toolContext).blockingGet();

assertThat(result).containsExactly("value", 42L);
}

@Test
public void create_withPojoParamWithFields() {
FunctionTool tool = FunctionTool.create(Functions.class, "pojoParamWithFields");
Expand Down Expand Up @@ -1064,6 +1089,14 @@ public static ImmutableMap<String, Object> returnAllSupportedParametersAsMap(
.buildOrThrow();
}

public static ImmutableMap<String, Object> echoPrimitiveLong(long value) {
return ImmutableMap.of("value", value);
}

public static ImmutableMap<String, Object> echoBoxedLong(Long value) {
return ImmutableMap.of("value", value);
}

public static ImmutableMap<String, Object> returnsParameterizedList(
List<Map<String, String>> listParam, ToolContext toolContext) {
return ImmutableMap.<String, Object>builder().put("listParam", listParam).buildOrThrow();
Expand Down