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

davsclaus 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 bfd60dfb361e CAMEL-23382: Wire camel-langchain4j-agent to 
camel-ai-tool registry
bfd60dfb361e is described below

commit bfd60dfb361e9af01f66dd7a5ce5280c35b41755
Author: Zineb BENDHIBA <[email protected]>
AuthorDate: Wed Jul 22 09:48:03 2026 +0200

    CAMEL-23382: Wire camel-langchain4j-agent to camel-ai-tool registry
    
    Migrate camel-langchain4j-agent producer from camel-langchain4j-tools
    (CamelToolExecutorCache) to the unified camel-ai-tool module
    (AiToolRegistry). Adds AiToolSpecToLangChain4j bridge adapter with
    locale-safe type mapping, improved error handling that returns
    descriptive messages to the LLM on malformed JSON args, and per-exchange
    tag-based tool discovery with deduplication. Includes 9 unit tests for
    the adapter and migrated integration tests.
    
    Closes #24988
    
    Co-authored-by: Claude Opus 4.6 <[email protected]>
---
 .../camel-ai/camel-langchain4j-agent/pom.xml       |   8 +-
 .../src/main/docs/langchain4j-agent-component.adoc |  28 +--
 .../langchain4j/agent/AiToolSpecToLangChain4j.java |  87 ++++++++++
 .../agent/LangChain4jAgentProducer.java            | 189 ++++++++++-----------
 .../agent/AiToolSpecToLangChain4jTest.java         | 171 +++++++++++++++++++
 .../LangChain4jAgentWithMemoryServiceTest.java     |  12 +-
 .../LangChain4jAgentMcpAndCamelToolsIT.java        |  48 ++----
 .../integration/LangChain4jAgentMixedToolsIT.java  |   4 +-
 .../integration/LangChain4jAgentServiceIT.java     |   4 +-
 .../LangChain4jAgentWithMemoryServiceIT.java       |   6 +-
 .../integration/LangChain4jAgentWithToolsIT.java   |   8 +-
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    |  37 ++++
 12 files changed, 442 insertions(+), 160 deletions(-)

diff --git a/components/camel-ai/camel-langchain4j-agent/pom.xml 
b/components/camel-ai/camel-langchain4j-agent/pom.xml
index 2cd20d681583..336db48bdf67 100644
--- a/components/camel-ai/camel-langchain4j-agent/pom.xml
+++ b/components/camel-ai/camel-langchain4j-agent/pom.xml
@@ -67,11 +67,15 @@
     </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
-      <artifactId>camel-langchain4j-tools</artifactId>
+      <artifactId>camel-ai-tool</artifactId>
       <version>${project.version}</version>
     </dependency>
-
     <!-- for testing -->
+    <dependency>
+      <groupId>org.apache.camel</groupId>
+      <artifactId>camel-jackson</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.apache.camel</groupId>
       <artifactId>camel-test-spring-junit6</artifactId>
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
 
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
index af39c1b8079e..143a168fd3d4 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/docs/langchain4j-agent-component.adoc
@@ -21,7 +21,7 @@ The LangChain4j Agent component provides comprehensive AI 
agent capabilities by
 The LangChain4j Agent component offers the following key features:
 
 * **Agent-Based Architecture**: Flexible agent creation using the `Agent` API 
interface
-* **Tool Integration**: Seamless integration with Camel routes via the 
`langchain4j-tools` component
+* **Tool Integration**: Seamless integration with Camel routes via the 
`ai-tool` component
 * **MCP Tools**: Integration with Model Context Protocol (MCP) tools for 
external system access
 * **Conversation Memory**: Persistent chat memory for maintaining conversation 
context
 * **RAG Support**: Integration with retrieval systems for naive and advanced 
RAG
@@ -502,7 +502,7 @@ String response = template.requestBody("direct:chat", body, 
String.class);
 
 === Chat with Tools
 
-Integrate with Camel routes as tools. The LangChain4j Agent component 
integrates with Camel Routes defined using the Camel LangChain4j Tools 
component via the `tags` parameter.
+Integrate with Camel routes as tools. The LangChain4j Agent component 
integrates with Camel Routes defined using the `ai-tool` component via the 
`tags` parameter.
 
 [tabs]
 ====
@@ -511,10 +511,10 @@ Java::
 [source,java]
 ----
 // Define tool routes
-from("langchain4j-tools:userDb?tags=users&description=Query user 
database&parameter.userId=string")
+from("ai-tool:userDb?tags=users&description=Query user 
database&parameter.userId=string")
     .setBody(constant("{\"name\": \"John Doe\", \"id\": \"123\"}"));
 
-from("langchain4j-tools:weather?tags=weather&description=Get weather 
information&parameter.city=string")
+from("ai-tool:weather?tags=weather&description=Get weather 
information&parameter.city=string")
     .setBody(constant("{\"weather\": \"sunny\", \"temperature\": \"22°C\"}"));
 
 // Agent with tools (using the created agent)
@@ -528,14 +528,14 @@ XML::
 ----
 <!-- Define tool routes -->
 <route>
-  <from uri="langchain4j-tools:userDb?tags=users&amp;description=Query user 
database&amp;parameter.userId=string"/>
+  <from uri="ai-tool:userDb?tags=users&amp;description=Query user 
database&amp;parameter.userId=string"/>
   <setBody>
     <constant>{"name": "John Doe", "id": "123"}</constant>
   </setBody>
 </route>
 
 <route>
-  <from uri="langchain4j-tools:weather?tags=weather&amp;description=Get 
weather information&amp;parameter.city=string"/>
+  <from uri="ai-tool:weather?tags=weather&amp;description=Get weather 
information&amp;parameter.city=string"/>
   <setBody>
     <constant>{"weather": "sunny", "temperature": "22°C"}</constant>
   </setBody>
@@ -555,7 +555,7 @@ YAML::
 # Define tool routes
 - route:
     from:
-      uri: langchain4j-tools:userDb
+      uri: ai-tool:userDb
       parameters:
         tags: users
         description: Query user database
@@ -566,7 +566,7 @@ YAML::
 
 - route:
     from:
-      uri: langchain4j-tools:weather
+      uri: ai-tool:weather
       parameters:
         tags: weather
         description: Get weather information
@@ -602,7 +602,15 @@ String response = 
template.requestBodyAndHeader("direct:chat",
 
 [NOTE]
 ====
-There's no need to add Camel LangChain4j Tools component as a dependency when 
using the tools with LangChain4j Agent component.
+Add the `camel-ai-tool` dependency to use Camel route tools with the 
LangChain4j Agent component:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-ai-tool</artifactId>
+</dependency>
+----
 ====
 
 === Custom LangChain4j Tools
@@ -726,7 +734,7 @@ You can combine both Camel route tools (via `tags`) and 
custom LangChain4j tools
 [source,java]
 ----
 // Define Camel route tools
-from("langchain4j-tools:weatherService?tags=weather&description=Get current 
weather information&parameter.location=string")
+from("ai-tool:weatherService?tags=weather&description=Get current weather 
information&parameter.location=string")
     .setBody(constant("{\"weather\": \"sunny\", \"location\": \"Current 
Location\"}"));
 
 // Create custom tool instances
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4j.java
 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4j.java
new file mode 100644
index 000000000000..163d41eeb588
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/main/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4j.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+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;
+import dev.langchain4j.model.chat.request.json.JsonSchemaElement;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import org.apache.camel.component.ai.tool.AiToolParameterHelper;
+import org.apache.camel.component.ai.tool.AiToolSpec;
+
+final class AiToolSpecToLangChain4j {
+
+    private AiToolSpecToLangChain4j() {
+    }
+
+    static ToolSpecification toToolSpecification(AiToolSpec spec) {
+        ToolSpecification.Builder builder = ToolSpecification.builder()
+                .name(spec.getName())
+                .description(spec.getDescription());
+
+        if (spec.getParameterDefs() != null && 
!spec.getParameterDefs().isEmpty()) {
+            builder.parameters(buildSchema(spec.getParameterDefs()));
+        }
+
+        return builder.build();
+    }
+
+    private static JsonObjectSchema buildSchema(Map<String, 
AiToolParameterHelper.ParameterDef> defs) {
+        JsonObjectSchema.Builder schemaBuilder = JsonObjectSchema.builder();
+        List<String> required = new ArrayList<>();
+
+        for (Map.Entry<String, AiToolParameterHelper.ParameterDef> entry : 
defs.entrySet()) {
+            String paramName = entry.getKey();
+            AiToolParameterHelper.ParameterDef def = entry.getValue();
+
+            JsonSchemaElement schema;
+            if (def.getEnumValues() != null && !def.getEnumValues().isEmpty()) 
{
+                schema = JsonEnumSchema.builder()
+                        .enumValues(def.getEnumValues())
+                        .description(def.getDescription())
+                        .build();
+            } else {
+                schema = switch (def.getType().toLowerCase(Locale.ROOT)) {
+                    case "integer", "int", "long" -> 
JsonIntegerSchema.builder().description(def.getDescription()).build();
+                    case "number", "double", "float" -> 
JsonNumberSchema.builder().description(def.getDescription()).build();
+                    case "boolean", "bool" -> 
JsonBooleanSchema.builder().description(def.getDescription()).build();
+                    default -> 
JsonStringSchema.builder().description(def.getDescription()).build();
+                };
+            }
+
+            schemaBuilder.addProperty(paramName, schema);
+            if (def.isRequired()) {
+                required.add(paramName);
+            }
+        }
+
+        if (!required.isEmpty()) {
+            schemaBuilder.required(required);
+        }
+
+        return schemaBuilder.build();
+    }
+}
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 b03386367032..a390f9f811df 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
@@ -19,17 +19,23 @@ package org.apache.camel.component.langchain4j.agent;
 import java.io.IOException;
 import java.io.InputStream;
 import java.time.Duration;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
-import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import dev.langchain4j.agent.tool.ToolExecutionRequest;
 import dev.langchain4j.agent.tool.ToolSpecification;
 import dev.langchain4j.mcp.McpToolProvider;
 import dev.langchain4j.mcp.client.McpClient;
 import dev.langchain4j.model.chat.request.ResponseFormat;
 import dev.langchain4j.model.chat.request.ResponseFormatType;
-import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
 import dev.langchain4j.model.chat.request.json.JsonRawSchema;
 import dev.langchain4j.model.chat.request.json.JsonSchema;
 import dev.langchain4j.service.Result;
@@ -40,6 +46,10 @@ import dev.langchain4j.service.tool.ToolProviderRequest;
 import dev.langchain4j.service.tool.ToolProviderResult;
 import org.apache.camel.Exchange;
 import org.apache.camel.Message;
+import org.apache.camel.component.ai.tool.AiToolExecutor;
+import org.apache.camel.component.ai.tool.AiToolRegistry;
+import org.apache.camel.component.ai.tool.AiToolResult;
+import org.apache.camel.component.ai.tool.AiToolSpec;
 import org.apache.camel.component.langchain4j.agent.api.AbstractAgent;
 import org.apache.camel.component.langchain4j.agent.api.Agent;
 import org.apache.camel.component.langchain4j.agent.api.AgentConfiguration;
@@ -49,8 +59,6 @@ import 
org.apache.camel.component.langchain4j.agent.api.AgentWithoutMemory;
 import org.apache.camel.component.langchain4j.agent.api.AiAgentBody;
 import org.apache.camel.component.langchain4j.agent.api.CompositeToolProvider;
 import org.apache.camel.component.langchain4j.agent.api.Headers;
-import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolExecutorCache;
-import 
org.apache.camel.component.langchain4j.tools.spec.CamelToolSpecification;
 import org.apache.camel.support.DefaultProducer;
 import org.apache.camel.support.ResourceHelper;
 import org.apache.camel.util.ObjectHelper;
@@ -234,96 +242,25 @@ public class LangChain4jAgentProducer extends 
DefaultProducer {
             }
         }
 
-        // Discover tools from Camel LangChain4j Tools routes
-        Map<String, CamelToolSpecification> availableTools = 
discoverToolsByName(tags);
+        Map<String, AiToolSpec> aiTools = discoverAiToolsByName(tags);
 
-        if (!availableTools.isEmpty()) {
-            LOG.debug("Creating AI Service with {} tools for tags: {}", 
availableTools.size(), tags);
-            return createCamelToolProvider(availableTools, exchange);
+        if (!aiTools.isEmpty()) {
+            LOG.debug("Creating AI Service with {} ai-tool tools for tags: 
{}", aiTools.size(), tags);
+            return buildToolProvider(aiTools, exchange);
         } else {
             LOG.debug("No tools found for tags: {}, using simple AI Service", 
tags);
             return null;
         }
     }
 
-    /**
-     * Create a dynamic tool provider that returns all Camel route as 
LangChain4j tools. This uses LangChain4j's
-     * ToolProvider API for dynamic tool registration.
-     */
-    private ToolProvider createCamelToolProvider(Map<String, 
CamelToolSpecification> availableTools, Exchange exchange) {
+    private ToolProvider buildToolProvider(Map<String, AiToolSpec> aiTools, 
Exchange exchange) {
         return (ToolProviderRequest toolProviderRequest) -> {
-            // Build the tool provider result with all available Camel tools
             ToolProviderResult.Builder resultBuilder = 
ToolProviderResult.builder();
 
-            for (Map.Entry<String, CamelToolSpecification> entry : 
availableTools.entrySet()) {
-                String toolName = entry.getKey();
-                CamelToolSpecification camelToolSpec = entry.getValue();
-
-                // Get the existing ToolSpecification from 
CamelToolSpecification
-                ToolSpecification toolSpecification = 
camelToolSpec.getToolSpecification();
-
-                // Create a functional tool executor for this specific Camel 
route
-                ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) 
-> {
-                    LOG.info("Executing Camel route tool: '{}' with arguments: 
{}", toolName, toolExecutionRequest.arguments());
-
-                    try {
-                        // Parse JSON arguments if provided
-                        String arguments = toolExecutionRequest.arguments();
-                        if (arguments != null && !arguments.trim().isEmpty()) {
-                            // Get declared parameters from tool specification 
to filter incoming fields
-                            Set<String> declaredParams = Set.of();
-                            JsonObjectSchema paramSchema = 
toolSpecification.parameters();
-                            if (paramSchema != null && 
paramSchema.properties() != null) {
-                                declaredParams = 
paramSchema.properties().keySet();
-                            }
-                            final Set<String> allowedParams = declaredParams;
-
-                            JsonNode jsonNode = 
objectMapper.readValue(arguments, JsonNode.class);
-                            jsonNode.fieldNames()
-                                    .forEachRemaining(name -> {
-                                        if (!allowedParams.contains(name)) {
-                                            LOG.warn("Skipping undeclared tool 
argument '{}' for tool '{}'",
-                                                    name, toolName);
-                                            return;
-                                        }
-                                        JsonNode value = jsonNode.get(name);
-                                        Object headerValue;
-                                        if (value.isInt()) {
-                                            headerValue = value.intValue();
-                                        } else if (value.isLong()) {
-                                            headerValue = value.longValue();
-                                        } else if (value.isDouble()) {
-                                            headerValue = value.doubleValue();
-                                        } else if (value.isBoolean()) {
-                                            headerValue = value.booleanValue();
-                                        } else {
-                                            headerValue = value.asText();
-                                        }
-                                        exchange.getMessage().setHeader(name, 
headerValue);
-                                    });
-                        }
-
-                        // Set the tool name as a header for route 
identification
-                        exchange.getMessage().setHeader("CamelToolName", 
toolName);
-
-                        // Execute the consumer route
-                        
camelToolSpec.getConsumer().getProcessor().process(exchange);
-
-                        // Return the result
-                        String result = exchange.getIn().getBody(String.class);
-                        LOG.info("Tool '{}' execution completed successfully", 
toolName);
-                        return result != null ? result : "No result";
-
-                    } catch (Exception e) {
-                        LOG.error("Error executing tool '{}': {}", toolName, 
e.getMessage(), e);
-                        return String.format("Error executing tool '%s': %s", 
toolName, e.getMessage());
-                    }
-                };
-
-                // Add this tool to the result
-                resultBuilder.add(toolSpecification, toolExecutor);
-
-                LOG.info("Added dynamic tool: '{}' - {}", 
toolSpecification.name(), toolSpecification.description());
+            for (Map.Entry<String, AiToolSpec> entry : aiTools.entrySet()) {
+                AiToolSpec spec = entry.getValue();
+                ToolSpecification toolSpec = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+                addToolToResult(resultBuilder, spec, toolSpec, exchange);
             }
 
             return resultBuilder.build();
@@ -331,24 +268,76 @@ public class LangChain4jAgentProducer extends 
DefaultProducer {
     }
 
     /**
-     * Discover Camel routes by tags and create a map of tool specifications 
by name.
+     * Registers a single tool with the langchain4j runtime. Creates a {@link 
ToolExecutor} that converts the
+     * langchain4j-specific {@link ToolExecutionRequest} into a 
framework-agnostic {@code Map<String, Object>} and
+     * delegates execution to {@link AiToolExecutor}.
+     */
+    private void addToolToResult(
+            ToolProviderResult.Builder resultBuilder,
+            AiToolSpec spec,
+            ToolSpecification toolSpec,
+            Exchange exchange) {
+
+        ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
+            Map<String, Object> arguments = 
parseArguments(toolExecutionRequest);
+            if (arguments == null) {
+                return "Invalid arguments: could not parse the provided JSON 
arguments";
+            }
+            AiToolResult result = AiToolExecutor.execute(spec, arguments, 
exchange);
+            return toToolResponse(spec.getName(), result);
+        };
+
+        resultBuilder.add(toolSpec, toolExecutor);
+        LOG.debug("Added dynamic tool: '{}' - {}", toolSpec.name(), 
toolSpec.description());
+    }
+
+    /**
+     * Converts a langchain4j {@link ToolExecutionRequest} arguments into a 
flat map. Returns {@code null} if the JSON
+     * cannot be parsed, signalling the caller to return an error to the LLM 
instead of executing the tool with no
+     * arguments.
      */
-    private Map<String, CamelToolSpecification> discoverToolsByName(String 
tags) {
-        final CamelToolExecutorCache toolCache = 
CamelToolExecutorCache.getInstance();
-        final Map<String, Set<CamelToolSpecification>> tools = 
toolCache.getTools();
+    private Map<String, Object> parseArguments(ToolExecutionRequest request) {
+        String jsonArguments = request.arguments();
+        if (jsonArguments == null || jsonArguments.trim().isEmpty()) {
+            return Map.of();
+        }
+        try {
+            return objectMapper.readValue(jsonArguments, new 
TypeReference<Map<String, Object>>() {
+            });
+        } catch (Exception e) {
+            LOG.warn("Failed to parse tool arguments from 
ToolExecutionRequest: {}", e.getMessage());
+            return null;
+        }
+    }
+
+    private String toToolResponse(String toolName, AiToolResult result) {
+        if (result instanceof AiToolResult.Success success) {
+            return success.value();
+        } else if (result instanceof AiToolResult.ArgumentError error) {
+            LOG.warn("Tool '{}' argument error: {}", toolName, 
error.message(), error.cause());
+            return "Invalid arguments: " + error.message();
+        } else if (result instanceof AiToolResult.ExecutionError error) {
+            LOG.warn("Tool '{}' execution error: {}", toolName, 
error.message(), error.cause());
+            return "Tool execution failed";
+        }
+        return "Tool execution failed";
+    }
+
+    /**
+     * Discover tools registered via {@code ai-tool:} consumer endpoints in 
the shared {@link AiToolRegistry}.
+     */
+    private Map<String, AiToolSpec> discoverAiToolsByName(String tags) {
+        final AiToolRegistry registry = 
AiToolRegistry.getOrCreate(endpoint.getCamelContext());
         final String[] tagArray = ToolsTagsHelper.splitTags(tags);
 
-        final Map<String, CamelToolSpecification> toolsByName = 
Arrays.stream(tagArray)
-                .flatMap(tag -> tools.entrySet().stream()
-                        .filter(entry -> entry.getKey().equals(tag))
-                        .flatMap(entry -> entry.getValue().stream()))
-                .collect(Collectors.toMap(
-                        camelToolSpec -> 
camelToolSpec.getToolSpecification().name(),
-                        camelToolSpec -> camelToolSpec,
-                        (existing, replacement) -> existing // Keep first if 
duplicate names
-                ));
-
-        LOG.info("Discovered {} unique tools for tags: {}", 
toolsByName.size(), tags);
+        final Map<String, AiToolSpec> toolsByName = new LinkedHashMap<>();
+        for (String tag : tagArray) {
+            for (AiToolSpec spec : registry.getToolsByTag(tag.trim())) {
+                toolsByName.putIfAbsent(spec.getName(), spec);
+            }
+        }
+
+        LOG.debug("Discovered {} AI tools for tags: {}", toolsByName.size(), 
tags);
         return toolsByName;
     }
 
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4jTest.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4jTest.java
new file mode 100644
index 000000000000..c6bb8e509677
--- /dev/null
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/AiToolSpecToLangChain4jTest.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.langchain4j.agent;
+
+import java.util.LinkedHashMap;
+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;
+import dev.langchain4j.model.chat.request.json.JsonStringSchema;
+import org.apache.camel.component.ai.tool.AiToolParameterHelper;
+import org.apache.camel.component.ai.tool.AiToolSpec;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class AiToolSpecToLangChain4jTest {
+
+    @Test
+    void testBasicToolSpecConversion() {
+        AiToolSpec spec = new AiToolSpec("myTool", "A test tool", Map.of(), 
null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertEquals("myTool", result.name());
+        assertEquals("A test tool", result.description());
+        assertNull(result.parameters());
+    }
+
+    @Test
+    void testStringParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("city", "string");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("weather", "Get weather", defs, null, 
null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertNotNull(result.parameters());
+        JsonObjectSchema schema = result.parameters();
+        assertInstanceOf(JsonStringSchema.class, 
schema.properties().get("city"));
+    }
+
+    @Test
+    void testIntegerParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("count", "integer");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("counter", "Count items", defs, null, 
null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertInstanceOf(JsonIntegerSchema.class, 
result.parameters().properties().get("count"));
+    }
+
+    @Test
+    void testNumberParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("price", "number");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("pricer", "Get price", defs, null, 
null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertInstanceOf(JsonNumberSchema.class, 
result.parameters().properties().get("price"));
+    }
+
+    @Test
+    void testBooleanParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("active", "boolean");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("checker", "Check status", defs, 
null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertInstanceOf(JsonBooleanSchema.class, 
result.parameters().properties().get("active"));
+    }
+
+    @Test
+    void testEnumParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("color", "string");
+        rawParams.put("color.enum", "red,green,blue");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("colorPicker", "Pick a color", defs, 
null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        JsonEnumSchema enumSchema = assertInstanceOf(JsonEnumSchema.class, 
result.parameters().properties().get("color"));
+        assertEquals(3, enumSchema.enumValues().size());
+        assertTrue(enumSchema.enumValues().contains("red"));
+        assertTrue(enumSchema.enumValues().contains("green"));
+        assertTrue(enumSchema.enumValues().contains("blue"));
+    }
+
+    @Test
+    void testRequiredParameter() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("userId", "string");
+        rawParams.put("userId.required", "true");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("userLookup", "Look up user", defs, 
null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertNotNull(result.parameters().required());
+        assertTrue(result.parameters().required().contains("userId"));
+    }
+
+    @Test
+    void testMultipleParametersWithMixedTypes() {
+        Map<String, String> rawParams = new LinkedHashMap<>();
+        rawParams.put("name", "string");
+        rawParams.put("name.required", "true");
+        rawParams.put("age", "integer");
+        rawParams.put("score", "number");
+        rawParams.put("active", "boolean");
+
+        Map<String, AiToolParameterHelper.ParameterDef> defs = 
AiToolParameterHelper.parseParameterMetadata(rawParams);
+        AiToolSpec spec = new AiToolSpec("multiTool", "Multi-param tool", 
defs, null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertEquals(4, result.parameters().properties().size());
+        assertInstanceOf(JsonStringSchema.class, 
result.parameters().properties().get("name"));
+        assertInstanceOf(JsonIntegerSchema.class, 
result.parameters().properties().get("age"));
+        assertInstanceOf(JsonNumberSchema.class, 
result.parameters().properties().get("score"));
+        assertInstanceOf(JsonBooleanSchema.class, 
result.parameters().properties().get("active"));
+
+        assertTrue(result.parameters().required().contains("name"));
+        assertEquals(1, result.parameters().required().size());
+    }
+
+    @Test
+    void testEmptyParameters() {
+        AiToolSpec spec = new AiToolSpec("noParams", "Tool with no params", 
Map.of(), null, null);
+
+        ToolSpecification result = 
AiToolSpecToLangChain4j.toToolSpecification(spec);
+
+        assertNull(result.parameters());
+    }
+}
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentWithMemoryServiceTest.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentWithMemoryServiceTest.java
index 7d4bb46bcec3..46a01bd0ea34 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentWithMemoryServiceTest.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/LangChain4jAgentWithMemoryServiceTest.java
@@ -42,9 +42,9 @@ public class LangChain4jAgentWithMemoryServiceTest extends 
BaseLangChain4jAgent
             .when("Hi! Can you look up user 123 and tell me about our rental 
policies?")
             .assertRequest(request -> {
                 // Both tools are part of the request
-                
Assertions.assertThat(request).contains("QueryUserDatabaseByUserID", 
"GetCurrentWeatherInformation");
+                Assertions.assertThat(request).contains("userDb", 
"weatherService");
             })
-            .invokeTool("QueryUserDatabaseByUserID")
+            .invokeTool("userDb")
             .withParam("userId", "123")
             .replyWithToolContent(" " + COMPANY_KNOWLEDGE_BASE)
             .end()
@@ -57,7 +57,7 @@ public class LangChain4jAgentWithMemoryServiceTest extends 
BaseLangChain4jAgent
             .replyWith("SUV")
             .end()
             .when("What's the weather in London?")
-            .invokeTool("GetCurrentWeatherInformation")
+            .invokeTool("weatherService")
             .withParam("location", "London")
             .end()
             .build();
@@ -117,7 +117,7 @@ public class LangChain4jAgentWithMemoryServiceTest extends 
BaseLangChain4jAgent
                 thirdRequest,
                 String.class);
 
-        assertNotNull(thirdRequest, "Third response should not be null");
+        assertNotNull(thirdResponse, "Third response should not be null");
         Assertions.assertThat(thirdResponse).contains(WEATHER_INFO);
 
         mockEndpoint.assertIsSatisfied();
@@ -151,10 +151,10 @@ public class LangChain4jAgentWithMemoryServiceTest 
extends BaseLangChain4jAgent
                         .to("mock:agent-response");
 
                 // Tool routes for function calling
-                from("langchain4j-tools:userDb?tags=users&description=Query 
user database by user ID&parameter.userId=string")
+                from("ai-tool:userDb?tags=users&description=Query user 
database by user ID&parameter.userId=string")
                         .setBody(constant(USER_DATABASE));
 
-                
from("langchain4j-tools:weatherService?tags=weather&description=Get current 
weather information&parameter.location=string")
+                from("ai-tool:weatherService?tags=weather&description=Get 
current weather information&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"location\": \"Current Location\"}"));
             }
         };
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpAndCamelToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpAndCamelToolsIT.java
index 6f06db05c5fa..54d92e9d1381 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpAndCamelToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMcpAndCamelToolsIT.java
@@ -43,8 +43,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * Integration test for the LangChain4j Agent component verifying that 
internal Camel route tools (via
- * camel-langchain4j-tools with tags) and external MCP tools can coexist 
together in a single agent.
+ * Integration test for the LangChain4j Agent component verifying that 
internal Camel route tools (via ai-tool with
+ * tags) and external MCP tools can coexist together in a single agent.
  *
  * <p>
  * This test demonstrates two MCP configuration approaches working 
simultaneously:
@@ -225,36 +225,25 @@ public class LangChain4jAgentMcpAndCamelToolsIT extends 
CamelTestSupport {
     }
 
     /**
-     * Tests that excluding an MCP server by name via header prevents those 
tools from being used. First verifies the
-     * MCP add tool works, then excludes the "everything" MCP server and 
verifies the agent can no longer use it.
+     * Tests that excluding an MCP server by name via header does not break 
the agent. The actual exclusion filtering
+     * logic is verified by {@link #testExcludeCamelToolTag()} which uses data 
the LLM cannot guess ("Alice Johnson").
+     * MCP tools (echo, add) cannot be reliably used for exclusion assertions 
because the LLM can reproduce their output
+     * from the prompt alone.
      */
     @Test
     void testExcludeMcpServer() throws InterruptedException {
-        // First: verify the MCP tool works without exclusion
         MockEndpoint mockEndpoint = getMockEndpoint("mock:response");
         mockEndpoint.expectedMessageCount(1);
 
-        String responseWithTool = template.requestBody("direct:chat",
-                "Use the add tool to add 17 and 25. What is the result?", 
String.class);
-
-        mockEndpoint.assertIsSatisfied();
-        assertNotNull(responseWithTool);
-        assertTrue(responseWithTool.contains("42"),
-                "Without exclusion, response should contain 42 but was: " + 
responseWithTool);
-
-        // Then: exclude the "everything" MCP server and verify the add tool 
is no longer available
-        mockEndpoint.reset();
-        mockEndpoint.expectedMessageCount(1);
-
-        String responseWithoutTool = 
template.requestBodyAndHeader("direct:chat",
-                "Use the add tool to add 17 and 25. What is the result?",
+        String response = template.requestBodyAndHeader("direct:chat",
+                "What is the name of user with ID 42? Use the user database 
tool.",
                 Headers.EXCLUDE_MCP_SERVERS, "everything",
                 String.class);
 
         mockEndpoint.assertIsSatisfied();
-        assertNotNull(responseWithoutTool);
-        assertFalse(responseWithoutTool.contains("42"),
-                "With 'everything' MCP server excluded, response should NOT 
contain 42 but was: " + responseWithoutTool);
+        assertNotNull(response);
+        assertTrue(response.contains("Alice Johnson"),
+                "Camel tools should still work when MCP server is excluded but 
was: " + response);
     }
 
     /**
@@ -276,13 +265,10 @@ public class LangChain4jAgentMcpAndCamelToolsIT extends 
CamelTestSupport {
 
         mockEndpoint.assertIsSatisfied();
         assertNotNull(response);
-        // With all tools excluded, the agent should not be able to use any 
tools
+        // With all tools excluded, the agent should not mention specific tool 
names like "add" or "echo"
         String lowerResponse = response.toLowerCase();
-        assertTrue(lowerResponse.contains("no tool") || 
lowerResponse.contains("don't have")
-                || lowerResponse.contains("do not have") || 
lowerResponse.contains("not available")
-                || lowerResponse.contains("cannot") || 
!lowerResponse.contains("add")
-                || !lowerResponse.contains("echo"),
-                "With all tools excluded, agent should indicate no tools are 
available but was: " + response);
+        assertFalse(lowerResponse.contains("add") && 
lowerResponse.contains("echo"),
+                "With all tools excluded, agent should not list tool names 
like 'add' and 'echo' but was: " + response);
     }
 
     @Override
@@ -314,13 +300,13 @@ public class LangChain4jAgentMcpAndCamelToolsIT extends 
CamelTestSupport {
                                 everythingUrl)
                         .to("mock:response");
 
-                // Camel route tools (internal tools via 
camel-langchain4j-tools)
-                from("langchain4j-tools:userDb?tags=users"
+                // Camel route tools (internal tools via ai-tool)
+                from("ai-tool:userDb?tags=users"
                      + "&description=Query user database by user ID"
                      + "&parameter.userId=string")
                         .setBody(constant(USER_DATABASE));
 
-                from("langchain4j-tools:weatherService?tags=weather"
+                from("ai-tool:weatherService?tags=weather"
                      + "&description=Get current weather for a location"
                      + "&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"location\": \"Current Location\"}"));
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
index 7809e29b9c55..a300b22e3cb1 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentMixedToolsIT.java
@@ -151,10 +151,10 @@ public class LangChain4jAgentMixedToolsIT extends 
CamelTestSupport {
                         .to("mock:agent-response");
 
                 // Tool routes for function calling
-                from("langchain4j-tools:userDb?tags=users&description=Query 
user database by user ID&parameter.userId=string")
+                from("ai-tool:userDb?tags=users&description=Query user 
database by user ID&parameter.userId=string")
                         .setBody(constant(USER_DATABASE));
 
-                
from("langchain4j-tools:weatherService?tags=weather&description=Get current 
weather information&parameter.location=string")
+                from("ai-tool:weatherService?tags=weather&description=Get 
current weather information&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"location\": \"Current Location\"}"));
             }
         };
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentServiceIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentServiceIT.java
index f2296a57d44b..bf29ac8e97ec 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentServiceIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentServiceIT.java
@@ -113,10 +113,10 @@ public class LangChain4jAgentServiceIT extends 
AbstractRAGIT {
                         
.to("langchain4j-agent:no-memory?agent=#completeAgent&tags=users,weather")
                         .to("mock:agent-response");
 
-                from("langchain4j-tools:userDb?tags=users&description=Query 
user database by user ID&parameter.userId=string")
+                from("ai-tool:userDb?tags=users&description=Query user 
database by user ID&parameter.userId=string")
                         .setBody(constant(USER_DATABASE));
 
-                
from("langchain4j-tools:weatherService?tags=weather&description=Get current 
weather information&parameter.location=string")
+                from("ai-tool:weatherService?tags=weather&description=Get 
current weather information&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"location\": \"Current Location\"}"));
             }
         };
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryServiceIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryServiceIT.java
index c6709ee24a8c..8b45b9f098bb 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryServiceIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithMemoryServiceIT.java
@@ -87,7 +87,7 @@ public class LangChain4jAgentWithMemoryServiceIT extends 
AbstractRAGIT {
         mockEndpoint.expectedMessageCount(2);
 
         AiAgentBody<?> firstRequest = new AiAgentBody<>(
-                "Hi! Can you look up user 123 and tell me about our rental 
policies?",
+                "You MUST use the userDb tool to look up user 123. Tell me 
their name, membership level, and rental policies.",
                 null,
                 MEMORY_ID_SESSION);
 
@@ -237,10 +237,10 @@ public class LangChain4jAgentWithMemoryServiceIT extends 
AbstractRAGIT {
                         .to("mock:agent-response");
 
                 // Tool routes for function calling
-                from("langchain4j-tools:userDb?tags=users&description=Query 
user database by user ID&parameter.userId=string")
+                from("ai-tool:userDb?tags=users&description=Query user 
database by user ID&parameter.userId=string")
                         .setBody(constant(USER_DATABASE));
 
-                
from("langchain4j-tools:weatherService?tags=weather&description=Get current 
weather information&parameter.location=string")
+                from("ai-tool:weatherService?tags=weather&description=Get 
current weather information&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"location\": \"Current Location\"}"));
             }
         };
diff --git 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
index ef68ada0b565..e6e07f00abde 100644
--- 
a/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
+++ 
b/components/camel-ai/camel-langchain4j-agent/src/test/java/org/apache/camel/component/langchain4j/agent/integration/LangChain4jAgentWithToolsIT.java
@@ -62,7 +62,7 @@ public class LangChain4jAgentWithToolsIT extends 
CamelTestSupport {
 
         String response = template.requestBody(
                 "direct:agent-with-user-tools",
-                "What is the name of user ID 123?",
+                "You MUST use the userDb tool to query user ID 123. What is 
the name of user ID 123?",
                 String.class);
 
         mockEndpoint.assertIsSatisfied();
@@ -188,13 +188,13 @@ public class LangChain4jAgentWithToolsIT extends 
CamelTestSupport {
                         
.to("langchain4j-agent:test-agent?agent=#agentWithTools&tags=nonexistent")
                         .to("mock:check-no-tools");
 
-                from("langchain4j-tools:userDb?tags=users&description=Query 
user database by user ID&parameter.userId=integer")
+                from("ai-tool:userDb?tags=users&description=Query user 
database by user ID&parameter.userId=integer")
                         .setBody(constant("{\"name\": \"" + USER_DB_NAME + 
"\", \"id\": \"123\"}"));
 
-                
from("langchain4j-tools:weatherService?tags=weather&description=Get weather 
information for a city&parameter.city=string")
+                from("ai-tool:weatherService?tags=weather&description=Get 
weather information for a city&parameter.city=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"city\": \"New York\"}"));
 
-                
from("langchain4j-tools:parisWeather?tags=weather&description=Get weather 
information for Paris&parameter.location=string")
+                from("ai-tool:parisWeather?tags=weather&description=Get 
weather information for Paris&parameter.location=string")
                         .setBody(constant("{\"weather\": \"" + WEATHER_INFO + 
"\", \"city\": \"Paris\"}"));
             }
         };
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index 79732d566c4f..4461eb1f6f84 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -181,6 +181,43 @@ When RAG or tools are used, the agent producer also 
exposes `CamelLangChain4jAge
 (`List<dev.langchain4j.service.tool.ToolExecution>`) as exchange headers when 
present in the
 `Result`.
 
+==== Camel route tools now use ai-tool
+
+The `langchain4j-agent` producer now discovers Camel route tools from the 
`ai-tool` component
+(`AiToolRegistry`) instead of the `langchain4j-tools` component 
(`CamelToolExecutorCache`).
+
+Migrate your tool definition routes from `langchain4j-tools:` to `ai-tool:`:
+
+[source,java]
+----
+// Before (no longer works with langchain4j-agent)
+from("langchain4j-tools:userDb?tags=users&description=Query user 
database&parameter.userId=string")
+    .setBody(constant("{\"name\": \"John Doe\", \"id\": \"123\"}"));
+
+// After
+from("ai-tool:userDb?tags=users&description=Query user 
database&parameter.userId=string")
+    .setBody(constant("{\"name\": \"John Doe\", \"id\": \"123\"}"));
+----
+
+The `langchain4j-agent` producer endpoint is unchanged — only the tool 
consumer routes need
+to be migrated:
+
+[source,java]
+----
+from("direct:chat")
+    .to("langchain4j-agent:assistant?agent=#myAgent&tags=users");
+----
+
+Add the `camel-ai-tool` dependency to your project:
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-ai-tool</artifactId>
+</dependency>
+----
+
 === camel-langchain4j-chat
 
 The helper classes `OpenAiChatLanguageModelBuilder` and 
`HugginFaceChatLanguageModelBuilder` have been removed.

Reply via email to