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 a58804f5c116 CAMEL-23074 - camel-langchain4j-tools: Add tool parameter 
metadata support (required, enum)
a58804f5c116 is described below

commit a58804f5c116ba8b962e147c3561cf58dc914f57
Author: Croway <[email protected]>
AuthorDate: Wed Feb 25 10:47:37 2026 +0100

    CAMEL-23074 - camel-langchain4j-tools: Add tool parameter metadata support 
(required, enum)
---
 .../catalog/components/langchain4j-tools.json      |   2 +-
 .../langchain4j/tools/langchain4j-tools.json       |   2 +-
 .../src/main/docs/langchain4j-tools-component.adoc |  41 ++
 .../tools/LangChain4jToolsEndpoint.java            | 146 ++++++-
 .../tools/spec/CamelSimpleToolParameter.java       |  33 ++
 .../LangChain4jToolRequiredParameterTest.java      | 426 +++++++++++++++++++++
 .../LangChain4jToolsEndpointBuilderFactory.java    |  18 +-
 7 files changed, 647 insertions(+), 21 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
index 3180eaf555e9..34b31f066148 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/langchain4j-tools.json
@@ -36,7 +36,7 @@
     "description": { "index": 2, "kind": "parameter", "displayName": 
"Description", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Tool description" },
     "exposed": { "index": 3, "kind": "parameter", "displayName": "Exposed", 
"group": "consumer", "label": "consumer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether the tool 
is automatically exposed to the LLM. When false, the tool is added to a 
searchable list and can be discovered via the tool-search-tool" },
     "name": { "index": 4, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
-    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
+    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters with optional metadata. Format: 
parameter.=, parameter..description=, parameter..required=, parameter [...]
     "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "camelToolParameter": { "index": 7, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
     "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
 
b/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
index 3180eaf555e9..34b31f066148 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/generated/resources/META-INF/org/apache/camel/component/langchain4j/tools/langchain4j-tools.json
@@ -36,7 +36,7 @@
     "description": { "index": 2, "kind": "parameter", "displayName": 
"Description", "group": "consumer", "label": "consumer", "required": false, 
"type": "string", "javaType": "java.lang.String", "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, "description": 
"Tool description" },
     "exposed": { "index": 3, "kind": "parameter", "displayName": "Exposed", 
"group": "consumer", "label": "consumer", "required": false, "type": "boolean", 
"javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "defaultValue": true, "description": "Whether the tool 
is automatically exposed to the LLM. When false, the tool is added to a 
searchable list and can be discovered via the tool-search-tool" },
     "name": { "index": 4, "kind": "parameter", "displayName": "Name", "group": 
"consumer", "label": "consumer", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "description": "Tool name" },
-    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters in the form of parameter.=. This is a 
multi-value option with prefix: parameter." },
+    "parameters": { "index": 5, "kind": "parameter", "displayName": 
"Parameters", "group": "consumer", "label": "consumer", "required": false, 
"type": "object", "javaType": "java.util.Map<java.lang.String, 
java.lang.String>", "prefix": "parameter.", "multiValue": true, "deprecated": 
false, "deprecationNote": "", "autowired": false, "secret": false, 
"description": "List of Tool parameters with optional metadata. Format: 
parameter.=, parameter..description=, parameter..required=, parameter [...]
     "bridgeErrorHandler": { "index": 6, "kind": "parameter", "displayName": 
"Bridge Error Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "boolean", "javaType": 
"boolean", "deprecated": false, "autowired": false, "secret": false, 
"defaultValue": false, "description": "Allows for bridging the consumer to the 
Camel routing Error Handler, which mean any exceptions (if possible) occurred 
while the Camel consumer is trying to pickup incoming  [...]
     "camelToolParameter": { "index": 7, "kind": "parameter", "displayName": 
"Camel Tool Parameter", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter", 
"deprecated": false, "deprecationNote": "", "autowired": false, "secret": 
false, "description": "Tool's Camel Parameters, programmatically define Tool 
description and parameters" },
     "exceptionHandler": { "index": 8, "kind": "parameter", "displayName": 
"Exception Handler", "group": "consumer (advanced)", "label": 
"consumer,advanced", "required": false, "type": "object", "javaType": 
"org.apache.camel.spi.ExceptionHandler", "optionalPrefix": "consumer.", 
"deprecated": false, "autowired": false, "secret": false, "description": "To 
let the consumer use a custom ExceptionHandler. Notice if the option 
bridgeErrorHandler is enabled then this option is not in use. By def [...]
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
 
b/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
index 093e376d1edc..cfe27505d5a2 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/docs/langchain4j-tools-component.adoc
@@ -103,6 +103,13 @@ or via the endpoint option `camelToolParameter` for a 
programmatic approach.
 The parameters can be found as headers in the consumer route, in particular, 
if you define `parameter.userId=5`,
 in the consumer route `${header.userId}` can be used.
 
+Parameters support optional metadata:
+
+* `parameter.<name>=<type>` — defines the parameter type (`string`, `integer`, 
`number`, `boolean`)
+* `parameter.<name>.description=<text>` — defines a description passed to the 
LLM
+* `parameter.<name>.required=<true|false>` — marks the parameter as required 
(default: `false`)
+* `parameter.<name>.enum=<value1,value2>` — restricts the parameter to a set 
of allowed values (comma-separated)
+
 .Producer and consumer example:
 [source, java]
 ----
@@ -113,6 +120,40 @@ from("langchain4j-tools:test1?tags=users&description=Query 
user database by user
     .to("sql:SELECT name FROM users WHERE id = :#userId");
 ----
 
+.Example with required parameters and descriptions:
+[source, java]
+----
+from("langchain4j-tools:weather?tags=weather&description=Get weather forecast"
+    + "&parameter.location=string"
+    + "&parameter.location.description=The city and state"
+    + "&parameter.location.required=true"
+    + "&parameter.unit=string"
+    + "&parameter.unit.description=Temperature unit"
+    + "&parameter.unit.enum=celsius,fahrenheit")
+    .process(exchange -> {
+        String location = exchange.getIn().getHeader("location", String.class);
+        // ...
+    });
+----
+
+When using the programmatic `CamelSimpleToolParameter` approach, required 
parameters can be specified as a list of parameter names.
+The full constructor also accepts `additionalProperties` (to restrict extra 
fields) and `definitions` (for recursive schemas using `JsonReferenceSchema`):
+
+[source, java]
+----
+CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
+    "Get weather forecast",
+    List.of(
+        new NamedJsonSchemaProperty("location",
+            JsonStringSchema.builder().description("The city and 
state").build()),
+        new NamedJsonSchemaProperty("unit",
+            JsonEnumSchema.builder().enumValues("celsius", "fahrenheit")
+                .description("Temperature unit").build())),
+    List.of("location"),  // required parameter names
+    false,                // additionalProperties
+    null);                // definitions (for recursive schemas)
+----
+
 .Usage example:
 [source, java]
 ----
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
index 3ab33610503a..e2e4cbd68146 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolsEndpoint.java
@@ -16,11 +16,14 @@
  */
 package org.apache.camel.component.langchain4j.tools;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 import dev.langchain4j.agent.tool.ToolSpecification;
 import dev.langchain4j.model.chat.request.json.JsonBooleanSchema;
+import dev.langchain4j.model.chat.request.json.JsonEnumSchema;
 import dev.langchain4j.model.chat.request.json.JsonIntegerSchema;
 import dev.langchain4j.model.chat.request.json.JsonNumberSchema;
 import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
@@ -73,8 +76,12 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
     private String name;
 
     @Metadata(label = "consumer")
-    @UriParam(description = "List of Tool parameters in the form of 
parameter.<name>=<type>", prefix = "parameter.",
-              multiValue = true)
+    @UriParam(description = "List of Tool parameters with optional metadata. "
+                            + "Format: parameter.<name>=<type>, 
parameter.<name>.description=<text>, "
+                            + "parameter.<name>.required=<true|false>, 
parameter.<name>.enum=<value1,value2>. "
+                            + "Example: parameter.location=string, 
parameter.location.description=The city and state, "
+                            + "parameter.location.required=true, 
parameter.unit.enum=celsius,fahrenheit",
+              prefix = "parameter.", multiValue = true)
     private Map<String, String> parameters;
 
     @Metadata(label = "consumer,advanced")
@@ -119,18 +126,25 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
                         namedProperty.getProperties());
             }
 
+            if (camelToolParameter.getRequired() != null && 
!camelToolParameter.getRequired().isEmpty()) {
+                parametersBuilder.required(camelToolParameter.getRequired());
+            }
+
+            if (camelToolParameter.getAdditionalProperties() != null) {
+                
parametersBuilder.additionalProperties(camelToolParameter.getAdditionalProperties());
+            }
+
+            if (camelToolParameter.getDefinitions() != null && 
!camelToolParameter.getDefinitions().isEmpty()) {
+                
parametersBuilder.definitions(camelToolParameter.getDefinitions());
+            }
+
             toolSpecificationBuilder.parameters(parametersBuilder.build());
 
         } else if (description != null) {
             toolSpecificationBuilder.description(description);
 
             if (parameters != null) {
-
-                JsonObjectSchema.Builder parametersBuilder = 
JsonObjectSchema.builder();
-
-                parameters.forEach((name, type) -> 
parametersBuilder.addProperty(name, createJsonSchema(type)));
-
-                toolSpecificationBuilder.parameters(parametersBuilder.build());
+                
toolSpecificationBuilder.parameters(buildParameterSchema(parameters));
             }
         } else {
             // Consumer without toolParameter or description
@@ -287,19 +301,121 @@ public class LangChain4jToolsEndpoint extends 
DefaultEndpoint {
     }
 
     /**
-     * Creates a JsonScheùaElement based on a String type
+     * Builds a {@link JsonObjectSchema} from the flat parameter map by 
parsing parameter metadata and constructing the
+     * appropriate schema elements.
+     *
+     * @param  parameters the flat parameter map
+     * @return            the built JsonObjectSchema
+     */
+    private JsonObjectSchema buildParameterSchema(Map<String, String> 
parameters) {
+        Map<String, ParameterMetadata> paramMetadata = 
parseParameterMetadata(parameters);
+
+        JsonObjectSchema.Builder builder = JsonObjectSchema.builder();
+        List<String> requiredParams = new ArrayList<>();
+
+        for (Map.Entry<String, ParameterMetadata> entry : 
paramMetadata.entrySet()) {
+            String paramName = entry.getKey();
+            ParameterMetadata metadata = entry.getValue();
+
+            JsonSchemaElement schema;
+            if (metadata.enumValues != null && !metadata.enumValues.isEmpty()) 
{
+                schema = JsonEnumSchema.builder()
+                        .enumValues(metadata.enumValues)
+                        .description(metadata.description)
+                        .build();
+            } else {
+                schema = createJsonSchema(metadata.type, metadata.description);
+            }
+
+            builder.addProperty(paramName, schema);
+
+            if (metadata.required) {
+                requiredParams.add(paramName);
+            }
+        }
+
+        if (!requiredParams.isEmpty()) {
+            builder.required(requiredParams);
+        }
+
+        return builder.build();
+    }
+
+    /**
+     * Creates a JsonSchemaElement based on a String type with an optional 
description.
      *
      * @param  type
+     * @param  description optional description, may be null
      * @return
      */
-    private JsonSchemaElement createJsonSchema(String type) {
+    private JsonSchemaElement createJsonSchema(String type, String 
description) {
         return switch (type.toLowerCase()) {
-            case "string" -> JsonStringSchema.builder().build();
-            case "integer" -> JsonIntegerSchema.builder().build();
-            case "number" -> JsonNumberSchema.builder().build();
-            case "boolean" -> JsonBooleanSchema.builder().build();
-            default -> JsonStringSchema.builder().build(); // fallback for 
unkown types
+            case "string" -> 
JsonStringSchema.builder().description(description).build();
+            case "integer" -> 
JsonIntegerSchema.builder().description(description).build();
+            case "number" -> 
JsonNumberSchema.builder().description(description).build();
+            case "boolean" -> 
JsonBooleanSchema.builder().description(description).build();
+            default -> 
JsonStringSchema.builder().description(description).build(); // fallback for 
unknown types
         };
     }
 
+    /**
+     * Parses the flat parameter map into structured metadata.
+     * <p>
+     * Handles parameter configurations like:
+     * <ul>
+     * <li>parameter.location=string</li>
+     * <li>parameter.location.description=The city and state</li>
+     * <li>parameter.location.required=true</li>
+     * <li>parameter.unit.enum=celsius,fahrenheit</li>
+     * </ul>
+     *
+     * @param  parameters the flat parameter map
+     * @return            map of parameter names to their metadata
+     */
+    private Map<String, ParameterMetadata> parseParameterMetadata(Map<String, 
String> parameters) {
+        Map<String, ParameterMetadata> metadata = new HashMap<>();
+
+        for (Map.Entry<String, String> entry : parameters.entrySet()) {
+            String key = entry.getKey();
+            String value = entry.getValue();
+
+            if (key.contains(".")) {
+                String[] parts = key.split("\\.", 2);
+                String paramName = parts[0];
+                String propertyName = parts[1];
+
+                ParameterMetadata meta = metadata.computeIfAbsent(paramName, k 
-> new ParameterMetadata());
+
+                switch (propertyName) {
+                    case "description":
+                        meta.description = value;
+                        break;
+                    case "required":
+                        meta.required = Boolean.parseBoolean(value);
+                        break;
+                    case "enum":
+                        meta.enumValues = List.of(value.split(","));
+                        break;
+                    default:
+                        break;
+                }
+            } else {
+                ParameterMetadata meta = metadata.computeIfAbsent(key, k -> 
new ParameterMetadata());
+                meta.type = value;
+            }
+        }
+
+        return metadata;
+    }
+
+    /**
+     * Internal class to hold parameter metadata.
+     */
+    private static class ParameterMetadata {
+        String type = "string";
+        String description;
+        boolean required = false;
+        List<String> enumValues;
+    }
+
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelSimpleToolParameter.java
 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelSimpleToolParameter.java
index 074b774e0b95..c54ee45394ec 100644
--- 
a/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelSimpleToolParameter.java
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/main/java/org/apache/camel/component/langchain4j/tools/spec/CamelSimpleToolParameter.java
@@ -16,7 +16,11 @@
  */
 package org.apache.camel.component.langchain4j.tools.spec;
 
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+
+import dev.langchain4j.model.chat.request.json.JsonSchemaElement;
 
 /**
  * langchain4j Simple Tool parameter implementation, this class can be used to 
provide multiple properties/input
@@ -26,10 +30,27 @@ public class CamelSimpleToolParameter {
 
     private final String description;
     private final List<NamedJsonSchemaProperty> properties;
+    private final List<String> required;
+    private final Boolean additionalProperties;
+    private final Map<String, JsonSchemaElement> definitions;
 
     public CamelSimpleToolParameter(String description, 
List<NamedJsonSchemaProperty> properties) {
+        this(description, properties, Collections.emptyList());
+    }
+
+    public CamelSimpleToolParameter(String description, 
List<NamedJsonSchemaProperty> properties,
+                                    List<String> required) {
+        this(description, properties, required, null, null);
+    }
+
+    public CamelSimpleToolParameter(String description, 
List<NamedJsonSchemaProperty> properties,
+                                    List<String> required, Boolean 
additionalProperties,
+                                    Map<String, JsonSchemaElement> 
definitions) {
         this.description = description;
         this.properties = properties;
+        this.required = required;
+        this.additionalProperties = additionalProperties;
+        this.definitions = definitions;
     }
 
     public List<NamedJsonSchemaProperty> getProperties() {
@@ -39,4 +60,16 @@ public class CamelSimpleToolParameter {
     public String getDescription() {
         return description;
     }
+
+    public List<String> getRequired() {
+        return required;
+    }
+
+    public Boolean getAdditionalProperties() {
+        return additionalProperties;
+    }
+
+    public Map<String, JsonSchemaElement> getDefinitions() {
+        return definitions;
+    }
 }
diff --git 
a/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolRequiredParameterTest.java
 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolRequiredParameterTest.java
new file mode 100644
index 000000000000..d2abdb1a5d8a
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-tools/src/test/java/org/apache/camel/component/langchain4j/tools/LangChain4jToolRequiredParameterTest.java
@@ -0,0 +1,426 @@
+/*
+ * 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.tools;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import dev.langchain4j.model.chat.request.json.JsonEnumSchema;
+import dev.langchain4j.model.chat.request.json.JsonIntegerSchema;
+import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
+import dev.langchain4j.model.chat.request.json.JsonReferenceSchema;
+import dev.langchain4j.model.chat.request.json.JsonSchemaElement;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import org.apache.camel.Consumer;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelSimpleToolParameter;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolExecutorCache;
+import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolSpecification;
+import 
org.apache.camel.component.langchain4j.tools.spec.NamedJsonSchemaProperty;
+import org.apache.camel.test.junit6.CamelTestSupport;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class LangChain4jToolRequiredParameterTest extends CamelTestSupport {
+
+    @AfterEach
+    void clearCache() {
+        CamelToolExecutorCache.getInstance().getTools().clear();
+    }
+
+    @Test
+    public void testUriParameterWithRequired() throws Exception {
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("location", "string");
+        parameters.put("location.description", "The city and state");
+        parameters.put("location.required", "true");
+        parameters.put("unit", "string");
+        parameters.put("unit.required", "false");
+        parameters.put("count", "integer");
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setParameters(parameters);
+        endpoint.setDescription("Test tool with required params");
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        // Retrieve the tool specification from the cache
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+        assertEquals(1, tools.size());
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        // Verify properties exist
+        assertNotNull(schema.properties().get("location"));
+        assertNotNull(schema.properties().get("unit"));
+        assertNotNull(schema.properties().get("count"));
+
+        // Verify required list contains only "location"
+        assertNotNull(schema.required());
+        assertEquals(1, schema.required().size());
+        assertTrue(schema.required().contains("location"));
+
+        // Verify description is set on location
+        assertEquals("The city and state", 
schema.properties().get("location").description());
+    }
+
+    @Test
+    public void testUriParameterWithNoRequired() throws Exception {
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("name", "string");
+        parameters.put("age", "integer");
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setParameters(parameters);
+        endpoint.setDescription("Test tool without required params");
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+        assertNotNull(schema.properties().get("name"));
+        assertNotNull(schema.properties().get("age"));
+
+        // No required parameters should be set
+        assertTrue(schema.required() == null || schema.required().isEmpty());
+    }
+
+    @Test
+    public void testProgrammaticWithRequired() throws Exception {
+        CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
+                "Query user by location and name",
+                List.of(
+                        new NamedJsonSchemaProperty(
+                                "location",
+                                JsonStringSchema.builder().description("The 
city").build()),
+                        new NamedJsonSchemaProperty(
+                                "name",
+                                JsonStringSchema.builder().build()),
+                        new NamedJsonSchemaProperty(
+                                "age",
+                                JsonIntegerSchema.builder().build())),
+                List.of("location", "name"));
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setCamelToolParameter(toolParameter);
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        // Verify required list
+        assertNotNull(schema.required());
+        assertEquals(2, schema.required().size());
+        assertTrue(schema.required().contains("location"));
+        assertTrue(schema.required().contains("name"));
+
+        // Verify description is preserved
+        assertEquals("The city", 
schema.properties().get("location").description());
+    }
+
+    @Test
+    public void testProgrammaticWithoutRequired() throws Exception {
+        CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
+                "Simple tool",
+                List.of(
+                        new NamedJsonSchemaProperty("name", 
JsonStringSchema.builder().build())));
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setCamelToolParameter(toolParameter);
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        // No required parameters
+        assertTrue(schema.required() == null || schema.required().isEmpty());
+    }
+
+    @Test
+    public void testUriParameterWithDescription() throws Exception {
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("city", "string");
+        parameters.put("city.description", "The name of the city");
+        parameters.put("temperature", "number");
+        parameters.put("temperature.description", "Temperature threshold");
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setParameters(parameters);
+        endpoint.setDescription("Weather tool");
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        assertEquals("The name of the city", 
schema.properties().get("city").description());
+        assertEquals("Temperature threshold", 
schema.properties().get("temperature").description());
+    }
+
+    @Test
+    public void testUriParameterWithEnum() throws Exception {
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("unit", "string");
+        parameters.put("unit.enum", "celsius,fahrenheit");
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setParameters(parameters);
+        endpoint.setDescription("Tool with enum param");
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        // Verify the parameter is a JsonEnumSchema
+        assertTrue(schema.properties().get("unit") instanceof JsonEnumSchema);
+        JsonEnumSchema enumSchema = (JsonEnumSchema) 
schema.properties().get("unit");
+        assertEquals(2, enumSchema.enumValues().size());
+        assertTrue(enumSchema.enumValues().contains("celsius"));
+        assertTrue(enumSchema.enumValues().contains("fahrenheit"));
+    }
+
+    @Test
+    public void testUriParameterWithEnumAndDescription() throws Exception {
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("unit", "string");
+        parameters.put("unit.enum", "C,F");
+        parameters.put("unit.description", "Temperature unit");
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setParameters(parameters);
+        endpoint.setDescription("Tool with enum and description");
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        assertTrue(schema.properties().get("unit") instanceof JsonEnumSchema);
+        JsonEnumSchema enumSchema = (JsonEnumSchema) 
schema.properties().get("unit");
+        assertEquals(2, enumSchema.enumValues().size());
+        assertTrue(enumSchema.enumValues().contains("C"));
+        assertTrue(enumSchema.enumValues().contains("F"));
+        assertEquals("Temperature unit", enumSchema.description());
+    }
+
+    @Test
+    public void testProgrammaticWithAdditionalProperties() throws Exception {
+        CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
+                "Strict tool",
+                List.of(
+                        new NamedJsonSchemaProperty("name", 
JsonStringSchema.builder().build())),
+                List.of("name"),
+                false,
+                null);
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setCamelToolParameter(toolParameter);
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+        assertEquals(false, schema.additionalProperties());
+    }
+
+    @Test
+    public void testProgrammaticWithDefinitions() throws Exception {
+        // Create a recursive schema: a "node" with a name and optional 
children (list of node references)
+        Map<String, JsonSchemaElement> definitions = Map.of(
+                "node", JsonObjectSchema.builder()
+                        .addStringProperty("name")
+                        .addProperty("parent", 
JsonReferenceSchema.builder().reference("node").build())
+                        .build());
+
+        CamelSimpleToolParameter toolParameter = new CamelSimpleToolParameter(
+                "Tool with recursive schema",
+                List.of(
+                        new NamedJsonSchemaProperty(
+                                "root",
+                                
JsonReferenceSchema.builder().reference("node").build())),
+                List.of("root"),
+                null,
+                definitions);
+
+        LangChain4jToolsComponent component
+                = context.getComponent(LangChain4jTools.SCHEME, 
LangChain4jToolsComponent.class);
+
+        LangChain4jToolsEndpoint endpoint = new LangChain4jToolsEndpoint(
+                "langchain4j-tools:test",
+                component,
+                "test-tool",
+                "test-tag",
+                new LangChain4jToolsConfiguration());
+
+        endpoint.setCamelContext(context);
+        endpoint.setCamelToolParameter(toolParameter);
+
+        Consumer consumer = endpoint.createConsumer(exchange -> {
+        });
+
+        assertNotNull(consumer);
+
+        Set<CamelToolSpecification> tools = 
CamelToolExecutorCache.getInstance().getTools().get("test-tag");
+        assertNotNull(tools);
+
+        JsonObjectSchema schema = (JsonObjectSchema) 
tools.iterator().next().getToolSpecification().parameters();
+        assertNotNull(schema);
+
+        // Verify definitions are set
+        assertNotNull(schema.definitions());
+        assertEquals(1, schema.definitions().size());
+        assertTrue(schema.definitions().containsKey("node"));
+
+        // Verify the root property is a reference
+        assertTrue(schema.properties().get("root") instanceof 
JsonReferenceSchema);
+    }
+}
diff --git 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
index b3ef3d1f00c3..969d5c8d49bd 100644
--- 
a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
+++ 
b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/LangChain4jToolsEndpointBuilderFactory.java
@@ -121,8 +121,13 @@ public interface LangChain4jToolsEndpointBuilderFactory {
             return this;
         }
         /**
-         * List of Tool parameters in the form of parameter.=. This is a
-         * multi-value option with prefix: parameter.
+         * List of Tool parameters with optional metadata. Format: parameter.=,
+         * parameter..description=, parameter..required=, parameter..enum=.
+         * Example: parameter.location=string,
+         * parameter.location.description=The city and state,
+         * parameter.location.required=true,
+         * parameter.unit.enum=celsius,fahrenheit. This is a multi-value option
+         * with prefix: parameter.
          * 
          * The option is a: <code>java.util.Map&lt;java.lang.String,
          * java.lang.String&gt;</code> type.
@@ -141,8 +146,13 @@ public interface LangChain4jToolsEndpointBuilderFactory {
             return this;
         }
         /**
-         * List of Tool parameters in the form of parameter.=. This is a
-         * multi-value option with prefix: parameter.
+         * List of Tool parameters with optional metadata. Format: parameter.=,
+         * parameter..description=, parameter..required=, parameter..enum=.
+         * Example: parameter.location=string,
+         * parameter.location.description=The city and state,
+         * parameter.location.required=true,
+         * parameter.unit.enum=celsius,fahrenheit. This is a multi-value option
+         * with prefix: parameter.
          * 
          * The option is a: <code>java.util.Map&lt;java.lang.String,
          * java.lang.String&gt;</code> type.


Reply via email to