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 @@ -288,7 +288,12 @@ ConverseRequest createRequest(Prompt prompt) {
List<ContentBlock> contents = new ArrayList<>();
if (message instanceof UserMessage) {
var userMessage = (UserMessage) message;
contents.add(ContentBlock.fromText(userMessage.getText()));
// The Converse API rejects empty text content blocks, so only send
// the text when there is any. A user message may legitimately carry
// media only (gh-6695).
if (StringUtils.hasText(userMessage.getText())) {
contents.add(ContentBlock.fromText(userMessage.getText()));
}

if (!CollectionUtils.isEmpty(userMessage.getMedia())) {
List<ContentBlock> mediaContent = userMessage.getMedia()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,58 @@ void shouldApplyCacheTtlOnToolsCachePoint() {
assertThat(tools.get(1).cachePoint().ttlAsString()).isEqualTo("1h");
}

// -------------------------------------------------------------------------
// Empty user message text (gh-6695)
// -------------------------------------------------------------------------

@Test
void mediaOnlyUserMessageOmitsEmptyTextContentBlock() {
BedrockProxyChatModel model = newModel();

Prompt prompt = new Prompt(List.of(UserMessage.builder().text("").media(pngMedia()).build()),
BedrockChatOptions.builder().build());

List<ContentBlock> contents = model.createRequest(prompt).messages().get(0).content();

assertThat(contents).hasSize(1);
assertThat(contents.get(0).image()).isNotNull();
assertThat(contents).noneMatch(content -> content.text() != null);
}

@Test
void blankUserMessageTextOmitsEmptyTextContentBlock() {
BedrockProxyChatModel model = newModel();

Prompt prompt = new Prompt(List.of(UserMessage.builder().text(" \n\t").media(pngMedia()).build()),
BedrockChatOptions.builder().build());

List<ContentBlock> contents = model.createRequest(prompt).messages().get(0).content();

assertThat(contents).hasSize(1);
assertThat(contents.get(0).image()).isNotNull();
}

@Test
void userMessageWithTextAndMediaKeepsBothContentBlocks() {
BedrockProxyChatModel model = newModel();

Prompt prompt = new Prompt(List.of(UserMessage.builder().text("Describe the image").media(pngMedia()).build()),
BedrockChatOptions.builder().build());

List<ContentBlock> contents = model.createRequest(prompt).messages().get(0).content();

assertThat(contents).hasSize(2);
assertThat(contents.get(0).text()).isEqualTo("Describe the image");
assertThat(contents.get(1).image()).isNotNull();
}

private static Media pngMedia() {
return Media.builder()
.mimeType(MimeType.valueOf("image/png"))
.data(new byte[] { (byte) 0x89, 'P', 'N', 'G' })
.build();
}

public record WeatherRequest(String location, String unit) {
}

Expand Down
Loading