Skip to content

Commit ce18dd9

Browse files
Merge pull request google#1074 from glaforge:main
PiperOrigin-RevId: 888064419
2 parents f869994 + cdc5199 commit ce18dd9

2 files changed

Lines changed: 129 additions & 1 deletion

File tree

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.google.adk.tools;
1818

19+
import com.google.adk.SchemaUtils;
1920
import com.google.genai.types.FunctionDeclaration;
2021
import com.google.genai.types.Schema;
2122
import io.reactivex.rxjava3.core.Single;
@@ -58,6 +59,10 @@ public Optional<FunctionDeclaration> declaration() {
5859
public Single<Map<String, Object>> runAsync(Map<String, Object> args, ToolContext toolContext) {
5960
// This tool is a marker for the final response, it doesn't do anything but return its arguments
6061
// which will be captured as the final result.
61-
return Single.just(args);
62+
return Single.fromCallable(
63+
() -> {
64+
SchemaUtils.validateMapOnSchema(args, outputSchema, /* isInput= */ false);
65+
return args;
66+
});
6267
}
6368
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* Copyright 2025 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.google.adk.tools;
18+
19+
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.Assert.assertThrows;
21+
22+
import com.google.common.collect.ImmutableList;
23+
import com.google.common.collect.ImmutableMap;
24+
import com.google.genai.types.FunctionDeclaration;
25+
import com.google.genai.types.Schema;
26+
import java.util.Map;
27+
import org.junit.Test;
28+
import org.junit.runner.RunWith;
29+
import org.junit.runners.JUnit4;
30+
31+
@RunWith(JUnit4.class)
32+
public final class SetModelResponseToolTest {
33+
34+
@Test
35+
public void declaration_returnsCorrectFunctionDeclaration() {
36+
Schema outputSchema =
37+
Schema.builder()
38+
.type("OBJECT")
39+
.properties(ImmutableMap.of("field1", Schema.builder().type("STRING").build()))
40+
.required(ImmutableList.of("field1"))
41+
.build();
42+
43+
SetModelResponseTool tool = new SetModelResponseTool(outputSchema);
44+
FunctionDeclaration declaration = tool.declaration().get();
45+
46+
assertThat(declaration.name()).hasValue("set_model_response");
47+
assertThat(declaration.description()).isPresent();
48+
assertThat(declaration.description().get()).contains("Set your final response");
49+
assertThat(declaration.parameters()).hasValue(outputSchema);
50+
}
51+
52+
@Test
53+
public void runAsync_returnsArgs() {
54+
Schema outputSchema =
55+
Schema.builder()
56+
.type("OBJECT")
57+
.properties(ImmutableMap.of("field1", Schema.builder().type("STRING").build()))
58+
.build();
59+
60+
SetModelResponseTool tool = new SetModelResponseTool(outputSchema);
61+
Map<String, Object> args = ImmutableMap.of("field1", "value1");
62+
63+
Map<String, Object> result = tool.runAsync(args, null).blockingGet();
64+
65+
assertThat(result).isEqualTo(args);
66+
}
67+
68+
@Test
69+
public void runAsync_validatesArgs() {
70+
Schema outputSchema =
71+
Schema.builder()
72+
.type("OBJECT")
73+
.properties(ImmutableMap.of("field1", Schema.builder().type("STRING").build()))
74+
.required(ImmutableList.of("field1"))
75+
.build();
76+
77+
SetModelResponseTool tool = new SetModelResponseTool(outputSchema);
78+
Map<String, Object> invalidArgs = ImmutableMap.of("field2", "value2");
79+
80+
// Should throw validation error
81+
IllegalArgumentException exception =
82+
assertThrows(
83+
IllegalArgumentException.class, () -> tool.runAsync(invalidArgs, null).blockingGet());
84+
85+
assertThat(exception).hasMessageThat().contains("does not match agent output schema");
86+
}
87+
88+
@Test
89+
public void runAsync_validatesComplexArgs() {
90+
Schema complexSchema =
91+
Schema.builder()
92+
.type("OBJECT")
93+
.properties(
94+
ImmutableMap.of(
95+
"id",
96+
Schema.builder().type("INTEGER").build(),
97+
"tags",
98+
Schema.builder()
99+
.type("ARRAY")
100+
.items(Schema.builder().type("STRING").build())
101+
.build(),
102+
"metadata",
103+
Schema.builder()
104+
.type("OBJECT")
105+
.properties(ImmutableMap.of("key", Schema.builder().type("STRING").build()))
106+
.build()))
107+
.required(ImmutableList.of("id", "tags", "metadata"))
108+
.build();
109+
110+
SetModelResponseTool tool = new SetModelResponseTool(complexSchema);
111+
Map<String, Object> complexArgs =
112+
ImmutableMap.of(
113+
"id", 123,
114+
"tags", ImmutableList.of("tag1", "tag2"),
115+
"metadata", ImmutableMap.of("key", "value"));
116+
117+
Map<String, Object> result = tool.runAsync(complexArgs, null).blockingGet();
118+
119+
assertThat(result).containsEntry("id", 123);
120+
assertThat(result).containsEntry("tags", ImmutableList.of("tag1", "tag2"));
121+
assertThat(result).containsEntry("metadata", ImmutableMap.of("key", "value"));
122+
}
123+
}

0 commit comments

Comments
 (0)