Skip to content

Commit f2df87b

Browse files
nlinhvutzolov
authored andcommitted
Fix Gemini Tool Calling for texts returned from MethodToolCallback
Signed-off-by: nlinhvu <[email protected]>
1 parent 499e8ba commit f2df87b

File tree

4 files changed

+54
-4
lines changed

4 files changed

+54
-4
lines changed

models/spring-ai-vertex-ai-gemini/src/main/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModel.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ private static Struct jsonToStruct(String json) {
340340

341341
Struct.Builder structBuilder = Struct.newBuilder();
342342

343-
if (rootNode.isArray()) {
343+
if (rootNode.isTextual()) {
344+
structBuilder.putFields("result", Value.newBuilder().setStringValue(json).build());
345+
}
346+
else if (rootNode.isArray()) {
344347
// Handle JSON array
345348
List<Value> values = new ArrayList<>();
346349

models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModelIT.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,38 @@ void jsonArrayToolCallingTest() {
361361

362362
}
363363

364+
@Test
365+
void jsonTextToolCallingTest() {
366+
// Test for the improved jsonToStruct method that handles JSON texts in tool
367+
// calling
368+
369+
ToolCallingManager toolCallingManager = ToolCallingManager.builder()
370+
.observationRegistry(ObservationRegistry.NOOP)
371+
.build();
372+
373+
VertexAiGeminiChatModel chatModelWithTools = VertexAiGeminiChatModel.builder()
374+
.vertexAI(vertexAiApi())
375+
.toolCallingManager(toolCallingManager)
376+
.defaultOptions(VertexAiGeminiChatOptions.builder()
377+
.model(VertexAiGeminiChatModel.ChatModel.GEMINI_2_0_FLASH)
378+
.temperature(0.1)
379+
.build())
380+
.build();
381+
382+
ChatClient chatClient = ChatClient.builder(chatModelWithTools).build();
383+
384+
// Create a prompt that will trigger the tool call with a specific request that
385+
// should invoke the tool
386+
String response = chatClient.prompt()
387+
.tools(new CurrentTimeTools())
388+
.user("Get the current time. Make sure to use the getCurrentDateTime tool to get this information.")
389+
.call()
390+
.content();
391+
392+
assertThat(response).isNotEmpty();
393+
assertThat(response).contains("2025-05-08T10:10:10+02:00[Europe/Berlin]");
394+
}
395+
364396
/**
365397
* Tool class that returns a JSON array to test the jsonToStruct method's ability to
366398
* handle JSON arrays. This specifically tests the PR changes that improve the
@@ -378,6 +410,21 @@ public List<Map<String, String>> getScientists() {
378410

379411
}
380412

413+
/**
414+
* Tool class that returns a String to test the jsonToStruct method's ability to
415+
* handle JSON texts. This specifically tests the PR changes that improve the
416+
* jsonToStruct method to handle JSON texts in addition to JSON objects and JSON
417+
* arrays.
418+
*/
419+
public static class CurrentTimeTools {
420+
421+
@Tool(description = "Get the current date and time in the user's timezone")
422+
String getCurrentDateTime() {
423+
return "2025-05-08T10:10:10+02:00[Europe/Berlin]";
424+
}
425+
426+
}
427+
381428
record ActorsFilmsRecord(String actor, List<String> movies) {
382429

383430
}

spring-ai-model/src/main/java/org/springframework/ai/tool/execution/DefaultToolCallResultConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public final class DefaultToolCallResultConverter implements ToolCallResultConve
4545
public String convert(@Nullable Object result, @Nullable Type returnType) {
4646
if (returnType == Void.TYPE) {
4747
logger.debug("The tool has no return type. Converting to conventional response.");
48-
return "Done";
48+
return JsonParser.toJson("Done");
4949
}
5050
if (result instanceof RenderedImage) {
5151
final var buf = new ByteArrayOutputStream(1024 * 4);

spring-ai-model/src/test/java/org/springframework/ai/tool/execution/DefaultToolCallResultConverterTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ void convertWithNullReturnTypeShouldReturn() {
5050
}
5151

5252
@Test
53-
void convertVoidReturnTypeShouldReturnDone() {
53+
void convertVoidReturnTypeShouldReturnDoneJson() {
5454
String result = this.converter.convert(null, void.class);
55-
assertThat(result).isEqualTo("Done");
55+
assertThat(result).isEqualTo("\"Done\"");
5656
}
5757

5858
@Test

0 commit comments

Comments
 (0)