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: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to