You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by "oscerd (via GitHub)" <gi...@apache.org> on 2026/10/12 08:06:41 UTC
[PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
oscerd opened a new pull request, #27714:
URL: https://github.com/apache/camel/pull/27714
CAMEL-25408: AI events — a common `AiEvent` API and an `Ai` event type in core, instead of component-specific `Custom` events.
## Problem
AI components fire their own `CamelEvent` classes, each typed `CamelEvent.Type.Custom`:
- `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticLoopCompletedEvent`, `OpenAIAgenticToolCallExecutedEvent`
- `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` (CAMEL-25404)
Because each is component-specific and only typed `Custom`, an `EventNotifier` (micrometer, dev console, management, a GenAI-observability backend) has to depend on every AI component and `instanceof` each class to recognise them, and `Type.Custom` says nothing about what the event is. None of them implemented `ExchangeEvent` either, although they all carry the exchange. GenAI observability (spans/metrics) already went shared on purpose (`camel-ai-observability-api`); the events were drifting the other way.
## What this does
Adds the AI event contract to the existing `org.apache.camel.ai` package in `core/camel-api`, and moves the component events onto it — **before the events ship in any release** (they are not in the `camel-4.23.0` tag), so the component-specific `Custom` events never reach a release.
**core/camel-api** (`@since 4.23`):
- a new `CamelEvent.Type.Ai` value;
- `AiEvent extends CamelEvent.ExchangeEvent` — the shared contract: `getProvider()` (a low-cardinality label such as `openai` / `ai-tool`), the exchange (for correlation), and `getType()` defaulted to `Ai`;
- nested sub-interfaces for what exists today: `ToolCallDeniedEvent` (also a `FailureEvent`, carrying the `CamelAuthorizationException`), `ToolCallExecutedEvent`, `AgentLoopStartedEvent`, `AgentLoopCompletedEvent`.
**camel-openai / camel-ai-tool**: the event classes stay in the components but now implement these interfaces and are `Type.Ai`; `getProvider()` returns `openai` / `ai-tool`. (`OpenAIAgenticToolCallExecutedEvent.getDurationMs()` → `getDurationMillis()` to match the interface — it had not shipped.)
**core/camel-management**: `ManagedEventNotifier` skips `Type.Ai` when building MBean notification infos, as it already does for `Custom` (AI events are concrete classes with their own notification names).
A listener can now do `event instanceof AiEvent` (or switch on `Type.Ai`) and read `getProvider()` / the sub-interface with no dependency on an AI component — which is what lets `camel-ai-observability` turn any `AiEvent` into metrics/spans with a single `EventNotifier` (a follow-up this enables).
## Design notes
- **No `ignoreAiEvents` flag** (an open question in the issue): these events are fired through `ManagementStrategy.notify()`, which delivers to every notifier and does **not** consult the `EventNotifier` ignore flags (those are applied on the `EventHelper` lifecycle-event path). A notifier that wants to drop AI events filters them in its own `isEnabled`/`notify`, so the flag would have no effect on the firing path and is not added. `AiEvent` is an `ExchangeEvent`, so it is still correlatable by exchange.
- `camel-event`'s `CamelEvent.Type` switch has a `default`, so the new value is handled there without change.
## Tests & docs
- Updated the existing event tests (`OpenAIAgenticEventNotifierTest`, `OpenAIResponsesAgenticTest`, `AiToolAuthorizationDeniedEventTest`) to recognise the events as `Type.Ai`; they assert the same behaviour through the new contract.
- `ai-tool-component.adoc` (Observing denials) and `openai-mcp.adoc` now describe the events as `AiEvent`s and match on the shared interface; catalog mirrors regenerated.
- No upgrade-guide entry: the component-specific `Custom` events never shipped (not in the `camel-4.23.0` tag), so there is nothing to migrate.
`main` only.
---
_Claude Code on behalf of oscerd_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on PR #27714:
URL: https://github.com/apache/camel/pull/27714#issuecomment-6140628069
Rebased onto latest `main` to clear the `camel-4x-upgrade-guide-4_24.adoc` conflict (the 4.24 guide grew to 22 sections overnight).
The rebase is **code-identical** to the previously-approved state — every `.java` file, catalog mirror and component doc is byte-for-byte unchanged (verified by diffing the files this branch owns against the prior approved head; only the upgrade guide differs). The one change is that the AI-events upgrade-guide entry now sits **between** existing sections (after `camel-lra`, before `camel-report-maven-plugin`) rather than at end-of-file, so it stops re-conflicting with new end-of-file notes.
Re-requesting @davsclaus and @luigidemasi — the rebase staled the prior approvals; there is no new code to re-review, this just restores them on the new head. CI is running.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4250245358
##########
core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEventNotifier.java:
##########
@@ -168,8 +168,8 @@ public MBeanNotificationInfo[] getNotificationInfo() {
// JmxNotificationEventNotifier uses the simple class name of the event as the notification type
List<MBeanNotificationInfo> infos = new ArrayList<>();
for (CamelEvent.Type type : CamelEvent.Type.values()) {
- if (type == CamelEvent.Type.Custom) {
- // custom events have their own class names
+ if (type == CamelEvent.Type.Custom || type == CamelEvent.Type.Ai) {
Review Comment:
Added in 122f4ab89c04 — `ManagedEventNotifierMBean` now declares `isIgnoreAiEvents()`/`setIgnoreAiEvents()` and `ManagedEventNotifier` delegates them, so the flag is visible and settable over JMX (JConsole/Hawtio) like every other ignore* flag.
_Claude Code on behalf of oscerd_
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -27,3 +27,33 @@ A `hashicorp:` property with a field of a secret that does not exist, such as `{
now resolves to no value, as it already did without a field, so its default value or an optional placeholder
(`{{?hashicorp:secret:missing#field}}`) applies. Before, without a default value, it failed with a
`NullPointerException`.
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. Events that relate to a single exchange implement the exchange-backed subtype
+`AiEvent.ExchangeAiEvent` (the root `AiEvent` itself is not an `ExchangeEvent`). This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`). An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because the shipped AI events are now `ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`), a notifier that filters on
+`instanceof ExchangeEvent` now also receives them. AI events are their own category: a new `ignoreAiEvents` flag
+(`EventNotifier.setIgnoreAiEvents(boolean)`, default `false`) opts a notifier out, and `ignoreExchangeEvents` does
+**not** drop AI events (so an AI-observability notifier can keep `ignoreExchangeEvents=true` for performance). Camel's
+own exchange-oriented notifiers (the debugger, the dev-console event ring, the micrometer exchange notifier) set
+`ignoreAiEvents=true` so AI events do not reach them; a custom exchange-focused notifier that should not see AI events
Review Comment:
Applied your suggestion in 122f4ab89c04 — the opt-out list now reads "the micrometer and OpenTelemetry metrics exchange notifiers".
_Claude Code on behalf of oscerd_
##########
components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventConsumer.java:
##########
@@ -309,6 +310,10 @@ private void configureEventNotifier() {
// Custom events are CamelContextEvents, so we need to enable context events
eventNotifier.setIgnoreCamelContextEvents(false);
break;
+ case Ai:
Review Comment:
Done in 122f4ab89c04 — added an `=== AI Events` group listing `Ai` (with a pointer to `org.apache.camel.ai.AiEvent`) in event-component.adoc and regenerated the catalog copy, so `event:Ai` is discoverable. Left the optional `event:Ai` subscription test as a follow-up.
_Claude Code on behalf of oscerd_
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -199,6 +231,75 @@ public void notify(CamelEvent event) {
AiToolResult result = AiToolExecutor.execute(spec, Map.of(), exchange);
assertThat(result).isInstanceOf(AiToolResult.AuthorizationDenied.class);
+ // the healthy @BeforeEach notifier still received the event despite the other one throwing
+ assertThat(events).hasSize(1);
Review Comment:
Already covered on the current head — the test was reworked: a healthy subscriber (`later`) is registered AFTER the failing notifiers and the test asserts IT received the event, so it proves delivery continues past a failure (not just ordering). It also exercises isIgnoreAiEvents/isEnabled/notify throwing, AI-scoped so teardown is unaffected.
_Claude Code on behalf of oscerd_
##########
core/camel-support/src/main/java/org/apache/camel/support/EventHelper.java:
##########
@@ -1574,6 +1576,49 @@ public static boolean notifyExchangeAsyncProcessingStartedEvent(CamelContext con
return answer;
}
+ /**
+ * Notifies an {@link AiEvent} to the started event notifiers, following the same path as every other event
+ * category: it loops the started notifiers, skips those that are disabled or have {@code ignoreAiEvents} set,
+ * creates the event lazily (via {@code eventSupplier}) only when some notifier wants it, and delivers through
+ * {@code doNotifyEvent} so one failing notifier does not stop delivery to the others.
+ * <p>
+ * AI events are their own category: {@code ignoreExchangeEvents} does <em>not</em> suppress them even though an
+ * {@code AiEvent} is an exchange event. A notifier opts out with {@code setIgnoreAiEvents(true)}.
+ *
+ * @since 4.24
+ */
+ public static boolean notifyAiEvent(CamelContext context, Supplier<AiEvent> eventSupplier) {
+ ManagementStrategy management = context != null ? context.getManagementStrategy() : null;
+ if (management == null) {
+ return false;
+ }
+
+ List<EventNotifier> notifiers = management.getStartedEventNotifiers();
+ if (notifiers == null || notifiers.isEmpty()) {
+ return false;
+ }
+
+ boolean answer = false;
+ CamelEvent event = null;
+ // optimise for loop using index access to avoid creating iterator object
+ for (int i = 0; i < notifiers.size(); i++) {
+ EventNotifier notifier = notifiers.get(i);
+ if (notifier.isDisabled() || notifier.isIgnoreAiEvents()) {
+ continue;
+ }
+
+ if (event == null) {
+ // only create event once, and only when a notifier wants it
+ event = eventSupplier.get();
+ if (event == null) {
+ return false;
+ }
+ }
+ answer |= doNotifyEvent(notifier, event);
Review Comment:
Went ahead and added it — `OpenTelemetryExchangeEventNotifier` (and the micrometer one) set `setIgnoreAiEvents(true)` in their constructors, so AI events are skipped in `notifyAiEvent` before the per-event route lookup. Thanks for the note.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4245954129
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
Review Comment:
⚠️ **Design decision reversal — implicit side-effects to audit**
The original `AiToolAuthorizationDeniedEvent` Javadoc (visible in the `camel-4.23.0` tag) said _"deliberately not a `CamelEvent.ExchangeEvent`, so it does not pollute generic exchange lifecycle metrics"_. This PR inverts that decision.
The consequence is that all AI events now flow through code that branches on `instanceof ExchangeEvent`:
- **`EventConsole`** routes them into the `exchangeEvents` ring buffer alongside regular exchange lifecycle events.
- **`DefaultDebugger`** enables itself for `instanceof ExchangeEvent` — AI events trigger that path.
- **`CamelEventJsonSupport`** serialises the `exchange` payload for `instanceof ExchangeEvent` events.
If the goal is just to inherit `getSource()` / `getExchange()` defaults, consider keeping `AiEvent extends CamelEvent` and adding an explicit `Exchange getExchange()` method:
```suggestion
public interface AiEvent extends CamelEvent {
/** The exchange the event relates to (for route-id / exchange-id correlation). */
Exchange getExchange();
```
Either way, please confirm the `EventConsole` / `DefaultDebugger` / `CamelEventJsonSupport` side-effects are intentional and add a note to the upgrade guide.
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
Review Comment:
💡 **`@since` tag is incorrect — `AiEvent` does not exist in 4.23.0**
The `camel-4.23.0` tag was created 2026-10-11 and does not contain this interface. Should be `@since 4.24` (same as the sub-interfaces and the `Type.Ai` enum value).
```suggestion
* @since 4.24
```
##########
core/camel-api/src/main/java/org/apache/camel/spi/CamelEvent.java:
##########
@@ -81,6 +81,13 @@ enum Type {
StepStarted,
StepCompleted,
StepFailed,
+ /**
+ * Events fired by Camel AI components (tool calls, agentic loops, ...); see
+ * {@link org.apache.camel.ai.AiEvent}.
+ *
+ * @since 4.24
+ */
+ Ai,
Review Comment:
ℹ️ **`Custom.ordinal()` changes — worth a note in the upgrade guide**
Inserting `Ai` before `Custom` shifts `Custom.ordinal()` from its previous value (87) to 90. The upgrade guide mentions type-string matching, but not ordinal. Worth a brief sentence for users who serialise the enum as an integer (e.g. to a database column or a protocol buffer).
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -140,7 +140,7 @@ void firesAnEventWhenThePolicyThrows() {
// ...and the denial is now observable as a single event
assertThat(events).hasSize(1);
AiToolAuthorizationDeniedEvent event = events.get(0);
- assertThat(event.getType()).isEqualTo(CamelEvent.Type.Custom);
+ assertThat(event.getType()).isEqualTo(CamelEvent.Type.Ai);
assertThat(event.getToolName()).isEqualTo("guarded");
assertThat(event.getExchange()).isSameAs(exchange);
Review Comment:
💡 **Missing `getProvider()` assertion**
The event now implements `AiEvent.ToolCallDeniedEvent.getProvider()`, which returns `"ai-tool"`. Consider asserting it here to guard against regressions:
```suggestion
assertThat(event.getType()).isEqualTo(CamelEvent.Type.Ai);
assertThat(event.getProvider()).isEqualTo("ai-tool");
assertThat(event.getToolName()).isEqualTo("guarded");
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #27714:
URL: https://github.com/apache/camel/pull/27714#issuecomment-6120304964
:star2: Thank you for your contribution to the Apache Camel project! :star2:
:robot: CI automation will test this PR automatically.
:camel: 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](https://camel.apache.org/community/team/#committers) have access to the summary.
:warning: Be careful when sharing logs. Review their contents before sharing them publicly.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "luigidemasi (via GitHub)" <gi...@apache.org>.
luigidemasi commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246140125
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
+ */
+public interface AiEvent extends CamelEvent.ExchangeEvent {
Review Comment:
Please keep the root independent of a live Exchange: `AiEvent extends CamelEvent`, with Exchange access on the exchange-backed subinterfaces.
This is needed for an existing Semantic API, not just a future monitoring feature: [SemanticLanguage.evaluate](https://github.com/apache/camel/blob/044b4b4c29c6cbdb51af08ec900d9125a993a68b/components/camel-ai/camel-semantic/src/main/java/org/apache/camel/language/semantic/SemanticLanguage.java#L154) calls `audit.begin(null, ...)`, and [SemanticObserver](https://github.com/apache/camel/blob/044b4b4c29c6cbdb51af08ec900d9125a993a68b/components/camel-ai/camel-semantic/src/main/java/org/apache/camel/semantic/SemanticObserver.java#L19) receives bounded snapshots rather than exchanges. A population-level drift signal likewise has no single Exchange. A mandatory `getExchange()` on the root would retain the same limitation even without the ExchangeEvent inheritance.
A small change that preserves the current tool/loop contracts:
- Make `AiEvent` extend `CamelEvent`, retaining `getProvider()` and the `Type.Ai` default.
- Add `ExchangeAiEvent extends AiEvent, CamelEvent.ExchangeEvent` (or directly extend both interfaces on each existing subtype).
- Move the four existing tool/loop subinterfaces and `AbstractOpenAIExchangeEvent` onto that exchange-backed contract, retaining their current members and accessors.
- Add a test dispatching an AiEvent without an Exchange through the new helper.
Semantic can then implement its own snapshot events without constructing a fake Exchange, weakening ExchangeEvent to allow null, or moving semantic record/result types into core. This split deliberately leaves the PR's proposed ExchangeEvent behavior on the four existing events; the listener compatibility work already requested still applies.
_AI-assisted review generated by Codex on behalf of Luigi De Masi (@luigidemasi)._
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
+ */
+public interface AiEvent extends CamelEvent.ExchangeEvent {
+
+ /**
+ * The AI provider the event originates from, e.g. {@code openai} or {@code ai-tool}. Intended as a low-cardinality
+ * label for metrics and spans.
Review Comment:
**Optional:** clarify that this identifies a stable publishing integration/provider family. The current `ai-tool` value already has that meaning; it is not an inference vendor. That lets a Semantic bridge consistently use `semantic`, while its domain payload retains the actual adapter provider, expert and model identity. It also gives route-decision and aggregate events a truthful label.
Suggested wording, if that convention is intended:
```suggestion
* The integration or provider family publishing the event, e.g. {@code openai}, {@code ai-tool}, or
* {@code semantic}. Intended as a stable, low-cardinality label for metrics and spans; not an expert instance,
* model revision, invocation ID, or an indication that the event necessarily involved inference.
```
_AI-assisted review generated by Codex on behalf of Luigi De Masi (@luigidemasi)._
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246464535
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
Review Comment:
Fixed — `AiEvent` and the other new types are now `@since 4.24` (commit 044b4b4c29c6). Confirmed they ship in 4.24.0, not 4.23.0.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "luigidemasi (via GitHub)" <gi...@apache.org>.
luigidemasi commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246758674
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -199,6 +231,75 @@ public void notify(CamelEvent event) {
AiToolResult result = AiToolExecutor.execute(spec, Map.of(), exchange);
assertThat(result).isInstanceOf(AiToolResult.AuthorizationDenied.class);
+ // the healthy @BeforeEach notifier still received the event despite the other one throwing
+ assertThat(events).hasSize(1);
Review Comment:
**P2 — assert receipt by a subscriber registered after the failing one**
The healthy collector is registered first in `@BeforeEach` (lines 119–129); this test adds the failing notifier afterward. Both have the same ordering, so the healthy collector already receives its event before the failure occurs. `events.hasSize(1)` therefore also passes when delivery aborts at the failing notifier. The prior whole-loop `catch(Throwable)` would preserve the refusal assertion as well.
Please register a fresh healthy subscriber after the failing notifier and assert that subscriber's own collection contains the event, while retaining the `AuthorizationDenied` assertion. Also cover `isEnabled()` throwing alongside `notify()` throwing.
The rationale is to make the test detect the behavior this helper fixes: one failing subscriber must not prevent subsequent subscribers from seeing an audit/monitoring event. The current implementation does isolate those two callbacks; the issue here is that this test would not catch losing that behavior.
_AI-assisted review generated by Codex on behalf of Luigi De Masi (@luigidemasi)._
##########
core/camel-support/src/main/java/org/apache/camel/support/EventHelper.java:
##########
@@ -1574,6 +1576,49 @@ public static boolean notifyExchangeAsyncProcessingStartedEvent(CamelContext con
return answer;
}
+ /**
+ * Notifies an {@link AiEvent} to the started event notifiers, following the same path as every other event
+ * category: it loops the started notifiers, skips those that are disabled or have {@code ignoreAiEvents} set,
+ * creates the event lazily (via {@code eventSupplier}) only when some notifier wants it, and delivers through
+ * {@code doNotifyEvent} so one failing notifier does not stop delivery to the others.
+ * <p>
+ * AI events are their own category: {@code ignoreExchangeEvents} does <em>not</em> suppress them even though an
+ * {@code AiEvent} is an exchange event. A notifier opts out with {@code setIgnoreAiEvents(true)}.
+ *
+ * @since 4.24
+ */
+ public static boolean notifyAiEvent(CamelContext context, Supplier<AiEvent> eventSupplier) {
+ ManagementStrategy management = context != null ? context.getManagementStrategy() : null;
+ if (management == null) {
+ return false;
+ }
+
+ List<EventNotifier> notifiers = management.getStartedEventNotifiers();
+ if (notifiers == null || notifiers.isEmpty()) {
+ return false;
+ }
+
+ boolean answer = false;
+ CamelEvent event = null;
+ // optimise for loop using index access to avoid creating iterator object
+ for (int i = 0; i < notifiers.size(); i++) {
+ EventNotifier notifier = notifiers.get(i);
+ if (notifier.isDisabled() || notifier.isIgnoreAiEvents()) {
Review Comment:
**P2 — isolate notifier eligibility failures before removing the producer's protection**
`isDisabled()` and `isIgnoreAiEvents()` are overridable notifier callbacks, but these calls are outside `doNotifyEvent`'s `Throwable` guards. This PR also removes [AiToolExecutor's outer notification guard](https://github.com/apache/camel/blob/131b9fe60539dea808b5318de8ce8a6a76e2ddbd/components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolExecutor.java#L201).
A concrete fault case is a custom notifier registered after context startup whose `isDisabled()` throws `AssertionError`. [Registration](https://github.com/apache/camel/blob/131b9fe60539dea808b5318de8ce8a6a76e2ddbd/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultManagementStrategy.java#L83) does not call that getter. When the tool's authorization policy denies access, publication reaches this check before `AuthorizationDenied` is constructed; the error escapes instead of returning the refusal, and later subscribers are skipped.
Please isolate these eligibility checks per notifier too: catch the failure, log it, skip that notifier and continue. Add coverage with the failing notifier followed by a healthy subscriber, asserting both `AuthorizationDenied` and delivery to the later subscriber. Restoring only an outer catch would protect the refusal but still lose subsequent delivery.
This requires a failing custom notifier; the stock flag getters are simple Boolean reads. It is a regression in the producer's existing best-effort notification guarantee, not an authorization bypass. The tool remains denied. This scenario is source-traced, not runtime-tested.
_AI-assisted review generated by Codex on behalf of Luigi De Masi (@luigidemasi)._
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246564519
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -140,7 +140,7 @@ void firesAnEventWhenThePolicyThrows() {
// ...and the denial is now observable as a single event
assertThat(events).hasSize(1);
AiToolAuthorizationDeniedEvent event = events.get(0);
- assertThat(event.getType()).isEqualTo(CamelEvent.Type.Custom);
+ assertThat(event.getType()).isEqualTo(CamelEvent.Type.Ai);
assertThat(event.getToolName()).isEqualTo("guarded");
assertThat(event.getExchange()).isSameAs(exchange);
Review Comment:
Added — `firesAnEventWhenThePolicyThrows` now asserts `event.getProvider()` is `ai-tool` and `event instanceof AiEvent.ToolCallDeniedEvent` (044b4b4c29c6).
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "github-actions[bot] (via GitHub)" <gi...@apache.org>.
github-actions[bot] commented on PR #27714:
URL: https://github.com/apache/camel/pull/27714#issuecomment-6121329870
<!-- ci-tested-modules -->
:test_tube: **CI tested the following changed modules:**
- `catalog/camel-catalog`
- `components/camel-ai/camel-ai-tool`
- `components/camel-ai/camel-openai`
- `core/camel-api`
- `core/camel-management`
- `docs`
> :information_source: Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the `test-dependents` label to force testing all dependents.
:repeat: **1 test passed only after a retry on JDK 17** (1 retried attempt)
<details><summary>Recovered flaky tests on JDK 17 (1)</summary>
| Module | Test | Failed attempts | First failure |
| --- | --- | --- | --- |
| `core/camel-management` | `ManagedAggregateControllerTest.testForceCompletionOfAll` | 1 | expected: <0> but was: <1> |
> :information_source: These tests did **not** fail the build. Surefire retried them and they passed.
> Retries are enabled project-wide by `surefire.rerunFailingTestsCount` in `parent/pom.xml`.
</details>
---
<details><summary>:microscope: Scalpel shadow comparison — Scalpel: 574 of 704 tested, 26 compile-only — current: 574 all tested</summary>
[Maveniverse Scalpel](https://github.com/maveniverse/scalpel) detected **574 affected modules** (current approach: 574).
**Skip-tests mode would test 574 modules** (6 direct + 570 downstream), **skip tests for 26** (generated code, meta-modules)
<details><summary>Modules Scalpel would test (574)</summary>
- `archetypes` ← downstream of org.apache.camel:camel-support
- `camel-a2a` ← downstream of org.apache.camel:camel-support
- `camel-activemq` ← downstream of org.apache.camel:camel-core-model
- `camel-activemq6` ← downstream of org.apache.camel:camel-core-model
- `camel-ai-observability` ← downstream of org.apache.camel:camel-support
- `camel-ai-observability-api` ← downstream of org.apache.camel:camel-support
- `camel-ai-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-ai-resource` ← downstream of org.apache.camel:camel-support
- `camel-ai-tool` ← components/camel-ai/camel-ai-tool/src/main/docs/ai-tool-component.adoc, components/camel-ai/camel-ai-tool/src/main/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEvent.java, components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java
- `camel-alibaba-common` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-eventbridge` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-fc` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-kms` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-mns` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-oss` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-ots` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-alibaba-sls` ← downstream of org.apache.camel:camel-support
- `camel-alibaba-sms` ← downstream of org.apache.camel:camel-support
- `camel-amqp` ← downstream of org.apache.camel:camel-core-model
- `camel-api` ← core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java, core/camel-api/src/main/java/org/apache/camel/spi/CamelEvent.java
- `camel-api-component-maven-plugin` ← downstream of org.apache.camel:camel-test-junit6
- `camel-arangodb` ← downstream of org.apache.camel:camel-support
- `camel-archetype-api-component` ← downstream of org.apache.camel:camel-support
- `camel-archetype-component` ← downstream of org.apache.camel:camel-support
- `camel-archetype-dataformat` ← downstream of org.apache.camel:camel-support
- `camel-archetype-java` ← downstream of org.apache.camel:camel-support
- `camel-archetype-main` ← downstream of org.apache.camel:camel-support
- `camel-as2` ← downstream of org.apache.camel:camel-support
- `camel-as2-api` ← downstream of org.apache.camel:camel-api
- `camel-as2-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-asn1` ← downstream of org.apache.camel:camel-support
- `camel-asterisk` ← downstream of org.apache.camel:camel-support
- `camel-atmosphere-websocket` ← downstream of org.apache.camel:camel-support
- `camel-atom` ← downstream of org.apache.camel:camel-support
- `camel-attachments` ← downstream of org.apache.camel:camel-support
- `camel-avro` ← downstream of org.apache.camel:camel-support
- `camel-avro-rpc` ← downstream of org.apache.camel:camel-support
- `camel-avro-rpc-jetty` ← downstream of org.apache.camel:camel-api
- `camel-avro-rpc-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-avro-rpc-spi` ← downstream of org.apache.camel:camel-core-model
- `camel-aws-bedrock` ← downstream of org.apache.camel:camel-support
- `camel-aws-cloudtrail` ← downstream of org.apache.camel:camel-support
- `camel-aws-common` ← downstream of org.apache.camel:camel-support
- `camel-aws-config` ← downstream of org.apache.camel:camel-support
- `camel-aws-parameter-store` ← downstream of org.apache.camel:camel-support
- `camel-aws-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-aws-secrets-manager` ← downstream of org.apache.camel:camel-support
- `camel-aws-security-hub` ← downstream of org.apache.camel:camel-support
- `camel-aws2-athena` ← downstream of org.apache.camel:camel-support
- `camel-aws2-comprehend` ← downstream of org.apache.camel:camel-support
- `camel-aws2-cw` ← downstream of org.apache.camel:camel-support
- `camel-aws2-ddb` ← downstream of org.apache.camel:camel-support
- `camel-aws2-ec2` ← downstream of org.apache.camel:camel-support
- `camel-aws2-ecs` ← downstream of org.apache.camel:camel-support
- `camel-aws2-eks` ← downstream of org.apache.camel:camel-support
- `camel-aws2-eventbridge` ← downstream of org.apache.camel:camel-support
- `camel-aws2-iam` ← downstream of org.apache.camel:camel-support
- `camel-aws2-kinesis` ← downstream of org.apache.camel:camel-support
- `camel-aws2-kms` ← downstream of org.apache.camel:camel-support
- `camel-aws2-lambda` ← downstream of org.apache.camel:camel-support
- `camel-aws2-mq` ← downstream of org.apache.camel:camel-support
- `camel-aws2-msk` ← downstream of org.apache.camel:camel-support
- `camel-aws2-polly` ← downstream of org.apache.camel:camel-support
- `camel-aws2-redshift` ← downstream of org.apache.camel:camel-support
- `camel-aws2-rekognition` ← downstream of org.apache.camel:camel-support
- `camel-aws2-s3` ← downstream of org.apache.camel:camel-support
- `camel-aws2-s3-vectors` ← downstream of org.apache.camel:camel-support
- `camel-aws2-ses` ← downstream of org.apache.camel:camel-support
- `camel-aws2-sns` ← downstream of org.apache.camel:camel-support
- `camel-aws2-sqs` ← downstream of org.apache.camel:camel-support
- `camel-aws2-step-functions` ← downstream of org.apache.camel:camel-support
- `camel-aws2-sts` ← downstream of org.apache.camel:camel-support
- `camel-aws2-textract` ← downstream of org.apache.camel:camel-support
- `camel-aws2-timestream` ← downstream of org.apache.camel:camel-support
- `camel-aws2-transcribe` ← downstream of org.apache.camel:camel-support
- `camel-aws2-translate` ← downstream of org.apache.camel:camel-support
- `camel-azure-common` ← downstream of org.apache.camel:camel-core-model
- `camel-azure-cosmosdb` ← downstream of org.apache.camel:camel-support
- `camel-azure-eventgrid` ← downstream of org.apache.camel:camel-support
- `camel-azure-eventhubs` ← downstream of org.apache.camel:camel-support
- `camel-azure-files` ← downstream of org.apache.camel:camel-core-model
- `camel-azure-functions` ← downstream of org.apache.camel:camel-support
- `camel-azure-key-vault` ← downstream of org.apache.camel:camel-support
- `camel-azure-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-azure-schema-registry` ← downstream of org.apache.camel:camel-support
- `camel-azure-servicebus` ← downstream of org.apache.camel:camel-support
- `camel-azure-storage-blob` ← downstream of org.apache.camel:camel-support
- `camel-azure-storage-datalake` ← downstream of org.apache.camel:camel-support
- `camel-azure-storage-queue` ← downstream of org.apache.camel:camel-support
- `camel-barcode` ← downstream of org.apache.camel:camel-support
- `camel-base` ← downstream of org.apache.camel:camel-api
- `camel-base-engine` ← downstream of org.apache.camel:camel-api
- `camel-base64` ← downstream of org.apache.camel:camel-support
- `camel-bean` ← downstream of org.apache.camel:camel-support
- `camel-bean-validator` ← downstream of org.apache.camel:camel-support
- `camel-beanio` ← downstream of org.apache.camel:camel-support
- `camel-bindy` ← downstream of org.apache.camel:camel-support
- `camel-bonita` ← downstream of org.apache.camel:camel-support
- `camel-box` ← downstream of org.apache.camel:camel-support
- `camel-box-api` ← downstream of org.apache.camel:camel-api
- `camel-box-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-braintree` ← downstream of org.apache.camel:camel-support
- `camel-browse` ← downstream of org.apache.camel:camel-support
- `camel-caffeine` ← downstream of org.apache.camel:camel-support
- `camel-camunda` ← downstream of org.apache.camel:camel-support
- `camel-cassandraql` ← downstream of org.apache.camel:camel-support
- `camel-catalog-common` ← downstream of org.apache.camel:camel-support
- `camel-cbor` ← downstream of org.apache.camel:camel-support
- `camel-chatscript` ← downstream of org.apache.camel:camel-support
- `camel-chunk` ← downstream of org.apache.camel:camel-support
- `camel-cli-connector` ← downstream of org.apache.camel:camel-management
- `camel-cli-debug` ← downstream of org.apache.camel:camel-cli-connector
- `camel-clickhouse` ← downstream of org.apache.camel:camel-support
- `camel-clickup` ← downstream of org.apache.camel:camel-support
- `camel-cloudevents` ← downstream of org.apache.camel:camel-support
- `camel-cluster` ← downstream of org.apache.camel:camel-api
- `camel-cm-sms` ← downstream of org.apache.camel:camel-support
- `camel-coap` ← downstream of org.apache.camel:camel-support
- `camel-cometd` ← downstream of org.apache.camel:camel-support
- `camel-console` ← downstream of org.apache.camel:camel-management
- `camel-consul` ← downstream of org.apache.camel:camel-support
- `camel-controlbus` ← downstream of org.apache.camel:camel-support
- `camel-core` ← downstream of org.apache.camel:camel-xml-io
- `camel-core-all` ← downstream of org.apache.camel:camel-api
- `camel-core-catalog` ← downstream of org.apache.camel:camel-api
- `camel-core-engine` ← downstream of org.apache.camel:camel-api
- `camel-core-languages` ← downstream of org.apache.camel:camel-api
- `camel-core-model` ← downstream of org.apache.camel:camel-api
- `camel-core-processor` ← downstream of org.apache.camel:camel-api
- `camel-core-reifier` ← downstream of org.apache.camel:camel-api
- `camel-core-xml` ← downstream of org.apache.camel:camel-core-engine
- `camel-couchbase` ← downstream of org.apache.camel:camel-support
- `camel-couchdb` ← downstream of org.apache.camel:camel-support
- `camel-cron` ← downstream of org.apache.camel:camel-support
- `camel-crypto` ← downstream of org.apache.camel:camel-support
- `camel-crypto-pgp` ← downstream of org.apache.camel:camel-support
- `camel-csv` ← downstream of org.apache.camel:camel-support
- `camel-cxf-common` ← downstream of org.apache.camel:camel-support
- `camel-cxf-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-cxf-rest` ← downstream of org.apache.camel:camel-support
- `camel-cxf-soap` ← downstream of org.apache.camel:camel-support
- `camel-cxf-spring-common` ← downstream of org.apache.camel:camel-support
- `camel-cxf-spring-rest` ← downstream of org.apache.camel:camel-core-model
- `camel-cxf-spring-soap` ← downstream of org.apache.camel:camel-core-model
- `camel-cxf-spring-transport` ← downstream of org.apache.camel:camel-core-model
- `camel-cxf-transport` ← downstream of org.apache.camel:camel-support
- `camel-cyberark-vault` ← downstream of org.apache.camel:camel-support
- `camel-dapr` ← downstream of org.apache.camel:camel-support
- `camel-dataformat` ← downstream of org.apache.camel:camel-support
- `camel-dataset` ← downstream of org.apache.camel:camel-core-model
- `camel-datasonnet` ← downstream of org.apache.camel:camel-support
- `camel-dataweave` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-common` ← downstream of org.apache.camel:camel-support
- `camel-debezium-common-parent` ← downstream of org.apache.camel:camel-support
- `camel-debezium-db2` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-maven-plugin` ← downstream of org.apache.camel:camel-support
- `camel-debezium-mongodb` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-mysql` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-oracle` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-postgres` ← downstream of org.apache.camel:camel-core-model
- `camel-debezium-sqlserver` ← downstream of org.apache.camel:camel-core-model
- `camel-debug` ← downstream of org.apache.camel:camel-management
- `camel-dfdl` ← downstream of org.apache.camel:camel-support
- `camel-dhis2` ← downstream of org.apache.camel:camel-support
- `camel-dhis2-api` ← downstream of org.apache.camel:camel-support
- `camel-dhis2-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-diagram` ← downstream of org.apache.camel:camel-management
- `camel-direct` ← downstream of org.apache.camel:camel-support
- `camel-disruptor` ← downstream of org.apache.camel:camel-support
- `camel-djl` ← downstream of org.apache.camel:camel-support
- `camel-dns` ← downstream of org.apache.camel:camel-support
- `camel-docker` ← downstream of org.apache.camel:camel-support
- `camel-docling` ← downstream of org.apache.camel:camel-support
- `camel-drill` ← downstream of org.apache.camel:camel-support
- `camel-dropbox` ← downstream of org.apache.camel:camel-support
- `camel-dsl-modeline` ← downstream of org.apache.camel:camel-support
- `camel-dsl-support` ← downstream of org.apache.camel:camel-support
- `camel-duckdb` ← downstream of org.apache.camel:camel-support
- `camel-dynamic-router` ← downstream of org.apache.camel:camel-management
- `camel-ehcache` ← downstream of org.apache.camel:camel-support
- `camel-elasticsearch` ← downstream of org.apache.camel:camel-support
- `camel-elasticsearch-rest-client` ← downstream of org.apache.camel:camel-support
- `camel-event` ← downstream of org.apache.camel:camel-support
- `camel-exec` ← downstream of org.apache.camel:camel-support
- `camel-fastjson` ← downstream of org.apache.camel:camel-support
- `camel-fhir` ← downstream of org.apache.camel:camel-support
- `camel-fhir-api` ← downstream of org.apache.camel:camel-support
- `camel-fhir-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-file` ← downstream of org.apache.camel:camel-support
- `camel-file-watch` ← downstream of org.apache.camel:camel-support
- `camel-flatpack` ← downstream of org.apache.camel:camel-core-model
- `camel-flink` ← downstream of org.apache.camel:camel-support
- `camel-flowable` ← downstream of org.apache.camel:camel-support
- `camel-fop` ← downstream of org.apache.camel:camel-support
- `camel-fory` ← downstream of org.apache.camel:camel-support
- `camel-freemarker` ← downstream of org.apache.camel:camel-management
- `camel-ftp` ← downstream of org.apache.camel:camel-core-model
- `camel-ftp-common` ← downstream of org.apache.camel:camel-core-model
- `camel-geocoder` ← downstream of org.apache.camel:camel-support
- `camel-git` ← downstream of org.apache.camel:camel-support
- `camel-github2` ← downstream of org.apache.camel:camel-support
- `camel-google-bigquery` ← downstream of org.apache.camel:camel-support
- `camel-google-calendar` ← downstream of org.apache.camel:camel-support
- `camel-google-common` ← downstream of org.apache.camel:camel-support
- `camel-google-drive` ← downstream of org.apache.camel:camel-support
- `camel-google-firestore` ← downstream of org.apache.camel:camel-support
- `camel-google-functions` ← downstream of org.apache.camel:camel-support
- `camel-google-mail` ← downstream of org.apache.camel:camel-support
- `camel-google-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-google-pubsub` ← downstream of org.apache.camel:camel-support
- `camel-google-secret-manager` ← downstream of org.apache.camel:camel-support
- `camel-google-sheets` ← downstream of org.apache.camel:camel-support
- `camel-google-speech-to-text` ← downstream of org.apache.camel:camel-support
- `camel-google-storage` ← downstream of org.apache.camel:camel-support
- `camel-google-text-to-speech` ← downstream of org.apache.camel:camel-support
- `camel-google-vertexai` ← downstream of org.apache.camel:camel-support
- `camel-google-vision` ← downstream of org.apache.camel:camel-support
- `camel-graphql` ← downstream of org.apache.camel:camel-support
- `camel-grok` ← downstream of org.apache.camel:camel-support
- `camel-groovy` ← downstream of org.apache.camel:camel-support
- `camel-grpc` ← downstream of org.apache.camel:camel-support
- `camel-gson` ← downstream of org.apache.camel:camel-support
- `camel-hashicorp-vault` ← downstream of org.apache.camel:camel-support
- `camel-hazelcast` ← downstream of org.apache.camel:camel-support
- `camel-health` ← downstream of org.apache.camel:camel-api
- `camel-hivemq` ← downstream of org.apache.camel:camel-support
- `camel-hl7` ← downstream of org.apache.camel:camel-core-model
- `camel-http` ← downstream of org.apache.camel:camel-management
- `camel-http-base` ← downstream of org.apache.camel:camel-support
- `camel-http-common` ← downstream of org.apache.camel:camel-support
- `camel-huawei-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-huaweicloud-common` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-dms` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-frs` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-functiongraph` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-iam` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-imagerecognition` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-obs` ← downstream of org.apache.camel:camel-support
- `camel-huaweicloud-smn` ← downstream of org.apache.camel:camel-support
- `camel-huggingface` ← downstream of org.apache.camel:camel-support
- `camel-ibm-cos` ← downstream of org.apache.camel:camel-support
- `camel-ibm-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-ibm-secrets-manager` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watson-discovery` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watson-language` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watson-speech-to-text` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watson-text-to-speech` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watsonx-ai` ← downstream of org.apache.camel:camel-support
- `camel-ibm-watsonx-data` ← downstream of org.apache.camel:camel-support
- `camel-ical` ← downstream of org.apache.camel:camel-support
- `camel-iggy` ← downstream of org.apache.camel:camel-support
- `camel-ignite` ← downstream of org.apache.camel:camel-support
- `camel-infinispan` ← downstream of org.apache.camel:camel-core-model
- `camel-infinispan-common` ← downstream of org.apache.camel:camel-support
- `camel-infinispan-embedded` ← downstream of org.apache.camel:camel-core-model
- `camel-infinispan-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-influxdb` ← downstream of org.apache.camel:camel-support
- `camel-influxdb2` ← downstream of org.apache.camel:camel-support
- `camel-iso8583` ← downstream of org.apache.camel:camel-support
- `camel-jackson` ← downstream of org.apache.camel:camel-core-model
- `camel-jackson-avro` ← downstream of org.apache.camel:camel-support
- `camel-jackson-protobuf` ← downstream of org.apache.camel:camel-support
- `camel-jackson3` ← downstream of org.apache.camel:camel-core-model
- `camel-jackson3-avro` ← downstream of org.apache.camel:camel-support
- `camel-jackson3-protobuf` ← downstream of org.apache.camel:camel-support
- `camel-jackson3xml` ← downstream of org.apache.camel:camel-support
- `camel-jacksonxml` ← downstream of org.apache.camel:camel-support
- `camel-jactl` ← downstream of org.apache.camel:camel-support
- `camel-jandex` ← downstream of org.apache.camel:camel-support
- `camel-jasypt` ← downstream of org.apache.camel:camel-base
- `camel-java-io` ← downstream of org.apache.camel:camel-xml-io
- `camel-java-joor-dsl` ← downstream of org.apache.camel:camel-core-languages
- `camel-javascript` ← downstream of org.apache.camel:camel-support
- `camel-jaxb` ← downstream of org.apache.camel:camel-core-model
- `camel-jbang-console` ← downstream of org.apache.camel:camel-management
- `camel-jbang-mcp` ← downstream of org.apache.camel:camel-catalog
- `camel-jbang-plugin-mcp` ← downstream of org.apache.camel:camel-jbang-core
- `camel-jbang-plugin-route-parser` ← downstream of org.apache.camel:camel-route-parser
- `camel-jbang-plugin-tui` ← downstream of org.apache.camel:camel-catalog
- `camel-jbang-plugin-validate` ← downstream of org.apache.camel:camel-yaml-dsl-validator
- `camel-jcache` ← downstream of org.apache.camel:camel-support
- `camel-jcr` ← downstream of org.apache.camel:camel-support
- `camel-jdbc` ← downstream of org.apache.camel:camel-support
- `camel-jetty` ← downstream of org.apache.camel:camel-management
- `camel-jetty-common` ← downstream of org.apache.camel:camel-core-model
- `camel-jfr` ← downstream of org.apache.camel:camel-support
- `camel-jgroups` ← downstream of org.apache.camel:camel-support
- `camel-jgroups-raft` ← downstream of org.apache.camel:camel-support
- `camel-jira` ← downstream of org.apache.camel:camel-support
- `camel-jms` ← downstream of org.apache.camel:camel-management
- `camel-jmx` ← downstream of org.apache.camel:camel-management
- `camel-jolt` ← downstream of org.apache.camel:camel-support
- `camel-jooq` ← downstream of org.apache.camel:camel-support
- `camel-joor` ← downstream of org.apache.camel:camel-support
- `camel-jpa` ← downstream of org.apache.camel:camel-support
- `camel-jq` ← downstream of org.apache.camel:camel-support
- `camel-jsch` ← downstream of org.apache.camel:camel-core-model
- `camel-jslt` ← downstream of org.apache.camel:camel-support
- `camel-json-validator` ← downstream of org.apache.camel:camel-support
- `camel-jsonapi` ← downstream of org.apache.camel:camel-support
- `camel-jsonata` ← downstream of org.apache.camel:camel-support
- `camel-jsonb` ← downstream of org.apache.camel:camel-support
- `camel-jsonpath` ← downstream of org.apache.camel:camel-support
- `camel-jsoup` ← downstream of org.apache.camel:camel-support
- `camel-jt400` ← downstream of org.apache.camel:camel-support
- `camel-jta` ← downstream of org.apache.camel:camel-support
- `camel-jte` ← downstream of org.apache.camel:camel-support
- `camel-kafka` ← downstream of org.apache.camel:camel-support
- `camel-kafka-common` ← downstream of org.apache.camel:camel-support
- `camel-kafka-share` ← downstream of org.apache.camel:camel-support
- `camel-kamelet` ← downstream of org.apache.camel:camel-management
- `camel-kamelet-main-support` ← downstream of org.apache.camel:camel-main
- `camel-keycloak` ← downstream of org.apache.camel:camel-support
- `camel-knative` ← downstream of org.apache.camel:camel-support
- `camel-knative-api` ← downstream of org.apache.camel:camel-support
- `camel-knative-http` ← downstream of org.apache.camel:camel-core-model
- `camel-knative-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-kserve` ← downstream of org.apache.camel:camel-support
- `camel-kubernetes` ← downstream of org.apache.camel:camel-support
- `camel-kudu` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-agent` ← downstream of org.apache.camel:camel-ai-tool
- `camel-langchain4j-agent-api` ← downstream of org.apache.camel:camel-api
- `camel-langchain4j-chat` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-core` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-embeddings` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-embeddingstore` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-embeddingstore-api` ← downstream of org.apache.camel:camel-api
- `camel-langchain4j-ingest` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-tokenizer` ← downstream of org.apache.camel:camel-support
- `camel-langchain4j-web-search` ← downstream of org.apache.camel:camel-support
- `camel-language` ← downstream of org.apache.camel:camel-support
- `camel-launcher-container` ← downstream of org.apache.camel:camel-launcher
- `camel-ldap` ← downstream of org.apache.camel:camel-support
- `camel-ldif` ← downstream of org.apache.camel:camel-support
- `camel-log` ← downstream of org.apache.camel:camel-support
- `camel-lra` ← downstream of org.apache.camel:camel-core-model
- `camel-lucene` ← downstream of org.apache.camel:camel-support
- `camel-lumberjack` ← downstream of org.apache.camel:camel-support
- `camel-lzf` ← downstream of org.apache.camel:camel-support
- `camel-mail` ← downstream of org.apache.camel:camel-support
- `camel-mail-microsoft-oauth` ← downstream of org.apache.camel:camel-core-model
- `camel-main` ← downstream of org.apache.camel:camel-api
- `camel-management` ← core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEventNotifier.java
- `camel-management-api` ← downstream of org.apache.camel:camel-api
- `camel-mapstruct` ← downstream of org.apache.camel:camel-support
- `camel-master` ← downstream of org.apache.camel:camel-support
- `camel-maven-plugin` ← downstream of org.apache.camel:camel-spring-main
- `camel-mcp-server` ← downstream of org.apache.camel:camel-openai
- `camel-mcp-server-api` ← downstream of org.apache.camel:camel-ai-tool
- `camel-mdc` ← downstream of org.apache.camel:camel-support
- `camel-metrics` ← downstream of org.apache.camel:camel-management
- `camel-micrometer` ← downstream of org.apache.camel:camel-management
- `camel-micrometer-observability` ← downstream of org.apache.camel:camel-core-model
- `camel-micrometer-prometheus` ← downstream of org.apache.camel:camel-core-model
- `camel-microprofile-config` ← downstream of org.apache.camel:camel-support
- `camel-microprofile-fault-tolerance` ← downstream of org.apache.camel:camel-management
- `camel-microprofile-health` ← downstream of org.apache.camel:camel-core-model
- `camel-microprofile-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-milo` ← downstream of org.apache.camel:camel-support
- `camel-milvus` ← downstream of org.apache.camel:camel-support
- `camel-mina` ← downstream of org.apache.camel:camel-support
- `camel-mina-sftp` ← downstream of org.apache.camel:camel-core-model
- `camel-minio` ← downstream of org.apache.camel:camel-support
- `camel-mllp` ← downstream of org.apache.camel:camel-support
- `camel-mock` ← downstream of org.apache.camel:camel-support
- `camel-mongodb` ← downstream of org.apache.camel:camel-support
- `camel-mongodb-gridfs` ← downstream of org.apache.camel:camel-support
- `camel-mustache` ← downstream of org.apache.camel:camel-support
- `camel-mvel` ← downstream of org.apache.camel:camel-support
- `camel-mybatis` ← downstream of org.apache.camel:camel-core-model
- `camel-nats` ← downstream of org.apache.camel:camel-support
- `camel-neo4j` ← downstream of org.apache.camel:camel-support
- `camel-netty` ← downstream of org.apache.camel:camel-management
- `camel-netty-http` ← downstream of org.apache.camel:camel-management
- `camel-oaipmh` ← downstream of org.apache.camel:camel-support
- `camel-oauth` ← downstream of org.apache.camel:camel-support
- `camel-observability-services` ← downstream of org.apache.camel:camel-management
- `camel-observation` ← downstream of org.apache.camel:camel-support
- `camel-ocsf` ← downstream of org.apache.camel:camel-support
- `camel-odata` ← downstream of org.apache.camel:camel-support
- `camel-ognl` ← downstream of org.apache.camel:camel-support
- `camel-olingo2` ← downstream of org.apache.camel:camel-support
- `camel-olingo2-api` ← downstream of org.apache.camel:camel-core-model
- `camel-olingo2-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-olingo4` ← downstream of org.apache.camel:camel-support
- `camel-olingo4-api` ← downstream of org.apache.camel:camel-support
- `camel-olingo4-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-once` ← downstream of org.apache.camel:camel-support
- `camel-opa` ← downstream of org.apache.camel:camel-support
- `camel-openai` ← components/camel-ai/camel-openai/src/main/docs/openai-mcp.adoc, components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/AbstractOpenAIExchangeEvent.java, components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIAgenticLoopCompletedEvent.java, components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIAgenticLoopStartedEvent.java, components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIAgenticToolCallExecutedEvent.java, components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIAgenticEventNotifierTest.java, components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/OpenAIResponsesAgenticTest.java
- `camel-openapi-java` ← downstream of org.apache.camel:camel-management
- `camel-openapi-rest-dsl-generator` ← downstream of org.apache.camel:camel-api
- `camel-openapi-validator` ← downstream of org.apache.camel:camel-core-model
- `camel-openfeature` ← downstream of org.apache.camel:camel-support
- `camel-openfga` ← downstream of org.apache.camel:camel-support
- `camel-opensearch` ← downstream of org.apache.camel:camel-support
- `camel-openstack` ← downstream of org.apache.camel:camel-support
- `camel-opentelemetry` ← downstream of org.apache.camel:camel-support
- `camel-opentelemetry-metrics` ← downstream of org.apache.camel:camel-support
- `camel-opentelemetry2` ← downstream of org.apache.camel:camel-core-model
- `camel-optaplanner` ← downstream of org.apache.camel:camel-support
- `camel-paho` ← downstream of org.apache.camel:camel-support
- `camel-paho-mqtt5` ← downstream of org.apache.camel:camel-support
- `camel-parquet-avro` ← downstream of org.apache.camel:camel-support
- `camel-pdf` ← downstream of org.apache.camel:camel-support
- `camel-pg-replication-slot` ← downstream of org.apache.camel:camel-support
- `camel-pgevent` ← downstream of org.apache.camel:camel-support
- `camel-pgvector` ← downstream of org.apache.camel:camel-support
- `camel-pinecone` ← downstream of org.apache.camel:camel-support
- `camel-platform-http` ← downstream of org.apache.camel:camel-core-model
- `camel-platform-http-jolokia` ← downstream of org.apache.camel:camel-support
- `camel-platform-http-main` ← downstream of org.apache.camel:camel-core-model
- `camel-platform-http-vertx` ← downstream of org.apache.camel:camel-management
- `camel-plc4x` ← downstream of org.apache.camel:camel-support
- `camel-pqc` ← downstream of org.apache.camel:camel-support
- `camel-printer` ← downstream of org.apache.camel:camel-support
- `camel-protobuf` ← downstream of org.apache.camel:camel-support
- `camel-pubnub` ← downstream of org.apache.camel:camel-support
- `camel-pulsar` ← downstream of org.apache.camel:camel-support
- `camel-python` ← downstream of org.apache.camel:camel-support
- `camel-python3` ← downstream of org.apache.camel:camel-support
- `camel-qdrant` ← downstream of org.apache.camel:camel-support
- `camel-quartz` ← downstream of org.apache.camel:camel-management
- `camel-quickfix` ← downstream of org.apache.camel:camel-support
- `camel-quickjs` ← downstream of org.apache.camel:camel-support
- `camel-reactive-streams` ← downstream of org.apache.camel:camel-management
- `camel-reactor` ← downstream of org.apache.camel:camel-support
- `camel-redis` ← downstream of org.apache.camel:camel-support
- `camel-ref` ← downstream of org.apache.camel:camel-support
- `camel-resilience4j` ← downstream of org.apache.camel:camel-management
- `camel-resilience4j-micrometer` ← downstream of org.apache.camel:camel-management
- `camel-resourceresolver-github` ← downstream of org.apache.camel:camel-support
- `camel-rest` ← downstream of org.apache.camel:camel-support
- `camel-rest-openapi` ← downstream of org.apache.camel:camel-support
- `camel-rest-postman` ← downstream of org.apache.camel:camel-support
- `camel-restdsl-openapi-plugin` ← downstream of org.apache.camel:camel-core-engine
- `camel-robotframework` ← downstream of org.apache.camel:camel-support
- `camel-rocketmq` ← downstream of org.apache.camel:camel-support
- `camel-rss` ← downstream of org.apache.camel:camel-support
- `camel-rxjava` ← downstream of org.apache.camel:camel-support
- `camel-saga` ← downstream of org.apache.camel:camel-support
- `camel-salesforce` ← downstream of org.apache.camel:camel-core-model
- `camel-salesforce-codegen` ← downstream of org.apache.camel:camel-core-model
- `camel-salesforce-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-sap-netweaver` ← downstream of org.apache.camel:camel-support
- `camel-saxon` ← downstream of org.apache.camel:camel-core-model
- `camel-scheduler` ← downstream of org.apache.camel:camel-support
- `camel-schematron` ← downstream of org.apache.camel:camel-support
- `camel-seda` ← downstream of org.apache.camel:camel-support
- `camel-semantic` ← downstream of org.apache.camel:camel-support
- `camel-servicenow` ← downstream of org.apache.camel:camel-support
- `camel-servicenow-maven-plugin` ← downstream of org.apache.camel:camel-core-model
- `camel-servicenow-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-servlet` ← downstream of org.apache.camel:camel-management
- `camel-shell` ← downstream of org.apache.camel:camel-support
- `camel-shiro` ← downstream of org.apache.camel:camel-support
- `camel-sjms` ← downstream of org.apache.camel:camel-support
- `camel-sjms2` ← downstream of org.apache.camel:camel-support
- `camel-slack` ← downstream of org.apache.camel:camel-support
- `camel-smb` ← downstream of org.apache.camel:camel-support
- `camel-smooks` ← downstream of org.apache.camel:camel-support
- `camel-smpp` ← downstream of org.apache.camel:camel-support
- `camel-snakeyaml` ← downstream of org.apache.camel:camel-support
- `camel-snmp` ← downstream of org.apache.camel:camel-support
- `camel-soap` ← downstream of org.apache.camel:camel-support
- `camel-solr` ← downstream of org.apache.camel:camel-support
- `camel-spiffe` ← downstream of org.apache.camel:camel-support
- `camel-splunk-hec` ← downstream of org.apache.camel:camel-support
- `camel-spring` ← downstream of org.apache.camel:camel-management-api
- `camel-spring-ai-chat` ← downstream of org.apache.camel:camel-ai-tool
- `camel-spring-ai-embeddings` ← downstream of org.apache.camel:camel-support
- `camel-spring-ai-image` ← downstream of org.apache.camel:camel-support
- `camel-spring-ai-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-spring-ai-vector-store` ← downstream of org.apache.camel:camel-support
- `camel-spring-batch` ← downstream of org.apache.camel:camel-support
- `camel-spring-cloud-config` ← downstream of org.apache.camel:camel-support
- `camel-spring-jdbc` ← downstream of org.apache.camel:camel-core-model
- `camel-spring-ldap` ← downstream of org.apache.camel:camel-support
- `camel-spring-main` ← downstream of org.apache.camel:camel-core-model
- `camel-spring-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-spring-rabbitmq` ← downstream of org.apache.camel:camel-support
- `camel-spring-redis` ← downstream of org.apache.camel:camel-support
- `camel-spring-security` ← downstream of org.apache.camel:camel-core-model
- `camel-spring-ws` ← downstream of org.apache.camel:camel-support
- `camel-spring-xml` ← downstream of org.apache.camel:camel-management
- `camel-sql` ← downstream of org.apache.camel:camel-support
- `camel-ssh` ← downstream of org.apache.camel:camel-support
- `camel-state-store` ← downstream of org.apache.camel:camel-support
- `camel-state-store-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-stax` ← downstream of org.apache.camel:camel-support
- `camel-stitch` ← downstream of org.apache.camel:camel-support
- `camel-stream` ← downstream of org.apache.camel:camel-support
- `camel-streamcaching-test` ← downstream of org.apache.camel:camel-test-junit6
- `camel-stringtemplate` ← downstream of org.apache.camel:camel-management
- `camel-stripe` ← downstream of org.apache.camel:camel-support
- `camel-stub` ← downstream of org.apache.camel:camel-core-model
- `camel-support` ← downstream of org.apache.camel:camel-api
- `camel-swift` ← downstream of org.apache.camel:camel-support
- `camel-syslog` ← downstream of org.apache.camel:camel-support
- `camel-tahu` ← downstream of org.apache.camel:camel-api
- `camel-tarfile` ← downstream of org.apache.camel:camel-core-model
- `camel-telegram` ← downstream of org.apache.camel:camel-support
- `camel-telemetry` ← downstream of org.apache.camel:camel-support
- `camel-telemetry-dev` ← downstream of org.apache.camel:camel-core-model
- `camel-tensorflow-serving` ← downstream of org.apache.camel:camel-support
- `camel-test-infra-all` ← downstream of org.apache.camel:camel-test-infra-artemis
- `camel-test-infra-artemis` ← downstream of org.apache.camel:camel-test-junit6
- `camel-test-infra-cli` ← downstream of org.apache.camel:camel-support
- `camel-test-infra-core` ← downstream of org.apache.camel:camel-core
- `camel-test-infra-smb` ← downstream of org.apache.camel:camel-test-junit6
- `camel-test-junit5` ← downstream of org.apache.camel:camel-management
- `camel-test-junit6` ← downstream of org.apache.camel:camel-management
- `camel-test-main-junit5` ← downstream of org.apache.camel:camel-management
- `camel-test-main-junit6` ← downstream of org.apache.camel:camel-management
- `camel-test-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-test-spring-junit5` ← downstream of org.apache.camel:camel-management
- `camel-test-spring-junit6` ← downstream of org.apache.camel:camel-management
- `camel-thrift` ← downstream of org.apache.camel:camel-support
- `camel-thymeleaf` ← downstream of org.apache.camel:camel-management
- `camel-tika` ← downstream of org.apache.camel:camel-support
- `camel-timer` ← downstream of org.apache.camel:camel-support
- `camel-tooling-maven` ← downstream of org.apache.camel:camel-support
- `camel-toon` ← downstream of org.apache.camel:camel-support
- `camel-tracing` ← downstream of org.apache.camel:camel-support
- `camel-twilio` ← downstream of org.apache.camel:camel-support
- `camel-twitter` ← downstream of org.apache.camel:camel-support
- `camel-typesafe-ai` ← downstream of org.apache.camel:camel-support
- `camel-ubl` ← downstream of org.apache.camel:camel-support
- `camel-undertow` ← downstream of org.apache.camel:camel-management
- `camel-undertow-spring-security` ← downstream of org.apache.camel:camel-core-model
- `camel-univocity-parsers` ← downstream of org.apache.camel:camel-support
- `camel-validator` ← downstream of org.apache.camel:camel-support
- `camel-velocity` ← downstream of org.apache.camel:camel-management
- `camel-vertx` ← downstream of org.apache.camel:camel-support
- `camel-vertx-common` ← downstream of org.apache.camel:camel-support
- `camel-vertx-http` ← downstream of org.apache.camel:camel-core-model
- `camel-vertx-parent` ← downstream of org.apache.camel:camel-core-model
- `camel-vertx-websocket` ← downstream of org.apache.camel:camel-support
- `camel-wal` ← downstream of org.apache.camel:camel-support
- `camel-wasm` ← downstream of org.apache.camel:camel-support
- `camel-weather` ← downstream of org.apache.camel:camel-support
- `camel-weaviate` ← downstream of org.apache.camel:camel-support
- `camel-web3j` ← downstream of org.apache.camel:camel-support
- `camel-webhook` ← downstream of org.apache.camel:camel-support
- `camel-whatsapp` ← downstream of org.apache.camel:camel-support
- `camel-wolf-defender` ← downstream of org.apache.camel:camel-support
- `camel-wordpress` ← downstream of org.apache.camel:camel-support
- `camel-workday` ← downstream of org.apache.camel:camel-support
- `camel-xchange` ← downstream of org.apache.camel:camel-support
- `camel-xj` ← downstream of org.apache.camel:camel-core-model
- `camel-xml-io` ← downstream of org.apache.camel:camel-api
- `camel-xml-io-dsl` ← downstream of org.apache.camel:camel-xml-io
- `camel-xml-jaxb` ← downstream of org.apache.camel:camel-api
- `camel-xml-jaxb-dsl` ← downstream of org.apache.camel:camel-core-languages
- `camel-xml-jaxb-dsl-test-definition` ← downstream of org.apache.camel:camel-management
- `camel-xml-jaxb-dsl-test-spring` ← downstream of org.apache.camel:camel-management
- `camel-xml-jaxp` ← downstream of org.apache.camel:camel-api
- `camel-xmlsecurity` ← downstream of org.apache.camel:camel-support
- `camel-xmpp` ← downstream of org.apache.camel:camel-support
- `camel-xpath` ← downstream of org.apache.camel:camel-support
- `camel-xslt` ← downstream of org.apache.camel:camel-support
- `camel-xslt-saxon` ← downstream of org.apache.camel:camel-core-model
- `camel-yaml-dsl-common` ← downstream of org.apache.camel:camel-core-engine
- `camel-yaml-dsl-validator` ← downstream of org.apache.camel:camel-catalog
- `camel-yaml-dsl-validator-maven-plugin` ← downstream of org.apache.camel:camel-yaml-dsl-validator
- `camel-yaml-io` ← downstream of org.apache.camel:camel-api
- `camel-zendesk` ← downstream of org.apache.camel:camel-support
- `camel-zip-deflater` ← downstream of org.apache.camel:camel-support
- `camel-zipfile` ← downstream of org.apache.camel:camel-support
- `camel-zookeeper` ← downstream of org.apache.camel:camel-management
- `camel-zookeeper-master` ← downstream of org.apache.camel:camel-support
- `components` ← downstream of org.apache.camel:camel-core-model
</details>
<details><summary>Modules with tests skipped (26)</summary>
- `apache-camel`
- `camel-allcomponents`
- `camel-catalog-console`
- `camel-catalog-maven`
- `camel-catalog-suggest`
- `camel-componentdsl`
- `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-salesforce-maven-plugin`
- `camel-yaml-dsl`
- `camel-yaml-dsl-deserializers`
- `camel-yaml-dsl-maven-plugin`
- `coverage`
- `dummy-component`
</details>
> :information_source: Shadow mode — Scalpel observes but does not affect test execution. [Learn more](https://github.com/maveniverse/scalpel)
</details>
:warning: **Some tests are disabled on GitHub Actions** (`@DisabledIfSystemProperty(named = "ci.env.name")`) and require manual verification:
- `components/camel-ai/camel-openai`: 7 test(s) disabled on GitHub Actions
<details><summary>Build reactor — dependencies compiled but only changed modules were tested (6 modules, 1m 40s total)</summary>
**Total reactor time:** 1m 40s
| Module | Duration | Status |
| --- | --- | --- |
| Camel :: AI :: OpenAI | 36.1s | SUCCESS |
| Camel :: Catalog :: Camel Catalog | 27.6s | SUCCESS |
| Camel :: Docs | 19.1s | SUCCESS |
| Camel :: API | 11.3s | SUCCESS |
| Camel :: AI :: Tool | 6.3s | SUCCESS |
| Camel :: Management | n/a | |
**Top 20 slowest modules:**
- `Camel :: AI :: OpenAI` (36.1s)
- `Camel :: Catalog :: Camel Catalog` (27.6s)
- `Camel :: Docs` (19.1s)
- `Camel :: API` (11.3s)
- `Camel :: AI :: Tool` (6.3s)
</details>
---
:gear: [View full build and test results](https://github.com/apache/camel/actions/runs/38222661589)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246525711
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
Review Comment:
💡 **Root `AiEvent` interface `@since` still says 4.23 (not fixed)**
The root `AiEvent` interface Javadoc says `@since 4.23` while all sub-interfaces say `@since 4.24`. The previous review flagged this; the author's response said it was fixed in `044b4b4c`, but this commit did not update the outer interface header.
```suggestion
* @since 4.24
```
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because an `AiEvent` is now a `CamelEvent.ExchangeEvent`, a notifier that filters on `instanceof ExchangeEvent`
+now also receives AI events. AI events are their own category: a new `ignoreAiEvents` flag
+(`EventNotifier.setIgnoreAiEvents(boolean)`, default `false`) opts a notifier out, and `ignoreExchangeEvents` does
+**not** drop AI events (so an AI-observability notifier can keep `ignoreExchangeEvents=true` for performance). Camel's
+own exchange-oriented notifiers (the debugger, the dev-console event ring, the micrometer exchange notifier) set
+`ignoreAiEvents=true` so AI events do not reach them; a custom exchange-focused notifier that should not see AI events
+should do the same.
Review Comment:
ℹ️ **`Custom.ordinal()` shift not documented (not fixed from prior review)**
Inserting `Type.Ai` before `Type.Custom` changes `Custom.ordinal()` from its previous value. The upgrade guide covers string-based migration but says nothing about the ordinal change. Users serialising the enum as an integer (Avro schemas, database columns, configuration files) will silently decode the wrong type after upgrading.
```suggestion
should do the same.
Note also that inserting `Type.Ai` before `Type.Custom` in the enum shifts `Type.Custom.ordinal()` from its previous value.
Users who serialise `CamelEvent.Type` as an integer (Avro schemas, database columns, config files) must migrate those values.
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246846802
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -199,6 +231,75 @@ public void notify(CamelEvent event) {
AiToolResult result = AiToolExecutor.execute(spec, Map.of(), exchange);
assertThat(result).isInstanceOf(AiToolResult.AuthorizationDenied.class);
+ // the healthy @BeforeEach notifier still received the event despite the other one throwing
+ assertThat(events).hasSize(1);
Review Comment:
💡 **Suggestion (minor):** The test verifies that the `@BeforeEach` notifier received the event even when the throwing notifier failed — but since the `@BeforeEach` notifier is at index 0 and the throwing notifier is at index 1, delivery to index 0 happens *before* the throw, not after it. The assertion therefore proves ordering rather than isolation.
To truly demonstrate that `doNotifyEvent` continues delivery past a failing notifier, a third notifier registered *after* the throwing one (index 2) would need to receive the event:
```suggestion
// add a trailing notifier (registered after the thrower) to prove delivery continues past a failure
List<AiEvent> trailing = new CopyOnWriteArrayList<>();
context.getManagementStrategy().addEventNotifier(new EventNotifierSupport() {
@Override
public void notify(CamelEvent event) {
if (event instanceof AiEvent ai) {
trailing.add(ai);
}
}
});
AiToolResult result = AiToolExecutor.execute(spec, Map.of(), exchange);
assertThat(result).isInstanceOf(AiToolResult.AuthorizationDenied.class);
// the healthy @BeforeEach notifier still received the event despite the other one throwing
assertThat(events).hasSize(1);
// the trailing notifier (registered after the thrower) also received it — proving isolation
assertThat(trailing).hasSize(1);
}
```
##########
core/camel-support/src/main/java/org/apache/camel/support/EventHelper.java:
##########
@@ -1574,6 +1576,49 @@ public static boolean notifyExchangeAsyncProcessingStartedEvent(CamelContext con
return answer;
}
+ /**
+ * Notifies an {@link AiEvent} to the started event notifiers, following the same path as every other event
+ * category: it loops the started notifiers, skips those that are disabled or have {@code ignoreAiEvents} set,
+ * creates the event lazily (via {@code eventSupplier}) only when some notifier wants it, and delivers through
+ * {@code doNotifyEvent} so one failing notifier does not stop delivery to the others.
+ * <p>
+ * AI events are their own category: {@code ignoreExchangeEvents} does <em>not</em> suppress them even though an
+ * {@code AiEvent} is an exchange event. A notifier opts out with {@code setIgnoreAiEvents(true)}.
+ *
+ * @since 4.24
+ */
+ public static boolean notifyAiEvent(CamelContext context, Supplier<AiEvent> eventSupplier) {
+ ManagementStrategy management = context != null ? context.getManagementStrategy() : null;
+ if (management == null) {
+ return false;
+ }
+
+ List<EventNotifier> notifiers = management.getStartedEventNotifiers();
+ if (notifiers == null || notifiers.isEmpty()) {
+ return false;
+ }
+
+ boolean answer = false;
+ CamelEvent event = null;
+ // optimise for loop using index access to avoid creating iterator object
+ for (int i = 0; i < notifiers.size(); i++) {
+ EventNotifier notifier = notifiers.get(i);
+ if (notifier.isDisabled() || notifier.isIgnoreAiEvents()) {
+ continue;
+ }
+
+ if (event == null) {
+ // only create event once, and only when a notifier wants it
+ event = eventSupplier.get();
+ if (event == null) {
+ return false;
+ }
+ }
+ answer |= doNotifyEvent(notifier, event);
Review Comment:
💡 **Suggestion (nit):** `OpenTelemetryExchangeEventNotifier.isEnabled()` already filters to `ExchangeEvent` subclasses, so AI events won't reach its `notify()` regardless. Setting `ignoreAiEvents(true)` in its constructor would be a minor early-exit optimisation (skipping the `isEnabled()` call entirely), but it's not a correctness concern.
Worth considering in a follow-up once this API stabilises — no need to block this PR on it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246679311
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
Review Comment:
⚠️ **Inaccurate description of AiEvent:** `AiEvent` extends `CamelEvent` directly — it is **not** a `CamelEvent.ExchangeEvent`. Only the nested `AiEvent.ExchangeAiEvent` sub-interface extends `ExchangeEvent`.
This sentence currently reads:
> `org.apache.camel.ai.AiEvent` (a `CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`)
Suggested correction:
```suggestion
The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
`CamelEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
```
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
Review Comment:
⚠️ **Incorrect generalisation:** Not all AI events are `CamelEvent.ExchangeEvent` instances — only those implementing `AiEvent.ExchangeAiEvent`. The root `AiEvent` has no exchange. The current events in camel-openai and camel-ai-tool all happen to implement `ExchangeAiEvent`, but the paragraph should not state it as a universal rule.
```suggestion
Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and the exchange-bearing
ones now implement `AiEvent.ExchangeAiEvent` (which extends `CamelEvent.ExchangeEvent`). An `EventNotifier` that recognised these events by
```
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because an `AiEvent` is now a `CamelEvent.ExchangeEvent`, a notifier that filters on `instanceof ExchangeEvent`
Review Comment:
⚠️ **Stale statement:** `AiEvent` itself is not a `CamelEvent.ExchangeEvent` — `AiEvent` extends `CamelEvent` directly. This paragraph should refer to `AiEvent.ExchangeAiEvent` instead.
```suggestion
Because `AiEvent.ExchangeAiEvent` (the exchange-bearing AI event sub-interface) extends `CamelEvent.ExchangeEvent`, a notifier that filters on `instanceof ExchangeEvent`
```
##########
core/camel-api/src/main/java/org/apache/camel/spi/EventNotifier.java:
##########
@@ -133,6 +133,24 @@ public interface EventNotifier {
/** Set whether to ignore step events. */
void setIgnoreStepEvents(boolean ignoreStepEvents);
+ /**
+ * Whether to ignore AI events (see {@link org.apache.camel.ai.AiEvent}). AI events are their own category and are
+ * not affected by {@link #isIgnoreExchangeEvents()} even though an {@code AiEvent} is an exchange event.
Review Comment:
⚠️ **Stale Javadoc:** `AiEvent` is not an exchange event — `AiEvent` extends `CamelEvent` directly. Only `AiEvent.ExchangeAiEvent` extends `ExchangeEvent`. Since the existing AI event concrete classes all implement `ExchangeAiEvent`, the practical note about `ignoreExchangeEvents` not dropping AI events is valid, but the rationale should be precise.
```suggestion
* Whether to ignore AI events (see {@link org.apache.camel.ai.AiEvent}). AI events are their own category and are
* not affected by {@link #isIgnoreExchangeEvents()} even though exchange-bearing AI events
* ({@link org.apache.camel.ai.AiEvent.ExchangeAiEvent}) extend {@link org.apache.camel.spi.CamelEvent.ExchangeEvent}.
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246747321
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
Review Comment:
Already fixed — the root `AiEvent` class javadoc is `@since 4.24` as of the split commit 051b7b1739e4 (I rewrote the file there; 044b4b4c had only bumped the sub-interfaces). Confirmed on the current head.
_Claude Code on behalf of oscerd_
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because an `AiEvent` is now a `CamelEvent.ExchangeEvent`, a notifier that filters on `instanceof ExchangeEvent`
+now also receives AI events. AI events are their own category: a new `ignoreAiEvents` flag
+(`EventNotifier.setIgnoreAiEvents(boolean)`, default `false`) opts a notifier out, and `ignoreExchangeEvents` does
+**not** drop AI events (so an AI-observability notifier can keep `ignoreExchangeEvents=true` for performance). Camel's
+own exchange-oriented notifiers (the debugger, the dev-console event ring, the micrometer exchange notifier) set
+`ignoreAiEvents=true` so AI events do not reach them; a custom exchange-focused notifier that should not see AI events
+should do the same.
Review Comment:
Moot now — 051b7b1739e4 appends `Type.Ai` LAST in the enum, so no pre-existing ordinal (including `Custom`) shifts. No integer-serialisation note needed.
_Claude Code on behalf of oscerd_
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
Review Comment:
Fixed in 131b9fe60539 — the guide now describes `AiEvent` as a `CamelEvent` of `Type.Ai` (not an `ExchangeEvent`) and notes that exchange-related events implement the `AiEvent.ExchangeAiEvent` subtype.
_Claude Code on behalf of oscerd_
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
Review Comment:
Fixed in 131b9fe60539 — reworded to '`CamelEvent.ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`)', which refers to the four shipped events (they implement the subtype), not all AI events.
_Claude Code on behalf of oscerd_
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -0,0 +1,43 @@
+= Apache Camel 4.x Upgrade Guide
+
+This document is for helping you upgrade your Apache Camel application
+from Camel 4.x to 4.y. For example, if you are upgrading Camel 4.0 to 4.2, then you should follow the guides
+from both 4.0 to 4.1 and 4.1 to 4.2.
+
+[NOTE]
+====
+https://github.com/apache/camel-upgrade-recipes/[The Camel Upgrade Recipes project] provides automated assistance for some common migration tasks.
+Note that manual migration is still required.
+See the xref:camel-upgrade-recipes-tool.adoc[documentation] page for details.
+====
+
+== Upgrading Camel 4.23 to 4.24
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent.ExchangeEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent` instances. An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because an `AiEvent` is now a `CamelEvent.ExchangeEvent`, a notifier that filters on `instanceof ExchangeEvent`
Review Comment:
Fixed in 131b9fe60539 — now reads 'the shipped AI events are now `ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`)', not the root `AiEvent`.
_Claude Code on behalf of oscerd_
##########
core/camel-api/src/main/java/org/apache/camel/spi/EventNotifier.java:
##########
@@ -133,6 +133,24 @@ public interface EventNotifier {
/** Set whether to ignore step events. */
void setIgnoreStepEvents(boolean ignoreStepEvents);
+ /**
+ * Whether to ignore AI events (see {@link org.apache.camel.ai.AiEvent}). AI events are their own category and are
+ * not affected by {@link #isIgnoreExchangeEvents()} even though an {@code AiEvent} is an exchange event.
Review Comment:
Fixed in 131b9fe60539 — the javadoc now says the flag is unaffected by `isIgnoreExchangeEvents()` 'even for the exchange-backed `ExchangeAiEvent` subtype', instead of calling `AiEvent` an exchange event.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246562784
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
+ */
+public interface AiEvent extends CamelEvent.ExchangeEvent {
Review Comment:
Done in 051b7b1739e4 — `AiEvent` now extends `CamelEvent` (not `ExchangeEvent`), and the four tool/loop sub-interfaces sit on a new `AiEvent.ExchangeAiEvent extends AiEvent, CamelEvent.ExchangeEvent`; `AbstractOpenAIExchangeEvent` moved onto it, accessors unchanged. An Exchange-free `AiEvent` dispatches fine through `EventHelper.notifyAiEvent` (new test `dispatchesAnAiEventThatHasNoExchange`). Thanks for the Semantic pointer — this keeps `SemanticObserver` / `audit.begin(null, ...)` able to publish without a synthetic exchange.
_Claude Code on behalf of oscerd_
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
+ */
+public interface AiEvent extends CamelEvent.ExchangeEvent {
+
+ /**
+ * The AI provider the event originates from, e.g. {@code openai} or {@code ai-tool}. Intended as a low-cardinality
+ * label for metrics and spans.
Review Comment:
Applied — `getProvider()` now documents a stable integration/provider family (`openai`, `ai-tool`, `semantic`), explicitly not an expert instance, model revision, invocation id, or an inference indicator (051b7b1739e4).
_Claude Code on behalf of oscerd_
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
Review Comment:
Addressed two ways: (1) the root `AiEvent` no longer extends `ExchangeEvent` — only the new `ExchangeAiEvent` subtype does, which is what the four shipped events implement; (2) the notifiers that branch on `instanceof ExchangeEvent` — `EventConsole`, `DefaultDebugger`, `MicrometerExchangeEventNotifier` — now set `ignoreAiEvents(true)`, and AI events are fired via `EventHelper.notifyAiEvent` which skips them, so they no longer reach the console ring / debugger / per-event route lookup. `camel-event` gets a `case Ai`. The 4.24 upgrade guide documents the ExchangeEvent reach and the `ignoreAiEvents` opt-out.
_Claude Code on behalf of oscerd_
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
Review Comment:
Fixed — `@since 4.24` on `AiEvent` and all new types (044b4b4c29c6).
_Claude Code on behalf of oscerd_
##########
core/camel-api/src/main/java/org/apache/camel/spi/CamelEvent.java:
##########
@@ -81,6 +81,13 @@ enum Type {
StepStarted,
StepCompleted,
StepFailed,
+ /**
+ * Events fired by Camel AI components (tool calls, agentic loops, ...); see
+ * {@link org.apache.camel.ai.AiEvent}.
+ *
+ * @since 4.24
+ */
+ Ai,
Review Comment:
`Type.Ai` is now appended last in the enum (051b7b1739e4), so every pre-existing ordinal (including `Custom`) is unchanged. No ordinal shift, so no note needed for integer-serialised enums.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4246979766
##########
core/camel-support/src/main/java/org/apache/camel/support/EventHelper.java:
##########
@@ -1574,6 +1576,49 @@ public static boolean notifyExchangeAsyncProcessingStartedEvent(CamelContext con
return answer;
}
+ /**
+ * Notifies an {@link AiEvent} to the started event notifiers, following the same path as every other event
+ * category: it loops the started notifiers, skips those that are disabled or have {@code ignoreAiEvents} set,
+ * creates the event lazily (via {@code eventSupplier}) only when some notifier wants it, and delivers through
+ * {@code doNotifyEvent} so one failing notifier does not stop delivery to the others.
+ * <p>
+ * AI events are their own category: {@code ignoreExchangeEvents} does <em>not</em> suppress them even though an
+ * {@code AiEvent} is an exchange event. A notifier opts out with {@code setIgnoreAiEvents(true)}.
+ *
+ * @since 4.24
+ */
+ public static boolean notifyAiEvent(CamelContext context, Supplier<AiEvent> eventSupplier) {
+ ManagementStrategy management = context != null ? context.getManagementStrategy() : null;
+ if (management == null) {
+ return false;
+ }
+
+ List<EventNotifier> notifiers = management.getStartedEventNotifiers();
+ if (notifiers == null || notifiers.isEmpty()) {
+ return false;
+ }
+
+ boolean answer = false;
+ CamelEvent event = null;
+ // optimise for loop using index access to avoid creating iterator object
+ for (int i = 0; i < notifiers.size(); i++) {
+ EventNotifier notifier = notifiers.get(i);
+ if (notifier.isDisabled() || notifier.isIgnoreAiEvents()) {
Review Comment:
Done in 5287ecd38ebb — `notifyAiEvent` now wraps the whole per-notifier body (including the `isDisabled()` / `isIgnoreAiEvents()` eligibility checks) in a `try/catch(Throwable)` that logs and skips just that notifier, so a broken eligibility callback neither escapes (the `AuthorizationDenied` refusal is preserved) nor stops delivery to later notifiers — per-notifier, not an outer catch.
Note on the test: a notifier throwing from `isDisabled()` also breaks the generic lifecycle paths (e.g. context stop's `notifyCamelContextStopping`, which calls `isDisabled()` unguarded — a pre-existing pattern across all `EventHelper.notifyXxx`, out of this PR's scope). So the test exercises the AI eligibility guard via `isIgnoreAiEvents()` (only `notifyAiEvent` calls it) plus `isEnabled()`/`notify()` throwing.
_Claude Code on behalf of oscerd_
##########
components/camel-ai/camel-ai-tool/src/test/java/org/apache/camel/component/ai/tool/AiToolAuthorizationDeniedEventTest.java:
##########
@@ -199,6 +231,75 @@ public void notify(CamelEvent event) {
AiToolResult result = AiToolExecutor.execute(spec, Map.of(), exchange);
assertThat(result).isInstanceOf(AiToolResult.AuthorizationDenied.class);
+ // the healthy @BeforeEach notifier still received the event despite the other one throwing
+ assertThat(events).hasSize(1);
Review Comment:
Fixed in 5287ecd38ebb — a fresh healthy subscriber is now registered AFTER the failing notifiers and the test asserts THAT subscriber's own collection received the event, so it would fail if delivery aborted at the failing notifier. It covers `isIgnoreAiEvents()`, `isEnabled()` and `notify()` throwing (AI-scoped so teardown is unaffected), and keeps the `AuthorizationDenied` assertion.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd merged PR #27714:
URL: https://github.com/apache/camel/pull/27714
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4249464843
##########
docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc:
##########
@@ -27,3 +27,33 @@ A `hashicorp:` property with a field of a secret that does not exist, such as `{
now resolves to no value, as it already did without a field, so its default value or an optional placeholder
(`{{?hashicorp:secret:missing#field}}`) applies. Before, without a default value, it failed with a
`NullPointerException`.
+
+=== camel-openai, camel-ai-tool - AI events now use CamelEvent.Type.Ai
+
+The events fired by the AI components now share a common contract, `org.apache.camel.ai.AiEvent` (a
+`CamelEvent` of the new `CamelEvent.Type.Ai`), instead of each being a component-specific
+`CamelEvent.Type.Custom` event. Events that relate to a single exchange implement the exchange-backed subtype
+`AiEvent.ExchangeAiEvent` (the root `AiEvent` itself is not an `ExchangeEvent`). This lets an `EventNotifier` recognise AI activity — and route it to metrics or
+tracing — by type and by the `AiEvent` sub-interfaces, without depending on an AI component.
+
+The events shipped in 4.23.0 are affected:
+
+* `camel-ai-tool`: `AiToolAuthorizationDeniedEvent` now implements `AiEvent.ToolCallDeniedEvent`;
+* `camel-openai`: `OpenAIAgenticLoopStartedEvent`, `OpenAIAgenticToolCallExecutedEvent` and
+ `OpenAIAgenticLoopCompletedEvent` now implement `AiEvent.AgentLoopStartedEvent`, `AiEvent.ToolCallExecutedEvent`
+ and `AiEvent.AgentLoopCompletedEvent`.
+
+Their `getType()` now returns `CamelEvent.Type.Ai` rather than `CamelEvent.Type.Custom`, and they are now
+`CamelEvent.ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`). An `EventNotifier` that recognised these events by
+`event.getType() == CamelEvent.Type.Custom` must match on `CamelEvent.Type.Ai` instead, or — preferably —
+on `event instanceof org.apache.camel.ai.AiEvent` (or one of its sub-interfaces), which no longer requires a
+dependency on the AI component. The concrete event classes and all their accessors are unchanged, so code that
+references them directly is not affected.
+
+Because the shipped AI events are now `ExchangeEvent`s (via `AiEvent.ExchangeAiEvent`), a notifier that filters on
+`instanceof ExchangeEvent` now also receives them. AI events are their own category: a new `ignoreAiEvents` flag
+(`EventNotifier.setIgnoreAiEvents(boolean)`, default `false`) opts a notifier out, and `ignoreExchangeEvents` does
+**not** drop AI events (so an AI-observability notifier can keep `ignoreExchangeEvents=true` for performance). Camel's
+own exchange-oriented notifiers (the debugger, the dev-console event ring, the micrometer exchange notifier) set
+`ignoreAiEvents=true` so AI events do not reach them; a custom exchange-focused notifier that should not see AI events
Review Comment:
The last commit also opts out `OpenTelemetryExchangeEventNotifier`, so it belongs in this list:
```suggestion
own exchange-oriented notifiers (the debugger, the dev-console event ring, the micrometer and OpenTelemetry metrics
exchange notifiers) set `ignoreAiEvents=true` so AI events do not reach them; a custom exchange-focused notifier that
should not see AI events
```
##########
components/camel-event/src/main/java/org/apache/camel/component/camelevent/CamelEventConsumer.java:
##########
@@ -309,6 +310,10 @@ private void configureEventNotifier() {
// Custom events are CamelContextEvents, so we need to enable context events
eventNotifier.setIgnoreCamelContextEvents(false);
break;
+ case Ai:
Review Comment:
`event:Ai` works now, but `event-component.adoc` ("The following event types are available") doesn't list `Ai` yet. Could you add it there, perhaps in a short "AI Events" group, and regenerate the catalog copy?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "gnodet-bot (via GitHub)" <gi...@apache.org>.
gnodet-bot commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4248498975
##########
core/camel-management/src/main/java/org/apache/camel/management/mbean/ManagedEventNotifier.java:
##########
@@ -168,8 +168,8 @@ public MBeanNotificationInfo[] getNotificationInfo() {
// JmxNotificationEventNotifier uses the simple class name of the event as the notification type
List<MBeanNotificationInfo> infos = new ArrayList<>();
for (CamelEvent.Type type : CamelEvent.Type.values()) {
- if (type == CamelEvent.Type.Custom) {
- // custom events have their own class names
+ if (type == CamelEvent.Type.Custom || type == CamelEvent.Type.Ai) {
Review Comment:
💡 **`ManagedEventNotifierMBean` is missing `isIgnoreAiEvents`/`setIgnoreAiEvents`**
`ManagedEventNotifier` correctly skips `Type.Ai` in `getNotificationInfo()` here, but `ManagedEventNotifierMBean` (the JMX interface) was not updated: it still ends at `setIgnoreStepEvents(boolean)` without declaring the new `ignoreAiEvents` attribute. JMX introspection exposes only what the MBean interface declares, so the attribute won't be visible or settable via JConsole/Hawtio — unlike every other `ignore*` flag which IS declared in that interface.
```suggestion
if (type == CamelEvent.Type.Custom || type == CamelEvent.Type.Ai) {
```
Fix: add to `ManagedEventNotifierMBean`:
```java
boolean isIgnoreAiEvents();
void setIgnoreAiEvents(boolean ignoreAiEvents);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "davsclaus (via GitHub)" <gi...@apache.org>.
davsclaus commented on code in PR #27714:
URL: https://github.com/apache/camel/pull/27714#discussion_r4245974549
##########
core/camel-api/src/main/java/org/apache/camel/ai/AiEvent.java:
##########
@@ -0,0 +1,110 @@
+/*
+ * 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.ai;
+
+import org.apache.camel.spi.CamelEvent;
+import org.jspecify.annotations.Nullable;
+
+/**
+ * Common contract for events fired by Camel AI components (tool calls, agentic loops, ...).
+ * <p>
+ * An {@code AiEvent} is a {@link CamelEvent.ExchangeEvent} of {@link CamelEvent.Type#Ai}: it carries the exchange it
+ * relates to (so it can be correlated by route id or exchange id) and is typed {@code Ai} rather than {@code Custom},
+ * so an {@link org.apache.camel.spi.EventNotifier} can recognise AI activity — and route it to metrics, tracing or a
+ * GenAI-observability backend — by type and by these sub-interfaces, without depending on any AI component or doing an
+ * {@code instanceof} against each component's own event class.
+ * <p>
+ * Concrete event classes live in the AI components (they implement these interfaces); the only thing shared across
+ * components is this contract.
+ *
+ * @since 4.23
Review Comment:
New in 4.24 like the rest of the PR:
```suggestion
* @since 4.24
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
Re: [PR] CAMEL-25408: camel-api, camel-openai, camel-ai-tool - a common AiEvent API and an Ai event type [camel]
Posted by "oscerd (via GitHub)" <gi...@apache.org>.
oscerd commented on PR #27714:
URL: https://github.com/apache/camel/pull/27714#issuecomment-6121447363
Thanks @davsclaus — all addressed in b9da6729b4ff. You were right that the direct `ManagementStrategy.notify()` was the reason `ignoreAiEvents` had no effect; I've moved AI events onto the normal path.
- **`EventHelper.notifyAiEvent(CamelContext, Supplier<AiEvent>)`** — loops `getStartedEventNotifiers()`, skips `isDisabled()` / `isIgnoreAiEvents()`, creates the event lazily (only when a notifier wants it), and delivers via `doNotifyEvent` (a failing notifier no longer stops the others). Both `camel-openai` (`OpenAIAgenticObservability`) and `camel-ai-tool` (`AiToolExecutor`) call it now, and their hand-written try/catch is gone.
- **`isIgnoreAiEvents()` / `setIgnoreAiEvents()`** — default methods on `EventNotifier` (so third-party implementations keep compiling) and real impls on `EventNotifierSupport`.
- **AI is its own category** — `notifyAiEvent` checks only `isIgnoreAiEvents()`, not `ignoreExchangeEvents`, so `ignoreExchangeEvents=true` does **not** drop AI events (an AI-observability notifier can keep it for performance).
- **Opt-outs** — `DebugEventNotifier`, `ConsoleEventNotifier` and `MicrometerExchangeEventNotifier` set `ignoreAiEvents(true)` so AI events don't reach the debugger / the exchange-event ring / the per-event route lookup. `camel-event`'s type switch gets a `case Ai` that turns the flag off when `Ai` is subscribed.
- **Tests** — `ignoreAiEvents` is honored (an ignoring notifier receives nothing while the default one does), and a notifier recognises the events via `instanceof AiEvent.ToolCallDeniedEvent` / `AiEvent.ToolCallExecutedEvent` reading `getProvider()`.
- **@since 4.24** on all new types (inline fixed); the **upgrade guide** now also notes that AI events reach `instanceof ExchangeEvent` notifiers and that `ignoreAiEvents` opts out. Milestone/`fixVersion` 4.24.0.
Full reactor BUILD SUCCESS; ai-tool (6) and openai (2+7) event tests green. Re-requesting your review.
_Claude Code on behalf of oscerd_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: commits-unsubscribe@camel.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org