This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 678827b11bcc CAMEL-24612: camel-langchain4j-agent - fix content
converter charset, content-type normalization and stream close
678827b11bcc is described below
commit 678827b11bccb825e5633161a9d1b8221ee1c0ee
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Sep 3 18:29:25 2026 +0200
CAMEL-24612: camel-langchain4j-agent - fix content converter charset,
content-type normalization and stream close
LangChain4jAgentConverter decoded text with the platform default charset,
did not normalize the content type on the WrappedFile path (unlike the
byte[]/InputStream path), and never closed the InputStream it read. Decode as
UTF-8, normalize the WrappedFile-path content types, and read the stream inside
try-with-resources.
Closes #26079
Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_01SC3EbLbPUMdbqy7butoKCD
---
.../agent/LangChain4jAgentConverter.java | 11 ++++---
.../agent/LangChain4jAgentConverterTest.java | 36 ++++++++++++++++++++++
2 files changed, 42 insertions(+), 5 deletions(-)
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverter.java
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverter.java
index a266e547a503..3b890a1ade04 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverter.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverter.java
@@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Base64;
@@ -195,8 +196,8 @@ public final class LangChain4jAgentConverter {
*/
@Converter
public static AiAgentBody<?> inputStreamToAiAgentBody(InputStream
inputStream, Exchange exchange) {
- try {
- byte[] data = inputStream.readAllBytes();
+ try (InputStream in = inputStream) {
+ byte[] data = in.readAllBytes();
return byteArrayToAiAgentBody(data, exchange);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to read input stream",
e);
@@ -248,7 +249,7 @@ public final class LangChain4jAgentConverter {
.build();
return PdfFileContent.from(pdfFile);
} else if (mimeType.startsWith("text/")) {
- return TextContent.from(new String(data));
+ return TextContent.from(new String(data, StandardCharsets.UTF_8));
} else {
throw new IllegalArgumentException(
"Unsupported MIME type: " + mimeType
@@ -271,13 +272,13 @@ public final class LangChain4jAgentConverter {
// Check agent-specific header first (highest priority)
String mediaType = exchange.getMessage().getHeader(MEDIA_TYPE,
String.class);
if (mediaType != null) {
- return mediaType;
+ return normalizeContentType(mediaType);
}
// Check file component's content type header
String fileContentType =
exchange.getMessage().getHeader(Exchange.FILE_CONTENT_TYPE, String.class);
if (fileContentType != null) {
- return fileContentType;
+ return normalizeContentType(fileContentType);
}
if (fileName == null) {
diff --git
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterTest.java
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterTest.java
index 92326a1f8507..b7da6ccf5d01 100644
---
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterTest.java
+++
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterTest.java
@@ -18,8 +18,11 @@ package org.apache.camel.component.langchain4j.agent;
import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.concurrent.atomic.AtomicBoolean;
import dev.langchain4j.data.message.ImageContent;
import dev.langchain4j.data.message.TextContent;
@@ -32,9 +35,11 @@ import org.apache.camel.test.junit6.CamelTestSupport;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
public class LangChain4jAgentConverterTest extends CamelTestSupport {
@@ -58,6 +63,37 @@ public class LangChain4jAgentConverterTest extends
CamelTestSupport {
assertInstanceOf(TextContent.class, body.getContent());
}
+ @Test
+ void shouldDecodeTextBytesAsUtf8() {
+ Exchange exchange =
context.getEndpoint("direct:test").createExchange();
+ exchange.getMessage().setHeader(Headers.MEDIA_TYPE, "text/plain");
+
+ byte[] utf8 = "café ☕".getBytes(StandardCharsets.UTF_8);
+ AiAgentBody<?> body =
context.getTypeConverter().convertTo(AiAgentBody.class, exchange, utf8);
+
+ assertInstanceOf(TextContent.class, body.getContent());
+ assertEquals("café ☕", ((TextContent) body.getContent()).text());
+ }
+
+ @Test
+ void shouldCloseInputStreamAfterConversion() {
+ Exchange exchange =
context.getEndpoint("direct:test").createExchange();
+ exchange.getMessage().setHeader(Headers.MEDIA_TYPE, "text/plain");
+
+ AtomicBoolean closed = new AtomicBoolean(false);
+ ByteArrayInputStream stream = new
ByteArrayInputStream("Hello".getBytes(StandardCharsets.UTF_8)) {
+ @Override
+ public void close() throws IOException {
+ closed.set(true);
+ super.close();
+ }
+ };
+
+ context.getTypeConverter().convertTo(AiAgentBody.class, exchange,
stream);
+
+ assertTrue(closed.get(), "the input stream must be closed after
conversion");
+ }
+
@Test
void shouldConvertRemoteWrappedFileUsingFileNameHeader() {
Exchange exchange =
context.getEndpoint("direct:test").createExchange();