Skip to content

CAMEL-24309: camel-ai-tool - AiToolRegistry listener SPI for tool registration changes - #25301

Open
Croway wants to merge 1 commit into
apache:mainfrom
Croway:CAMEL-24309-ai-tool-registry-listener
Open

CAMEL-24309: camel-ai-tool - AiToolRegistry listener SPI for tool registration changes#25301
Croway wants to merge 1 commit into
apache:mainfrom
Croway:CAMEL-24309-ai-tool-registry-listener

Conversation

@Croway

@Croway Croway commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

CAMEL-24309: AiToolRegistry listener SPI for tool registration changes

Sub-task of CAMEL-24308 (camel-mcp-server). JIRA: CAMEL-24309

Changes

Adds a listener SPI to the camel-ai-tool registry so adapters can react to tools appearing/disappearing instead of polling — the prerequisite for the MCP server's tools/list_changed notification.

  • New AiToolRegistryListener interface with toolRegistered(String tag, AiToolSpec spec) / toolDeregistered(String tag, AiToolSpec spec); tag == null denotes the default (untagged) pool, and a multi-tag endpoint fires one event per tag.
  • AiToolRegistry.addListener/removeListener; callbacks fire outside the registry lock (so a listener can safely re-read the registry), only on actual state changes (idempotent re-put of the same spec and removal of an absent spec fire nothing, a rejected duplicate-name registration fires nothing), and a throwing listener is logged without affecting the registration or other listeners.
  • Javadoc documents the subscribe-then-snapshot idiom for observing current state without missing concurrent events.

Existing adapters (langchain4j-agent, spring-ai-chat) re-query the registry per exchange and are unaffected.

Testing

  • AiToolRegistryListenerTest — registry-level semantics (8 tests: event on put/remove, default pool null tag, no event on no-op or rejected mutations, listener isolation, removeListener).
  • AiToolRegistryListenerLifecycleTest — events driven by real ai-tool route lifecycle (4 tests: start/stop, suspend/resume, multi-tag, untagged default pool).

All 12 new tests pass; full camel-ai-tool module test run is green.


This PR was written by Claude Code on behalf of Federico Mariani (@Croway).

🤖 Generated with Claude Code

…istration changes

Add AiToolRegistryListener with toolRegistered/toolDeregistered callbacks
fired on ai-tool consumer lifecycle events (route start/resume registers,
stop/suspend deregisters). Callbacks fire outside the registry lock, only
on actual state changes, and a failing listener cannot break registration.
Prerequisite for MCP tools/list_changed notifications (CAMEL-24308).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Croway
Croway requested a review from orpiske August 3, 2026 07:31
@Croway Croway added the enhancement New feature or request label Aug 3, 2026
@Croway
Croway requested review from davsclaus and zbendhiba August 3, 2026 07:31

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review was generated by Claude Code, an AI assistant, on behalf of @gnodet.

This is a well-crafted SPI addition. The implementation is clean and the test coverage is thorough. Approving with a few minor suggestions below.

What works well

  • Lock discipline: Notifications fire outside the ReentrantLock, so listeners can safely re-read the registry (e.g., call getTools()) without deadlocking. This is documented in the AiToolRegistryListener Javadoc.
  • Error isolation: A throwing listener is caught and logged without affecting the registration itself or other listeners. This is verified by testListenerExceptionDoesNotBreakRegistrationOrOtherListeners.
  • Idempotent no-ops: Re-adding the same spec instance fires no duplicate event; removing an absent spec fires nothing. Both are tested.
  • Test quality: Tests follow all Camel conventions -- package-private classes, AssertJ, no Thread.sleep(), no JUnit public. The lifecycle test uses CopyOnWriteArrayList for thread safety while the unit test correctly uses plain ArrayList.
  • @since 4.22 on the new AiToolRegistryListener interface.

Minor suggestions

  1. removeListener missing Javadoc — For consistency with addListener (which has a doc block), consider adding a brief Javadoc comment, e.g.:

    /**
     * Removes a previously added listener. No-op if the listener was not registered.
     */
    public void removeListener(AiToolRegistryListener listener) {
  2. No null guard on addListener — If null is passed, CopyOnWriteArrayList accepts it silently. Later, during notification, listener.toolRegistered(...) throws NPE which is caught and logged as a generic warning — making the root cause hard to diagnose. An early Objects.requireNonNull would fail fast:

    public void addListener(AiToolRegistryListener listener) {
        Objects.requireNonNull(listener, "listener");
        listeners.add(listener);
    }
  3. Concurrency ordering caveat — Since notifications fire outside the lock, two concurrent threads performing put and remove on the same spec could theoretically deliver deregistered before registered. In practice Camel route lifecycle is sequential per route, so this is unlikely. But since the Javadoc already documents the "subscribe-then-snapshot" idiom (showing attention to concurrency semantics), consider adding a note: "Notification ordering is guaranteed within a single thread but not across concurrent threads."

All minor — none are blockers. Nice work!

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-ai/camel-ai-tool

🔬 Scalpel shadow comparison — Scalpel: 11 tested, 29 compile-only — current: 11 all tested

Maveniverse Scalpel detected 40 affected modules (current approach: 11).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 11 modules (1 direct + 10 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (11)
  • camel-ai-tool
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-langchain4j-agent
  • camel-launcher-container
  • camel-spring-ai-chat
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (40 modules)
  • Camel :: AI :: LangChain4j :: Agent
  • Camel :: AI :: Tool
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: Component DSL
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: Kamelet Main
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Spring AI :: Chat
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin

⚙️ View full build and test results

@zbendhiba

Copy link
Copy Markdown
Contributor

LGTM!

@JiriOndrusek please review if there's an impact for Camel quarkus ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants