This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch camel-4.18.x
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/camel-4.18.x by this push:
     new d40cf55ee9aa [backport camel-4.18.x] CAMEL-24612: 
camel-langchain4j-agent - fix content converter charset, content-type 
normalization and stream close (#26104)
d40cf55ee9aa is described below

commit d40cf55ee9aa9c4baab09c983b9e1edbc4e6a510
Author: Guillaume Nodet <[email protected]>
AuthorDate: Thu Sep 3 21:53:47 2026 +0200

    [backport camel-4.18.x] CAMEL-24612: camel-langchain4j-agent - fix content 
converter charset, content-type normalization and stream close (#26104)
---
 .../agent/LangChain4jAgentConverter.java           | 20 +++++++++---
 .../agent/LangChain4jAgentConverterTest.java       | 36 ++++++++++++++++++++++
 2 files changed, 51 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 eb5e0ddf3e92..51ab3daad6d8 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
@@ -19,6 +19,8 @@ package org.apache.camel.component.langchain4j.agent;
 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;
 
@@ -214,8 +216,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);
@@ -252,7 +254,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
@@ -275,13 +277,13 @@ public final class LangChain4jAgentConverter {
         // Check agent-specific header first (highest priority)
         String mediaType = exchange.getIn().getHeader(MEDIA_TYPE, 
String.class);
         if (mediaType != null) {
-            return mediaType;
+            return normalizeContentType(mediaType);
         }
 
         // Check file component's content type header
         String fileContentType = 
exchange.getIn().getHeader(Exchange.FILE_CONTENT_TYPE, String.class);
         if (fileContentType != null) {
-            return fileContentType;
+            return normalizeContentType(fileContentType);
         }
 
         if (fileName == null) {
@@ -344,6 +346,14 @@ public final class LangChain4jAgentConverter {
             return normalizeContentType(fileContentType);
         }
 
+        String fileName = exchange.getIn().getHeader(Exchange.FILE_NAME, 
String.class);
+        if (fileName != null) {
+            String mime = URLConnection.guessContentTypeFromName(fileName);
+            if (mime != null) {
+                return normalizeContentType(mime);
+            }
+        }
+
         throw new IllegalArgumentException(
                 "MIME type is required for byte[] or InputStream input. "
                                            + "Please set the 
CamelLangChain4jAgentMediaType header.");
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 2c01e7091cae..27c7f28cf057 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.junit5.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();

Reply via email to