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

JiriOndrusek pushed a commit to branch camel-main
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git

commit d2dad48be48ed7cc8071aa3dcaf728d16fc6bf85
Author: Jiri Ondrusek <[email protected]>
AuthorDate: Mon Jul 27 16:55:48 2026 +0200

    Fixes #8768. Add CamelAiToolProvider bridge and @CamelAiTools tag filtering 
for langchain4j
    
    Bridges Camel's AiToolRegistry to langchain4j's ToolProvider SPI in
    extensions-support/langchain4j. When both camel-ai-tool and
    quarkus-langchain4j are on the classpath, the deployment processor
    auto-registers CamelAiToolProvider as a CDI bean, making Camel AI tools
    available to @RegisterAiService AI services without explicit wiring.
    
    Introduces @CamelAiTools("tag") annotation for per-AI-service tool
    filtering via a CDI interceptor + ThreadLocal pattern. Tag resolution:
    ThreadLocal present -> getToolsByTag(), absent -> getAllTools(). Services
    without @CamelAiTools always see all tools.
    
    Includes integration tests with mock ToolCallingChatModels verifying
    end-to-end tool invocation and tag isolation across weather + admin
    AI services, plus an Ollama-based test behind -Pollama.
    
    Document LangChain4j integration and @CamelAiTools tag filtering in ai-tool 
usage.adoc
    
    Co-Authored-By: Claude Opus 4.6 <[email protected]>
---
 .../ROOT/pages/reference/extensions/ai-tool.adoc   |  56 +++
 .../ROOT/pages/reference/extensions/core.adoc      | 406 ---------------------
 extensions-support/langchain4j/deployment/pom.xml  |   5 +
 .../langchain4j/deployment/AiToolPresent.java      |  36 ++
 .../SupportQuarkusLangchain4jProcessor.java        | 111 +++++-
 extensions-support/langchain4j/runtime/pom.xml     |  10 +
 ...ain4jRecorder.java => AiToolSpecConverter.java} |  28 +-
 .../support/langchain4j/CamelAiToolProvider.java   | 129 +++++++
 .../support/langchain4j/CamelAiTools.java          |  48 +++
 .../langchain4j/CamelAiToolsInterceptor.java       |  73 ++++
 .../langchain4j/QuarkusLangchain4jRecorder.java    |   5 +
 extensions/ai-tool/runtime/src/main/doc/usage.adoc |  54 +++
 integration-tests/ai-tool-langchain4j/README.adoc  |  15 +
 integration-tests/ai-tool-langchain4j/pom.xml      | 222 +++++++++++
 .../it/AiToolLangchain4jOllamaResource.java        |  54 +++
 .../langchain4j/it/AiToolLangchain4jResource.java  |  90 +++++
 .../langchain4j/it/AiToolLangchain4jRoutes.java    |  40 ++
 .../it/model/AbstractToolCallingChatModel.java     |  93 +++++
 .../it/model/AdminToolCallingChatModel.java        |  45 +++
 .../it/model/WeatherToolCallingChatModel.java      |  45 +++
 .../it/model/WrongTagToolCallingChatModel.java     |  78 ++++
 .../langchain4j/it/service/AdminAiService.java     |  31 ++
 .../langchain4j/it/service/WeatherAiService.java   |  31 ++
 .../it/service/WeatherAiServiceOllama.java         |  30 ++
 .../it/service/WeatherAiServiceOllamaWrongTag.java |  30 ++
 .../it/service/WeatherAiServiceWrongTag.java       |  31 ++
 .../src/main/resources/application.properties      |  18 +
 .../tool/langchain4j/it/AiToolLangchain4jIT.java   |  23 ++
 .../langchain4j/it/AiToolLangchain4jOllamaIT.java  |  25 ++
 .../it/AiToolLangchain4jOllamaTest.java            |  68 ++++
 .../tool/langchain4j/it/AiToolLangchain4jTest.java |  97 +++++
 integration-tests/pom.xml                          |   1 +
 tooling/scripts/test-categories.yaml               |   1 +
 33 files changed, 1603 insertions(+), 426 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/extensions/ai-tool.adoc 
b/docs/modules/ROOT/pages/reference/extensions/ai-tool.adoc
index 16920abb9a..1012044469 100644
--- a/docs/modules/ROOT/pages/reference/extensions/ai-tool.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/ai-tool.adoc
@@ -92,3 +92,59 @@ from("ai-tool:greet?description=Greet a user"
     .setBody(simple("Hello, ${header.name}!"));
 ----
 
+[id="extensions-ai-tool-usage-langchain4j-integration"]
+=== LangChain4j integration
+
+When both `camel-quarkus-ai-tool` and a Quarkus LangChain4j extension 
(`quarkus-langchain4j-ollama`, `quarkus-langchain4j-openai`, etc.) are on the 
classpath, a `ToolProvider` CDI bean is registered automatically at build time.
+All routes registered via `ai-tool:` endpoints become available to 
`@RegisterAiService` AI services without explicit wiring.
+
+You must also add `camel-langchain4j-agent` to your project dependencies. This 
artifact provides the `AiToolSpec` to `ToolSpecification` conversion and is not 
brought in transitively.
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-langchain4j-agent</artifactId>
+</dependency>
+----
+
+With both dependencies in place, a `@RegisterAiService` interface can call 
Camel tools directly:
+
+[source,java]
+----
+@RegisterAiService
+public interface WeatherAiService {
+    String chat(@UserMessage String question);
+}
+----
+
+Any `ai-tool:` route is now callable by the LLM behind `WeatherAiService`. No 
`toolProvider` attribute or manual bean reference is needed.
+
+[id="extensions-ai-tool-usage-tag-filtering-with-camelaitools"]
+==== Tag filtering with `@CamelAiTools`
+
+By default, all registered `ai-tool:` routes are visible to every AI service. 
When you need different AI services to see different subsets of tools, annotate 
the service interface with `@CamelAiTools` and specify a tag value that matches 
the `tags` parameter on your `ai-tool:` routes.
+
+[source,java]
+----
+@RegisterAiService
+@CamelAiTools("weather")
+public interface WeatherAgent {
+    String chat(@UserMessage String question);
+}
+
+@RegisterAiService
+@CamelAiTools("support")
+public interface SupportAgent {
+    String chat(@UserMessage String question);
+}
+----
+
+With this setup:
+
+* `WeatherAgent` sees only tools tagged with `weather` (plus any untagged 
tools from the default pool).
+* `SupportAgent` sees only tools tagged with `support` (plus any untagged 
tools from the default pool).
+* A `@RegisterAiService` without `@CamelAiTools` sees all registered tools 
regardless of tags.
+
+NOTE: The `@CamelAiTools` value must match a tag declared in the `ai-tool:` 
endpoint URI (e.g. `from("ai-tool:getWeather?tags=weather&...")`). If the 
annotation value is blank or does not match any route tag, the AI service will 
only see untagged tools.
+
diff --git a/docs/modules/ROOT/pages/reference/extensions/core.adoc 
b/docs/modules/ROOT/pages/reference/extensions/core.adoc
index 9a9aa274f9..db73e5ab49 100644
--- a/docs/modules/ROOT/pages/reference/extensions/core.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/core.adoc
@@ -124,409 +124,3 @@ camel.beans.customBeanWithSetterInjection.counter = 123
 
 As such, the class `PropertiesCustomBeanWithSetterInjection` needs to be 
link:https://quarkus.io/guides/writing-native-applications-tips#registering-for-reflection[registered
 for reflection], note that field access could be omitted in this case.
 
-
-[width="100%",cols="80,5,15",options="header"]
-|===
-| Configuration property | Type | Default
-
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-service-discovery-exclude-patterns]]`link:#quarkus-camel-service-discovery-exclude-patterns[quarkus.camel.service.discovery.exclude-patterns]`
-
-A comma-separated list of Ant-path style patterns to match Camel service 
definition files in the classpath. The
-services defined in the matching files will *not* be discoverable via the 
**`org.apache.camel.spi.FactoryFinder`
-mechanism.
-
-The excludes have higher precedence than includes. The excludes defined here 
can also be used to veto the
-discoverability of services included by Camel Quarkus extensions.
-
-Example values: 
`META-INF/services/org/apache/camel/foo/++*++,META-INF/services/org/apache/camel/foo/++**++/bar`
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-service-discovery-include-patterns]]`link:#quarkus-camel-service-discovery-include-patterns[quarkus.camel.service.discovery.include-patterns]`
-
-A comma-separated list of Ant-path style patterns to match Camel service 
definition files in the classpath. The
-services defined in the matching files will be discoverable via the 
`org.apache.camel.spi.FactoryFinder` mechanism
-unless the given file is excluded via `exclude-patterns`.
-
-Note that Camel Quarkus extensions may include some services by default. The 
services selected here added to those
-services and the exclusions defined in `exclude-patterns` are applied to the 
union set.
-
-Example values: 
`META-INF/services/org/apache/camel/foo/++*++,META-INF/services/org/apache/camel/foo/++**++/bar`
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-service-registry-exclude-patterns]]`link:#quarkus-camel-service-registry-exclude-patterns[quarkus.camel.service.registry.exclude-patterns]`
-
-A comma-separated list of Ant-path style patterns to match Camel service 
definition files in the classpath. The
-services defined in the matching files will *not* be added to Camel registry 
during application's static
-initialization.
-
-The excludes have higher precedence than includes. The excludes defined here 
can also be used to veto the
-registration of services included by Camel Quarkus extensions.
-
-Example values: 
`META-INF/services/org/apache/camel/foo/++*++,META-INF/services/org/apache/camel/foo/++**++/bar`**
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-service-registry-include-patterns]]`link:#quarkus-camel-service-registry-include-patterns[quarkus.camel.service.registry.include-patterns]`
-
-A comma-separated list of Ant-path style patterns to match Camel service 
definition files in the classpath. The
-services defined in the matching files will be added to Camel registry during 
application's static initialization
-unless the given file is excluded via `exclude-patterns`.
-
-Note that Camel Quarkus extensions may include some services by default. The 
services selected here added to those
-services and the exclusions defined in `exclude-patterns` are applied to the 
union set.
-
-Example values: 
`META-INF/services/org/apache/camel/foo/++*++,META-INF/services/org/apache/camel/foo/++**++/bar`
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-components]]`link:#quarkus-camel-runtime-catalog-components[quarkus.camel.runtime-catalog.components]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel components
-available in the application; otherwise component JSON schemas will not be 
available in the Runtime Camel Catalog and
-any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-languages]]`link:#quarkus-camel-runtime-catalog-languages[quarkus.camel.runtime-catalog.languages]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel languages
-available in the application; otherwise language JSON schemas will not be 
available in the Runtime Camel Catalog and
-any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-dataformats]]`link:#quarkus-camel-runtime-catalog-dataformats[quarkus.camel.runtime-catalog.dataformats]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel data formats
-available in the application; otherwise data format JSON schemas will not be 
available in the Runtime Camel Catalog
-and any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-devconsoles]]`link:#quarkus-camel-runtime-catalog-devconsoles[quarkus.camel.runtime-catalog.devconsoles]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel dev consoles
-available in the application; otherwise dev console JSON schemas will not be 
available in the Runtime Camel Catalog
-and any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-models]]`link:#quarkus-camel-runtime-catalog-models[quarkus.camel.runtime-catalog.models]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel EIP models
-available in the application; otherwise EIP model JSON schemas will not be 
available in the Runtime Camel Catalog and
-any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-runtime-catalog-transformers]]`link:#quarkus-camel-runtime-catalog-transformers[quarkus.camel.runtime-catalog.transformers]`
-
-If `true` the Runtime Camel Catalog embedded in the application will contain 
JSON schemas of Camel transformers
-available in the application; otherwise transformer JSON schemas will not be 
available in the Runtime Camel Catalog
-and any attempt to access those will result in a RuntimeException.
-
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `false` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-routes-discovery-exclude-patterns]]`link:#quarkus-camel-routes-discovery-exclude-patterns[quarkus.camel.routes-discovery.exclude-patterns]`
-
-Used for exclusive filtering scanning of RouteBuilder classes. The exclusive 
filtering takes precedence over
-inclusive filtering. The pattern is using Ant-path style pattern. Multiple 
patterns can be specified separated by
-comma. For example to exclude all classes starting with Bar use: 
++**++/Bar++*++ To exclude all routes from a
-specific package use: com/mycompany/bar/++*++ To exclude all routes from a 
specific package and its sub-packages use
-double wildcards: com/mycompany/bar/++**++ And to exclude all routes from two 
specific packages use:
-com/mycompany/bar/++*++,com/mycompany/stuff/++*++
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-routes-discovery-include-patterns]]`link:#quarkus-camel-routes-discovery-include-patterns[quarkus.camel.routes-discovery.include-patterns]`
-
-Used for inclusive filtering scanning of RouteBuilder classes. The exclusive 
filtering takes precedence over
-inclusive filtering. The pattern is using Ant-path style pattern. Multiple 
patterns can be specified separated by
-comma. For example to include all classes starting with Foo use: 
++**++/Foo++*++ To include all routes from a
-specific package use: com/mycompany/foo/++*++ To include all routes from a 
specific package and its sub-packages use
-double wildcards: com/mycompany/foo/++**++ And to include all routes from two 
specific packages use:
-com/mycompany/foo/++*++,com/mycompany/stuff/++*++
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-native-reflection-exclude-patterns]]`link:#quarkus-camel-native-reflection-exclude-patterns[quarkus.camel.native.reflection.exclude-patterns]`
-
-A comma separated list of Ant-path style patterns to match class names that 
should be *excluded* from registering for
-reflection. Use the class name format as returned by the 
`java.lang.Class.getName()` method: package segments
-delimited by period `.` and inner classes by dollar sign `$`.
-
-This option narrows down the set selected by `include-patterns`. By default, 
no classes are excluded.
-
-This option cannot be used to unregister classes which have been registered 
internally by Quarkus extensions.
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-native-reflection-include-patterns]]`link:#quarkus-camel-native-reflection-include-patterns[quarkus.camel.native.reflection.include-patterns]`
-
-A comma separated list of Ant-path style patterns to match class names that 
should be registered for reflection. Use
-the class name format as returned by the `java.lang.Class.getName()` method: 
package segments delimited by period `.`
-and inner classes by dollar sign `$`.
-
-By default, no classes are included. The set selected by this option can be 
narrowed down by `exclude-patterns`.
-
-Note that Quarkus extensions typically register the required classes for 
reflection by themselves. This option is
-useful in situations when the built in functionality is not sufficient.
-
-Note that this option enables the full reflective access for constructors, 
fields and methods. If you need a finer
-grained control, consider using 
`io.quarkus.runtime.annotations.RegisterForReflection` annotation in your Java 
code.
-
-For this option to work properly, at least one of the following conditions 
must be satisfied:
-
-- There are no wildcards (`++*++` or `/`) in the patterns
-- The artifacts containing the selected classes contain a Jandex index 
(`META-INF/jandex.idx`)
-- The artifacts containing the selected classes are registered for indexing 
using the
-`quarkus.index-dependency.++*++` family of options in `application.properties` 
- e.g.
-
-[source,properties]
-----
-quarkus.index-dependency.my-dep.group-id = org.my-group
-quarkus.index-dependency.my-dep.artifact-id = my-artifact
-----
-
-where `my-dep` is a label of your choice to tell Quarkus that `org.my-group` 
and with `my-artifact` belong together.
-| List of `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-native-reflection-serialization-enabled]]`link:#quarkus-camel-native-reflection-serialization-enabled[quarkus.camel.native.reflection.serialization-enabled]`
-
-If `true`, basic classes are registered for serialization; otherwise basic 
classes won't be registered automatically
-for serialization in native mode. The list of classes automatically registered 
for serialization can be found in
-link:https://github.com/apache/camel-quarkus/blob/main/extensions-core/core/deployment/src/main/java/org/apache/camel/quarkus/core/deployment/CamelSerializationProcessor.java[CamelSerializationProcessor.BASE_SERIALIZATION_CLASSES].
-Setting this to `false` helps to reduce the size of the native image. In JVM 
mode, there is no real benefit of
-setting this flag to `true` except for making the behavior consistent with 
native mode.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-expression-on-build-time-analysis-failure]]`link:#quarkus-camel-expression-on-build-time-analysis-failure[quarkus.camel.expression.on-build-time-analysis-failure]`
-
-What to do if it is not possible to extract expressions from a route 
definition at build time.
-| `fail`, `warn`, `ignore`
-| `warn`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-expression-extraction-enabled]]`link:#quarkus-camel-expression-extraction-enabled[quarkus.camel.expression.extraction-enabled]`
-
-Indicates whether the expression extraction from the route definitions at 
build time must be done. If disabled, the
-expressions are compiled at runtime.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-event-bridge-enabled]]`link:#quarkus-camel-event-bridge-enabled[quarkus.camel.event-bridge.enabled]`
-
-Whether to enable the bridging of Camel events to CDI events.
-
-This allows CDI observers to be configured for Camel events. E.g. those 
belonging to the
-`org.apache.camel.quarkus.core.events`, `org.apache.camel.quarkus.main.events` 
& `org.apache.camel.impl.event`
-packages.
-
-Note that this configuration item only has any effect when observers 
configured for Camel events are present in the
-application.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-source-location-enabled]]`link:#quarkus-camel-source-location-enabled[quarkus.camel.source-location-enabled]`
-
-Build time configuration options for enable/disable camel source location.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-enabled]]`link:#quarkus-camel-trace-enabled[quarkus.camel.trace.enabled]`
-
-Enables tracer in your Camel application.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-standby]]`link:#quarkus-camel-trace-standby[quarkus.camel.trace.standby]`
-
-To set the tracer in standby mode, where the tracer will be installed, but not 
automatically enabled. The tracer can
-then be enabled explicitly later from Java, JMX or tooling.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-backlog-size]]`link:#quarkus-camel-trace-backlog-size[quarkus.camel.trace.backlog-size]`
-
-Defines how many of the last messages to keep in the tracer.
-| `int`
-| `1000`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-remove-on-dump]]`link:#quarkus-camel-trace-remove-on-dump[quarkus.camel.trace.remove-on-dump]`
-
-Whether all traced messages should be removed when the tracer is dumping. By 
default, the messages are removed, which
-means that dumping will not contain previous dumped messages.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-body-max-chars]]`link:#quarkus-camel-trace-body-max-chars[quarkus.camel.trace.body-max-chars]`
-
-To limit the message body to a maximum size in the traced message. Use 0 or 
negative value to use unlimited size.
-| `int`
-| `131072`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-body-include-streams]]`link:#quarkus-camel-trace-body-include-streams[quarkus.camel.trace.body-include-streams]`
-
-Whether to include the message body of stream based messages. If enabled then 
beware the stream may not be
-re-readable later. See more about Stream Caching.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-body-include-files]]`link:#quarkus-camel-trace-body-include-files[quarkus.camel.trace.body-include-files]`
-
-Whether to include the message body of file based messages. The overhead is 
that the file content has to be read from
-the file.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-include-exchange-properties]]`link:#quarkus-camel-trace-include-exchange-properties[quarkus.camel.trace.include-exchange-properties]`
-
-Whether to include the exchange properties in the traced message.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-include-exchange-variables]]`link:#quarkus-camel-trace-include-exchange-variables[quarkus.camel.trace.include-exchange-variables]`
-
-Whether to include the exchange variables in the traced message.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-include-exception]]`link:#quarkus-camel-trace-include-exception[quarkus.camel.trace.include-exception]`
-
-Whether to include the exception in the traced message in case of failed 
exchange.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-trace-rests]]`link:#quarkus-camel-trace-trace-rests[quarkus.camel.trace.trace-rests]`
-
-Whether to trace routes that is created from Rest DSL.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-trace-templates]]`link:#quarkus-camel-trace-trace-templates[quarkus.camel.trace.trace-templates]`
-
-Whether to trace routes that is created from route templates or kamelets.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-trace-pattern]]`link:#quarkus-camel-trace-trace-pattern[quarkus.camel.trace.trace-pattern]`
-
-Filter for tracing by route or node id.
-| `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-trace-trace-filter]]`link:#quarkus-camel-trace-trace-filter[quarkus.camel.trace.trace-filter]`
-
-Filter for tracing messages.
-| `string`
-| 
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-type-converter-statistics-enabled]]`link:#quarkus-camel-type-converter-statistics-enabled[quarkus.camel.type-converter.statistics-enabled]`
-
-Whether type converter statistics are enabled. By default, type converter 
utilization statistics are disabled. Note
-that enabling statistics incurs a minor performance impact under very heavy 
load.
-| `boolean`
-| `false`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-dev-ui-update-interval]]`link:#quarkus-camel-dev-ui-update-interval[quarkus.camel.dev-ui.update-interval]`
-
-The interval at which data is updated in Camel Quarkus Dev UI pages.
-| 
link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html[`Duration`]
 link:#duration-note-anchor-core[icon:question-circle[title=More information 
about the Duration format]]
-| `5S`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-main-shutdown-timeout]]`link:#quarkus-camel-main-shutdown-timeout[quarkus.camel.main.shutdown.timeout]`
-
-A timeout (with millisecond precision) to wait for `CamelMain++#++stop()` to 
finish
-| 
link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html[`Duration`]
 link:#duration-note-anchor-core[icon:question-circle[title=More information 
about the Duration format]]
-| `PT3S`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-main-arguments-on-unknown]]`link:#quarkus-camel-main-arguments-on-unknown[quarkus.camel.main.arguments.on-unknown]`
-
-The action to take when `CamelMain` encounters an unknown argument. fail - 
Prints the `CamelMain` usage statement and
-throws a `RuntimeException` ignore - Suppresses any warnings and the 
application startup proceeds as normal warn -
-Prints the `CamelMain` usage statement but allows the application startup to 
proceed as normal
-| `fail`, `warn`, `ignore`
-| `warn`
-
-a| 
[[camel-dataformat-data-format-configs]]`link:#camel-dataformat-data-format-configs[camel.dataformat."data-format-configs"]`
-
-Camel data format configuration.
-
-The format of the configuration is as follows.
-
-[source,properties]
-----
-camel.dataformat.<name>.<property> = value
-----
-
-For example.
-[source,properties]
-----
-camel.dataformat.beanio.stream-name = test-stream
-camel.dataformat.beanio.mapping = test-mapping.xml
-----
-| `Map<String,Map<String,String>>`
-| 
-
-a| 
[[quarkus-camel-bootstrap-enabled]]`link:#quarkus-camel-bootstrap-enabled[quarkus.camel.bootstrap.enabled]`
-
-When set to true, the {@link CamelRuntime} will be started automatically.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-routes-discovery-enabled]]`link:#quarkus-camel-routes-discovery-enabled[quarkus.camel.routes-discovery.enabled]`
-
-Enable automatic discovery of routes during static initialization.
-| `boolean`
-| `true`
-
-a|icon:lock[title=Fixed at build time] 
[[quarkus-camel-csimple-on-build-time-analysis-failure]]`link:#quarkus-camel-csimple-on-build-time-analysis-failure[quarkus.camel.csimple.on-build-time-analysis-failure]`
-
-What to do if it is not possible to extract CSimple expressions from a route 
definition at build time.
-| `fail`, `warn`, `ignore`
-| `warn`
-|===
-
-[.configuration-legend]
-{doc-link-icon-lock}[title=Fixed at build time] Configuration property fixed 
at build time. All other configuration properties are overridable at runtime.
-
-[NOTE]
-[id=duration-note-anchor-core]
-.About the Duration format
-====
-To write duration values, use the standard `java.time.Duration` format.
-See the 
link:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/Duration.html#parse(java.lang.CharSequence)[Duration#parse()
 Java API documentation] for more information.
-
-You can also use a simplified format, starting with a number:
-
-* If the value is only a number, it represents time in seconds.
-* If the value is a number followed by `ms`, it represents time in 
milliseconds.
-
-In other cases, the simplified format is translated to the 
`java.time.Duration` format for parsing:
-
-* If the value is a number followed by `h`, `m`, or `s`, it is prefixed with 
`PT`.
-* If the value is a number followed by `d`, it is prefixed with `P`.
-====
-
diff --git a/extensions-support/langchain4j/deployment/pom.xml 
b/extensions-support/langchain4j/deployment/pom.xml
index 34dc906096..d0e48ad94c 100644
--- a/extensions-support/langchain4j/deployment/pom.xml
+++ b/extensions-support/langchain4j/deployment/pom.xml
@@ -42,6 +42,11 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-support-langchain4j</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-ai-tool</artifactId>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/AiToolPresent.java
 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/AiToolPresent.java
new file mode 100644
index 0000000000..7168ec2d43
--- /dev/null
+++ 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/AiToolPresent.java
@@ -0,0 +1,36 @@
+/*
+ * 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.quarkus.component.support.langchain4j.deployment;
+
+import java.util.function.BooleanSupplier;
+
+public class AiToolPresent implements BooleanSupplier {
+    private static final String AI_TOOL_REGISTRY_CLASS = 
"org.apache.camel.component.ai.tool.AiToolRegistry";
+    private static final String AI_TOOL_SPEC_CONVERTER_CLASS = 
"org.apache.camel.component.langchain4j.agent.AiToolSpecToLangChain4j";
+
+    @Override
+    public boolean getAsBoolean() {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        try {
+            cl.loadClass(AI_TOOL_REGISTRY_CLASS);
+            cl.loadClass(AI_TOOL_SPEC_CONVERTER_CLASS);
+            return true;
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+}
diff --git 
a/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
index 79283e8693..8dcabb9aaa 100644
--- 
a/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
+++ 
b/extensions-support/langchain4j/deployment/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/deployment/SupportQuarkusLangchain4jProcessor.java
@@ -16,13 +16,19 @@
  */
 package org.apache.camel.quarkus.component.support.langchain4j.deployment;
 
+import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
 import dev.langchain4j.guardrail.Guardrail;
 import dev.langchain4j.guardrail.InputGuardrail;
 import dev.langchain4j.guardrail.OutputGuardrail;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
+import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
 import io.quarkus.arc.deployment.SyntheticBeanBuildItem;
 import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
 import io.quarkus.deployment.annotations.BuildProducer;
@@ -34,7 +40,14 @@ import 
io.quarkus.deployment.builditem.CombinedIndexBuildItem;
 import io.quarkus.deployment.builditem.SystemPropertyBuildItem;
 import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
 import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
+import io.quarkus.gizmo.ClassCreator;
+import io.quarkus.gizmo.MethodCreator;
+import io.quarkus.gizmo.MethodDescriptor;
+import io.quarkus.gizmo.ResultHandle;
 import jakarta.inject.Singleton;
+import 
org.apache.camel.quarkus.component.support.langchain4j.AiToolSpecConverter;
+import 
org.apache.camel.quarkus.component.support.langchain4j.CamelAiToolProvider;
+import 
org.apache.camel.quarkus.component.support.langchain4j.CamelAiToolsInterceptor;
 import 
org.apache.camel.quarkus.component.support.langchain4j.QuarkusLangchain4jRecorder;
 import org.jboss.jandex.AnnotationInstance;
 import org.jboss.jandex.AnnotationTarget;
@@ -53,6 +66,8 @@ class SupportQuarkusLangchain4jProcessor {
 
     public static final DotName REGISTER_AI_SERVICES_DOTNAME = DotName
             .createSimple("io.quarkiverse.langchain4j.RegisterAiService");
+    private static final DotName CAMEL_AI_TOOLS_DOTNAME = DotName
+            
.createSimple("org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools");
 
     private static final Logger LOG = 
Logger.getLogger(SupportQuarkusLangchain4jProcessor.class);
 
@@ -127,10 +142,104 @@ class SupportQuarkusLangchain4jProcessor {
                 .build());
     }
 
+    @BuildStep(onlyIf = AiToolPresent.class)
+    AdditionalBeanBuildItem registerCamelAiToolProvider() {
+        LOG.info("Camel AI Tool detected - registering CamelAiToolProvider as 
CDI bean for ToolProvider auto-discovery");
+        return 
AdditionalBeanBuildItem.unremovableOf(CamelAiToolProvider.class);
+    }
+
+    @BuildStep(onlyIf = AiToolPresent.class)
+    void generateAiToolSpecConverter(BuildProducer<GeneratedBeanBuildItem> 
generatedBeans,
+            BuildProducer<UnremovableBeanBuildItem> unremovableBeans) {
+
+        String generatedClassName = 
"org.apache.camel.quarkus.component.support.langchain4j.AiToolSpecConverterImpl";
+
+        try (ClassCreator cc = ClassCreator.builder()
+                .classOutput(new GeneratedBeanGizmoAdaptor(generatedBeans))
+                .className(generatedClassName)
+                .interfaces(AiToolSpecConverter.class)
+                .build()) {
+
+            cc.addAnnotation(Singleton.class);
+
+            String toolSpecClass = 
"dev.langchain4j.agent.tool.ToolSpecification";
+            String aiToolSpecClass = 
"org.apache.camel.component.ai.tool.AiToolSpec";
+
+            try (MethodCreator mc = cc.getMethodCreator("toToolSpecification",
+                    toolSpecClass, aiToolSpecClass)) {
+
+                ResultHandle spec = mc.getMethodParam(0);
+                ResultHandle result = mc.invokeStaticMethod(
+                        MethodDescriptor.ofMethod(
+                                
"org.apache.camel.component.langchain4j.agent.AiToolSpecToLangChain4j",
+                                "toToolSpecification",
+                                toolSpecClass,
+                                aiToolSpecClass),
+                        spec);
+                mc.returnValue(result);
+            }
+        }
+
+        unremovableBeans.produce(beanClassNames(generatedClassName));
+    }
+
+    @BuildStep(onlyIf = AiToolPresent.class)
+    @Record(ExecutionTime.STATIC_INIT)
+    void configureCamelAiToolTags(
+            CombinedIndexBuildItem combinedIndex,
+            BuildProducer<AdditionalBeanBuildItem> additionalBeans,
+            QuarkusLangchain4jRecorder recorder) {
+
+        IndexView index = combinedIndex.getIndex();
+        Map<String, String> tagMap = new HashMap<>();
+        for (AnnotationInstance annotation : 
index.getAnnotations(CAMEL_AI_TOOLS_DOTNAME)) {
+            if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {
+                String className = 
annotation.target().asClass().name().toString();
+                if (annotation.value() == null) {
+                    LOG.warnf("@CamelAiTools on %s has no value — skipping", 
className);
+                    continue;
+                }
+                String tagValue = annotation.value().asString();
+                if (tagValue.isBlank()) {
+                    LOG.warnf("@CamelAiTools on %s has blank value — 
skipping", className);
+                    continue;
+                }
+                tagMap.put(className, tagValue);
+                LOG.infof("Discovered @CamelAiTools(\"%s\") on %s", tagValue, 
className);
+            }
+        }
+
+        if (tagMap.isEmpty()) {
+            return;
+        }
+
+        recorder.setCamelAiToolTagMap(tagMap);
+
+        additionalBeans.produce(AdditionalBeanBuildItem.builder()
+                .addBeanClasses(CamelAiToolsInterceptor.class)
+                .setUnremovable()
+                .build());
+    }
+
     @BuildStep
-    void markAiServicesAsUnremovable(
+    void validateAndRegisterAiServices(
             CombinedIndexBuildItem indexBuildItem,
             BuildProducer<UnremovableBeanBuildItem> unremovableBeans) {
+
+        if (!new AiToolPresent().getAsBoolean()) {
+            Collection<AnnotationInstance> aiToolsAnnotations = 
indexBuildItem.getIndex()
+                    .getAnnotations(CAMEL_AI_TOOLS_DOTNAME);
+            if (!aiToolsAnnotations.isEmpty()) {
+                LOG.warnf("@CamelAiTools annotations found but 
camel-langchain4j-agent is not on the classpath. "
+                        + "Add camel-langchain4j-agent dependency to enable 
the Camel AI tool bridge. "
+                        + "Affected classes: %s",
+                        aiToolsAnnotations.stream()
+                                .filter(a -> a.target().kind() == 
AnnotationTarget.Kind.CLASS)
+                                .map(a -> 
a.target().asClass().name().toString())
+                                .collect(Collectors.joining(", ")));
+            }
+        }
+
         LOG.debug("Discovering classes annotated with @RegisterAiService to 
mark implementation beans as unremovable");
 
         for (AnnotationInstance instance : 
indexBuildItem.getIndex().getAnnotations(REGISTER_AI_SERVICES_DOTNAME)) {
diff --git a/extensions-support/langchain4j/runtime/pom.xml 
b/extensions-support/langchain4j/runtime/pom.xml
index 85b61f8a6e..9214158d85 100644
--- a/extensions-support/langchain4j/runtime/pom.xml
+++ b/extensions-support/langchain4j/runtime/pom.xml
@@ -50,6 +50,16 @@
             <groupId>dev.langchain4j</groupId>
             <artifactId>langchain4j-embeddings</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-ai-tool</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-langchain4j-agent</artifactId>
+            <optional>true</optional>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/AiToolSpecConverter.java
similarity index 51%
copy from 
extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
copy to 
extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/AiToolSpecConverter.java
index af6301a6c9..adf443d9fc 100644
--- 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/AiToolSpecConverter.java
@@ -16,24 +16,14 @@
  */
 package org.apache.camel.quarkus.component.support.langchain4j;
 
-import java.lang.reflect.InvocationTargetException;
+import dev.langchain4j.agent.tool.ToolSpecification;
+import org.apache.camel.component.ai.tool.AiToolSpec;
 
-import dev.langchain4j.guardrail.Guardrail;
-import io.quarkus.runtime.RuntimeValue;
-import io.quarkus.runtime.annotations.Recorder;
-import org.jboss.logging.Logger;
-
-@Recorder
-public class QuarkusLangchain4jRecorder {
-
-    public RuntimeValue<Guardrail<?, ?>> 
instantiateGuardrails(Class<Guardrail<?, ?>> guardrailClass) {
-        try {
-            return new 
RuntimeValue<>(guardrailClass.getConstructor().newInstance());
-        } catch (NoSuchMethodException | InvocationTargetException | 
InstantiationException
-                | IllegalAccessException e) {
-            Logger.getLogger(QuarkusLangchain4jRecorder.class).debugf(e,
-                    "Can not instantiate guardrail of class %s", 
guardrailClass.getName());
-            return null;
-        }
-    }
+/**
+ * Converts a Camel {@link AiToolSpec} to a langchain4j {@link 
ToolSpecification}.
+ * The implementation is generated at build time via Gizmo to avoid a 
compile-time
+ * dependency on {@code camel-langchain4j-agent}.
+ */
+public interface AiToolSpecConverter {
+    ToolSpecification toToolSpecification(AiToolSpec spec);
 }
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolProvider.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolProvider.java
new file mode 100644
index 0000000000..dbe66ddf67
--- /dev/null
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolProvider.java
@@ -0,0 +1,129 @@
+/*
+ * 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.quarkus.component.support.langchain4j;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+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.service.tool.ToolExecutor;
+import dev.langchain4j.service.tool.ToolProvider;
+import dev.langchain4j.service.tool.ToolProviderRequest;
+import dev.langchain4j.service.tool.ToolProviderResult;
+import jakarta.inject.Inject;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+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.support.DefaultExchange;
+import org.jboss.logging.Logger;
+
+/**
+ * Bridges Camel's {@link AiToolRegistry} to langchain4j's {@link 
ToolProvider} SPI. When registered as a CDI bean (done
+ * automatically by the deployment processor when both {@code camel-ai-tool} 
and quarkus-langchain4j are on the
+ * classpath), all Camel routes registered via {@code ai-tool:} endpoints 
become available to
+ * {@code @RegisterAiService} AI services without explicit configuration.
+ */
+public class CamelAiToolProvider implements ToolProvider {
+
+    private static final Logger LOG = 
Logger.getLogger(CamelAiToolProvider.class);
+    static final Map<String, String> TAG_MAP = new ConcurrentHashMap<>();
+    // Set by CamelAiToolsInterceptor before each AI service call so 
provideTools() can filter by the calling service's tag
+    private static final ThreadLocal<String> CURRENT_TAG = new ThreadLocal<>();
+
+    @Inject
+    CamelContext camelContext;
+
+    @Inject
+    ObjectMapper objectMapper;
+
+    @Inject
+    AiToolSpecConverter converter;
+
+    static String getCurrentTag() {
+        return CURRENT_TAG.get();
+    }
+
+    static void setCurrentTag(String tag) {
+        CURRENT_TAG.set(tag);
+    }
+
+    static void clearCurrentTag() {
+        CURRENT_TAG.remove();
+    }
+
+    @Override
+    public ToolProviderResult provideTools(ToolProviderRequest request) {
+        AiToolRegistry registry = AiToolRegistry.getOrCreate(camelContext);
+        String effectiveTag = CURRENT_TAG.get();
+        Set<AiToolSpec> tools = effectiveTag != null ? 
registry.getToolsByTag(effectiveTag) : registry.getAllTools();
+
+        ToolProviderResult.Builder resultBuilder = 
ToolProviderResult.builder();
+        for (AiToolSpec spec : tools) {
+            ToolSpecification toolSpec = converter.toToolSpecification(spec);
+            ToolExecutor executor = createExecutor(spec);
+            resultBuilder.add(toolSpec, executor);
+        }
+
+        return resultBuilder.build();
+    }
+
+    private ToolExecutor createExecutor(AiToolSpec spec) {
+        return (ToolExecutionRequest request, Object memoryId) -> {
+            Map<String, Object> arguments = parseArguments(request);
+            if (arguments == null) {
+                return "Invalid arguments: could not parse the provided JSON 
arguments: " + request.arguments();
+            }
+            Exchange exchange = new DefaultExchange(camelContext);
+            AiToolResult result = AiToolExecutor.execute(spec, arguments, 
exchange);
+            return toToolResponse(spec.getName(), result);
+        };
+    }
+
+    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<>() 
{
+            });
+        } catch (Exception e) {
+            LOG.debugf(e, "Failed to parse tool arguments: %s", jsonArguments);
+            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) {
+            return "Invalid arguments: " + error.message();
+        } else if (result instanceof AiToolResult.ExecutionError error) {
+            LOG.warnf("Tool '%s' execution failed: %s", toolName, 
error.message());
+            return "Tool execution failed";
+        }
+        return "Tool execution failed";
+    }
+
+}
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiTools.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiTools.java
new file mode 100644
index 0000000000..8be0eeacbf
--- /dev/null
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiTools.java
@@ -0,0 +1,48 @@
+/*
+ * 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.quarkus.component.support.langchain4j;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import jakarta.enterprise.util.Nonbinding;
+import jakarta.interceptor.InterceptorBinding;
+
+/**
+ * Filters the Camel AI tools exposed to a {@code @RegisterAiService} by tag. 
When placed on a
+ * {@code @RegisterAiService} interface, only {@code ai-tool:} routes whose 
{@code tags} parameter includes the
+ * specified value (plus any routes in the default pool) are provided to the 
AI service.
+ *
+ * <pre>
+ * &#64;RegisterAiService
+ * &#64;CamelAiTools("support")
+ * public interface SupportAgent {
+ *     String chat(@UserMessage String message);
+ * }
+ * </pre>
+ */
+@InterceptorBinding
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface CamelAiTools {
+    @Nonbinding
+    String value() default "";
+}
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolsInterceptor.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolsInterceptor.java
new file mode 100644
index 0000000000..239ab26976
--- /dev/null
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/CamelAiToolsInterceptor.java
@@ -0,0 +1,73 @@
+/*
+ * 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.quarkus.component.support.langchain4j;
+
+import jakarta.annotation.Priority;
+import jakarta.interceptor.AroundInvoke;
+import jakarta.interceptor.Interceptor;
+import jakarta.interceptor.InvocationContext;
+
+/**
+ * CDI interceptor that sets the current Camel AI tool tag on a ThreadLocal 
before an AI service method executes.
+ * This allows {@link CamelAiToolProvider#provideTools} to filter tools by the 
tag associated with the calling AI
+ * service,
+ * enabling multiple {@code @RegisterAiService} interfaces with different 
{@code @CamelAiTools} tags in the same
+ * application.
+ */
+@Interceptor
+@CamelAiTools
+@Priority(Interceptor.Priority.LIBRARY_BEFORE + 100)
+public class CamelAiToolsInterceptor {
+
+    @AroundInvoke
+    Object aroundInvoke(InvocationContext ctx) throws Exception {
+        Class<?> targetClass = ctx.getTarget().getClass();
+        String tag = resolveTag(targetClass);
+        String previous = CamelAiToolProvider.getCurrentTag();
+        if (tag != null) {
+            CamelAiToolProvider.setCurrentTag(tag);
+        }
+        try {
+            return ctx.proceed();
+        } finally {
+            if (previous != null) {
+                CamelAiToolProvider.setCurrentTag(previous);
+            } else {
+                CamelAiToolProvider.clearCurrentTag();
+            }
+        }
+    }
+
+    private String resolveTag(Class<?> targetClass) {
+        // Walk the full class hierarchy: ArC creates $$QuarkusImpl_Subclass 
extending $$QuarkusImpl,
+        // and the @CamelAiTools interface is declared on $$QuarkusImpl (not 
the subclass), so we
+        // must check superclasses and all their interfaces.
+        for (Class<?> clazz = targetClass; clazz != null && clazz != 
Object.class; clazz = clazz.getSuperclass()) {
+            String tag = CamelAiToolProvider.TAG_MAP.get(clazz.getName());
+            if (tag != null) {
+                return tag;
+            }
+            for (Class<?> iface : clazz.getInterfaces()) {
+                tag = CamelAiToolProvider.TAG_MAP.get(iface.getName());
+                if (tag != null) {
+                    return tag;
+                }
+            }
+        }
+        return null;
+    }
+}
diff --git 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
index af6301a6c9..ac23912b1b 100644
--- 
a/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
+++ 
b/extensions-support/langchain4j/runtime/src/main/java/org/apache/camel/quarkus/component/support/langchain4j/QuarkusLangchain4jRecorder.java
@@ -17,6 +17,7 @@
 package org.apache.camel.quarkus.component.support.langchain4j;
 
 import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
 
 import dev.langchain4j.guardrail.Guardrail;
 import io.quarkus.runtime.RuntimeValue;
@@ -26,6 +27,10 @@ import org.jboss.logging.Logger;
 @Recorder
 public class QuarkusLangchain4jRecorder {
 
+    public void setCamelAiToolTagMap(Map<String, String> tagMap) {
+        CamelAiToolProvider.TAG_MAP.putAll(tagMap);
+    }
+
     public RuntimeValue<Guardrail<?, ?>> 
instantiateGuardrails(Class<Guardrail<?, ?>> guardrailClass) {
         try {
             return new 
RuntimeValue<>(guardrailClass.getConstructor().newInstance());
diff --git a/extensions/ai-tool/runtime/src/main/doc/usage.adoc 
b/extensions/ai-tool/runtime/src/main/doc/usage.adoc
index 677f114f7c..36359bf410 100644
--- a/extensions/ai-tool/runtime/src/main/doc/usage.adoc
+++ b/extensions/ai-tool/runtime/src/main/doc/usage.adoc
@@ -41,3 +41,57 @@ from("ai-tool:greet?description=Greet a user"
         + "&parameter.name=string&parameter.name.required=true")
     .setBody(simple("Hello, ${header.name}!"));
 ----
+
+=== LangChain4j integration
+
+When both `camel-quarkus-ai-tool` and a Quarkus LangChain4j extension 
(`quarkus-langchain4j-ollama`, `quarkus-langchain4j-openai`, etc.) are on the 
classpath, a `ToolProvider` CDI bean is registered automatically at build time.
+All routes registered via `ai-tool:` endpoints become available to 
`@RegisterAiService` AI services without explicit wiring.
+
+You must also add `camel-langchain4j-agent` to your project dependencies. This 
artifact provides the `AiToolSpec` to `ToolSpecification` conversion and is not 
brought in transitively.
+
+[source,xml]
+----
+<dependency>
+    <groupId>org.apache.camel</groupId>
+    <artifactId>camel-langchain4j-agent</artifactId>
+</dependency>
+----
+
+With both dependencies in place, a `@RegisterAiService` interface can call 
Camel tools directly:
+
+[source,java]
+----
+@RegisterAiService
+public interface WeatherAiService {
+    String chat(@UserMessage String question);
+}
+----
+
+Any `ai-tool:` route is now callable by the LLM behind `WeatherAiService`. No 
`toolProvider` attribute or manual bean reference is needed.
+
+==== Tag filtering with `@CamelAiTools`
+
+By default, all registered `ai-tool:` routes are visible to every AI service. 
When you need different AI services to see different subsets of tools, annotate 
the service interface with `@CamelAiTools` and specify a tag value that matches 
the `tags` parameter on your `ai-tool:` routes.
+
+[source,java]
+----
+@RegisterAiService
+@CamelAiTools("weather")
+public interface WeatherAgent {
+    String chat(@UserMessage String question);
+}
+
+@RegisterAiService
+@CamelAiTools("support")
+public interface SupportAgent {
+    String chat(@UserMessage String question);
+}
+----
+
+With this setup:
+
+* `WeatherAgent` sees only tools tagged with `weather` (plus any untagged 
tools from the default pool).
+* `SupportAgent` sees only tools tagged with `support` (plus any untagged 
tools from the default pool).
+* A `@RegisterAiService` without `@CamelAiTools` sees all registered tools 
regardless of tags.
+
+NOTE: The `@CamelAiTools` value must match a tag declared in the `ai-tool:` 
endpoint URI (e.g. `from("ai-tool:getWeather?tags=weather&...")`). If the 
annotation value is blank or does not match any route tag, the AI service will 
only see untagged tools.
diff --git a/integration-tests/ai-tool-langchain4j/README.adoc 
b/integration-tests/ai-tool-langchain4j/README.adoc
new file mode 100644
index 0000000000..40a56d5e24
--- /dev/null
+++ b/integration-tests/ai-tool-langchain4j/README.adoc
@@ -0,0 +1,15 @@
+== Camel Quarkus AI Tool LangChain4j Integration Tests
+
+By default, the tests use a mock `ChatModel` that simulates tool calling 
without a real LLM.
+
+=== Running with a real Ollama LLM
+
+To run additional tests against a real Ollama model (qwen3:1.7b) via dev 
services, activate the `ollama` Maven profile.
+This requires Docker to be running.
+
+[source,shell]
+----
+./mvnw verify -f integration-tests/ai-tool-langchain4j -Pollama
+----
+
+The first run may take longer as the Ollama container image and model are 
downloaded.
diff --git a/integration-tests/ai-tool-langchain4j/pom.xml 
b/integration-tests/ai-tool-langchain4j/pom.xml
new file mode 100644
index 0000000000..433e1df189
--- /dev/null
+++ b/integration-tests/ai-tool-langchain4j/pom.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-build-parent-it</artifactId>
+        <version>3.39.0-SNAPSHOT</version>
+        <relativePath>../../poms/build-parent-it/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-integration-test-ai-tool-langchain4j</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: AI Tool LangChain4j</name>
+    <description>Integration tests for Camel AI Tool bridge with Quarkus 
LangChain4j</description>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>io.quarkiverse.langchain4j</groupId>
+                <artifactId>quarkus-langchain4j-bom</artifactId>
+                <version>${quarkiverse-langchain4j.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-ai-tool</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-bean</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-rest</artifactId>
+        </dependency>
+
+        <!-- Camel Quarkus LangChain4j support (provides the AiToolRegistry → 
ToolProvider bridge) -->
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-support-langchain4j</artifactId>
+        </dependency>
+        <!-- Required at runtime for AiToolSpec → ToolSpecification conversion 
(optional in support module) -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-langchain4j-agent</artifactId>
+        </dependency>
+        <!-- Quarkus LangChain4j -->
+        <dependency>
+            <groupId>io.quarkiverse.langchain4j</groupId>
+            <artifactId>quarkus-langchain4j-ollama</artifactId>
+        </dependency>
+
+        <!-- test dependencies -->
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.rest-assured</groupId>
+            <artifactId>rest-assured</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.native.enabled>true</quarkus.native.enabled>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>ollama</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <systemPropertyVariables>
+                                <ollama.test>true</ollama.test>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <configuration>
+                            <systemPropertyVariables>
+                                <ollama.test>true</ollama.test>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>virtualDependencies</id>
+            <activation>
+                <property>
+                    <name>!noVirtualDependencies</name>
+                </property>
+            </activation>
+            <dependencies>
+                <!-- The following dependencies guarantee that this module is 
built after them. You can update them by running `mvn process-resources 
-Pformat -N` from the source tree root directory -->
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-ai-tool-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-bean-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    <artifactId>camel-quarkus-direct-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+                <dependency>
+                    <groupId>org.apache.camel.quarkus</groupId>
+                    
<artifactId>camel-quarkus-support-langchain4j-deployment</artifactId>
+                    <version>${project.version}</version>
+                    <type>pom</type>
+                    <scope>test</scope>
+                    <exclusions>
+                        <exclusion>
+                            <groupId>*</groupId>
+                            <artifactId>*</artifactId>
+                        </exclusion>
+                    </exclusions>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>skip-testcontainers-tests</id>
+            <activation>
+                <property>
+                    <name>skip-testcontainers-tests</name>
+                </property>
+            </activation>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </profile>
+    </profiles>
+</project>
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaResource.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaResource.java
new file mode 100644
index 0000000000..60fdd44967
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaResource.java
@@ -0,0 +1,54 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.service.WeatherAiServiceOllama;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.service.WeatherAiServiceOllamaWrongTag;
+
+@Path("/ai-tool-langchain4j-ollama")
+@ApplicationScoped
+public class AiToolLangchain4jOllamaResource {
+
+    @Inject
+    WeatherAiServiceOllama weatherAiService;
+
+    @Inject
+    WeatherAiServiceOllamaWrongTag weatherAiServiceWrongTag;
+
+    @Path("/chat")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String chat(String message) {
+        return weatherAiService.chat(message);
+    }
+
+    @Path("/chat-wrong-tag")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String chatWrongTag(String message) {
+        return weatherAiServiceWrongTag.chat(message);
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jResource.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jResource.java
new file mode 100644
index 0000000000..82770665ac
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jResource.java
@@ -0,0 +1,90 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.ai.tool.AiToolRegistry;
+import org.apache.camel.component.ai.tool.AiToolSpec;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.service.AdminAiService;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.service.WeatherAiService;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.service.WeatherAiServiceWrongTag;
+
+@Path("/ai-tool-langchain4j")
+@ApplicationScoped
+public class AiToolLangchain4jResource {
+
+    @Inject
+    CamelContext camelContext;
+
+    @Inject
+    WeatherAiService weatherAiService;
+
+    @Inject
+    AdminAiService adminAiService;
+
+    @Inject
+    WeatherAiServiceWrongTag weatherAiServiceWrongTag;
+
+    @Path("/weather/chat")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String weatherChat(String message) {
+        return weatherAiService.chat(message);
+    }
+
+    @Path("/admin/chat")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String adminChat(String message) {
+        return adminAiService.chat(message);
+    }
+
+    @Path("/weather-wrong-tag/chat")
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.TEXT_PLAIN)
+    public String weatherChatWrongTag(String message) {
+        return weatherAiServiceWrongTag.chat(message);
+    }
+
+    @Path("/tools/{tag}")
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    public String listToolsByTag(@PathParam("tag") String tag) {
+        AiToolRegistry registry = AiToolRegistry.getOrCreate(camelContext);
+        Set<AiToolSpec> tools = registry.getToolsByTag(tag);
+        return tools.stream()
+                .map(AiToolSpec::getName)
+                .sorted()
+                .collect(Collectors.joining(","));
+    }
+
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jRoutes.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jRoutes.java
new file mode 100644
index 0000000000..8f8b45acf6
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jRoutes.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.ai.tool.langchain4j.it;
+
+import org.apache.camel.builder.RouteBuilder;
+
+public class AiToolLangchain4jRoutes extends RouteBuilder {
+    @Override
+    public void configure() {
+        from("ai-tool:getWeather?"
+                + "tags=weatherTag"
+                + "&description=Get the current weather for a city"
+                + "&parameter.city=string"
+                + "&parameter.city.required=true"
+                + "&parameter.city.description=The city name")
+                .setBody(simple("Sunny in ${header.city}, 1111 celsius"));
+
+        from("ai-tool:getNews?"
+                + "tags=adminTag"
+                + "&description=Get the latest news about a topic"
+                + "&parameter.topic=string"
+                + "&parameter.topic.required=true"
+                + "&parameter.topic.description=The news topic")
+                .setBody(simple("Latest news about ${header.topic}"));
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AbstractToolCallingChatModel.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AbstractToolCallingChatModel.java
new file mode 100644
index 0000000000..a4be0986b9
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AbstractToolCallingChatModel.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.ai.tool.langchain4j.it.model;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import dev.langchain4j.agent.tool.ToolExecutionRequest;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.ChatMessage;
+import dev.langchain4j.data.message.ToolExecutionResultMessage;
+import dev.langchain4j.model.chat.ChatModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+
+/**
+ * Simulates the two-turn tool-calling protocol used by langchain4j:
+ *
+ * <ol>
+ * <li><b>Turn 1</b> — langchain4j sends the user message and available tool 
specifications to the model.
+ * The model responds with a {@link ToolExecutionRequest} ("I want to call 
tool X with args Y").
+ * No tool is executed yet.</li>
+ * <li><b>Tool execution</b> — langchain4j sees the request, invokes the 
matching {@code ToolExecutor}
+ * (in our case the Camel {@code ai-tool:} route), and captures the 
result.</li>
+ * <li><b>Turn 2</b> — langchain4j calls the model again, appending a {@link 
ToolExecutionResultMessage}
+ * with the tool's output. The model returns a final text answer.</li>
+ * </ol>
+ *
+ * Subclasses only define which tool to call and how to format the final 
response.
+ */
+public abstract class AbstractToolCallingChatModel implements 
Supplier<ChatModel> {
+
+    // Correlation ID for matching ToolExecutionResultMessage back to the 
request — required by the
+    // builder but the actual value is irrelevant in tests with a single tool 
call per turn.
+    protected abstract String toolCallId();
+
+    protected abstract String toolName();
+
+    protected abstract String toolArguments();
+
+    protected abstract String formatResponse(String toolResult);
+
+    protected abstract String getNameOfService();
+
+    @Override
+    public ChatModel get() {
+        return new ChatModel() {
+            @Override
+            public ChatResponse doChat(ChatRequest chatRequest) {
+                List<ChatMessage> messages = chatRequest.messages();
+
+                boolean hasToolResult = messages.stream()
+                        .anyMatch(m -> m instanceof 
ToolExecutionResultMessage);
+
+                if (!hasToolResult) {
+                    ToolExecutionRequest toolRequest = 
ToolExecutionRequest.builder()
+                            .id(toolCallId())
+                            .name(toolName())
+                            .arguments(toolArguments())
+                            .build();
+                    return ChatResponse.builder()
+                            .aiMessage(AiMessage.from(toolRequest))
+                            .build();
+                }
+
+                // #2 tool's response already present
+                String toolResult = messages.stream()
+                        .filter(m -> m instanceof ToolExecutionResultMessage)
+                        .map(m -> ((ToolExecutionResultMessage) m).text())
+                        .findFirst()
+                        .orElse("unknown");
+
+                return ChatResponse.builder()
+                        .aiMessage(new AiMessage(formatResponse(toolResult)))
+                        .build();
+            }
+        };
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AdminToolCallingChatModel.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AdminToolCallingChatModel.java
new file mode 100644
index 0000000000..2bff6c1e12
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/AdminToolCallingChatModel.java
@@ -0,0 +1,45 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.model;
+
+public class AdminToolCallingChatModel extends AbstractToolCallingChatModel {
+
+    @Override
+    protected String getNameOfService() {
+        return "adminTag";
+    }
+
+    @Override
+    protected String toolCallId() {
+        return "call_admin_1";
+    }
+
+    @Override
+    protected String toolName() {
+        return "getNews";
+    }
+
+    @Override
+    protected String toolArguments() {
+        return "{\"topic\":\"camel\"}";
+    }
+
+    @Override
+    protected String formatResponse(String toolResult) {
+        return "News result: " + toolResult;
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WeatherToolCallingChatModel.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WeatherToolCallingChatModel.java
new file mode 100644
index 0000000000..4a52902d80
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WeatherToolCallingChatModel.java
@@ -0,0 +1,45 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.model;
+
+public class WeatherToolCallingChatModel extends AbstractToolCallingChatModel {
+
+    @Override
+    protected String getNameOfService() {
+        return "weatherTag";
+    }
+
+    @Override
+    protected String toolCallId() {
+        return "call_1";
+    }
+
+    @Override
+    protected String toolName() {
+        return "getWeather";
+    }
+
+    @Override
+    protected String toolArguments() {
+        return "{\"city\":\"Prague\"}";
+    }
+
+    @Override
+    protected String formatResponse(String toolResult) {
+        return toolResult;
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WrongTagToolCallingChatModel.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WrongTagToolCallingChatModel.java
new file mode 100644
index 0000000000..a4c1803a46
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/model/WrongTagToolCallingChatModel.java
@@ -0,0 +1,78 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.model;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import dev.langchain4j.agent.tool.ToolExecutionRequest;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.ChatMessage;
+import dev.langchain4j.data.message.ToolExecutionResultMessage;
+import dev.langchain4j.model.chat.ChatModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+
+/**
+ * Mock model for testing tag isolation. Calls {@code getWeather} only if it 
appears in the
+ * available tool specifications — when the interceptor works correctly and 
this service is
+ * tagged with {@code adminTag}, the weather tool should NOT be visible.
+ */
+public class WrongTagToolCallingChatModel implements Supplier<ChatModel> {
+
+    @Override
+    public ChatModel get() {
+        return new ChatModel() {
+            @Override
+            public ChatResponse doChat(ChatRequest chatRequest) {
+                List<ChatMessage> messages = chatRequest.messages();
+                boolean hasToolResult = messages.stream()
+                        .anyMatch(m -> m instanceof 
ToolExecutionResultMessage);
+
+                if (!hasToolResult) {
+                    boolean weatherToolAvailable = 
chatRequest.toolSpecifications() != null
+                            && chatRequest.toolSpecifications().stream()
+                                    .anyMatch(ts -> 
"getWeather".equals(ts.name()));
+
+                    if (weatherToolAvailable) {
+                        ToolExecutionRequest request = 
ToolExecutionRequest.builder()
+                                .id("call_wrong_tag")
+                                .name("getWeather")
+                                .arguments("{\"city\":\"Prague\"}")
+                                .build();
+                        return ChatResponse.builder()
+                                .aiMessage(AiMessage.from(request))
+                                .build();
+                    }
+
+                    return ChatResponse.builder()
+                            .aiMessage(new AiMessage("No weather tool 
available"))
+                            .build();
+                }
+
+                String toolResult = messages.stream()
+                        .filter(m -> m instanceof ToolExecutionResultMessage)
+                        .map(m -> ((ToolExecutionResultMessage) m).text())
+                        .findFirst()
+                        .orElse("unknown");
+                return ChatResponse.builder()
+                        .aiMessage(new AiMessage(toolResult))
+                        .build();
+            }
+        };
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/AdminAiService.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/AdminAiService.java
new file mode 100644
index 0000000000..b54e0d4d12
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/AdminAiService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.service;
+
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+import jakarta.enterprise.context.ApplicationScoped;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.model.AdminToolCallingChatModel;
+import org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools;
+
+@ApplicationScoped
+@RegisterAiService(chatLanguageModelSupplier = AdminToolCallingChatModel.class)
+@CamelAiTools("adminTag")
+public interface AdminAiService {
+
+    String chat(@UserMessage String message);
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiService.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiService.java
new file mode 100644
index 0000000000..9a1e8501a1
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiService.java
@@ -0,0 +1,31 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.service;
+
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+import jakarta.enterprise.context.ApplicationScoped;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.model.WeatherToolCallingChatModel;
+import org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools;
+
+@ApplicationScoped
+@RegisterAiService(chatLanguageModelSupplier = 
WeatherToolCallingChatModel.class)
+@CamelAiTools("weatherTag")
+public interface WeatherAiService {
+
+    String chat(@UserMessage String message);
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllama.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllama.java
new file mode 100644
index 0000000000..76829813cb
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllama.java
@@ -0,0 +1,30 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.service;
+
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools;
+
+@ApplicationScoped
+@RegisterAiService
+@CamelAiTools("weatherTag")
+public interface WeatherAiServiceOllama {
+
+    String chat(@UserMessage String message);
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllamaWrongTag.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllamaWrongTag.java
new file mode 100644
index 0000000000..1545589a33
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceOllamaWrongTag.java
@@ -0,0 +1,30 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.service;
+
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+import jakarta.enterprise.context.ApplicationScoped;
+import org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools;
+
+@ApplicationScoped
+@RegisterAiService
+@CamelAiTools("adminTag")
+public interface WeatherAiServiceOllamaWrongTag {
+
+    String chat(@UserMessage String message);
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceWrongTag.java
 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceWrongTag.java
new file mode 100644
index 0000000000..7e4a78d7b6
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/service/WeatherAiServiceWrongTag.java
@@ -0,0 +1,31 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it.service;
+
+import dev.langchain4j.service.UserMessage;
+import io.quarkiverse.langchain4j.RegisterAiService;
+import jakarta.enterprise.context.ApplicationScoped;
+import 
org.apache.camel.quarkus.component.ai.tool.langchain4j.it.model.WrongTagToolCallingChatModel;
+import org.apache.camel.quarkus.component.support.langchain4j.CamelAiTools;
+
+@ApplicationScoped
+@RegisterAiService(chatLanguageModelSupplier = 
WrongTagToolCallingChatModel.class)
+@CamelAiTools("adminTag")
+public interface WeatherAiServiceWrongTag {
+
+    String chat(@UserMessage String message);
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/main/resources/application.properties
 
b/integration-tests/ai-tool-langchain4j/src/main/resources/application.properties
new file mode 100644
index 0000000000..a58bbb874a
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+## ---------------------------------------------------------------------------
+## 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.
+## ---------------------------------------------------------------------------
+quarkus.devservices.enabled=false
+quarkus.langchain4j.ollama.chat-model.model-id=qwen3:1.7b
diff --git 
a/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jIT.java
 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jIT.java
new file mode 100644
index 0000000000..40dd473753
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jIT.java
@@ -0,0 +1,23 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+
+@QuarkusIntegrationTest
+class AiToolLangchain4jIT extends AiToolLangchain4jTest {
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaIT.java
 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaIT.java
new file mode 100644
index 0000000000..b263b5abc2
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaIT.java
@@ -0,0 +1,25 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import io.quarkus.test.junit.QuarkusIntegrationTest;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+
+@QuarkusIntegrationTest
+@EnabledIfSystemProperty(named = "ollama.test", matches = "true")
+class AiToolLangchain4jOllamaIT extends AiToolLangchain4jOllamaTest {
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaTest.java
 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaTest.java
new file mode 100644
index 0000000000..d4b5fef08d
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jOllamaTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import java.util.Map;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.quarkus.test.junit.QuarkusTestProfile;
+import io.quarkus.test.junit.TestProfile;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+
+@QuarkusTest
+@TestProfile(AiToolLangchain4jOllamaTest.OllamaProfile.class)
+@EnabledIfSystemProperty(named = "ollama.test", matches = "true")
+class AiToolLangchain4jOllamaTest {
+
+    @Test
+    void weatherFromToolTest() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What is the weather in Prague?")
+                .post("/ai-tool-langchain4j-ollama/chat")
+                .then()
+                .statusCode(200)
+                .body(containsString("1111"));
+    }
+
+    // Verifies that the @CamelAiTools interceptor filters tools by tag: a 
service tagged "adminTag"
+    // should not see the getWeather tool (tagged "weatherTag"), so the real 
LLM won't call it
+    // and "1111" won't appear in the response. Fails if the interceptor is 
broken and all tools are visible.
+    @Test
+    void weatherWithWrongTag() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What is the weather in Prague?")
+                .post("/ai-tool-langchain4j-ollama/chat-wrong-tag")
+                .then()
+                .statusCode(200)
+                .body(not(containsString("1111")));
+    }
+
+    public static class OllamaProfile implements QuarkusTestProfile {
+        @Override
+        public Map<String, String> getConfigOverrides() {
+            return Map.of(
+                    "quarkus.devservices.enabled", "true");
+        }
+    }
+}
diff --git 
a/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jTest.java
 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jTest.java
new file mode 100644
index 0000000000..2b7cf401a6
--- /dev/null
+++ 
b/integration-tests/ai-tool-langchain4j/src/test/java/org/apache/camel/quarkus/component/ai/tool/langchain4j/it/AiToolLangchain4jTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.quarkus.component.ai.tool.langchain4j.it;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.RestAssured;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.not;
+
+@QuarkusTest
+class AiToolLangchain4jTest {
+
+    @Test
+    void weatherServiceTest() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What is the weather in Prague?")
+                .post("/ai-tool-langchain4j/weather/chat")
+                .then()
+                .statusCode(200)
+                .body(containsString("1111"));
+    }
+
+    @Test
+    void weatherServiceTestWithWrongTag() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What is the weather in Prague?")
+                .post("/ai-tool-langchain4j/admin/chat")
+                .then()
+                .statusCode(200)
+                .body(containsString("Latest news about camel"));
+    }
+
+    @Test
+    void aiToolRegistryToolsByWeatherTagTest() {
+        RestAssured.given()
+                .get("/ai-tool-langchain4j/tools/weatherTag")
+                .then()
+                .statusCode(200)
+                .body(containsString("getWeather"))
+                .body(not(containsString("getNews")));
+    }
+
+    @Test
+    void aiToolRegistryToolsByAdminTagTest() {
+        RestAssured.given()
+                .get("/ai-tool-langchain4j/tools/adminTag")
+                .then()
+                .statusCode(200)
+                .body(containsString("getNews"))
+                .body(not(containsString("getWeather")));
+    }
+
+    @Test
+    void adminServiceTest() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What are the latest news about camel?")
+                .post("/ai-tool-langchain4j/admin/chat")
+                .then()
+                .statusCode(200)
+                .body(containsString("camel"))
+                .body(containsString("news"));
+    }
+
+    // Verifies that the @CamelAiTools interceptor filters tools by tag: a 
service tagged "adminTag"
+    // should not see the getWeather tool (tagged "weatherTag"), so the mock 
model won't call it
+    // and "1111" won't appear in the response. Fails if the interceptor is 
broken and all tools are visible.
+    @Test
+    void weatherWithWrongTagTest() {
+        RestAssured.given()
+                .contentType("text/plain")
+                .body("What is the weather in Prague?")
+                .post("/ai-tool-langchain4j/weather-wrong-tag/chat")
+                .then()
+                .statusCode(200)
+                .body(not(containsString("1111")));
+    }
+
+}
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 8ffee5a4dd..ce58500c83 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -52,6 +52,7 @@
         <module>activemq</module>
         <module>activemq6</module>
         <module>ai-tool</module>
+        <module>ai-tool-langchain4j</module>
         <module>amqp</module>
         <module>arangodb</module>
         <module>as2</module>
diff --git a/tooling/scripts/test-categories.yaml 
b/tooling/scripts/test-categories.yaml
index a4df390265..97b679b994 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -232,6 +232,7 @@ group-11:
   - xslt-saxon
 group-12:
   - ai-tool
+  - ai-tool-langchain4j
   - aws2-grouped
   - csimple
   - github2

Reply via email to