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

fmariani 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 bf38b30ad657 use UserMessage for Multimodality
bf38b30ad657 is described below

commit bf38b30ad657505374e59215ed7847a1da0af5de
Author: Croway <[email protected]>
AuthorDate: Tue Dec 9 12:56:50 2025 +0100

    use UserMessage for Multimodality
---
 .../catalog/components/langchain4j-agent.json      |   4 +-
 .../{AgentWithMemory.java => AbstractAgent.java}   |  69 ++--
 .../component/langchain4j/agent/api/Agent.java     |  21 +-
 .../langchain4j/agent/api/AgentWithMemory.java     |  77 ++--
 .../langchain4j/agent/api/AgentWithoutMemory.java  |  74 ++--
 .../langchain4j/agent/api/AiAgentBody.java         |   4 +-
 .../agent/api/AiAgentWithMemoryService.java        |  29 +-
 .../agent/api/AiAgentWithoutMemoryService.java     |  32 +-
 .../component/langchain4j/agent/api/Headers.java   |   7 +
 .../agent/LangChain4jAgentConverterLoader.java     |  76 ++++
 .../langchain4j/agent/langchain4j-agent.json       |   4 +-
 .../services/org/apache/camel/TypeConverterLoader  |   2 +
 .../src/main/docs/langchain4j-agent-component.adoc | 119 ++++++
 .../agent/LangChain4jAgentConverter.java           | 408 +++++++++++++++++++++
 .../agent/integration/AbstractRAGIT.java           |   2 -
 .../integration/LangChain4jAgentCustomToolsIT.java |   2 -
 .../LangChain4jAgentGuardrailsIntegrationIT.java   |   2 -
 .../integration/LangChain4jAgentMcpToolsIT.java    |   2 -
 .../integration/LangChain4jAgentMixedToolsIT.java  |   2 -
 .../LangChain4jAgentMultimodalityIT.java           | 168 +++++++++
 .../integration/LangChain4jAgentWithMemoryIT.java  |   2 -
 .../integration/LangChain4jAgentWithToolsIT.java   |   2 -
 .../integration/LangChain4jAgentWrappedFileIT.java | 148 ++++++++
 .../integration/LangChain4jSimpleAgentIT.java      |   2 -
 .../langchain4j/agent/integration/ModelHelper.java |  24 +-
 .../src/test/resources/camel-logo.png              | Bin 0 -> 190434 bytes
 .../src/test/resources/test-document.pdf           |  20 +
 .../camel-langchain4j-agent/test-execution.md      |   2 +-
 .../LangChain4jAgentEndpointBuilderFactory.java    |  26 ++
 .../test/infra/openai/mock/RequestContext.java     |  28 +-
 30 files changed, 1186 insertions(+), 172 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
index 8f87aaa2d87f..6594b80bf1fc 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-agent.json
@@ -33,7 +33,9 @@
   },
   "headers": {
     "CamelLangChain4jAgentSystemMessage": { "index": 0, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The system prompt.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#SYSTEM_MESSAGE" },
-    "CamelLangChain4jAgentMemoryId": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Memory ID.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEMORY_ID" }
+    "CamelLangChain4jAgentMemoryId": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Memory ID.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEMORY_ID" },
+    "CamelLangChain4jAgentUserMessage": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The user message to accompany file 
content when using WrappedFile as input.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#USER_MESSAGE" },
+    "CamelLangChain4jAgentMediaType": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The media type (MIME type) of the file 
content. Overrides auto-detection from file extension.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEDIA_TYPE" }
   },
   "properties": {
     "agentId": { "index": 0, "kind": "path", "displayName": "Agent Id", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The Agent id" },
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
similarity index 60%
copy from 
components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
copy to 
components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
index b6c7238393e0..f7a19d62973b 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AbstractAgent.java
@@ -22,49 +22,67 @@ import dev.langchain4j.mcp.McpToolProvider;
 import dev.langchain4j.service.AiServices;
 import dev.langchain4j.service.tool.ToolProvider;
 import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
- * Implementation of Agent for AI agents with memory support. This agent 
handles chat interactions while maintaining
- * conversation history.
+ * Abstract base class for AI agents that provides common configuration logic 
for building LangChain4j AI services.
  *
- * This is an internal class used only within the LangChain4j agent component.
+ * <p>
+ * This class encapsulates the shared logic for configuring:
+ * <ul>
+ * <li>Apache Camel Tool Provider</li>
+ * <li>MCP (Model Context Protocol) clients</li>
+ * <li>Custom LangChain4j tools</li>
+ * <li>RAG (Retrieval Augmented Generation)</li>
+ * <li>Input and Output Guardrails</li>
+ * </ul>
+ *
+ * <p>
+ * Subclasses must implement the {@link #chat(AiAgentBody, ToolProvider)} 
method to provide specific chat behavior.
+ *
+ * @param <S> the type of the AI service interface (e.g., 
AiAgentWithMemoryService or AiAgentWithoutMemoryService)
  */
-public class AgentWithMemory implements Agent {
-    private static final Logger LOG = 
LoggerFactory.getLogger(AgentWithMemory.class);
+public abstract class AbstractAgent<S> implements Agent {
 
-    private final AgentConfiguration configuration;
+    protected final AgentConfiguration configuration;
 
-    public AgentWithMemory(AgentConfiguration configuration) {
+    protected AbstractAgent(AgentConfiguration configuration) {
         this.configuration = configuration;
     }
 
-    @Override
-    public String chat(AiAgentBody<?> aiAgentBody, ToolProvider toolProvider) {
-        AiAgentWithMemoryService agentService = 
createAiAgentService(toolProvider);
-
-        return aiAgentBody.getSystemMessage() != null
-                ? agentService.chat(aiAgentBody.getMemoryId(), 
aiAgentBody.getUserMessage(), aiAgentBody.getSystemMessage())
-                : agentService.chat(aiAgentBody.getMemoryId(), 
aiAgentBody.getUserMessage());
+    /**
+     * Gets the agent configuration.
+     *
+     * @return the agent configuration
+     */
+    protected AgentConfiguration getConfiguration() {
+        return configuration;
     }
 
     /**
-     * Create AI service with a single universal tool that handles multiple 
Camel routes, Memory Provider, and
-     * additional tools
+     * Configures the common aspects of the AI service builder.
+     *
+     * <p>
+     * This method applies the following configurations to the builder:
+     * <ul>
+     * <li>Apache Camel Tool Provider (if provided)</li>
+     * <li>MCP Tool Provider (if MCP clients are configured)</li>
+     * <li>Custom LangChain4j tools (if configured)</li>
+     * <li>RAG Retrieval Augmentor (if configured)</li>
+     * <li>Input Guardrails (if configured)</li>
+     * <li>Output Guardrails (if configured)</li>
+     * </ul>
+     *
+     * @param builder      the AI services builder to configure
+     * @param toolProvider the Apache Camel tool provider (may be null)
      */
-    private AiAgentWithMemoryService createAiAgentService(ToolProvider 
toolProvider) {
-        var builder = AiServices.builder(AiAgentWithMemoryService.class)
-                .chatModel(configuration.getChatModel())
-                .chatMemoryProvider(configuration.getChatMemoryProvider());
-
+    @SuppressWarnings("unchecked")
+    protected void configureBuilder(AiServices<S> builder, ToolProvider 
toolProvider) {
         // Apache Camel Tool Provider
         if (toolProvider != null) {
             builder.toolProvider(toolProvider);
         }
 
         // MCP Clients - create MCP ToolProvider if MCP clients are configured
-        // import org.apache.camel.util.ObjectHelper
         if (ObjectHelper.isNotEmpty(configuration.getMcpClients())) {
             McpToolProvider.Builder mcpBuilder = McpToolProvider.builder()
                     .mcpClients(configuration.getMcpClients());
@@ -96,8 +114,5 @@ public class AgentWithMemory implements Agent {
         if (configuration.getOutputGuardrailClasses() != null && 
!configuration.getOutputGuardrailClasses().isEmpty()) {
             builder.outputGuardrailClasses((List) 
configuration.getOutputGuardrailClasses());
         }
-
-        return builder.build();
     }
-
 }
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Agent.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Agent.java
index ac1e006787d9..d8be18186470 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Agent.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Agent.java
@@ -70,7 +70,10 @@ public interface Agent {
      * <li>The {@link Headers#MEMORY_ID} header value as the memory identifier 
(if present)</li>
      * </ul>
      * </li>
-     * <li>For any other payload type, it throws an {@link 
InvalidPayloadRuntimeException}</li>
+     * <li>For other payload types (WrappedFile, byte[], InputStream), it uses 
the Camel TypeConverter to convert to an
+     * {@link AiAgentBody} with the appropriate content type. This supports 
file, ftp, sftp, aws2-s3,
+     * azure-storage-blob, and other components.</li>
+     * <li>If no conversion is possible, it throws an {@link 
InvalidPayloadRuntimeException}</li>
      * </ul>
      *
      * <p>
@@ -93,14 +96,20 @@ public interface Agent {
             return payload;
         }
 
-        if (!(messagePayload instanceof String)) {
-            throw new InvalidPayloadRuntimeException(exchange, 
AiAgentBody.class);
+        if (messagePayload instanceof String) {
+            String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
+            Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
+            return new AiAgentBody<>((String) messagePayload, systemMessage, 
memoryId);
         }
 
-        String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
-        Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
+        // Try to convert using TypeConverter (supports WrappedFile, byte[], 
InputStream, etc.)
+        AiAgentBody<?> body = exchange.getContext().getTypeConverter()
+                .tryConvertTo(AiAgentBody.class, exchange, messagePayload);
+        if (body != null) {
+            return body;
+        }
 
-        return new AiAgentBody<>((String) messagePayload, systemMessage, 
memoryId);
+        throw new InvalidPayloadRuntimeException(exchange, AiAgentBody.class);
     }
 
     /**
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
index b6c7238393e0..2f33a925349a 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithMemory.java
@@ -16,88 +16,55 @@
  */
 package org.apache.camel.component.langchain4j.agent.api;
 
-import java.util.List;
-
-import dev.langchain4j.mcp.McpToolProvider;
+import dev.langchain4j.data.message.Content;
 import dev.langchain4j.service.AiServices;
 import dev.langchain4j.service.tool.ToolProvider;
-import org.apache.camel.util.ObjectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Implementation of Agent for AI agents with memory support. This agent 
handles chat interactions while maintaining
  * conversation history.
  *
+ * <p>
  * This is an internal class used only within the LangChain4j agent component.
  */
-public class AgentWithMemory implements Agent {
-    private static final Logger LOG = 
LoggerFactory.getLogger(AgentWithMemory.class);
-
-    private final AgentConfiguration configuration;
+public class AgentWithMemory extends AbstractAgent<AiAgentWithMemoryService> {
 
     public AgentWithMemory(AgentConfiguration configuration) {
-        this.configuration = configuration;
+        super(configuration);
     }
 
     @Override
     public String chat(AiAgentBody<?> aiAgentBody, ToolProvider toolProvider) {
         AiAgentWithMemoryService agentService = 
createAiAgentService(toolProvider);
 
-        return aiAgentBody.getSystemMessage() != null
-                ? agentService.chat(aiAgentBody.getMemoryId(), 
aiAgentBody.getUserMessage(), aiAgentBody.getSystemMessage())
-                : agentService.chat(aiAgentBody.getMemoryId(), 
aiAgentBody.getUserMessage());
+        String userMessage = aiAgentBody.getUserMessage();
+        Object memoryId = aiAgentBody.getMemoryId();
+        String systemMessage = aiAgentBody.getSystemMessage();
+        Content content = aiAgentBody.getContent();
+
+        if (content != null) {
+            // Multi-modal message with content
+            return systemMessage != null
+                    ? agentService.chat(memoryId, userMessage, content, 
systemMessage)
+                    : agentService.chat(memoryId, userMessage, content);
+        } else {
+            // Text-only message
+            return systemMessage != null
+                    ? agentService.chat(memoryId, userMessage, systemMessage)
+                    : agentService.chat(memoryId, userMessage);
+        }
     }
 
     /**
-     * Create AI service with a single universal tool that handles multiple 
Camel routes, Memory Provider, and
-     * additional tools
+     * Create AI service with memory provider and common configurations.
      */
     private AiAgentWithMemoryService createAiAgentService(ToolProvider 
toolProvider) {
         var builder = AiServices.builder(AiAgentWithMemoryService.class)
                 .chatModel(configuration.getChatModel())
                 .chatMemoryProvider(configuration.getChatMemoryProvider());
 
-        // Apache Camel Tool Provider
-        if (toolProvider != null) {
-            builder.toolProvider(toolProvider);
-        }
-
-        // MCP Clients - create MCP ToolProvider if MCP clients are configured
-        // import org.apache.camel.util.ObjectHelper
-        if (ObjectHelper.isNotEmpty(configuration.getMcpClients())) {
-            McpToolProvider.Builder mcpBuilder = McpToolProvider.builder()
-                    .mcpClients(configuration.getMcpClients());
-
-            // Apply MCP tool filter if configured
-            if (configuration.getMcpToolProviderFilter() != null) {
-                mcpBuilder.filter(configuration.getMcpToolProviderFilter());
-            }
-
-            builder.toolProvider(mcpBuilder.build());
-        }
-
-        // Additional custom LangChain4j Tool Instances (objects with @Tool 
methods)
-        if (configuration.getCustomTools() != null && 
!configuration.getCustomTools().isEmpty()) {
-            builder.tools(configuration.getCustomTools());
-        }
-
-        // RAG
-        if (configuration.getRetrievalAugmentor() != null) {
-            builder.retrievalAugmentor(configuration.getRetrievalAugmentor());
-        }
-
-        // Input Guardrails
-        if (configuration.getInputGuardrailClasses() != null && 
!configuration.getInputGuardrailClasses().isEmpty()) {
-            builder.inputGuardrailClasses((List) 
configuration.getInputGuardrailClasses());
-        }
-
-        // Output Guardrails
-        if (configuration.getOutputGuardrailClasses() != null && 
!configuration.getOutputGuardrailClasses().isEmpty()) {
-            builder.outputGuardrailClasses((List) 
configuration.getOutputGuardrailClasses());
-        }
+        configureBuilder(builder, toolProvider);
 
         return builder.build();
     }
-
 }
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithoutMemory.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithoutMemory.java
index c5b8baa6b042..82d26fbf0fd6 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithoutMemory.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentWithoutMemory.java
@@ -16,82 +16,52 @@
  */
 package org.apache.camel.component.langchain4j.agent.api;
 
-import java.util.List;
-
-import dev.langchain4j.mcp.McpToolProvider;
+import dev.langchain4j.data.message.Content;
 import dev.langchain4j.service.AiServices;
 import dev.langchain4j.service.tool.ToolProvider;
-import org.apache.camel.util.ObjectHelper;
 
 /**
  * Implementation of Agent for AI agents without memory support. This agent 
handles chat interactions without
  * maintaining conversation history.
  *
+ * <p>
  * This is an internal class used only within the LangChain4j agent component.
  */
-public class AgentWithoutMemory implements Agent {
-
-    private final AgentConfiguration configuration;
+public class AgentWithoutMemory extends 
AbstractAgent<AiAgentWithoutMemoryService> {
 
     public AgentWithoutMemory(AgentConfiguration configuration) {
-        this.configuration = configuration;
+        super(configuration);
     }
 
     @Override
     public String chat(AiAgentBody<?> aiAgentBody, ToolProvider toolProvider) {
         AiAgentWithoutMemoryService agentService = 
createAiAgentService(toolProvider);
 
-        return aiAgentBody.getSystemMessage() != null
-                ? agentService.chat(aiAgentBody.getUserMessage(), 
aiAgentBody.getSystemMessage())
-                : agentService.chat(aiAgentBody.getUserMessage());
+        String userMessage = aiAgentBody.getUserMessage();
+        String systemMessage = aiAgentBody.getSystemMessage();
+        Content content = aiAgentBody.getContent();
+
+        if (content != null) {
+            // Multi-modal message with content
+            return systemMessage != null
+                    ? agentService.chat(userMessage, content, systemMessage)
+                    : agentService.chat(userMessage, content);
+        } else {
+            // Text-only message
+            return systemMessage != null
+                    ? agentService.chat(userMessage, systemMessage)
+                    : agentService.chat(userMessage);
+        }
     }
 
     /**
-     * Create AI service with a single universal tool that handles multiple 
Camel routes and additional tools
+     * Create AI service with common configurations (no memory provider).
      */
-    private AiAgentWithoutMemoryService createAiAgentService(
-            ToolProvider toolProvider) {
+    private AiAgentWithoutMemoryService createAiAgentService(ToolProvider 
toolProvider) {
         var builder = AiServices.builder(AiAgentWithoutMemoryService.class)
                 .chatModel(configuration.getChatModel());
 
-        // Apache Camel Tool Provider
-        if (toolProvider != null) {
-            builder.toolProvider(toolProvider);
-        }
-
-        // MCP Clients - create MCP ToolProvider if MCP clients are configured
-        // import org.apache.camel.util.ObjectHelper
-        if (ObjectHelper.isNotEmpty(configuration.getMcpClients())) {
-            McpToolProvider.Builder mcpBuilder = McpToolProvider.builder()
-                    .mcpClients(configuration.getMcpClients());
-
-            // Apply MCP tool filter if configured
-            if (configuration.getMcpToolProviderFilter() != null) {
-                mcpBuilder.filter(configuration.getMcpToolProviderFilter());
-            }
-
-            builder.toolProvider(mcpBuilder.build());
-        }
-
-        // Additional custom LangChain4j Tool Instances (objects with @Tool 
methods)
-        if (configuration.getCustomTools() != null && 
!configuration.getCustomTools().isEmpty()) {
-            builder.tools(configuration.getCustomTools());
-        }
-
-        // RAG
-        if (configuration.getRetrievalAugmentor() != null) {
-            builder.retrievalAugmentor(configuration.getRetrievalAugmentor());
-        }
-
-        // Input Guardrails
-        if (configuration.getInputGuardrailClasses() != null && 
!configuration.getInputGuardrailClasses().isEmpty()) {
-            builder.inputGuardrailClasses((List) 
configuration.getInputGuardrailClasses());
-        }
-
-        // Output Guardrails
-        if (configuration.getOutputGuardrailClasses() != null && 
!configuration.getOutputGuardrailClasses().isEmpty()) {
-            builder.outputGuardrailClasses((List) 
configuration.getOutputGuardrailClasses());
-        }
+        configureBuilder(builder, toolProvider);
 
         return builder.build();
     }
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentBody.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentBody.java
index f07eb022f8aa..c7386498cb27 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentBody.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentBody.java
@@ -16,6 +16,8 @@
  */
 package org.apache.camel.component.langchain4j.agent.api;
 
+import dev.langchain4j.data.message.Content;
+
 /**
  * Request body class for AI agent chat interactions in the Apache Camel 
LangChain4j integration.
  *
@@ -56,7 +58,7 @@ package org.apache.camel.component.langchain4j.agent.api;
  * @param <C> the type of content (e.g., TextContent, ImageContent, 
AudioContent, VideoContent, PdfFileContent)
  * @since     4.9.0
  */
-public class AiAgentBody<C> {
+public class AiAgentBody<C extends Content> {
     private String userMessage;
     private String systemMessage;
     private Object memoryId;
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithMemoryService.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithMemoryService.java
index 8f7d292690ec..4837a096e917 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithMemoryService.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithMemoryService.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.langchain4j.agent.api;
 
+import dev.langchain4j.data.message.Content;
 import dev.langchain4j.service.MemoryId;
 import dev.langchain4j.service.SystemMessage;
 import dev.langchain4j.service.UserMessage;
@@ -36,6 +37,16 @@ public interface AiAgentWithMemoryService {
      */
     String chat(@MemoryId Object memoryId, @UserMessage String message);
 
+    /**
+     * Chat with a user message containing both text and additional content 
(e.g., images, audio) with memory support.
+     *
+     * @param  memoryId the memory identifier for conversation history
+     * @param  message  the text portion of the user message
+     * @param  content  additional content such as ImageContent, AudioContent, 
etc.
+     * @return          the AI response
+     */
+    String chat(@MemoryId Object memoryId, @UserMessage String message, 
@UserMessage Content content);
+
     /**
      * Simple chat with a user message, system message and memory window
      *
@@ -45,6 +56,22 @@ public interface AiAgentWithMemoryService {
      * @return
      */
     @SystemMessage("{{prompt}}")
-    String chat(@MemoryId Object memoryId, @UserMessage String message, 
@V("prompt") String prompt);
+    String chat(
+            @MemoryId Object memoryId, @UserMessage String message,
+            @V("prompt") String prompt);
+
+    /**
+     * Chat with a user message containing both text and additional content, 
with system message and memory support.
+     *
+     * @param  memoryId the memory identifier for conversation history
+     * @param  message  the text portion of the user message
+     * @param  content  additional content such as ImageContent, AudioContent, 
etc.
+     * @param  prompt   the system message template
+     * @return          the AI response
+     */
+    @SystemMessage("{{prompt}}")
+    String chat(
+            @MemoryId Object memoryId, @UserMessage String message,
+            @UserMessage Content content, @V("prompt") String prompt);
 
 }
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithoutMemoryService.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithoutMemoryService.java
index 961a73e04375..dfa72a61e6e6 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithoutMemoryService.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AiAgentWithoutMemoryService.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.langchain4j.agent.api;
 
+import dev.langchain4j.data.message.Content;
 import dev.langchain4j.service.SystemMessage;
 import dev.langchain4j.service.UserMessage;
 import dev.langchain4j.service.V;
@@ -28,18 +29,39 @@ public interface AiAgentWithoutMemoryService {
     /**
      * Simple chat with a single user message
      *
-     * @param message the user message
+     * @param  message the user message
+     * @return         the AI response
      */
     String chat(@UserMessage String message);
 
     /**
-     * Simple chat with a single user message and single prompt
+     * Chat with a user message containing both text and additional content 
(e.g., images, audio).
      *
-     * @param  message
-     * @param  prompt
-     * @return
+     * @param  message the text portion of the user message
+     * @param  content additional content such as ImageContent, AudioContent, 
etc.
+     * @return         the AI response
+     */
+    String chat(@UserMessage String message, @UserMessage Content content);
+
+    /**
+     * Simple chat with a single user message and system message
+     *
+     * @param  message the user message
+     * @param  prompt  the system message template
+     * @return         the AI response
      */
     @SystemMessage("{{prompt}}")
     String chat(@UserMessage String message, @V("prompt") String prompt);
 
+    /**
+     * Chat with a user message containing both text and additional content, 
with system message.
+     *
+     * @param  message the text portion of the user message
+     * @param  content additional content such as ImageContent, AudioContent, 
etc.
+     * @param  prompt  the system message template
+     * @return         the AI response
+     */
+    @SystemMessage("{{prompt}}")
+    String chat(@UserMessage String message, @UserMessage Content content, 
@V("prompt") String prompt);
+
 }
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
index 5e53a96dcd52..c6a56b3a26df 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
@@ -28,4 +28,11 @@ public class Headers {
 
     @Metadata(description = "Memory ID.", javaType = "Object")
     public static final String MEMORY_ID = "CamelLangChain4jAgentMemoryId";
+
+    @Metadata(description = "The user message to accompany file content when 
using WrappedFile as input.", javaType = "String")
+    public static final String USER_MESSAGE = 
"CamelLangChain4jAgentUserMessage";
+
+    @Metadata(description = "The media type (MIME type) of the file content. 
Overrides auto-detection from file extension.",
+              javaType = "String")
+    public static final String MEDIA_TYPE = "CamelLangChain4jAgentMediaType";
 }
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterLoader.java
 
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterLoader.java
new file mode 100644
index 000000000000..1186963e3e9c
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/generated/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverterLoader.java
@@ -0,0 +1,76 @@
+/* Generated by camel build tools - do NOT edit this file! */
+package org.apache.camel.component.langchain4j.agent;
+
+import javax.annotation.processing.Generated;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.CamelContextAware;
+import org.apache.camel.DeferredContextBinding;
+import org.apache.camel.Exchange;
+import org.apache.camel.TypeConversionException;
+import org.apache.camel.TypeConverterLoaderException;
+import org.apache.camel.spi.TypeConverterLoader;
+import org.apache.camel.spi.TypeConverterRegistry;
+import org.apache.camel.support.SimpleTypeConverter;
+import org.apache.camel.support.TypeConverterSupport;
+import org.apache.camel.util.DoubleMap;
+
+/**
+ * Generated by camel build tools - do NOT edit this file!
+ */
+@Generated("org.apache.camel.maven.packaging.TypeConverterLoaderGeneratorMojo")
+@SuppressWarnings("unchecked")
+@DeferredContextBinding
+public final class LangChain4jAgentConverterLoader implements 
TypeConverterLoader, CamelContextAware {
+
+    private CamelContext camelContext;
+
+    public LangChain4jAgentConverterLoader() {
+    }
+
+    @Override
+    public void setCamelContext(CamelContext camelContext) {
+        this.camelContext = camelContext;
+    }
+
+    @Override
+    public CamelContext getCamelContext() {
+        return camelContext;
+    }
+
+    @Override
+    public void load(TypeConverterRegistry registry) throws 
TypeConverterLoaderException {
+        registerConverters(registry);
+    }
+
+    private void registerConverters(TypeConverterRegistry registry) {
+        addTypeConverter(registry, 
org.apache.camel.component.langchain4j.agent.api.AiAgentBody.class, 
byte[].class, false,
+            (type, exchange, value) -> {
+                Object answer = 
org.apache.camel.component.langchain4j.agent.LangChain4jAgentConverter.byteArrayToAiAgentBody((byte[])
 value, exchange);
+                if (false && answer == null) {
+                    answer = Void.class;
+                }
+                return answer;
+            });
+        addTypeConverter(registry, 
org.apache.camel.component.langchain4j.agent.api.AiAgentBody.class, 
java.io.InputStream.class, false,
+            (type, exchange, value) -> {
+                Object answer = 
org.apache.camel.component.langchain4j.agent.LangChain4jAgentConverter.inputStreamToAiAgentBody((java.io.InputStream)
 value, exchange);
+                if (false && answer == null) {
+                    answer = Void.class;
+                }
+                return answer;
+            });
+        addTypeConverter(registry, 
org.apache.camel.component.langchain4j.agent.api.AiAgentBody.class, 
org.apache.camel.WrappedFile.class, false,
+            (type, exchange, value) -> {
+                Object answer = 
org.apache.camel.component.langchain4j.agent.LangChain4jAgentConverter.toAiAgentBody((org.apache.camel.WrappedFile)
 value, exchange);
+                if (false && answer == null) {
+                    answer = Void.class;
+                }
+                return answer;
+            });
+    }
+
+    private static void addTypeConverter(TypeConverterRegistry registry, 
Class<?> toType, Class<?> fromType, boolean allowNull, 
SimpleTypeConverter.ConversionMethod method) {
+        registry.addTypeConverter(toType, fromType, new 
SimpleTypeConverter(allowNull, method));
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
 
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
index 8f87aaa2d87f..6594b80bf1fc 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/agent/langchain4j-agent.json
@@ -33,7 +33,9 @@
   },
   "headers": {
     "CamelLangChain4jAgentSystemMessage": { "index": 0, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The system prompt.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#SYSTEM_MESSAGE" },
-    "CamelLangChain4jAgentMemoryId": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Memory ID.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEMORY_ID" }
+    "CamelLangChain4jAgentMemoryId": { "index": 1, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "Object", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "Memory ID.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEMORY_ID" },
+    "CamelLangChain4jAgentUserMessage": { "index": 2, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The user message to accompany file 
content when using WrappedFile as input.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#USER_MESSAGE" },
+    "CamelLangChain4jAgentMediaType": { "index": 3, "kind": "header", 
"displayName": "", "group": "producer", "label": "", "required": false, 
"javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "description": "The media type (MIME type) of the file 
content. Overrides auto-detection from file extension.", "constantName": 
"org.apache.camel.component.langchain4j.agent.api.Headers#MEDIA_TYPE" }
   },
   "properties": {
     "agentId": { "index": 0, "kind": "path", "displayName": "Agent Id", 
"group": "producer", "label": "", "required": true, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "The Agent id" },
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader
 
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader
new file mode 100644
index 000000000000..59ed6c3979de
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/generated/resources/META-INF/services/org/apache/camel/TypeConverterLoader
@@ -0,0 +1,2 @@
+# Generated by camel build tools - do NOT edit this file!
+org.apache.camel.component.langchain4j.agent.LangChain4jAgentConverterLoader
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
 
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
index c47c8fe26d3d..bd83b7b2e245 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
@@ -28,6 +28,7 @@ The LangChain4j Agent component offers the following key 
features:
 * **RAG Support**: Integration with retrieval systems for naive and advanced 
RAG
 * **Guardrails**: Input and output validation and transformation
 * **Configuration Flexibility**: Centralized agent configuration using 
`AgentConfiguration`
+* **Multimodal Content**: Support for images, PDFs, audio, video, and text 
files from file-based Camel components
 
 == Component Options
 
@@ -576,3 +577,121 @@ from("direct:agent-with-guardrails")
 ====
 The current version of the component returns a String as response. If the 
outputGuardrails extends JsonExtractorOutputGuardrail class, make sure to 
return a Json in String format.
 ====
+
+=== Multimodal Content Support
+
+The LangChain4j Agent component supports multimodal content, allowing you to 
send images, PDFs, audio, video, and text files to AI models that support 
vision and document understanding capabilities.
+
+==== Sending Multimodal Content via AiAgentBody
+
+You can explicitly create an `AiAgentBody` with multimodal content:
+
+[source,java]
+----
+// Load an image and create ImageContent
+byte[] imageBytes = Files.readAllBytes(Path.of("image.png"));
+String base64Image = Base64.getEncoder().encodeToString(imageBytes);
+Image image = Image.builder()
+    .base64Data(base64Image)
+    .mimeType("image/png")
+    .build();
+ImageContent imageContent = ImageContent.from(image);
+
+// Create request body with image content
+AiAgentBody<ImageContent> body = new AiAgentBody<ImageContent>()
+    .withUserMessage("What do you see in this image?")
+    .withContent(imageContent);
+
+String response = template.requestBody("direct:chat", body, String.class);
+----
+
+==== Automatic File Conversion from Camel Components
+
+The agent component automatically converts files from various Camel components 
to multimodal content. This enables seamless integration with file-based 
sources.
+
+===== Supported Input Types
+
+[cols="1,2,2"]
+|===
+|Input Type |Source Components |MIME Type Detection
+
+|`WrappedFile`
+|`file:`, `ftp:`, `sftp:`, `smb:`
+|From file extension or headers
+
+|`byte[]`
+|`aws2-s3:`, `azure-storage-blob:`, `google-storage:`
+|From content type headers (required)
+
+|`InputStream`
+|Various streaming components
+|From content type headers (required)
+|===
+
+===== Example: Processing Images from File Component
+
+[source,java]
+----
+from("file:inbox/images?noop=true&include=.*\\.png")
+    .setHeader("CamelLangChain4jAgentUserMessage", constant("Describe this 
image"))
+    .to("langchain4j-agent:vision?agent=#visionAgent")
+    .to("log:response");
+----
+
+===== Example: Processing Files from AWS S3
+
+[source,java]
+----
+from("aws2-s3://my-bucket?prefix=images/&includeBody=true")
+    .setHeader("CamelLangChain4jAgentUserMessage", constant("What do you see 
in this image?"))
+    .to("langchain4j-agent:vision?agent=#visionAgent")
+    .to("log:response");
+----
+
+[NOTE]
+====
+When using `byte[]` or `InputStream` inputs, a MIME type header is required 
since the type cannot be auto-detected from the content. The component checks 
for MIME type in this priority order:
+
+1. `CamelLangChain4jAgentMediaType` header (highest priority - explicit 
override)
+2. `CamelAwsS3ContentType` header (from AWS S3)
+3. `Content-Type` header
+4. `CamelFileContentType` header (from file components)
+====
+
+===== Example: Overriding MIME Type
+
+[source,java]
+----
+from("direct:process-file")
+    .setHeader("CamelLangChain4jAgentUserMessage", constant("Analyze this 
document"))
+    .setHeader("CamelLangChain4jAgentMediaType", constant("application/pdf"))
+    .to("langchain4j-agent:analyzer?agent=#analyzerAgent");
+----
+
+==== Complete Multimodal Route Example
+
+Here's a complete example showing how to process images from a file system and 
send them to an AI agent for analysis:
+
+[source,java]
+----
+// Create a vision-capable chat model
+ChatModel chatModel = OpenAiChatModel.builder()
+    .apiKey(apiKey)
+    .modelName("gpt-4o")  // Vision-capable model
+    .build();
+
+// Create agent configuration
+AgentConfiguration configuration = new AgentConfiguration()
+    .withChatModel(chatModel);
+
+Agent visionAgent = new AgentWithoutMemory(configuration);
+context.getRegistry().bind("visionAgent", visionAgent);
+
+// Route to process images
+from("file:inbox/images?noop=true&include=.*\\.(png|jpg|jpeg)")
+    .setHeader("CamelLangChain4jAgentUserMessage",
+        constant("Describe what you see in this image. Be detailed but 
concise."))
+    .to("langchain4j-agent:vision?agent=#visionAgent")
+    .log("AI Response: ${body}")
+    .to("file:outbox/descriptions");
+----
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
new file mode 100644
index 000000000000..07ec8ca41e80
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentConverter.java
@@ -0,0 +1,408 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.Base64;
+
+import dev.langchain4j.data.audio.Audio;
+import dev.langchain4j.data.image.Image;
+import dev.langchain4j.data.message.AudioContent;
+import dev.langchain4j.data.message.Content;
+import dev.langchain4j.data.message.ImageContent;
+import dev.langchain4j.data.message.PdfFileContent;
+import dev.langchain4j.data.message.TextContent;
+import dev.langchain4j.data.message.VideoContent;
+import dev.langchain4j.data.pdf.PdfFile;
+import dev.langchain4j.data.video.Video;
+import org.apache.camel.Converter;
+import org.apache.camel.Exchange;
+import org.apache.camel.WrappedFile;
+import org.apache.camel.component.langchain4j.agent.api.AiAgentBody;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.MEDIA_TYPE;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.MEMORY_ID;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.USER_MESSAGE;
+
+/**
+ * Type converters for the LangChain4j Agent component.
+ * <p>
+ * Provides automatic conversion from various input types to {@link 
AiAgentBody} with appropriate LangChain4j
+ * {@link Content} types based on the MIME type.
+ * </p>
+ * <p>
+ * Supported input types:
+ * </p>
+ * <ul>
+ * <li>{@link WrappedFile} - from file, ftp, sftp components</li>
+ * <li>{@code byte[]} - from aws2-s3, azure-storage-blob, and other cloud 
components</li>
+ * <li>{@link InputStream} - from various streaming components</li>
+ * </ul>
+ * <p>
+ * <strong>Note:</strong> For {@code byte[]} and {@link InputStream}, the MIME 
type must be provided via the
+ * {@code CamelLangChain4jAgentMediaType} header or a component-specific 
content type header.
+ * </p>
+ */
+@Converter(generateLoader = true)
+public final class LangChain4jAgentConverter {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(LangChain4jAgentConverter.class);
+
+    private LangChain4jAgentConverter() {
+    }
+
+    /**
+     * Converts a {@link WrappedFile} to an {@link AiAgentBody} with the 
appropriate {@link Content} type.
+     * <p>
+     * The conversion uses the following headers from the exchange:
+     * </p>
+     * <ul>
+     * <li>{@code CamelLangChain4jAgentUserMessage} - The text message to 
accompany the file content</li>
+     * <li>{@code CamelLangChain4jAgentSystemMessage} - Optional system 
message for the AI agent</li>
+     * <li>{@code CamelLangChain4jAgentMemoryId} - Optional memory ID for 
stateful conversations</li>
+     * <li>{@code CamelLangChain4jAgentMediaType} - Optional MIME type 
override (highest priority)</li>
+     * <li>{@code Exchange.FILE_CONTENT_TYPE} - MIME type from file components 
(second priority)</li>
+     * </ul>
+     * <p>
+     * If no MIME type header is found, the type is auto-detected from the 
file extension.
+     * </p>
+     *
+     * @param  wrappedFile              the wrapped file from file-based 
components (file, ftp, sftp, etc.)
+     * @param  exchange                 the Camel exchange containing headers
+     * @return                          an AiAgentBody with the appropriate 
Content type
+     * @throws IllegalArgumentException if the file cannot be read or the MIME 
type is unsupported
+     */
+    @Converter
+    public static AiAgentBody<?> toAiAgentBody(WrappedFile<?> wrappedFile, 
Exchange exchange) {
+        Object fileObj = wrappedFile.getFile();
+        if (fileObj == null) {
+            throw new IllegalArgumentException("WrappedFile contains null 
file");
+        }
+        if (!(fileObj instanceof File)) {
+            throw new IllegalArgumentException(
+                    "WrappedFile must contain a java.io.File instance, got: " 
+ fileObj.getClass().getName());
+        }
+
+        File file = (File) fileObj;
+        String mimeType = detectMimeType(file, exchange);
+        byte[] fileData = readFileBytes(file);
+        Content content = createContent(fileData, mimeType);
+
+        String userMessage = exchange.getIn().getHeader(USER_MESSAGE, 
String.class);
+        String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
+        Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
+
+        AiAgentBody<Content> body = new AiAgentBody<>();
+        body.setUserMessage(userMessage != null ? userMessage : "");
+        body.setSystemMessage(systemMessage);
+        body.setMemoryId(memoryId);
+        body.setContent(content);
+
+        return body;
+    }
+
+    /**
+     * Converts a {@code byte[]} to an {@link AiAgentBody} with the 
appropriate {@link Content} type.
+     * <p>
+     * This converter is useful for cloud storage components like aws2-s3, 
azure-storage-blob, etc. that return file
+     * content as byte arrays.
+     * </p>
+     * <p>
+     * <strong>Important:</strong> The MIME type must be provided via headers 
since it cannot be auto-detected from byte
+     * arrays. Supported headers (in priority order):
+     * </p>
+     * <ul>
+     * <li>{@code CamelLangChain4jAgentMediaType} header (highest 
priority)</li>
+     * <li>{@code CamelAwsS3ContentType} header (from AWS S3)</li>
+     * <li>{@code CamelAzureStorageBlobContentType} header (from Azure Blob 
Storage)</li>
+     * <li>{@code CamelAzureStorageDataLakeContentType} header (from Azure 
Data Lake Storage)</li>
+     * <li>{@code CamelGoogleCloudStorageContentType} header (from Google 
Cloud Storage)</li>
+     * <li>{@code CamelMinioContentType} header (from Minio)</li>
+     * <li>{@code CamelIBMCOSContentType} header (from IBM Cloud Object 
Storage)</li>
+     * <li>{@code Content-Type} header</li>
+     * <li>{@code CamelFileContentType} header (from file components)</li>
+     * </ul>
+     *
+     * @param  data                     the file content as a byte array
+     * @param  exchange                 the Camel exchange containing headers
+     * @return                          an AiAgentBody with the appropriate 
Content type
+     * @throws IllegalArgumentException if the MIME type is not provided or is 
unsupported
+     */
+    @Converter
+    public static AiAgentBody<?> byteArrayToAiAgentBody(byte[] data, Exchange 
exchange) {
+        String mimeType = detectMimeTypeFromHeaders(exchange);
+        Content content = createContent(data, mimeType);
+
+        String userMessage = exchange.getIn().getHeader(USER_MESSAGE, 
String.class);
+        String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
+        Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
+
+        AiAgentBody<Content> body = new AiAgentBody<>();
+        body.setUserMessage(userMessage != null ? userMessage : "");
+        body.setSystemMessage(systemMessage);
+        body.setMemoryId(memoryId);
+        body.setContent(content);
+
+        return body;
+    }
+
+    /**
+     * Converts an {@link InputStream} to an {@link AiAgentBody} with the 
appropriate {@link Content} type.
+     * <p>
+     * This converter is useful for streaming components that return file 
content as input streams.
+     * </p>
+     * <p>
+     * <strong>Important:</strong> The MIME type must be provided via headers 
since it cannot be auto-detected from
+     * streams.
+     * </p>
+     *
+     * @param  inputStream              the file content as an input stream
+     * @param  exchange                 the Camel exchange containing headers
+     * @return                          an AiAgentBody with the appropriate 
Content type
+     * @throws IllegalArgumentException if the stream cannot be read or the 
MIME type is not provided/unsupported
+     */
+    @Converter
+    public static AiAgentBody<?> inputStreamToAiAgentBody(InputStream 
inputStream, Exchange exchange) {
+        try {
+            byte[] data = inputStream.readAllBytes();
+            return byteArrayToAiAgentBody(data, exchange);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Failed to read input stream", 
e);
+        }
+    }
+
+    /**
+     * Creates the appropriate LangChain4j Content object based on the MIME 
type.
+     */
+    static Content createContent(byte[] data, String mimeType) {
+        String base64Data = Base64.getEncoder().encodeToString(data);
+
+        if (mimeType.startsWith("image/")) {
+            Image image = Image.builder()
+                    .base64Data(base64Data)
+                    .mimeType(mimeType)
+                    .build();
+            return ImageContent.from(image);
+        } else if (mimeType.startsWith("audio/")) {
+            Audio audio = Audio.builder()
+                    .base64Data(base64Data)
+                    .mimeType(mimeType)
+                    .build();
+            return AudioContent.from(audio);
+        } else if (mimeType.startsWith("video/")) {
+            Video video = Video.builder()
+                    .base64Data(base64Data)
+                    .mimeType(mimeType)
+                    .build();
+            return VideoContent.from(video);
+        } else if ("application/pdf".equals(mimeType)) {
+            PdfFile pdfFile = PdfFile.builder()
+                    .base64Data(base64Data)
+                    .build();
+            return PdfFileContent.from(pdfFile);
+        } else if (mimeType.startsWith("text/")) {
+            return TextContent.from(new String(data));
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported MIME type: " + mimeType
+                                               + ". Supported types: image/*, 
audio/*, video/*, application/pdf, text/*");
+        }
+    }
+
+    /**
+     * Detects the MIME type from headers or file extension.
+     * <p>
+     * Priority:
+     * </p>
+     * <ol>
+     * <li>CamelLangChain4jAgentMediaType header (highest priority)</li>
+     * <li>Exchange.FILE_CONTENT_TYPE header (from file components)</li>
+     * <li>Auto-detection from file extension</li>
+     * </ol>
+     */
+    private static String detectMimeType(File file, Exchange exchange) {
+        // Check agent-specific header first (highest priority)
+        String mediaType = exchange.getIn().getHeader(MEDIA_TYPE, 
String.class);
+        if (mediaType != null) {
+            return mediaType;
+        }
+
+        // Check file component's content type header
+        String fileContentType = 
exchange.getIn().getHeader(Exchange.FILE_CONTENT_TYPE, String.class);
+        if (fileContentType != null) {
+            return fileContentType;
+        }
+
+        // Auto-detect from file extension
+        return detectMimeTypeFromExtension(file.getName());
+    }
+
+    /**
+     * Detects the MIME type from headers only (for byte[] and InputStream 
where file extension is not available).
+     * <p>
+     * Priority:
+     * </p>
+     * <ol>
+     * <li>CamelLangChain4jAgentMediaType header (highest priority)</li>
+     * <li>Cloud storage component headers (AWS S3, Azure Blob, Google Cloud, 
Minio, IBM COS)</li>
+     * <li>Exchange.CONTENT_TYPE header</li>
+     * <li>Exchange.FILE_CONTENT_TYPE header</li>
+     * </ol>
+     *
+     * @throws IllegalArgumentException if no MIME type header is found
+     */
+    private static String detectMimeTypeFromHeaders(Exchange exchange) {
+        // Check agent-specific header first (highest priority)
+        String mediaType = exchange.getIn().getHeader(MEDIA_TYPE, 
String.class);
+        if (mediaType != null) {
+            return normalizeContentType(mediaType);
+        }
+
+        // Cloud storage component content type headers
+        String[] cloudContentTypeHeaders = {
+                "CamelAwsS3ContentType",                  // AWS S3
+                "CamelAzureStorageBlobContentType",       // Azure Blob Storage
+                "CamelAzureStorageDataLakeContentType",   // Azure Data Lake 
Storage
+                "CamelGoogleCloudStorageContentType",     // Google Cloud 
Storage
+                "CamelMinioContentType",                  // Minio 
(S3-compatible)
+                "CamelIBMCOSContentType"                  // IBM Cloud Object 
Storage
+        };
+
+        for (String header : cloudContentTypeHeaders) {
+            String cloudContentType = exchange.getIn().getHeader(header, 
String.class);
+            if (cloudContentType != null) {
+                return normalizeContentType(cloudContentType);
+            }
+        }
+
+        // Check standard content type header
+        String contentType = exchange.getIn().getHeader(Exchange.CONTENT_TYPE, 
String.class);
+        if (contentType != null) {
+            return normalizeContentType(contentType);
+        }
+
+        // Check file component's content type header
+        String fileContentType = 
exchange.getIn().getHeader(Exchange.FILE_CONTENT_TYPE, String.class);
+        if (fileContentType != null) {
+            return normalizeContentType(fileContentType);
+        }
+
+        throw new IllegalArgumentException(
+                "MIME type is required for byte[] or InputStream input. "
+                                           + "Please set the 
CamelLangChain4jAgentMediaType header.");
+    }
+
+    /**
+     * Normalizes a content type by removing charset and other parameters.
+     * <p>
+     * For example: "text/html; charset=utf-8" becomes "text/html"
+     * </p>
+     */
+    private static String normalizeContentType(String contentType) {
+        int semicolon = contentType.indexOf(';');
+        return semicolon > 0 ? contentType.substring(0, semicolon).trim() : 
contentType;
+    }
+
+    /**
+     * Detects the MIME type from the file extension.
+     */
+    private static String detectMimeTypeFromExtension(String fileName) {
+        String lowerName = fileName.toLowerCase();
+
+        // Image formats
+        if (lowerName.endsWith(".png")) {
+            return "image/png";
+        } else if (lowerName.endsWith(".jpg") || lowerName.endsWith(".jpeg")) {
+            return "image/jpeg";
+        } else if (lowerName.endsWith(".gif")) {
+            return "image/gif";
+        } else if (lowerName.endsWith(".webp")) {
+            return "image/webp";
+        } else if (lowerName.endsWith(".bmp")) {
+            return "image/bmp";
+        } else if (lowerName.endsWith(".tiff") || lowerName.endsWith(".tif")) {
+            return "image/tiff";
+        } else if (lowerName.endsWith(".svg")) {
+            return "image/svg+xml";
+        }
+        // Video formats
+        else if (lowerName.endsWith(".mp4")) {
+            return "video/mp4";
+        } else if (lowerName.endsWith(".webm")) {
+            return "video/webm";
+        } else if (lowerName.endsWith(".mov")) {
+            return "video/quicktime";
+        } else if (lowerName.endsWith(".mkv")) {
+            return "video/x-matroska";
+        } else if (lowerName.endsWith(".avi")) {
+            return "video/x-msvideo";
+        }
+        // Audio formats
+        else if (lowerName.endsWith(".wav")) {
+            return "audio/wav";
+        } else if (lowerName.endsWith(".mp3")) {
+            return "audio/mpeg";
+        } else if (lowerName.endsWith(".ogg")) {
+            return "audio/ogg";
+        } else if (lowerName.endsWith(".m4a")) {
+            return "audio/mp4";
+        } else if (lowerName.endsWith(".flac")) {
+            return "audio/flac";
+        }
+        // Document formats
+        else if (lowerName.endsWith(".pdf")) {
+            return "application/pdf";
+        }
+        // Text formats
+        else if (lowerName.endsWith(".txt")) {
+            return "text/plain";
+        } else if (lowerName.endsWith(".csv")) {
+            return "text/csv";
+        } else if (lowerName.endsWith(".html") || lowerName.endsWith(".htm")) {
+            return "text/html";
+        } else if (lowerName.endsWith(".md")) {
+            return "text/markdown";
+        } else if (lowerName.endsWith(".xml")) {
+            return "text/xml";
+        } else if (lowerName.endsWith(".json")) {
+            return "application/json";
+        }
+
+        LOG.warn("Could not detect MIME type from file extension: {}. Please 
set the CamelLangChain4jAgentMediaType header.",
+                fileName);
+        throw new IllegalArgumentException(
+                "Cannot determine MIME type for file: " + fileName
+                                           + ". Please set the 
CamelLangChain4jAgentMediaType header.");
+    }
+
+    /**
+     * Reads the file content as a byte array.
+     */
+    private static byte[] readFileBytes(File file) {
+        try {
+            return Files.readAllBytes(file.toPath());
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Failed to read file: " + 
file.getAbsolutePath(), e);
+        }
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/AbstractRAGIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/AbstractRAGIT.java
index bfeca686642d..af2698e6cc35 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/AbstractRAGIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/AbstractRAGIT.java
@@ -31,11 +31,9 @@ import 
dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore;
 import org.apache.camel.component.langchain4j.agent.BaseLangChain4jAgent;
 import org.apache.camel.test.infra.ollama.services.OllamaService;
 import org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 public abstract class AbstractRAGIT extends BaseLangChain4jAgent {
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentCustomToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentCustomToolsIT.java
index edf8ad1b6d6e..43e72c96c0a8 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentCustomToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentCustomToolsIT.java
@@ -33,7 +33,6 @@ import 
org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -50,7 +49,6 @@ public class LangChain4jAgentCustomToolsIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentGuardrailsIntegrationIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentGuardrailsIntegrationIT.java
index c09d6946b073..98fc914c8e8c 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentGuardrailsIntegrationIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentGuardrailsIntegrationIT.java
@@ -33,7 +33,6 @@ import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -45,7 +44,6 @@ public class LangChain4jAgentGuardrailsIntegrationIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpToolsIT.java
index 2ad87bfddc59..6fff04f75f7a 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpToolsIT.java
@@ -38,7 +38,6 @@ import 
org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.io.TempDir;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -64,7 +63,6 @@ public class LangChain4jAgentMcpToolsIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
index b2e73760ad59..3ce1841e466d 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
@@ -32,7 +32,6 @@ import 
org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -53,7 +52,6 @@ public class LangChain4jAgentMixedToolsIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMultimodalityIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMultimodalityIT.java
new file mode 100644
index 000000000000..a2ac1014d928
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMultimodalityIT.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent.integration;
+
+import java.io.InputStream;
+import java.util.Base64;
+import java.util.List;
+
+import dev.langchain4j.data.image.Image;
+import dev.langchain4j.data.message.ImageContent;
+import dev.langchain4j.data.message.TextContent;
+import dev.langchain4j.model.chat.ChatModel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.langchain4j.agent.api.Agent;
+import org.apache.camel.component.langchain4j.agent.api.AgentConfiguration;
+import org.apache.camel.component.langchain4j.agent.api.AgentWithoutMemory;
+import org.apache.camel.component.langchain4j.agent.api.AiAgentBody;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.infra.ollama.services.OllamaService;
+import org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Integration tests for multimodal content support in the LangChain4j Agent 
component. Tests the ability to send both
+ * TextContent and ImageContent to AI models.
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Requires too much network resources")
+public class LangChain4jAgentMultimodalityIT extends CamelTestSupport {
+
+    private static final String TEST_IMAGE_PATH = "camel-logo.png";
+
+    protected ChatModel chatModel;
+
+    static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
+            ? null
+            : OllamaServiceFactory.createSingletonService();
+
+    @Override
+    protected void setupResources() throws Exception {
+        super.setupResources();
+
+        chatModel = OLLAMA != null ? ModelHelper.loadChatModel(OLLAMA) : 
ModelHelper.loadFromEnv();
+    }
+
+    /**
+     * Tests sending a message with TextContent. This validates that the 
Content parameter works correctly with simple
+     * text content.
+     */
+    @Test
+    void testTextContent() throws InterruptedException {
+        MockEndpoint mockEndpoint = this.context.getEndpoint("mock:response", 
MockEndpoint.class);
+        mockEndpoint.expectedMessageCount(1);
+
+        TextContent textContent = TextContent.from("This is additional context 
about Apache Camel integration framework.");
+
+        AiAgentBody<TextContent> body = new AiAgentBody<TextContent>()
+                .withUserMessage("What can you tell me about the text I 
provided?")
+                .withContent(textContent);
+
+        String response = template.requestBody("direct:multimodal-agent", 
body, String.class);
+
+        mockEndpoint.assertIsSatisfied();
+        assertNotNull(response, "AI response should not be null");
+        assertTrue(response.length() > 0, "AI response should not be empty");
+        assertTrue(response.contains("Camel"), "AI response should contain 
Camel " + response);
+    }
+
+    /**
+     * Tests sending a message with ImageContent. This validates that the 
agent can process image content for
+     * vision-capable models.
+     */
+    @Test
+    void testImageContent() throws Exception {
+        MockEndpoint mockEndpoint = this.context.getEndpoint("mock:response", 
MockEndpoint.class);
+        mockEndpoint.expectedMessageCount(1);
+
+        // Load the test image
+        byte[] imageBytes;
+        try (InputStream is = 
getClass().getClassLoader().getResourceAsStream(TEST_IMAGE_PATH)) {
+            if (is == null) {
+                throw new IllegalStateException("Test image not found: " + 
TEST_IMAGE_PATH);
+            }
+            imageBytes = is.readAllBytes();
+        }
+
+        // Create ImageContent from base64-encoded image
+        String base64Image = Base64.getEncoder().encodeToString(imageBytes);
+        Image image = Image.builder()
+                .base64Data(base64Image)
+                .mimeType("image/png")
+                .build();
+        ImageContent imageContent = ImageContent.from(image);
+
+        AiAgentBody<ImageContent> body = new AiAgentBody<ImageContent>()
+                .withUserMessage("What do you see in this image? Describe it 
briefly.")
+                .withContent(imageContent);
+
+        String response = template.requestBody("direct:multimodal-agent", 
body, String.class);
+
+        mockEndpoint.assertIsSatisfied();
+        assertNotNull(response, "AI response should not be null");
+        assertTrue(response.length() > 0, "AI response should not be empty");
+        assertTrue(response.contains("Camel"), "AI response should contain 
Camel " + response);
+    }
+
+    /**
+     * Tests sending a message with TextContent and a system message. This 
validates that the Content parameter works
+     * correctly alongside system messages.
+     */
+    @Test
+    void testTextContentWithSystemMessage() throws InterruptedException {
+        MockEndpoint mockEndpoint = this.context.getEndpoint("mock:response", 
MockEndpoint.class);
+        mockEndpoint.expectedMessageCount(1);
+
+        TextContent textContent = TextContent.from("Apache Camel is an 
open-source integration framework.");
+
+        AiAgentBody<TextContent> body = new AiAgentBody<TextContent>()
+                .withUserMessage("Summarize the provided text in one 
sentence.")
+                .withSystemMessage("You are a technical documentation 
assistant. Be concise and accurate.")
+                .withContent(textContent);
+
+        String response = template.requestBody("direct:multimodal-agent", 
body, String.class);
+
+        mockEndpoint.assertIsSatisfied();
+        assertNotNull(response, "AI response should not be null");
+        assertTrue(response.length() > 0, "AI response should not be empty");
+        assertTrue(response.contains("Camel"), "AI response should contain 
Camel " + response);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        AgentConfiguration configuration = new AgentConfiguration()
+                .withChatModel(chatModel)
+                .withInputGuardrailClasses(List.of())
+                .withOutputGuardrailClasses(List.of());
+
+        Agent multimodalAgent = new AgentWithoutMemory(configuration);
+
+        this.context.getRegistry().bind("multimodalAgent", multimodalAgent);
+
+        return new RouteBuilder() {
+            public void configure() {
+                from("direct:multimodal-agent")
+                        
.to("langchain4j-agent:multimodal?agent=#multimodalAgent")
+                        .to("mock:response");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryIT.java
index e906a706eecb..281c02228a98 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryIT.java
@@ -34,7 +34,6 @@ import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static 
org.apache.camel.component.langchain4j.agent.api.Headers.MEMORY_ID;
 import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
@@ -53,7 +52,6 @@ public class LangChain4jAgentWithMemoryIT extends 
CamelTestSupport {
     protected ChatMemoryProvider chatMemoryProvider;
     private PersistentChatMemoryStore store;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
index 46a3c78cccbf..637fa752889b 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
@@ -30,7 +30,6 @@ import 
org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -45,7 +44,6 @@ public class LangChain4jAgentWithToolsIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWrappedFileIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWrappedFileIT.java
new file mode 100644
index 000000000000..b2bff35d4157
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWrappedFileIT.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent.integration;
+
+import java.net.URL;
+import java.util.List;
+
+import dev.langchain4j.model.chat.ChatModel;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.langchain4j.agent.api.Agent;
+import org.apache.camel.component.langchain4j.agent.api.AgentConfiguration;
+import org.apache.camel.component.langchain4j.agent.api.AgentWithoutMemory;
+import org.apache.camel.component.langchain4j.agent.api.Headers;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Integration tests for WrappedFile support in the LangChain4j Agent 
component. Tests the ability to process files from
+ * the file component directly, with automatic Content type conversion based 
on MIME type.
+ * <p>
+ * Requires environment variables to be set:
+ * <ul>
+ * <li>API_KEY - The API key for the LLM provider</li>
+ * <li>MODEL_PROVIDER - The provider name (e.g., "openai", "gemini", 
"ollama")</li>
+ * <li>MODEL_BASE_URL - (Optional) Custom base URL for OpenAI-compatible 
endpoints</li>
+ * <li>MODEL_NAME - (Optional) Custom model name</li>
+ * </ul>
+ */
+@DisabledIfSystemProperty(named = "ci.env.name", matches = ".*", 
disabledReason = "Requires too much network resources")
+public class LangChain4jAgentWrappedFileIT extends CamelTestSupport {
+
+    private static final String IMAGE_ROUTE_ID = "image-route";
+    private static final String PDF_ROUTE_ID = "pdf-route";
+
+    protected ChatModel chatModel;
+    private String resourcesPath;
+
+    @Override
+    protected void setupResources() throws Exception {
+        super.setupResources();
+
+        if (!ModelHelper.hasEnvironmentConfiguration()) {
+            throw new IllegalStateException(
+                    "This test requires environment variables: API_KEY, 
MODEL_PROVIDER. "
+                                            + "Optionally: MODEL_BASE_URL, 
MODEL_NAME");
+        }
+
+        chatModel = ModelHelper.loadFromEnv();
+
+        // Get the path to test resources
+        URL resourceUrl = 
getClass().getClassLoader().getResource("camel-logo.png");
+        assertNotNull(resourceUrl, "Test resources not found");
+        resourcesPath = resourceUrl.getPath().replace("/camel-logo.png", "");
+    }
+
+    /**
+     * Tests that an image file from the file component is automatically 
converted to ImageContent and processed by the
+     * agent.
+     */
+    @Test
+    void testImageFileFromFileComponent() throws Exception {
+        // Start only the image route
+        context.getRouteController().startRoute(IMAGE_ROUTE_ID);
+
+        MockEndpoint mockEndpoint = 
this.context.getEndpoint("mock:image-response", MockEndpoint.class);
+        mockEndpoint.expectedMessageCount(1);
+
+        // Wait for the file to be processed
+        mockEndpoint.assertIsSatisfied(60000);
+
+        // Verify the response
+        String response = 
mockEndpoint.getExchanges().get(0).getIn().getBody(String.class);
+        assertNotNull(response, "Response should not be null");
+        assertTrue(response.length() > 0, "Response should not be empty");
+    }
+
+    /**
+     * Tests that a PDF file from the file component is automatically 
converted to PdfFileContent and processed by the
+     * agent.
+     */
+    @Test
+    void testPdfFileFromFileComponent() throws Exception {
+        // Start only the PDF route
+        context.getRouteController().startRoute(PDF_ROUTE_ID);
+
+        MockEndpoint mockEndpoint = 
this.context.getEndpoint("mock:pdf-response", MockEndpoint.class);
+        mockEndpoint.expectedMessageCount(1);
+
+        // Wait for the file to be processed
+        mockEndpoint.assertIsSatisfied(60000);
+
+        // Verify the response
+        String response = 
mockEndpoint.getExchanges().get(0).getIn().getBody(String.class);
+        assertNotNull(response, "Response should not be null");
+        assertTrue(response.length() > 0, "Response should not be empty");
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        AgentConfiguration configuration = new AgentConfiguration()
+                .withChatModel(chatModel)
+                .withInputGuardrailClasses(List.of())
+                .withOutputGuardrailClasses(List.of());
+
+        Agent agent = new AgentWithoutMemory(configuration);
+
+        this.context.getRegistry().bind("fileAgent", agent);
+
+        return new RouteBuilder() {
+            public void configure() {
+                // Route for processing image files from resources folder 
(starts stopped)
+                from("file:" + resourcesPath + "?noop=true&include=.*\\.png")
+                        .routeId(IMAGE_ROUTE_ID)
+                        .autoStartup(false)
+                        .setHeader(Headers.USER_MESSAGE, constant("What do you 
see in this image? Describe it briefly."))
+                        .to("langchain4j-agent:describe?agent=#fileAgent")
+                        .to("mock:image-response");
+
+                // Route for processing PDF files from resources folder 
(starts stopped)
+                from("file:" + resourcesPath + "?noop=true&include=.*\\.pdf")
+                        .routeId(PDF_ROUTE_ID)
+                        .autoStartup(false)
+                        .setHeader(Headers.USER_MESSAGE, constant("What is 
this document about? Summarize it briefly."))
+                        .to("langchain4j-agent:describe?agent=#fileAgent")
+                        .to("mock:pdf-response");
+            }
+        };
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jSimpleAgentIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jSimpleAgentIT.java
index 5e0cad56d308..fead99f99156 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jSimpleAgentIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jSimpleAgentIT.java
@@ -30,7 +30,6 @@ import 
org.apache.camel.test.infra.ollama.services.OllamaServiceFactory;
 import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.DisabledIfSystemProperty;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
@@ -51,7 +50,6 @@ public class LangChain4jSimpleAgentIT extends 
CamelTestSupport {
 
     protected ChatModel chatModel;
 
-    @RegisterExtension
     static OllamaService OLLAMA = ModelHelper.hasEnvironmentConfiguration()
             ? null
             : OllamaServiceFactory.createSingletonService();
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/ModelHelper.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/ModelHelper.java
index 3b711c6e8df4..04379b647141 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/ModelHelper.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/ModelHelper.java
@@ -43,7 +43,7 @@ public class ModelHelper {
     protected static ChatModel createGeminiModel(String apiKey) {
         return GoogleAiGeminiChatModel.builder()
                 .apiKey(apiKey)
-                .modelName("gemini-2.5-flash")
+                .modelName("gemini-2.5-flash-lite")
                 .temperature(1.0)
                 .timeout(ofSeconds(60))
                 .logRequestsAndResponses(true)
@@ -51,14 +51,28 @@ public class ModelHelper {
     }
 
     protected static ChatModel createOpenAiModel(String apiKey) {
-        return OpenAiChatModel.builder()
+        OpenAiChatModel.OpenAiChatModelBuilder builder = 
OpenAiChatModel.builder()
                 .apiKey(apiKey)
-                .modelName(OpenAiChatModelName.GPT_4_O_MINI)
                 .temperature(1.0)
                 .timeout(ofSeconds(60))
                 .logRequests(true)
-                .logResponses(true)
-                .build();
+                .logResponses(true);
+
+        // Support custom base URL for OpenAI-compatible endpoints
+        String baseUrl = System.getenv(MODEL_BASE_URL);
+        if (baseUrl != null && !baseUrl.trim().isEmpty()) {
+            builder.baseUrl(baseUrl);
+        }
+
+        // Support custom model name, default to GPT-4o-mini
+        String modelName = System.getenv(MODEL_NAME);
+        if (modelName != null && !modelName.trim().isEmpty()) {
+            builder.modelName(modelName);
+        } else {
+            builder.modelName(OpenAiChatModelName.GPT_4_O_MINI);
+        }
+
+        return builder.build();
     }
 
     protected static ChatModel createExternalChatModel(String name, String 
apiKey) {
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/resources/camel-logo.png 
b/components/camel-ai/camel-langchain4j-agent/src/test/resources/camel-logo.png
new file mode 100644
index 000000000000..e4029249e6c4
Binary files /dev/null and 
b/components/camel-ai/camel-langchain4j-agent/src/test/resources/camel-logo.png 
differ
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/resources/test-document.pdf
 
b/components/camel-ai/camel-langchain4j-agent/src/test/resources/test-document.pdf
new file mode 100644
index 000000000000..3cedc4da23fb
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/resources/test-document.pdf
@@ -0,0 +1,20 @@
+%PDF-1.4
+1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
+2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj
+3 0 obj << /Type /Page /Parent 2 0 R /Resources << /Font << /F1 4 0 R >> >> 
/MediaBox [0 0 612 792] /Contents 5 0 R >> endobj
+4 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj
+5 0 obj << /Length 44 >> stream
+BT /F1 12 Tf 100 700 Td (Test PDF) Tj ET
+endstream endobj
+xref
+0 6
+0000000000 65535 f 
+0000000009 00000 n 
+0000000058 00000 n 
+0000000115 00000 n 
+0000000261 00000 n 
+0000000330 00000 n 
+trailer << /Size 6 /Root 1 0 R >>
+startxref
+422
+%%EOF
diff --git a/components/camel-ai/camel-langchain4j-agent/test-execution.md 
b/components/camel-ai/camel-langchain4j-agent/test-execution.md
index 4402c014b932..ad514ecc889c 100644
--- a/components/camel-ai/camel-langchain4j-agent/test-execution.md
+++ b/components/camel-ai/camel-langchain4j-agent/test-execution.md
@@ -4,7 +4,7 @@
 If ollama is already installed on the system execute the test with 
 
 ```bash
-mvn verify -Dollama.endpoint=http://localhost:11434/ 
-Dollama.model=granite4:tiny-h -Dollama.instance.type=remote
+mvn verify -Dollama.endpoint=http://localhost:11434/ 
-Dollama.model=granite4:3b -Dollama.instance.type=remote
 ```
 
 The Ollama docker image is really slow on macbook without nvidia hardware 
acceleration
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
index 1ce4c56ae4a4..5bf843a02cf4 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jAgentEndpointBuilderFactory.java
@@ -270,6 +270,32 @@ public interface LangChain4jAgentEndpointBuilderFactory {
         public String langChain4jAgentMemoryId() {
             return "CamelLangChain4jAgentMemoryId";
         }
+        /**
+         * The user message to accompany file content when using WrappedFile as
+         * input.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code LangChain4jAgentUserMessage}.
+         */
+        public String langChain4jAgentUserMessage() {
+            return "CamelLangChain4jAgentUserMessage";
+        }
+        /**
+         * The media type (MIME type) of the file content. Overrides
+         * auto-detection from file extension.
+         * 
+         * The option is a: {@code String} type.
+         * 
+         * Group: producer
+         * 
+         * @return the name of the header {@code LangChain4jAgentMediaType}.
+         */
+        public String langChain4jAgentMediaType() {
+            return "CamelLangChain4jAgentMediaType";
+        }
     }
     static LangChain4jAgentEndpointBuilder endpointBuilder(String 
componentName, String path) {
         class LangChain4jAgentEndpointBuilderImpl extends 
AbstractEndpointBuilder implements LangChain4jAgentEndpointBuilder, 
AdvancedLangChain4jAgentEndpointBuilder {
diff --git 
a/test-infra/camel-test-infra-openai-mock/src/main/java/org/apache/camel/test/infra/openai/mock/RequestContext.java
 
b/test-infra/camel-test-infra-openai-mock/src/main/java/org/apache/camel/test/infra/openai/mock/RequestContext.java
index 93eab20d9f86..7ea25229f919 100644
--- 
a/test-infra/camel-test-infra-openai-mock/src/main/java/org/apache/camel/test/infra/openai/mock/RequestContext.java
+++ 
b/test-infra/camel-test-infra-openai-mock/src/main/java/org/apache/camel/test/infra/openai/mock/RequestContext.java
@@ -51,13 +51,39 @@ public class RequestContext {
 
             String role = messageNode.path("role").asText();
             if ("user".equals(role)) {
-                return messageNode.path("content").asText();
+                return extractContentText(messageNode.path("content"));
             }
         }
 
         return null;
     }
 
+    /**
+     * Extracts text content from either a plain string or an array of content 
parts. Supports formats: - Simple string:
+     * "Hello" - Array of content parts: [{"type": "text", "text": "Hello"}]
+     */
+    private String extractContentText(JsonNode contentNode) {
+        if (contentNode.isTextual()) {
+            return contentNode.asText();
+        }
+
+        if (contentNode.isArray()) {
+            StringBuilder textBuilder = new StringBuilder();
+            for (JsonNode part : contentNode) {
+                String type = part.path("type").asText();
+                if ("text".equals(type)) {
+                    if (textBuilder.length() > 0) {
+                        textBuilder.append(" ");
+                    }
+                    textBuilder.append(part.path("text").asText());
+                }
+            }
+            return textBuilder.length() > 0 ? textBuilder.toString() : null;
+        }
+
+        return null;
+    }
+
     public JsonNode getMessagesNode() {
         return messagesNode;
     }


Reply via email to