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();

Reply via email to