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

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

commit eda29bc13c92daff2160ef71d397512e4463f43d
Author: Otavio Rodolfo Piske <[email protected]>
AuthorDate: Mon Sep 1 13:38:35 2025 +0200

    CAMEL-22398: allow agents to define the specifics of the exchange body
---
 .../catalog/components/langchain4j-agent.json      |  4 +-
 .../component/langchain4j/agent/api/Agent.java     | 59 ++++++++++++++++++++++
 .../langchain4j/agent/api/AgentFactory.java        |  3 +-
 .../component/langchain4j/agent/api}/Headers.java  |  2 +-
 .../langchain4j/agent/langchain4j-agent.json       |  4 +-
 .../agent/LangChain4jAgentEndpoint.java            |  1 +
 .../agent/LangChain4jAgentProducer.java            | 33 ++----------
 .../integration/LangChain4jAgentNaiveRagIT.java    |  2 +-
 .../integration/LangChain4jAgentWithMemoryIT.java  |  4 +-
 .../integration/LangChain4jSimpleAgentIT.java      |  2 +-
 10 files changed, 75 insertions(+), 39 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 7edf39e80f9..a02042ed669 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
@@ -32,8 +32,8 @@
     "autowiredEnabled": { "index": 5, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
   "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.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.Headers#MEMORY_ID" }
+    "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" }
   },
   "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/Agent.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Agent.java
index fff853701a7..8df5577e954 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
@@ -17,6 +17,11 @@
 package org.apache.camel.component.langchain4j.agent.api;
 
 import dev.langchain4j.service.tool.ToolProvider;
+import org.apache.camel.Exchange;
+import org.apache.camel.InvalidPayloadRuntimeException;
+
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.MEMORY_ID;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
 
 /**
  * Core agent interface that abstracts different types of AI agents within the 
Apache Camel LangChain4j integration.
@@ -44,6 +49,60 @@ import dev.langchain4j.service.tool.ToolProvider;
  */
 public interface Agent {
 
+    /**
+     * Processes and normalizes the exchange message payload into an {@link 
AiAgentBody} instance.
+     *
+     * <p>
+     * This method serves as a payload adapter that ensures consistent input 
format for AI agent chat interactions. It
+     * handles different payload types and automatically extracts relevant 
headers to construct a properly formatted
+     * {@link AiAgentBody} object.
+     * </p>
+     *
+     * <p>
+     * The method performs the following transformations:
+     * </p>
+     * <ul>
+     * <li>If the payload is already an {@link AiAgentBody}, it returns it 
unchanged</li>
+     * <li>If the payload is a {@link String}, it creates a new {@link 
AiAgentBody} with:
+     * <ul>
+     * <li>The string as the user message</li>
+     * <li>The {@link Headers#SYSTEM_MESSAGE} header value as the system 
message (if present)</li>
+     * <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>
+     * </ul>
+     *
+     * <p>
+     * This method is typically called automatically by the LangChain4j agent 
component before invoking the
+     * {@link #chat(AiAgentBody, ToolProvider)} method, ensuring that the 
agent always receives a properly structured
+     * request body regardless of how the original message was formatted.
+     * </p>
+     *
+     * @param  messagePayload                 the message payload from the 
exchange body; must be either an
+     *                                        {@link AiAgentBody} or a {@link 
String}
+     * @param  exchange                       the Camel exchange containing 
headers and context information
+     * @return                                an {@link AiAgentBody} instance 
ready for agent processing; returns the
+     *                                        original payload if it's already 
an {@link AiAgentBody}, or creates a new
+     *                                        one from a string payload and 
relevant headers
+     * @throws InvalidPayloadRuntimeException if the payload is neither an 
{@link AiAgentBody} nor a {@link String}
+     * @throws Exception                      if any other error occurs during 
payload processing
+     */
+    default AiAgentBody processBody(Object messagePayload, Exchange exchange) 
throws Exception {
+        if (messagePayload instanceof AiAgentBody) {
+            return (AiAgentBody) messagePayload;
+        }
+
+        if (!(messagePayload instanceof String)) {
+            throw new InvalidPayloadRuntimeException(exchange, 
AiAgentBody.class);
+        }
+
+        String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
+        Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
+
+        return new AiAgentBody((String) messagePayload, systemMessage, 
memoryId);
+    }
+
     /**
      * Executes a chat interaction with the AI agent using the provided 
request body and tool provider.
      *
diff --git 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentFactory.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentFactory.java
index 61cb3e6cfa4..c14f3ce8272 100644
--- 
a/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentFactory.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/AgentFactory.java
@@ -64,7 +64,8 @@ public interface AgentFactory extends CamelContextAware {
      * configuration remains unchanged. The returned agent will be fully 
configured and ready to handle chat
      * interactions.
      * </p>
-     * @param exchange the exchange being processed which is triggering the 
creation of the agent
+     *
+     * @param  exchange  the exchange being processed which is triggering the 
creation of the agent
      *
      * @return           a configured {@link Agent} instance ready for chat 
interactions
      * @throws Exception if unable to create the agent due to configuration 
issues, missing dependencies, or
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/Headers.java
 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
similarity index 95%
rename from 
components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/Headers.java
rename to 
components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
index dec5e0d5d0a..5e53a96dcd5 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/Headers.java
+++ 
b/components/camel-ai/camel-langchain4j-agent-api/src/main/java/org/apache/camel/component/langchain4j/agent/api/Headers.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.camel.component.langchain4j.agent;
+package org.apache.camel.component.langchain4j.agent.api;
 
 import org.apache.camel.spi.Metadata;
 
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 7edf39e80f9..a02042ed669 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
@@ -32,8 +32,8 @@
     "autowiredEnabled": { "index": 5, "kind": "property", "displayName": 
"Autowired Enabled", "group": "advanced", "label": "advanced", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": true, "description": 
"Whether autowiring is enabled. This is used for automatic autowiring options 
(the option must be marked as autowired) by looking up in the registry to find 
if there is a single instance of matching t [...]
   },
   "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.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.Headers#MEMORY_ID" }
+    "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" }
   },
   "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/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpoint.java
 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpoint.java
index 9aa3d1c8fa5..65583b13b1d 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpoint.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentEndpoint.java
@@ -21,6 +21,7 @@ import org.apache.camel.Component;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import org.apache.camel.component.langchain4j.agent.api.Headers;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
index 2e7a920037b..09537d4d7bc 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentProducer.java
@@ -27,7 +27,6 @@ import dev.langchain4j.service.tool.ToolProvider;
 import dev.langchain4j.service.tool.ToolProviderRequest;
 import dev.langchain4j.service.tool.ToolProviderResult;
 import org.apache.camel.Exchange;
-import org.apache.camel.InvalidPayloadRuntimeException;
 import org.apache.camel.component.langchain4j.agent.api.Agent;
 import org.apache.camel.component.langchain4j.agent.api.AgentFactory;
 import org.apache.camel.component.langchain4j.agent.api.AiAgentBody;
@@ -38,9 +37,6 @@ import org.apache.camel.util.ObjectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.camel.component.langchain4j.agent.Headers.MEMORY_ID;
-import static 
org.apache.camel.component.langchain4j.agent.Headers.SYSTEM_MESSAGE;
-
 public class LangChain4jAgentProducer extends DefaultProducer {
     private static final Logger LOG = 
LoggerFactory.getLogger(LangChain4jAgentProducer.class);
 
@@ -58,6 +54,9 @@ public class LangChain4jAgentProducer extends DefaultProducer 
{
         Object messagePayload = exchange.getIn().getBody();
         ObjectHelper.notNull(messagePayload, "body");
 
+        // tags for Camel Routes as Tools
+        String tags = endpoint.getConfiguration().getTags();
+
         Agent agent;
         if (agentFactory != null) {
             agent = agentFactory.createAgent(exchange);
@@ -65,37 +64,13 @@ public class LangChain4jAgentProducer extends 
DefaultProducer {
             agent = endpoint.getConfiguration().getAgent();
         }
 
-        AiAgentBody aiAgentBody = processBody(messagePayload, exchange);
-
-        // tags for Camel Routes as Tools
-        String tags = endpoint.getConfiguration().getTags();
+        AiAgentBody aiAgentBody = agent.processBody(messagePayload, exchange);
 
         ToolProvider toolProvider = createCamelToolProvider(tags, exchange);
         String response = agent.chat(aiAgentBody, toolProvider);
         exchange.getMessage().setBody(response);
     }
 
-    /**
-     * No matter if the user uses an AiAgentBody or headers, we manipulate an 
AiAgentBody
-     *
-     * @param messagePayload
-     * @param exchange
-     */
-    private AiAgentBody processBody(Object messagePayload, Exchange exchange) {
-        if (messagePayload instanceof AiAgentBody) {
-            return (AiAgentBody) messagePayload;
-        }
-
-        if (!(messagePayload instanceof String)) {
-            throw new InvalidPayloadRuntimeException(exchange, 
AiAgentBody.class);
-        }
-
-        String systemMessage = exchange.getIn().getHeader(SYSTEM_MESSAGE, 
String.class);
-        Object memoryId = exchange.getIn().getHeader(MEMORY_ID);
-
-        return new AiAgentBody((String) messagePayload, systemMessage, 
memoryId);
-    }
-
     /**
      * We create our own Tool Provider
      *
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentNaiveRagIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentNaiveRagIT.java
index 7f1116e6d05..d20a2423730 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentNaiveRagIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentNaiveRagIT.java
@@ -26,7 +26,7 @@ import org.apache.camel.component.mock.MockEndpoint;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.EnabledIf;
 
-import static 
org.apache.camel.component.langchain4j.agent.Headers.SYSTEM_MESSAGE;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
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 e65cd370fe3..4a7b7f82a01 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
@@ -33,8 +33,8 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.EnabledIf;
 
-import static org.apache.camel.component.langchain4j.agent.Headers.MEMORY_ID;
-import static 
org.apache.camel.component.langchain4j.agent.Headers.SYSTEM_MESSAGE;
+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.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
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 b80c9b8b384..471ca255e13 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
@@ -29,7 +29,7 @@ import org.apache.camel.test.junit5.CamelTestSupport;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.condition.EnabledIf;
 
-import static 
org.apache.camel.component.langchain4j.agent.Headers.SYSTEM_MESSAGE;
+import static 
org.apache.camel.component.langchain4j.agent.api.Headers.SYSTEM_MESSAGE;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;

Reply via email to