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

commit 76718ccf446a184babe709873d33b3b98dd98de3
Author: Croway <federico.mariani.1...@gmail.com>
AuthorDate: Fri May 31 18:36:28 2024 +0200

    CAMEL-20822: Implement OpenAI Tool Capabilities natively in Camel
---
 components/camel-ai/camel-langchain4j-chat/pom.xml | 16 ++++
 .../src/main/docs/langchain4j-chat-component.adoc  | 34 ++++++++
 .../langchain4j/chat/LangChain4jChatConsumer.java  | 28 +++++++
 .../langchain4j/chat/LangChain4jChatEndpoint.java  | 83 ++++++++++++++++++-
 .../langchain4j/chat/LangChain4jChatProducer.java  | 56 ++++++++++++-
 .../chat/tool/CamelSimpleToolParameter.java        | 42 ++++++++++
 .../chat/tool/CamelToolExecutorCache.java          | 59 ++++++++++++++
 .../chat/tool/CamelToolSpecification.java          | 51 ++++++++++++
 .../chat/tool/NamedJsonSchemaProperty.java         | 40 ++++++++++
 .../langchain4j.chat/LangChain4jConsumerIT.java    | 93 ++++++++++++++++++++++
 10 files changed, 498 insertions(+), 4 deletions(-)

diff --git a/components/camel-ai/camel-langchain4j-chat/pom.xml 
b/components/camel-ai/camel-langchain4j-chat/pom.xml
index 604500a8feb..bc1e423b84a 100644
--- a/components/camel-ai/camel-langchain4j-chat/pom.xml
+++ b/components/camel-ai/camel-langchain4j-chat/pom.xml
@@ -43,6 +43,16 @@
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-langchain4j-core</artifactId>
         </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j</artifactId>
+            <version>${langchain4j-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson2-version}</version>
+        </dependency>
 
         <!-- for testing -->
         <dependency>
@@ -63,6 +73,12 @@
             <type>test-jar</type>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-open-ai</artifactId>
+            <version>${langchain4j-version}</version>
+            <scope>test</scope>
+        </dependency>
 
     </dependencies>
 
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/docs/langchain4j-chat-component.adoc
 
b/components/camel-ai/camel-langchain4j-chat/src/main/docs/langchain4j-chat-component.adoc
index 441f3f796f9..792d6c209ba 100644
--- 
a/components/camel-ai/camel-langchain4j-chat/src/main/docs/langchain4j-chat-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/docs/langchain4j-chat-component.adoc
@@ -143,3 +143,37 @@ messages.add(new SystemMessage("You are asked to provide 
recommendations for a r
 
 String response = template.requestBody("direct:send-multiple", messages, 
String.class);
 ----
+
+== Chat with Tool
+Camel langchain4j-chat used as a consumer can be used to implement a Tool,
+right now Tools are supported only via the OpenAiChatModel
+backed by OpenAI APIs.
+
+Tool Input parameter can be defined via parameterName and parameterType in 
case of only one parameter,
+or via the endpoint option camelToolParameter in case of multiple parameters.
+The parameters can be found as headers in the consumer route, in particular, 
if you define a `parameterName=userId`,
+in the consumer route `${header.userId}` can be used.
+
+Example of a producer and a consumer:
+[source, java]
+----
+from("direct:test")
+    .to("langchain4j-chat:test1?chatOperation=CHAT_MULTIPLE_MESSAGES");
+
+from("langchain4j-chat:test1?description=Query user database by 
number&parameterName=number&parameterType=integer")
+    .to("sql:SELECT name FROM users WHERE id = :#number");
+----
+
+Example of usage:
+[source, java]
+----
+List<ChatMessage> messages = new ArrayList<>();
+        messages.add(new SystemMessage("""
+                You provide information about specific user name querying the 
database given a number.
+                """));
+        messages.add(new UserMessage("""
+                What is the name of the user 1?
+                """));
+
+        Exchange message = 
fluentTemplate.to("direct:test").withBody(messages).request(Exchange.class);
+----
\ No newline at end of file
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatConsumer.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatConsumer.java
new file mode 100644
index 00000000000..c88c6f0d20e
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatConsumer.java
@@ -0,0 +1,28 @@
+/*
+ * 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.chat;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.support.DefaultConsumer;
+
+public class LangChain4jChatConsumer extends DefaultConsumer {
+
+    public LangChain4jChatConsumer(Endpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java
index c8324d32af5..b8598b45852 100644
--- 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatEndpoint.java
@@ -16,10 +16,18 @@
  */
 package org.apache.camel.component.langchain4j.chat;
 
+import java.util.UUID;
+
+import dev.langchain4j.agent.tool.JsonSchemaProperty;
+import dev.langchain4j.agent.tool.ToolSpecification;
 import org.apache.camel.Category;
 import org.apache.camel.Consumer;
 import org.apache.camel.Processor;
 import org.apache.camel.Producer;
+import 
org.apache.camel.component.langchain4j.chat.tool.CamelSimpleToolParameter;
+import org.apache.camel.component.langchain4j.chat.tool.CamelToolExecutorCache;
+import org.apache.camel.component.langchain4j.chat.tool.CamelToolSpecification;
+import 
org.apache.camel.component.langchain4j.chat.tool.NamedJsonSchemaProperty;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
 import org.apache.camel.spi.UriParam;
@@ -41,6 +49,22 @@ public class LangChain4jChatEndpoint extends DefaultEndpoint 
{
     @UriParam
     private LangChain4jChatConfiguration configuration;
 
+    @Metadata(label = "consumer")
+    @UriParam(description = "simple Tool description")
+    private String description;
+
+    @Metadata(label = "consumer")
+    @UriParam(description = "simple Tool paramenter name")
+    private String parameterName;
+
+    @Metadata(label = "consumer")
+    @UriParam(description = "Simple Tool parameter type", enums = 
"string,integer,number,object,array,boolean,null")
+    private String parameterType;
+
+    @Metadata(label = "consumer,advanced")
+    @UriParam(description = "Tool's Parameters, to be used in case of multiple 
arguments")
+    private CamelSimpleToolParameter camelToolParameter;
+
     public LangChain4jChatEndpoint(String uri, LangChain4jChatComponent 
component, String chatId,
                                    LangChain4jChatConfiguration configuration) 
{
         super(uri, component);
@@ -55,7 +79,33 @@ public class LangChain4jChatEndpoint extends DefaultEndpoint 
{
 
     @Override
     public Consumer createConsumer(Processor processor) throws Exception {
-        throw new UnsupportedOperationException("Cannot consume from an 
LangChain4j chat Endpoint: " + getEndpointUri());
+        ToolSpecification.Builder toolSpecificationBuilder = 
ToolSpecification.builder();
+        toolSpecificationBuilder.name(UUID.randomUUID().toString());
+        if (camelToolParameter != null) {
+            
toolSpecificationBuilder.description(camelToolParameter.getDescription());
+
+            for (NamedJsonSchemaProperty namedJsonSchemaProperty : 
camelToolParameter.getProperties()) {
+                
toolSpecificationBuilder.addParameter(namedJsonSchemaProperty.getName(),
+                        namedJsonSchemaProperty.getProperties());
+            }
+        } else if (description != null) {
+            toolSpecificationBuilder.description(description);
+
+            if (parameterName != null) {
+                toolSpecificationBuilder.addParameter(parameterName, 
JsonSchemaProperty.type(parameterType));
+            }
+        } else {
+            // Consumer without toolParameter or description
+            throw new IllegalArgumentException(
+                    "In order to use the langchain4j component as a consumer, 
you need to specify at least description, or a camelToolParameter");
+        }
+        ToolSpecification toolSpecification = toolSpecificationBuilder.build();
+
+        CamelToolSpecification camelToolSpecification
+                = new CamelToolSpecification(toolSpecification, new 
LangChain4jChatConsumer(this, processor));
+        CamelToolExecutorCache.getInstance().put(chatId, 
camelToolSpecification);
+
+        return camelToolSpecification.getConsumer();
     }
 
     /**
@@ -71,4 +121,35 @@ public class LangChain4jChatEndpoint extends 
DefaultEndpoint {
         return configuration;
     }
 
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getParameterName() {
+        return parameterName;
+    }
+
+    public void setParameterName(String parameterName) {
+        this.parameterName = parameterName;
+    }
+
+    public String getParameterType() {
+        return parameterType;
+    }
+
+    public void setParameterType(String parameterType) {
+        this.parameterType = parameterType;
+    }
+
+    public CamelSimpleToolParameter getCamelToolParameter() {
+        return camelToolParameter;
+    }
+
+    public void setCamelToolParameter(CamelSimpleToolParameter 
camelToolParameter) {
+        this.camelToolParameter = camelToolParameter;
+    }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatProducer.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatProducer.java
index 08033def4ae..f17e9530768 100644
--- 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatProducer.java
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/LangChain4jChatProducer.java
@@ -18,9 +18,15 @@ package org.apache.camel.component.langchain4j.chat;
 
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import dev.langchain4j.agent.tool.ToolExecutionRequest;
+import dev.langchain4j.agent.tool.ToolSpecification;
 import dev.langchain4j.data.message.AiMessage;
 import dev.langchain4j.data.message.ChatMessage;
+import dev.langchain4j.data.message.ToolExecutionResultMessage;
 import dev.langchain4j.model.chat.ChatLanguageModel;
 import dev.langchain4j.model.input.Prompt;
 import dev.langchain4j.model.input.PromptTemplate;
@@ -28,6 +34,8 @@ import dev.langchain4j.model.output.Response;
 import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
 import org.apache.camel.NoSuchHeaderException;
+import org.apache.camel.component.langchain4j.chat.tool.CamelToolExecutorCache;
+import org.apache.camel.component.langchain4j.chat.tool.CamelToolSpecification;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.util.ObjectHelper;
 
@@ -37,6 +45,8 @@ public class LangChain4jChatProducer extends DefaultProducer {
 
     private ChatLanguageModel chatLanguageModel;
 
+    private final ObjectMapper objectMapper = new ObjectMapper();
+
     public LangChain4jChatProducer(LangChain4jChatEndpoint endpoint) {
         super(endpoint);
         this.endpoint = endpoint;
@@ -85,7 +95,7 @@ public class LangChain4jChatProducer extends DefaultProducer {
     @SuppressWarnings("unchecked")
     private void processMultipleMessages(Exchange exchange) throws 
InvalidPayloadException {
         List<ChatMessage> messages = 
exchange.getIn().getMandatoryBody(List.class);
-        populateResponse(sendListChatMessage(messages), exchange);
+        populateResponse(sendListChatMessage(messages, exchange), exchange);
     }
 
     @Override
@@ -126,8 +136,48 @@ public class LangChain4jChatProducer extends 
DefaultProducer {
      * @param  chatMessages
      * @return
      */
-    private String sendListChatMessage(List<ChatMessage> chatMessages) {
-        Response<AiMessage> response = 
this.chatLanguageModel.generate(chatMessages);
+    private String sendListChatMessage(List<ChatMessage> chatMessages, 
Exchange exchange) {
+        LangChain4jChatEndpoint langChain4jChatEndpoint = 
(LangChain4jChatEndpoint) getEndpoint();
+
+        List<ToolSpecification> toolSpecifications = 
CamelToolExecutorCache.getInstance().getTools()
+                .get(langChain4jChatEndpoint.getChatId()).stream()
+                .map(camelToolSpecification -> 
camelToolSpecification.getToolSpecification())
+                .collect(Collectors.toList());
+
+        Response<AiMessage> response = 
this.chatLanguageModel.generate(chatMessages, toolSpecifications);
+
+        if (response.content().hasToolExecutionRequests()) {
+            chatMessages.add(response.content());
+
+            for (ToolExecutionRequest toolExecutionRequest : 
response.content().toolExecutionRequests()) {
+                String toolName = toolExecutionRequest.name();
+                CamelToolSpecification camelToolSpecification = 
CamelToolExecutorCache.getInstance().getTools()
+                        .get(langChain4jChatEndpoint.getChatId()).stream()
+                        .filter(cts -> 
cts.getToolSpecification().name().equals(toolName))
+                        .findFirst().orElseThrow(() -> new 
RuntimeException("Tool " + toolName + " not found"));
+                try {
+                    // Map Json to Header
+                    JsonNode jsonNode = 
objectMapper.readValue(toolExecutionRequest.arguments(), JsonNode.class);
+
+                    jsonNode.fieldNames()
+                            .forEachRemaining(name -> 
exchange.getMessage().setHeader(name, jsonNode.get(name)));
+
+                    // Execute the consumer route
+                    
camelToolSpecification.getConsumer().getProcessor().process(exchange);
+                } catch (Exception e) {
+                    // How to handle this exception?
+                    exchange.setException(e);
+                }
+
+                chatMessages.add(new ToolExecutionResultMessage(
+                        toolExecutionRequest.id(),
+                        toolExecutionRequest.name(),
+                        exchange.getIn().getBody(String.class)));
+            }
+
+            response = this.chatLanguageModel.generate(chatMessages);
+        }
+
         return extractAiResponse(response);
     }
 
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelSimpleToolParameter.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelSimpleToolParameter.java
new file mode 100644
index 00000000000..0751c15240d
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelSimpleToolParameter.java
@@ -0,0 +1,42 @@
+/*
+ * 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.chat.tool;
+
+import java.util.List;
+
+/**
+ * langchain4j Simple Tool parameter implementation, this class can be used to 
provide multiple properties/input
+ * parameters to the tool itself, the NamedJsonSchemaProperty can be then 
found as headers into the consumer route
+ */
+public class CamelSimpleToolParameter {
+
+    private final String description;
+    private final List<NamedJsonSchemaProperty> properties;
+
+    public CamelSimpleToolParameter(String description, 
List<NamedJsonSchemaProperty> properties) {
+        this.description = description;
+        this.properties = properties;
+    }
+
+    public List<NamedJsonSchemaProperty> getProperties() {
+        return properties;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolExecutorCache.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolExecutorCache.java
new file mode 100644
index 00000000000..20c139cb5d2
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolExecutorCache.java
@@ -0,0 +1,59 @@
+/*
+ * 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.chat.tool;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Caches Tools Specification and Consumer route reference by the chatId, so 
that different chats can have different
+ * Tool implementation
+ */
+public final class CamelToolExecutorCache {
+
+    private static CamelToolExecutorCache INSTANCE;
+    private Map<String, List<CamelToolSpecification>> tools;
+
+    private CamelToolExecutorCache() {
+        tools = new ConcurrentHashMap<>();
+    }
+
+    public synchronized static CamelToolExecutorCache getInstance() {
+        if (INSTANCE == null) {
+            INSTANCE = new CamelToolExecutorCache();
+        }
+
+        return INSTANCE;
+    }
+
+    public void put(String chatId, CamelToolSpecification specification) {
+        if (tools.get(chatId) != null) {
+            tools.get(chatId).add(specification);
+        } else {
+            List<CamelToolSpecification> camelToolSpecifications = new 
ArrayList<>();
+            camelToolSpecifications.add(specification);
+            tools.put(chatId, camelToolSpecifications);
+        }
+    }
+
+    public Map<String, List<CamelToolSpecification>> getTools() {
+        return tools;
+    }
+
+}
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolSpecification.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolSpecification.java
new file mode 100644
index 00000000000..9b2d402916d
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/CamelToolSpecification.java
@@ -0,0 +1,51 @@
+/*
+ * 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.chat.tool;
+
+import dev.langchain4j.agent.tool.ToolSpecification;
+import org.apache.camel.component.langchain4j.chat.LangChain4jChatConsumer;
+
+/**
+ * Holds ToolSpecification needed by langchain4j and the associated Camel 
Consumer. In this way, a specific route can be
+ * invoked by a specific Tool
+ */
+public class CamelToolSpecification {
+
+    private ToolSpecification toolSpecification;
+    private LangChain4jChatConsumer consumer;
+
+    public CamelToolSpecification(ToolSpecification toolSpecification, 
LangChain4jChatConsumer consumer) {
+        this.toolSpecification = toolSpecification;
+        this.consumer = consumer;
+    }
+
+    public ToolSpecification getToolSpecification() {
+        return toolSpecification;
+    }
+
+    public void setToolSpecification(ToolSpecification toolSpecification) {
+        this.toolSpecification = toolSpecification;
+    }
+
+    public LangChain4jChatConsumer getConsumer() {
+        return consumer;
+    }
+
+    public void setConsumer(LangChain4jChatConsumer consumer) {
+        this.consumer = consumer;
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/NamedJsonSchemaProperty.java
 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/NamedJsonSchemaProperty.java
new file mode 100644
index 00000000000..d187c780696
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/main/java/org/apache/camel/component/langchain4j/chat/tool/NamedJsonSchemaProperty.java
@@ -0,0 +1,40 @@
+/*
+ * 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.chat.tool;
+
+import java.util.List;
+
+import dev.langchain4j.agent.tool.JsonSchemaProperty;
+
+public class NamedJsonSchemaProperty {
+
+    private final String name;
+    private final List<JsonSchemaProperty> properties;
+
+    public NamedJsonSchemaProperty(String name, List<JsonSchemaProperty> 
properties) {
+        this.name = name;
+        this.properties = properties;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public List<JsonSchemaProperty> getProperties() {
+        return properties;
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-chat/src/test/java/org/apache/camel/component/langchain4j.chat/LangChain4jConsumerIT.java
 
b/components/camel-ai/camel-langchain4j-chat/src/test/java/org/apache/camel/component/langchain4j.chat/LangChain4jConsumerIT.java
new file mode 100644
index 00000000000..de4018ce1a3
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-chat/src/test/java/org/apache/camel/component/langchain4j.chat/LangChain4jConsumerIT.java
@@ -0,0 +1,93 @@
+/*
+ * 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.chat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import dev.langchain4j.agent.tool.JsonSchemaProperty;
+import dev.langchain4j.data.message.ChatMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import 
org.apache.camel.component.langchain4j.chat.tool.CamelSimpleToolParameter;
+import 
org.apache.camel.component.langchain4j.chat.tool.NamedJsonSchemaProperty;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
+@EnabledIfEnvironmentVariable(named = "OPENAI_API_KEY", matches = ".*")
+public class LangChain4jConsumerIT extends CamelTestSupport {
+
+    private final String nameFromDB = "pippo";
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+
+        LangChain4jChatComponent component
+                = context.getComponent(LangChain4jChat.SCHEME, 
LangChain4jChatComponent.class);
+
+        component.getConfiguration().setChatModel(
+                OpenAiChatModel.withApiKey(System.getenv("OPENAI_API_KEY")));
+
+        return context;
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() {
+        return new RouteBuilder() {
+            public void configure() {
+
+                NamedJsonSchemaProperty namedJsonSchemaProperty
+                        = new NamedJsonSchemaProperty("name", 
List.of(JsonSchemaProperty.STRING));
+                CamelSimpleToolParameter camelToolParameter = new 
CamelSimpleToolParameter(
+                        "This is a tool description",
+                        List.of(namedJsonSchemaProperty));
+                context().getRegistry().bind("parameters", camelToolParameter);
+
+                from("direct:test")
+                        
.to("langchain4j-chat:test1?chatOperation=CHAT_MULTIPLE_MESSAGES");
+
+                from("langchain4j-chat:test1?description=Query user database 
by number&parameterName=number&parameterType=integer")
+                        .process(exchange -> 
exchange.getIn().setBody(nameFromDB));
+
+                from("langchain4j-chat:test1?camelToolParameter=#parameters")
+                        .setBody(constant("Hello World"));
+            }
+        };
+    }
+
+    @Test
+    public void testSimpleInvocation() {
+        List<ChatMessage> messages = new ArrayList<>();
+        messages.add(new SystemMessage("""
+                You provide information about specific user name querying the 
database given a number.
+                """));
+        messages.add(new UserMessage("""
+                What is the name of the user 1?
+                """));
+
+        Exchange message = 
fluentTemplate.to("direct:test").withBody(messages).request(Exchange.class);
+
+        
Assertions.assertTrue(message.getMessage().getBody().toString().contains(nameFromDB));
+    }
+}

Reply via email to