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
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,13 @@
* <ul>
* <li>Text blocks</li>
* <li>Tool use blocks (function_call)</li>
* <li>Tool result blocks (function_response as independent Content)</li>
* <li>Tool result blocks (function_response grouped into one user Content per message)</li>
* <li>Multimodal content (image, audio, video)</li>
* </ul>
*
* <p><b>Important Conversion Behaviors:</b>
* <ul>
* <li>Tool result blocks are converted to independent "user" role Content</li>
* <li>Tool result blocks from one message are converted to one "user" role Content</li>
* <li>Multiple tool outputs are formatted with "- " prefix per line</li>
Comment thread
Zbhbb marked this conversation as resolved.
* <li>System messages are treated as "user" role (Gemini API requirement)</li>
* </ul>
Expand Down Expand Up @@ -88,6 +88,7 @@ public List<Content> convertMessages(List<Msg> msgs) {

for (Msg msg : msgs) {
List<Part> parts = new ArrayList<>();
List<Part> toolResultParts = new ArrayList<>();

for (ContentBlock block : msg.getContent()) {
if (block instanceof TextBlock tb) {
Expand Down Expand Up @@ -137,7 +138,7 @@ public List<Content> convertMessages(List<Msg> msgs) {
parts.add(partBuilder.build());

} else if (block instanceof ToolResultBlock trb) {
// IMPORTANT: Tool result as independent Content with "user" role
// Tool results from the same message share one user Content.
String textOutput = convertToolResultToString(trb.getOutput());

// Create response map with "output" key
Expand All @@ -154,14 +155,7 @@ public List<Content> convertMessages(List<Msg> msgs) {
Part functionResponsePart =
Part.builder().functionResponse(functionResponse).build();

Content toolResultContent =
Content.builder()
.role("user")
.parts(List.of(functionResponsePart))
.build();

result.add(toolResultContent);
// Skip adding to current message parts
toolResultParts.add(functionResponsePart);
continue;

} else if (block instanceof ImageBlock ib) {
Expand Down Expand Up @@ -190,6 +184,12 @@ public List<Content> convertMessages(List<Msg> msgs) {
}
}

if (!toolResultParts.isEmpty()) {
Content toolResultContent =
Content.builder().role("user").parts(toolResultParts).build();
result.add(toolResultContent);
}

// Add message if there are parts
if (!parts.isEmpty()) {
String role = convertRole(msg.getRole());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,38 @@ void testConvertToolResultBlock() {
assertEquals("Result text", part.functionResponse().get().response().get().get("output"));
}

@Test
@DisplayName("Should group tool results from one message into one user Content")
void testConvertMultipleToolResultBlocks() {
ToolResultBlock firstResult =
ToolResultBlock.builder()
.id("call_123")
.name("search")
.output(List.of(TextBlock.builder().text("First result").build()))
.build();
ToolResultBlock secondResult =
ToolResultBlock.builder()
.id("call_456")
.name("lookup")
.output(List.of(TextBlock.builder().text("Second result").build()))
.build();
Msg msg =
Msg.builder()
.name("system")
.content(List.of(firstResult, secondResult))
.role(MsgRole.TOOL)
.build();

List<Content> result = converter.convertMessages(List.of(msg));

assertEquals(1, result.size());
Content content = result.get(0);
assertEquals("user", content.role().get());
assertEquals(2, content.parts().get().size());
assertEquals("call_123", content.parts().get().get(0).functionResponse().get().id().get());
assertEquals("call_456", content.parts().get().get(1).functionResponse().get().id().get());
}

@Test
@DisplayName("Should format tool result with single output")
void testToolResultSingleOutput() {
Expand Down
Loading